WordPress: How to prevent the function in one plugin used by another?

I create WordPress Plugin A with button whose id is ‘convert-button’ and there is a JS function like below:

$(‘#convert-button’).on(‘click’, function() {

However, in Plugin B, there is also a button with id ‘convert-button’, and it also has a function like below:

$(‘#convert-button’).on(‘click’, function() {

Now the problem is when I click the “convert” button in Plugin A, both onclick functions in two plugins will be called. How to prevent this? One way is to rename the id of the button, but there are many such buttons and it is time-consuming to rename all of them. Is there better solution for such a case?

What is the best scalable way to implement a ContextProvider to fetch and filter data

I have been working on a project that requires fetching a bunch of data and provides multiple ways to filter/search the data, and I though about keeping filtering on the server-side considering I’ll be using pagination.

I started using React Context recently and tried an approach that didn’t work.

here’s the custom React hook I’m using to fetch data

import { useState, useEffect } from 'react';

const useFetch = (url, url_params) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [refresh, setRefresh] = useState(0);

    if (url_params) {
        url = url + '?' + url_params.toString();
    }

    const refreshData = () => {
        setRefresh((prev) => prev + 1);
    }

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const result = await response.json();
                setData(result);
            } catch (error) {
                setError(error);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, [refresh, url]);

    return { data, loading, error, refreshData };
};

export default useFetch;

and here is the contextProvider:

import { createContext, useState, useEffect, useContext } from "react";
import { listing_url } from "../../Hooks/api_endpoints";
import useFetch from "../../Hooks/useFetch";
import { useSearchParams } from "react-router-dom";

export const HouseContext = createContext();

export const HouseProvider = ({ children }) => {
    const [selectedHouse, setSelectedHouse] = useState(null);
    // I have tried multiple approaches for searchParams (one is search params and the other is testParams
    const [searchParams, setSearchparams] = useState({
        address__icontains: '',
        apartment_no__icontains: '',
        block__iexact: '',
        currency__iexact: '',
        floor__iexact: '',
        gross__gte: '',
        gross__lte: '',
        net__gte: '',
        net__lte: '',
        num_of_floors__iexact: '',
        num_of_rooms__iexact: '',
        owner__icontains: '',
        owner_phone_num__icontains: '',
        price__gte: '',
        price__lte: '',
        status__iexact: '',
        view__icontains: '',
    });

    // second attempt at implementing searchParams
    const testParams = new URLSearchParams({
        address__icontains: '',
        apartment_no__icontains: '',
        block__iexact: '',
        currency__iexact: '',
        floor__iexact: '',
        gross__gte: '',
        gross__lte: '',
        net__gte: '',
        net__lte: '',
        num_of_floors__iexact: '',
        num_of_rooms__iexact: '',
        owner__icontains: '',
        owner_phone_num__icontains: '',
        price__gte: '',
        price__lte: '',
        status__iexact: '',
        view__icontains: '',
    });

    const { data: houses, error: housesError, loading: housesLoading, refreshData: houseRefresh } = useFetch(listing_url, testParams);

    const createHouse = async (house) => {

        const newHouse = await fetch(listing_url, {
            method: "POST",
            body: JSON.stringify(houseData),
        });
        setHouses([...houses, newHouse]);
    }

    // useEffect(() => {
    //     console.log("houses were updated")
    //     console.log(' search params were updated')
    // }, [houses, testParams])

    const updateSearchParams = (key, value) => {
        console.log("firing updateSearchParams")
        houseRefresh();
        testParams.set(key, value);
    }

    return (
        <HouseContext.Provider value={{ houses, selectedHouse, housesError, housesLoading, setSelectedHouse, createHouse, testParams, updateSearchParams }}>
            {children}
        </HouseContext.Provider>
    )
}

and here’s how I tried to use the filtering options in my Homepage:

import { HouseContext } from '../../Context/House/House';

// .....

