Not Standard Input behavior?

I’m trying to automate something with a browser extension, and I’m facing a problem with an input.

The thing is, I can’t set that specific input value to anything from the extension. If I do it manually from the console it works.
Setting the value does not work.
Using events does not work.
.click and .focus do not work, the value I set appears in the ui but the .value property is still "" and after a few seconds it disappears.
I found a thread on reddit describing the same problem a year ago but it does not provide a solution.

Any idea of what else can I do?

How do I retrieve a list of Facebook Business Pages?

I am trying to retrieve a list of all pages (business and non-business) that the account has, but only non-business pages get returned.

First I allow the user to login. He/she gets a Facebook Login popup, where he/she can select the pages.
Then I generate a long lived token, like so:

const response = await axios.get(
  "https://graph.facebook.com/v21.0/oauth/access_token",
  {
    params: {
      grant_type: "fb_exchange_token",
      client_id: process.env.FB_APP_ID,
      client_secret: process.env.FB_APP_SECRET,
      fb_exchange_token: fbAccessToken,
    },
  }
);

I get a token just fine. I return the token and the client makes an api call to retrieve the pages:

const handleFacebookCallback = async (response: any) => {
  if (!response?.id) {
    return;
  }
  setLoading(true);
  const { data } = await api.post("/api/integrations/facebook/user", {
    userId: user._id,
    fbAccessToken: response.accessToken,
    fbUserId: response.id,
  });
  const url = `https://graph.facebook.com/v21.0/${response.id}/accounts?access_token=${data.longLivedToken}`;

  const fbResponse = await fetch(url);
  const fbData = await fbResponse.json();
  setResponseFbPages(fbData.data);
  setLoading(false);
};

Now, I have 3 pages – 2 are business and 1 non-business. Only the latter gets returned.

I tried to query the /accounts endpoint, and I am expecting to get a full list of pages returned.

Custom tag names in Remark Plugin

I’m trying to modify specific emphases nodes and turn them to badges.
(I want to replace the node’s tag with a custom Material Web element tag)!

I tried to set the type of the node to element in order to set a custom tagName value, but this only results in a div element being inserted into the page, instead of my desired element! (in my code, the desired element is md-assist-chip)

Any idea how to fix this?

code:

/**
 * 
 * This transformer adds badges to documentation
 *
 * See: https://github.com/syntax-tree/mdast-util-to-hast
 * 
**/


// Update nodes!
// (This is the part that is not working properly)
const updateNode = (node, name, description, href, classNames = []) => {
    // Change tag name to "md-assist-chip"
    node.type = 'element';
    node.tagName = 'md-assist-chip';
    // ^^ For some reason, this doesn't work! ^^
    // It only renames the element's tag to "div" (this is caused by setting the type to 'element')

    // Update node data
    node.data = {
        hProperties: {
            label: name,
            title: description,
            href,
            className: ['badge-chip', ...classNames],
            "data-role": "presentation",
            tabindex: "-1"
        }
    };
    node.children[0].value = name;
};

// You can ignore the rest of this code, but I included it here in case you needed to check the way I call this function!


import { visitParents } from 'unist-util-visit-parents';

export default function attacher() {
    return transformer;
}

const BADGES = [
    'omni!js',
    'omni!cpp',
    'omni!java'
];
const BADGES_INFO = [
    {
        name: 'JS',
        href: ''
    },
    {
        name: 'C++',
        href: ''
    },
    {
        name: 'Java',
        href: ''
    }
];
const DEPRECATED = 'deprecated';
const EXPERIMENTAL = 'experimental';
const CAREFUL_USE = 'careful';

function transformer(tree) {
    visitParents(tree, 'emphasis', visitor);
}