export default function Home() {
// .....

    const { testParams, updateSearchParams } = useContext(HouseContext)

    // ......
    return (
          // ......

          <div className='flex'>
            <span className='text-sm/3 my-auto pr-2 dark:text-white'>floor</span>
            <input type='number' placeholder='floor' min={0} onChange={(e) => { updateSearchParams('floor__iexact', e.target.value) }} className='w-14 rounded border border-black' />
          </div>
    // .....

now I have 2 questions about this:

  1. why is the houses list not getting updated when updateSearchParams is firing?
  2. is this approach valid or should I just resort to fetching the data and then filtering client-side? and if so, how will I do so once pagination is added?

Stripe Manual Capture with Apple Pay

I’m working on a web application where a seller needs to authorize buyer’s credit card and then charge it when the item is shipped, I’m using Stripe’s PaymentIntent.create with manual capture, first I create a PaymentMethod and then use it to create the PaymentIntent:

async function createPaymentIntent(paymentMethodId) {
  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount: price, // Amount in cents
      currency: 'usd',
      payment_method: paymentMethodId,
      capture_method: 'manual',
    });

    console.log('Payment Intent:', paymentIntent);
    return paymentIntent.client_secret;
  } catch (error) {
    console.error('Error creating PaymentIntent:', error);
    throw error;
  }
}

Now, I need to add Apple Pay support. Stripe’s documentation mentions that authorization and capture with Apple Pay is possible (link), but I couldn’t find any detailed instructions on how to actually implement it.

How should I approach adding Apple Pay to this setup to ensure proper authorization and capture flow? Any guidance or advise is greatly appreciated!

Vercel Rewrites for Serverless Sites

I’m building a static html css and js site, and I’m essentially using Vercel rewrites to do stuff like this:

getbrandkit.com/b/brandkit, should be given to the JavaScript as getbrandkit.com/b/main.html?b=brandkit. BUT, I never want the user to see the url parameters in their URL bar.

getbrandkit.com/b/brandkit is NOT an existent file in my code.

I’m using Vercel rewrites:

{
  "rewrites": [
    {
      "source": "/b/:b",
      "destination": "/b/main.html?b=:b"
    }
  ]
}

^^ This is clearly doing something because it is loading main.html when I visit getbrandkit.com/b/brandkit, but, I’m not able to get the b value using URL parameters, unless I physically type, getbrandkit.com/b/main.html?b=brandkit.

Ultimately, going to: getbrandkit.com/b/brandkit should console.log brandkit, and getbrandkit.com/b/anything should console.log anything.

TLDR: How do I get the value from getbrandkit.com/b/ANYTHING, on a serverless site, even though the file doesn’t exist.

Using async in googlescripts webapp

I am building a small web service version inside google scripts

I have 2 questions I couldn’t find an answer to,

  1. Logging, I have tried Logger.log and Console.log
    But whenever I am calling the script using API, it runs but not logging
    And the execution record is not expandable to see any logs.

How can it be logged? in order to debug and so.

  1. I have noticed that I can’t use ‘async’ functions,
    (from some other posts and by getting errors myself)
    Now, I need some of the requests to use fetch, which will require await,
    How can it be approached?

Here’s a code of mine using a simple post-request
which is meant to shorten a URL

    function doPost(e) {
    logSpreadsheet(e)
    Logger.log("doPost initiated");

    let reqbody = e.postData.contents
    reqbody = reqbody ? JSON.parse(reqbody): reqbody;
    
    let action = reqbody.action;

    if (action === "shorten_url") {
        Logger.log("shorten_url function initiated")
        if (reqbody.url) {
            let shortened_url = shorten_url(reqbody.url)
            return ContentService.createTextOutput(
                JSON.stringify({"shortened_url": shortened_url}))
        }
        else {
            return ContentService.createTextOutput(
                JSON.stringify({"error": "`url` parameter is missing"}))
        }
    }
    else {
        return ContentService.createTextOutput(JSON.stringify(
            {"error": "`action` parameter is missing"}))
    }

}

function logSpreadsheet (e) {
    let ss = SpreadsheetApp.getActiveSpreadsheet();
    let sheet = ss.getSheetByName("Logs")
    sheet.getRange(sheet.getLastRow()+1,1).setValue("test")
}


const shorten_url = async (source_url) => {
    console.log("shortening_url")

    encoded_url = source_url ? encodeURIComponent(source_url) : "";

    let res;
    let shortened_url;
    let cuttly_apikey = '***'
    let url = `https://cutt.ly/api/api.php`
    let params = `?key=${cuttly_apikey}&short=${encoded_url}`
    let options = {
        method: "get",
        mode: "no-cors",
        headers: { 'Content-Type': 'application/json' }
    }
    try {
        response = await UrlFetchApp.fetch(url + params, options)
        let resData = response.getContentText();
        if (resData) {
            response = JSON.parse(response);
            console.log('cuttly response:', response)
            shortened_url = response.url.shortLink
        }
    }
    catch (err) {
        console.log(`Error getting user data!n${err} `);
    }

    return shortened_url ? shortened_url : source_url;
}