function visitor(node) {
    if (node.children.length === 1 && (node.children[0]).type === 'text') {
        const tag = node.children[0].value.toLowerCase();
        if (BADGES.includes(tag)) {
            // Get info
            const i = BADGES.indexOf(tag);
            const info = BADGES_INFO[i];
            const name = info.name;
            const href = info.href;
            updateNode(
                node,
                name,
                'Supported target language',
                href,
                ['badge-chip--lang']
            );
        } else if (tag === DEPRECATED) {
            updateNode(
                node,
                'Deprecated',
                'Deprecated feature (may be removed in the feature)',
                "/",
                ['badge-chip--deprecated']
            );
        } else if (tag === EXPERIMENTAL) {
            updateNode(
                node,
                'Experimental',
                'Experimental feature (may change in the feature)',
                "/",
                ['badge-chip--experimental']
            );
        } else if (tag === CAREFUL_USE) {
            updateNode(
                node,
                'Careful',
                'Careful use advised!',
                "/",
                ['badge-chip--careful']
            );
        }
    }
}

The current final output:

enter image description here

If you want to test this, you can download this repository and try to start the Docusaurus project on localhost, and visit the page ://localhost:3000/docs/old/intro

Unpopulate input field of certian value when box is unchecked

Context:

Adds values to input field:

 $('input:checkbox').change((e) => {
     if ($(e.currentTarget).is(':checked')) {
         var curVal = $('#name').val();
         if (curVal) {
             $('#name').val(curVal + ', ' + e.currentTarget.value);
         } else {

             $('#name').val(e.currentTarget.value);
         }
     } else if (!($(e.currentTarget).is(':checked'))) {
         var curVal = $('#name').val().split(',');
         var filteredVal = curVal.filter(el => el.trim() !== e.currentTarget.value)
         $('#name').val(filteredVal.join(','));
     }
 });

Removes Checkboxes from HTML table:

 const checkboxes = document.querySelectorAll('input[type=checkbox]:checked');
 if (checkboxes.length >= 2) {
     checkboxes[1].checked = false;
     
 }

Problem: When the second box that is checked unchecked, the value is still present in input field. I want the value removed. Can some help me modify the code or find a solution to my problem? I tried everything I could think of and it is not working. Note: Names in input field in photo are fictional.
Pictures:
Input field:
enter image description here

Table:

enter image description here

What I tried was Researching online and trying different things that I found and modifying it to where it fits my project. What I expected to happen was second value in input field gets removed. What really happened is that the second value did not get removed

Update variable within if

I have an array of 6 JSON objects from where I get each value to name and type in a loop. No problems with that. But I have created a variable named title and I want to change the value of that variable. The title’s value is depending on the type value which I get from JSON. The values for the title should be ‘SinglePost’ (if type value is post), ‘SinglePage’ (if type value is page) or ‘SingleMovie’ (if type value is movies).

I want to write the values for “name” and “type” from every objects plus my title value, in 6 lines I want this:
Name value – Type value – title value
So for the first object it should be “Item 1 – page – SinglePage”. I can get name and type from JSON but the problem is that the title variable doesn’t update it’s value. I get
the last title value (SingleMovie) every time.


[
{
"name":"Item 1",
"href":"http://localhost/Wordpress/",
"id":"23",
"type":"page"
},
{"name":"Item 2",
"href":"http://localhost/Wordpress/item-2",
"id":"2",
"type":"page"
},
{"name":"Item 3",
"href":"http://localhost/Wordpress/item-3",
"id":"10",
"type":"page"
},
{"name":"Item 4",
"href":"http://localhost/Wordpress/item-4",
"id":"12",
"type":"page"
},
{"name":"Item 5",
"href":"http://localhost/Wordpress/item-5",
"id":"1",
"type":"post"
},
{"name":"Item 6",
"href":"http://localhost/Wordpress/item-6",
"id":"54",
"type":"movies"
}
]
<p v-for="item in newComp" :key="item.id">{{ item.name + " - " + item.type + " - " + this.title }}</p>

export default {
    data() {
      let title = '';
        return {
            posts: [],
            title:'',
        }
    },
    mounted() {
        fetch('http://localhost/Wordpress/wp-json/wp/v2/test') 
        .then(res => res.json())
        .then(data => this.posts = data)
        .then(err => console.log(err)) 
    },
    computed: {
      newComp() {
        const posts = this.posts;
       
        if(posts.filter(item => item.type === 'post'))
        {
          this.title = 'SinglePost';
        }
        if(posts.filter(item => item.type === 'page'))
        {
          this.title = 'SinglePage';
        }
        if(posts.filter(item => item.type === 'movies'))
        {
          this.title = 'SingleMovie';
      }
        return posts  
    }
    },
}

Huge gap at the bottom of the webiste

Here is my website: https://enmasantos.github.io/vitality_vista, for a personal project I am making, on below the footer there is a huge white space. And I have checked margin both for the footer and surrounding elements.
Here is the code I am using for the footer:

/* footer.css */

.footer {
    color: #ffffff;
    padding: 1.5rem 0;
    text-align: center;
    transition: background-color 0.3s ease; /* Smooth transition for dynamic color change */
    height: 16%;
    border: 15px solid red;
}

.social-icons a img {
    width: 24px;
    height: 24px;
    transition: transform 0.3s ease, fill 0.3s ease; /* Smooth color and scale transition */
}

.social-icons a img:hover {
    transform: scale(1.1);
}

.footer-bottom p {
    font-size: 0.875rem;
    margin: 0;
    color: #f1f1f1;
}

here are my general style, but don’t know if they have any relationship with what’s going on:

/* global.css */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
/* Root Variables for Color Palette and Fonts */
:root {
  --fandango: #a4036f;
  --bittersweet: #ff595e;
  --sunglow: #ffca3a;
  --yellow-green: #8ac926;
  --steel-blue: #1982c4;
  --text-color: #333;
  --background-color: #f9f9f9;
  --font-family: 'Arial', sans-serif;
  --font-size-base: 16px;
}

/* General Reset */
body {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  
}

body {
  font-family: var(--font-family);
  font-size: var(--font-size-base);
  color: var(--text-color);
  background-color: var(--background-color);
  line-height: 1.6;
}

/* Headings */
h1, h2, h3, h4, h5, h6 {
  color: var(--fandango);
  margin-bottom: 0.5em;
  font-weight: bold;
}

h1 {
  font-size: 2rem;
}

h2 {
  font-size: 1.75rem;
}

h3 {
  font-size: 1.5rem;
}

/* Paragraphs */
p {
  
  color: var(--text-color);
}

/* Links */
a {
  color: var(--steel-blue);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* Buttons */
button {
  font-family: var(--font-family);
  padding: 10px 20px;
  border-radius: 5px;
  border: none;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

button:hover {
  opacity: 0.9;
}

/* Container Layout */
.container {
  width: 90%;
  max-width: 100%;
  margin: 0 auto;
}

/* Utility Classes */
.text-center {
  text-align: center;
}

.mt-2 {
  margin-top: 1rem;
}

.mb-2 {
  margin-bottom: 1rem;
}

/* Dashboard Container */
.dashboard-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); /* Responsive card size */
  gap: 1.25rem;
  padding: 2rem;
}

/* Card Styles */
.dashboard-card {
  background-color: #ffffff;
  padding: 1rem;
  border-radius: 0.625rem;
  box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.1);
  transition: transform 0.2s ease;
}

.dashboard-card:hover {
  transform: translateY(-0.3125rem);
}

.dashboard-card h3 {
  color: var(--fandango);
  font-size: 1.2rem;
  margin-bottom: 0.625rem;
}

.dashboard-card p {
  color: #333;
  margin-bottom: 0.625rem;
  font-size: 1rem;
}

.dashboard-card button {
  padding: 0.625rem 1.25rem; /* Spacing is now based on rem */
  border: none;
  border-radius: 0.3125rem;
  background-color: var(--bittersweet);
  color: #ffffff;
  cursor: pointer;
  font-size: 1rem;
  transition: background-color 0.3s ease;
}