Thank you for helping.

Transition for changing text on a website

on my website I have a part for showing some data. This is hooked up to a button to load other data when pressed. The elements stay the same, but the text inside the spans is changed to show the data. I’ve noticed that just changing the texts and numbers looks a little boring, so I was searching for something like an animation for changing the text. Something like the CSS transition argument, but for changing text. From my own research I did not find anything suiting my needs, maybe one of you has some code to share.

I tried creating a new class, giving it the transition property and on text change, change the class of the element, then change the text and change back the class after a timeout for the transition, but the text still changed immediatly.

NestJS not injecting mocked module unless provider tokens are used

I’m writing unit tests for a sandbox project to test a few things in NestJS. I’ve run into an issue where a class that takes an injected service (authService) is showing up as undefined when being mocked in unit tests. However, the moment I inject it using provider tokens, the service seems to get mocked properly and doesn’t show up as undefined.

I imagine that this issue is with me not making the mock module properly because BOTH approaches work just find in practice (outside of unit tests). It’s only during testing that I can only mock using provider tokens otherwise the authService in AuthImplementation shows up as undefined.

Here is my module – auth.module.ts

@Module({
    imports: [DatabaseModule],
    controllers: [AuthController],
    providers: [
        {
            provide: 'UserRepository',
            useFactory: (databaseAdapterService: DatabaseAdapterService) =>
                databaseAdapterService.getUserRepository(),
            inject: [DatabaseAdapterService],
        },
        {
            provide: AuthService,
            useFactory: (userRepository: UserRepository) => {
                return new AuthService(userRepository);
            },
            inject: ['UserRepository'],
        },
        {
            provide: AuthImplementation,
            useFactory: (authService: IAuthService) =>
                new AuthImplementation(authService),
            inject: [AuthService],
        },
    ]
})

The AuthImplementation class is the following – auth.implementation.ts

import { Inject } from '@nestjs/common';
import { User } from 'src/domain/entities/user.entity';
import { AUTH_SERVICE, IAuthService } from 'src/domain/ports/auth-service.interface';

export class AuthImplementation {
    constructor(@Inject(AUTH_SERVICE) private readonly authService: IAuthService) { }
    
    // This approach, without the provider token, fails the unit tests because
    // authService shows up as undefined when mocked
    // constructor(private readonly authService: IAuthService) { }

    async register(username: string, password: string): Promise<User> {
        return this.authService.register(username, password);
    }

    async login(username: string, password: string): Promise<User | null> {
        return this.authService.login(username, password);
    }
}

And the unit test that only works when the provide field for the mockAuthService is defined with a provider token looks as the following – auth.implementation.spec.ts