.dashboard-card button:hover {
  background-color: var(--sunglow);
}

body, main {
  overflow-x: hidden;
}

Cookies not being set in browser

I’m making a simple express.js aplication, it has a login form that sends a request, and if authenticated redirects to a page in the frontend and attaches a JWT token to the website’s cookies. The JWT token is being generated, the user is being redirected, but no token is being set.

Here’s the server.js:

app.use(cookieParser());

const allowedOrigins = ['http://127.0.0.1:5501', 'http://127.0.0.1:5500']; // Live server ports

app.use(cors({
    origin: allowedOrigins,
    credentials: true // Permite envio de cookies e outras credenciais
}));

dotenv.config()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

Here’s the login route:

router.post('/', (req, res) => {
    console.log('nnn-----------------------/LOGIN/--------------------------');
    const { login, senha } = req.body;

    try {
        const users = ler_dbJSON();
        const conta = users.filter(user => user.senha === senha && user.login === login);

        if (conta.length > 0) {
            const contaVerificada = conta[0]
            const secret = process.env.SECRET;
            const token = jwt.sign({ id: contaVerificada.id }, secret, { expiresIn: "7d" });

            console.log("Token: ", token)
            res.cookie("token", token, {
                httpOnly: true,
                sameSite: 'lax',
                secure: true
            });

            const responseUrl = contaVerificada.adm === true ? "page1.html" : `pages2.html`;
            console.log('-----------------------/LOGIN/--------------------------nnn');
            return res.status(200).json({ url: responseUrl });

        } else {
            return res.status(401).json({ msg: "Login ou senha incorretos." });
        }
    } catch (err) {
        return res.status(500).json({ msg: "Ocorreu um erro ao carregar o banco de dados", erro: err.message });
    }
});

Finaly, the request in the front end

axios.post(api_url, {
        login: login,
        senha: senha
    }, { withCredentials: true }

I’ve used postman to test the route, it’s working perfectly. In the frontend it’s parcially working, i’m being redirected as expected to the correct pages, but no cookies are present (tested it by inspecting the page, and using console.log(), both showed a page with no cookies.)

Articulate 360 Storyline Text Variables Javascript Execution

I am creating a storyline 360 slide trigger that executes Javascript when the timeline starts. The code is supposed to take created project text variables in storyline and replace their default values with specific messages based on what the slide number is.

In preview, the console provides the following message:

bootstrapper.min.js:2 actionator::exeJavaScript – Script1 is not defined

Here is the code placed into the Execute Javascript trigger:

function setTexts(SlideNumber) {
    console.log("setTexts function called with slideNumber: " + slideNumber); // Log the function call

    var correctTexts = [
        "This is a credit card statement with the amount of money that student owes.",
        "This document is intended to give a record of purchases and payments. It gives the card holder a summary of how much the card has been used during the billing period, as well as the amount that is due for that billing cycle."
    ];

    var incorrectPromptTexts = [
        "Here's a hint, there are dollar amounts on there and itemized activity, what type of document best fit these?",
        "Think about why you would need a statement for bills, please try again."
    ];

    var studentUnderstandTexts = [
        "Got it!  I always get these confused with my car insurance for some reason.",
        "Yes now that I think about it, having an itemized record is very helpful, even if it's quite annoying to always get these in the mail."
    ];

    var positiveFeedbackTexts = [
        "_user_ you answered correctly! Awesome job!",
        "_user_ you got the question correct!",
        "_user_ you answered correctly awesome job!",
        "_user_! You answered correctly!",
        "_user_! You answered the question right!",
        "_user_, You answered right!",
        "_user_, You answered the question right!",
        "_user_, you answered correctly! Keep it up!",
        "_user_, You answered the question right! Keep up the great work",
        "_user_ you are doing great! Keep it up!"
    ];

    var negativeFeedbackTexts = [
        "_user_, sorry. the answer you gave wasn't what I was looking for.",
        "_user_, your answer was not quite right.",
        "_user_, It looks like you picked the wrong answer.",
        "_user_, I'm afraid the answer you chose wasn't the best one."
    ];

    var player = GetPlayer();

    // Log the text being set for each variable
    var correctText = correctTexts[slideNumber - 1];
    console.log("Setting Correct to: " + correctText);
    player.SetVar("Correct", correctText);

    var incorrectPromptText = incorrectPromptTexts[slideNumber - 1];
    console.log("Setting IncorrectPrompt to: " + incorrectPromptText);
    player.SetVar("IncorrectPrompt", incorrectPromptText);

    var studentUnderstandText = studentUnderstandTexts[slideNumber - 1];
    console.log("Setting StudentUnderstand to: " + studentUnderstandText);
    player.SetVar("StudentUnderstand", studentUnderstandText);

    // Randomly select positive and negative feedback
    var randomPositiveFeedback = positiveFeedbackTexts[Math.floor(Math.random() * positiveFeedbackTexts.length)];
    var randomNegativeFeedback = negativeFeedbackTexts[Math.floor(Math.random() * negativeFeedbackTexts.length)];

    console.log("Setting PositiveFeedbacktoUser to: " + randomPositiveFeedback);
    player.SetVar("PositiveFeedbacktoUser", randomPositiveFeedback);

    console.log("Setting NegativeFeedbacktoUser to: " + randomNegativeFeedback);
    player.SetVar("NegativeFeedbacktoUser", randomNegativeFeedback);
}

Why do only some operations effect the origional array? JavaScrpt

I do understand there are other ways of doing this, so I don’t need a different solution, I just want to understand why this happens!

While working on something else I came across an issue addressing arrays from a function which I don’t understand, so I made a simple version to look at the issue.

const origionalArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

const removeElementByIndex = function(ind, arr) {
  let j = 0, tmpArr = [];
  for (let i=0; i<arr.length; i++) {
    if (i !== ind) {
      tmpArr[j] = arr[i];
      j++;
    };
  };
  
  arr.splice(0, arr.length);
  console.log(origionalArray, arr,  tmpArr);
  arr = [...tmpArr];
  console.log(origionalArray, arr, tmpArr);
};

removeElementByIndex(4, origionalArray);

As you can see the funciton takes two arguments, the name of the array and the index of an element to be removed. (Yes, I do know arrayName.splice(index, 1); will achieve the same result) puts the elements that should remain in the origional array into a temp array, clears the origional array, then attempts to populate the origional array with the values from the temp array:

And here is the problem I don’t understand.

arr.splice(0, arr.length); does clear the array (both arr withing function and origioanlArray
but
arr = [...tmpArr]; ONLY populates arr within the function! origionalArray is uneffected

why is one line effecting the origionalArray and another not?

It obviously isn’t a scope issue and using splice alone in the fuction instead does work, and that is probably why I am confused.

const origionalArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

const removeElementByIndex = function(ind, arr) {
  arr.splice(ind, 1);
};

removeElementByIndex(4, origionalArray);
console.log(origionalArray);

I do have ways around the problem as I said, but I was expecting origionalArray to be populated and don’t undestandy why it isn’t occurring.

401 Unauthorized Error When Fetching User Profile in React, Despite Valid Token

I have a React application where I fetch user profiles from my backend API. It was working fine before, but now I keep getting a 401 Unauthorized error when I attempt to fetch the user profile, even though I’m certain that the token is valid.

Here’s my relevant code:

ProfilePage.jsx:

import { useEffect, useRef, useState } from "react";
import { Link, useParams, useNavigate } from "react-router-dom";
import Posts from "../../components/common/Posts";
import ProfileHeaderSkeleton from "../../components/skeletons/ProfileHeaderSkeleton";
import EditProfileModal from "./EditProfileModal";
import { useQuery } from "@tanstack/react-query";
import useFollow from "../../hooks/useFollow";
import useUpdateUserProfile from "../../hooks/useUpdateUserProfile";

const ProfilePage = () => {
    const [feedType, setFeedType] = useState("posts");
    const { username } = useParams();
    const navigate = useNavigate();
    const { follow, isPending } = useFollow();
    const { data: authUser } = useQuery({ queryKey: ["authUser"] });
    const token = localStorage.getItem('token');

    const { data: userProfile, isLoading, refetch, error } = useQuery({
        queryKey: ["userProfile", username],
        queryFn: async () => {
            const res = await fetch(`http://127.0.0.1:8000/profile/${username}/`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'Content-Type': 'application/json',
                },
            });

            if (!res.ok) {
                const responseText = await res.text();
                console.error("Error response:", responseText);
                throw new Error(responseText || "Something went wrong");
            }
            return await res.json();
        },
    });

    useEffect(() => {
        if (!authUser) {
            navigate('/login');
        } else {
            refetch();
        }
    }, [authUser, navigate, refetch]);

    // ...rest of the component code
};