describe('AuthImplementation', () => {
    let authImplementation: AuthImplementation;
    let mockAuthService: jest.Mocked<IAuthService>;

    beforeEach(async () => {
        mockAuthService = {
            register: jest.fn(),
            login: jest.fn(),
        };

        const module: TestingModule = await Test.createTestingModule({
            providers: [
                AuthImplementation,
                {
                    // NOTE: This approach does not work
                    //provide: AuthService,

                    // NOTE: This works just fine
                    provide: AUTH_SERVICE,
                    useValue: mockAuthService,
                },
            ],
        }).compile();

        authImplementation = module.get<AuthImplementation>(AuthImplementation);
    });

    describe('register', () => {
        it('should register a user and return the user object', async () => {
            const username = 'testuser';
            const password = 'testpass';
            const mockUser = new User(new ObjectId(), username, password);

            mockAuthService.register.mockResolvedValue(mockUser);

            const result = await authImplementation.register(username, password);

            expect(mockAuthService.register).toHaveBeenCalledWith(username, password);
            expect(result).toBe(mockUser);
        });
    });

So my question is that, instead of having to define a provider token such as export const AUTH_SERVICE = Symbol('AUTH_SERVICE'); and using it when injecting the auth service, is there any way to directly refer to the AuthService in the testing module? Why can I get away with:

provide: AUTH_SERVICE,

but not

provide: AuthService,

which yields as undefined in the AuthImplementation when logging authService?

Error when saving data in SQL database XAMPP phpMyAdim with REACT

I don’t know what happens. When I save the form no error appears, but the form is not saved in the database. I’ve been trying for a while to see if it’s the connection, the names, errors in the code, but I can’t find a solution.

enter image description here

enter image description here

Can someone help me see what my error is? even though according to the form there is no problem saving it, this is not reflected in the database.

This is my Create.jsx document

import React, { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import axios from 'axios';
import { Link } from 'react-router-dom'; 


function Create() {
    const [values, setValues] = useState({
        name: '',
        email: '',
        age: '',
        gender: ''
    });

    const [message, setMessage] = useState('');
    const [isError, setIsError] = useState(false);

    const handleChange = (e) => {
        const { name, value } = e.target;
        setValues(prevValues => ({ ...prevValues, [name]: value }));
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        axios.post('http://localhost:5000/add_user', values)
            .then((res) => {
                setMessage('Estudiante agregado con éxito');
                setIsError(false);
                setValues({
                    name: '',
                    email: '',
                    age: '',
                    gender: ''
                });
            })
            .catch((err) => {
                setMessage('Error al agregar el estudiante: ' + err.message);
                setIsError(true);
            });
    };    

    return (
        <div className='container vh-100 d-flex justify-content-center align-items-center'>
            <div className='col-md-8 col-lg-6'>
                <div className='card'>
                    <div className='card-header bg-primary text-white'>
                        <h4 className='mb-0'>Añadir Estudiante</h4>
                    </div>
                    <div className='card-body'>
                        <form onSubmit={handleSubmit}>
                            {message && (
                                <div className={`alert ${isError ? 'alert-danger' : 'alert-success'}`} role='alert'>
                                    {message}
                                </div>
                            )}
                            <div className='mb-3'>
                                <label htmlFor='name' className='form-label'>Nombre</label>
                                <input
                                    type='text'
                                    name='name'
                                    id='name'
                                    className='form-control'
                                    required
                                    value={values.name}
                                    onChange={handleChange}
                                />
                            </div>
                            <div className='mb-3'>
                                <label htmlFor='email' className='form-label'>Correo Electrónico</label>
                                <input
                                    type='email'
                                    name='email'
                                    id='email'
                                    className='form-control'
                                    required
                                    value={values.email}
                                    onChange={handleChange}
                                />
                            </div>
                            <div className='mb-3'>
                                <label htmlFor='age' className='form-label'>Edad</label>
                                <input
                                    type='number'
                                    name='age'
                                    id='age'
                                    className='form-control'
                                    required
                                    value={values.age}
                                    onChange={handleChange}
                                />
                            </div>
                            <div className='mb-3'>
                                <label htmlFor='gender' className='form-label'>Género</label>
                                <select
                                    name='gender'
                                    id='gender'
                                    className='form-select'
                                    required
                                    value={values.gender}
                                    onChange={handleChange}
                                >
                                    <option value=''>Selecciona tu género</option>
                                    <option value='male'>Masculino</option>
                                    <option value='female'>Femenino</option>
                                    <option value='other'>Otro</option>
                                </select>
                            </div>
                            <div className='d-flex justify-content-between'>
                                <button type='submit' className='btn btn-success'>Guardar</button>
                                <Link to='/' className='btn btn-secondary'>Regresar</Link>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default Create;

This is my App.js document

import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import "bootstrap/dist/css/bootstrap.min.css";
import './App.css';
import Create from './components/Create';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/create" element={<Create />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

This is my server.js document

const express = require("express");
const mysql = require("mysql");
const cors = require("cors");
const path = require("path");

const app = express();

//path.resolve()

app.use(express.static(path.join(__dirname, "public")));
app.use(cors());
app.use(express.json());

const port = 5000;
const db = mysql.createConnection({
  host: "localhost",
  user: "root",
  password: "12345",
  database: "students",
});

app.listen(port, () => {
  console.log(`listening`);
});

app.post("/add_user", (req, res) => {
  const sql =
    "INSERT INTO student_details (`name`,`email`,`age`,`gender`) VALUES (?, ?, ?, ?)";
  const values = [req.body.name, req.body.email, req.body.age, req.body.gender];
  db.query(sql, values, (err, result) => {
    if (err)
      return res.json({ message: "Something unexpected has occured" + err });
    return res.json({ success: "Student added successfully" });
  });
});

Why is the name variable empty when it is sent to my postgres database?

I am trying to Post data in my postgres database using javascript and express. I think that the “app.use(express.json());” line in my code is the one giving me problem, but I’m new to javascript and I’m not comfortable yet with middleware.

This is the error I receive in my terminal after making the POST request with postman (it might be slightly different because i translated it from french)

error: a NULL value violates the constraint NOT NULL in the column « name » in the table « players » 

This is the value of the fields i try to insert in my table:

(4, null, null, null)

This is my code

import express from 'express';
import pkg from 'pg';

const { Pool } = pkg;
const db = new Pool({
    user: "postgres",
    host: "localhost",
    database: "postgres", 
    password: "123456", 
    port: 5433
});

const app = express();
const port = process.env.PORT || 3000;

app.use(express.json());

app.get('/', (req, res) => {
    res.send('Hello World!');
  });

app.post('/players', async (req, res) => {
    console.log(req.body);
    const {
        name,
        email,
        password,
        } = req.body;
    try{
        const client = await db.connect();
        const result = await client.query(
            'INSERT INTO players (name,email,password) VALUES ($1, $2, $3) RETURNING *', 
            [name,email,password]);
            res.status(201).json(result.rows[0]);
            client.release();
        } catch(err){
            console.error(err);
            res.status(500).send('Error creating user');
        }
    });

app.listen(port, () => {
    console.log(`Server listening on port ${port}`)
});

I was expecting the value to be the same as the body of my POST request :

{
    "name": "Zelda",
    "email": "[email protected]",
    "password": "zelda123",
}

The server is working because if I make the get request, I get back “Hello world”

Grid.js – Data imported from HTML Table Source breaks Sort

I’m working on adding progressive enhancement to my htmx powered site with grid.js for smarter tables with client side sorting. I already have links in these tables. However when you try to sort a column that has html in it it does nothing.

How do I fix it so my columns containing html are sortable? I’d rather not build a data fetcher service for what I’m doing here.

I’ve tried looking at the search documentation but there is little mention of the import from an html table options.

<table class="dc-dt">
    <thead>
        <tr>
            <th>Member Type</th>
            <th>Congress Member</th>
            <th>Party</th>
            <th>State</th>
            <th>Document Filer</th>
            <th>Destination</th>
            <th>Departure Date</th>
            <th>Return Date</th>
            <th>Sponsor</th>
        </tr>
    </thead>
    <tbody>
        <tr class="table-row-striped">
            <td class="px-4 py-2">
                <span class="badge bg-gray-500">Representative</span>
            </td>
            <td>
                <a href="/congress-member/J000304">Ronny Jackson</a>
            </td>
            <td>R</td>
            <td>TX</td>
            <td>
                Bryan Brody
            </td>
            <td>
                <a href="/travel-by-destination/New York, NY">New York, NY</a>
            </td>
            <td>Jul 25, 2024</td>
            <td>Jul 26, 2024</td>
            <td>United Nations Foundation</td>
        </tr>
        <tr class="table-row-striped">
            <td class="px-4 py-2">
                <span class="badge bg-gray-500">Representative</span>
            </td>
            <td>
                <a href="/congress-member/B001298">Don Bacon</a>
            </td>
            <td>R</td>
            <td>NE</td>
            <td>
                Matthew Duglin
            </td>
            <td>
                <a href="/travel-by-destination/Israel">Israel</a>
            </td>
            <td>Jul 13, 2024</td>
            <td>Jul 21, 2024</td>
            <td>American Israel Education Foundation</td>
        </tr>
    </tbody>
</table>

<script type="module">
    import {
        Grid,
        html
    } from "https://unpkg.com/gridjs?module";


    (function() {
        let x = document.getElementsByClassName('dc-dt');
        let tbl = new Grid({
            from: x[0],
            sort: true,
            search: true
        })

        tbl.render(document.getElementById('grid'));

        console.log(tbl);
    })();
</script>

Web Speech API and WebView compatibility

I have a website that uses the SpeechSynthesis from the Web Speech API. Now, I need to migrate this site to Android, but the Android WebView doesn’t support SpeechSynthesis, while Chrome on Android does.

  1. Is there any way to use the Chrome Android engine in WebView?

  2. I would like to know if there is any community-made alternative WebView that supports the Web Speech API?

  3. Is there any free API similar to the Web Speech API that is compatible with WebView?

Thanks in advance for your help!

I tried Android-AdvancedWebView without success.

Rails 6 to 7 upgrade javascript not loading

I am trying to upgrade a project from Rails 6 to Rails 7.

Gemfile

ruby '3.1.2'
gem 'rails',           '7.0.4'
gem "sassc-rails",     '2.1.2'
gem "sprockets-rails", "3.4.2"
gem "importmap-rails", "1.1.0"
gem "turbo-rails",     "1.1.1"
gem "stimulus-rails",  "1.0.4"
gem "jbuilder",        "2.11.5"
gem "puma",            "5.6.4"
gem "bootsnap",        "1.12.0", require: false
gem 'sass-rails',      '6.0.0'

app/assets/config/manifest.js

// link_directory ../javascripts .js
//= link_tree ../images
//= link_directory ../stylesheets .css
//= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js

config/importmap.rb

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin_all_from "app/javascript/custom",      under: "custom"

app/javascript/application.js

import "@hotwired/turbo-rails"
import "controllers"
import "custom/menu"
alert('hello');

I have moved all my javascript files from app/assets/javascripts/ to app/javascript/ (all except the old application.js which remains in assets).

The javascript in app/javascript/application.js should be loaded, which means an alert box with “hello” in should appear, but it does not. Where am I going wrong?

Global Variable is not being accesses in a particular block

I created a boolean variable at the top of my js code, It worked perfectly throughout the code and changes globally when its value changes in all Functions/Block where it is used. But in a particular block, I had to declare and initialize it again before it could be accessed in that block.It was a “document.addEventListener” block

I’m working on a responsive design so I created different event listeners for different width sizes.

It happened like this:

let isVisible = false
let query = window.matchMedia("(max-width: 600px)");

document.addEventListener("DOMContentLoaded", () => {
  if (query.matches) {
    button.addEventListener("click", () => {
      if (!isVisible) {
        searchBar.style.display = "block";
        isVisible = true;
      } else if (isVisible && searchBar.value) {
        get_movie(searchBar.value);
      } else {
        searchBar.style.display = "none";
        isVisible = false;
      }
    });
  }
});

The button.addEventListener doesn’t run at all because the isVisible conditions are yet to be met which is because the global variable is not being accessed.

It only starts running when I declare isVisible again inside that document.addEventListener block.

Coldfusion not redirecting after login

I have a simple coldfusion app that uses Google Single Sign On. When a user logs in, they should be redirected to the index.cfm page. And their session tokens should be set. However, they keep being redirected back to the login page. I’ve been troubleshooting this for a while and I’m stuck. I’ve tried modifying onRequestStart and I can only get a too many redirects error. I just want to get users to the main page after signing in. I must be missing something.

Application.cfc:

<cfcomponent>
    <cfset this.name = "myApp">
    <cfset this.sessionManagement = true>
    <cfset session.email=''>
    <cfset session.loggedIn = false>
            
   <cffunction name="onRequestStart" returntype="void">
    <cfargument name="targetPage" type="string" required="false">
    
    <cfif session.loggedIn EQ "false" AND targetPage NEQ "login.cfm">
        <cflocation url="login.cfm" addtoken="false">
    </cfif>
        
</cffunction>        
</cfcomponent>

login.cfm:

<script>
        
        function decodeJwtResponseFromGoogleAPI(token) {
            var base64Url = token.split('.')[1]
            var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
            var jsonPayload = 
           decodeURIComponent(atob(base64).split('').map(function (c) {
                return '%' + ('00' + 
           c.charCodeAt(0).toString(16)).slice(-2);
            }).join(''));
            return JSON.parse(jsonPayload)
        }
    
        function handleCredentialResponse(response) {
            responsePayload = decodeJwtResponseFromGoogleAPI(response.credential);

            email = responsePayload.email;
            
            $.ajax({
                url: 'setSession.cfm',
                type: 'POST',
                data: { email: email },
            });
                window.location.href="index.cfm";
        };
       
            window.onload = function () {
                    google.accounts.id.initialize({
                        client_id: CLIENT_ID,
                        callback: handleCredentialResponse
                    });
                    google.accounts.id.renderButton(
                        document.getElementById('g_id_signin'),
                        { theme: 'outline', size: 'large' }
                    );
                    google.accounts.id.prompt();   
        };
       
    </script>

setSession.cfm:

<cfif structKeyExists(form, "email")>
        <cfset email = form.email>
        <cfset session.loggedIn = true>
        <cfset session.email = email>
</cfif>