export default ProfilePage;

Console Log Output:

When I try to fetch the user profile, I see this in the console:

Error response: {"error":"Unauthorized"}

Notes:

  • The token is stored in local storage and is retrieved correctly.
  • The API works when accessed directly via the browser.
  • CORS settings on the backend are correctly configured.

Questions:

  • What could be causing the 401 Unauthorized error despite using a valid token?
  • Are there any specific troubleshooting steps I should follow to resolve this issue?
  • Is there a chance that the token could be expired or invalid without any indication?

Any assistance would be greatly appreciated!

Not showing the products initial – JavaScript

I have a HTLM, CSS and JavaScript files, I’m try to create a product browser there three categories of products(Electonics, Clothing, Books) and I want to create a Wishlist where the user can add the products in whisklist.

I’m facing the problem when I run the HTML file I’m not showing the products but then I click the button on anyone from the category then I’m showing that category product but I want to show initial three products when I run the HTML file but I’m facing the problems at that stage.

HTML code


<body>
    <h1>Product Browser </h1>

    <div id="categories">
        <button onclick="filterProducts('electronics')">Electronics</button>
        <button onclick="filterProducts('clothing')">Clothing</button>
        <button onclick="filterProducts('books')">Books</button>
    </div>


    <div id="product-list">
    </div>

    <div id="wishlist">
        <h2>Wishlist</h2>
        <div id="wishlist-items"></div>
        <p id="wishlist-summary"></p>
        <button onclick="clearWishlist()">Clear Wishlist</button>
    </div>

    <script src="LabExamScript.js"></script>

JAVASCRIPT code

const products = [
    { id: 1, name: "Smartphone", category: "electronics", image: "https://via.placeholder.com/150" },
    { id: 2, name: "Jeans", category: "clothing", image: "https://via.placeholder.com/150" },
    { id: 3, name: "Magazine", category: "books", image: "https://via.placeholder.com/150" }
];




let whishlist = []


function filterProducts(category) {
    const productList = document.getElementById("product-list");
    productList.innerHTML = ""; // Clear previous content

    // Filter products by category and display them
    const filteredProducts = products.filter(product => product.category === category);
    filteredProducts.forEach(product => {
        const productCard = document.createElement("div");
        productCard.classList.add("product-card");

        productCard.innerHTML = `
            <img src="${product.image}" alt="${product.name}">
            <h2>${product.name}</h2>
            <button onclick="addToWishlist(${product.id})">Add to Wishlist</button>
        `;
        
        productList.appendChild(productCard);
    });
}

Outputs

Initial Output

enter image description here

when I clicked any product button

enter image description here

(Un)zooming a canvas is not precise

When I zoom a canvas, usually multiple times, then unzoom the same number of times, the canvas doesn’t unzoom the same. Below are the results of 1 zoom in and 1 out. You see the image never goes back to exactly the original size.

This shows what the problem is. I do not think it’s a bug, just unexpected behavior.

console.log(bgImageCanvas.width); // original size: 300
 console.log(bgImageCanvas.width*1.1); // zoom in: 330
 console.log(bgImageCanvas.width*.9); // zoom out: 270` needs to be 300

Here’s my zoom function:

function zoomBgImage(callBtn) {
  let tempCanvas = createTmpCanvas(bgImageCanvas.width, bgImageCanvas.height);
  let tctx = tempCanvas.getContext("2d")
  let zoomAmount, newZoom;
  
  tctx.drawImage(bgImageCanvas, 0, 0);
  bgImagectx.clearRect(0, 0, bgImageCanvas.width, bgImageCanvas.height);
  bgImagectx.save();

  if (callBtn == "zoomIn") {
    zoomAmount = zoomInAmount;
    newZoom = currentZoom + zoomIncrement;
  } else {
    zoomAmount = zoomOutAmount;
    newZoom = currentZoom - zoomIncrement;
  }

  bgImageCanvas.width = bgImageCanvas.width * zoomAmount;
  bgImageCanvas.height = bgImageCanvas.height * zoomAmount;
  bgImagectx.scale(newZoom, newZoom);
  bgImagectx.translate(panX, panY);
  bgImagectx.drawImage(tempCanvas, 0, 0);
  bgImagectx.restore();
}

Cloud Function deploy error in Flutter (JavaScript)

I want to send a welcome email to the user when logging in to Google using Cloud Functions in Flutter Web, and save the user information to FireStore. I want to create a separate admin and project in the future to manage it directly. Currently, Google login is possible, but Cloud Function deployment is not possible. Below is the Cloud Function code written in JS.

Please let me know what the problem is.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');

admin.initializeApp();

const transporter = nodemailer.createTransport({
  host: 'smtp.gmail.com',
  port: 465,
  secure: true,
  auth: {
    user: "[email protected]",
    pass: "myPW",
  }
});

exports.onUserCreated = functions.auth.user().onCreate(async (user) => {
  try {
    console.log('User object:', user);
    
    if (!user) {
      console.error('User object is undefined');
      return;
    }

    
    await admin.firestore().collection('auth_users').doc(user.uid).set({
      email: user.email || '',
      displayName: user.displayName || '',
      photoURL: user.photoURL || '',
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
      lastLoginAt: admin.firestore.FieldValue.serverTimestamp()
    });

    
    const mailOptions = {
      from: '[email protected]',
      to: user.email,
      subject: 'welcome!',
      text: `Hi, ${user.displayName || ''},`
    };

    await transporter.sendMail(mailOptions);
    console.log('Welcome email sent to:', user.email);

  } catch (error) {
    console.error('Error in onUserCreated:', error);
  }
});

Below is the error message

TypeError: Cannot read properties of undefined (reading 'user')
    at Object.<anonymous> (/Users/myproject/Documents/project/test002/functions/index.js:18:40)
    at Module._compile (node:internal/modules/cjs/loader:1364:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1422:10)
    at Module.load (node:internal/modules/cjs/loader:1203:32)
    at Module._load (node:internal/modules/cjs/loader:1019:12)
    at Module.require (node:internal/modules/cjs/loader:1231:19)
    at require (node:internal/modules/helpers:177:18)
    at loadModule (/Users/myproject/Documents/project/test002/functions/node_modules/firebase-functions/lib/runtime/loader.js:40:16)
    at loadStack (/Users/myproject/Documents/project/test002/functions/node_modules/firebase-functions/lib/runtime/loader.js:157:23)
    at /Users/myproject/Documents/project/test002/functions/node_modules/firebase-functions/lib/bin/firebase-functions.js:56:56


Error: Functions codebase could not be analyzed successfully. It may have a syntax or runtime error

And I would also appreciate it if you could let me know if coding cloud functions in Python would result in fewer errors.