Why does calling the contract function always fail?

I have deployed the contract on the Polygon PoS mainnet,javascript code as follows:
····

const accounts = await ethereum.request({ method: 'eth_requestAccounts' });            
const userAddress = accounts[0];                                              
const amount = web3.utils.toWei('2', 'ether');                      
const receipt = await contract.methods.receivepol1().send({ from: userAddress, value: amount}); 

····
Why does calling the contract function always fail?
The error message is as follows:

main.js:34 Uncaught (in promise) Error: Transaction has been reverted by the EVM: {  "blockHash": "0x8de7cb8140833f504cb4d31627628049c1300bc9ed6597f3d98f66abf1dbb2b3",  "blockNumber": 70361196,  "contractAddress": null,  "cumulativeGasUsed": 8623465,  "effectiveGasPrice": "0x60db88429",  "from": "0x48e31c37a86b206f101c07e064513161d462cb12",  "gasUsed": 21637,  "logsBloom": "0x00000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000000000000000000000000000010000008000000000000000000800000000000000000400100000000000000000000000000000000000000000000000000000000040080000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000100000",  "status": false,  "to": "0x33b078c6490236ee9756934c929190d8bb35ea0e",  "transactionHash": "0x5ffbeaecca98421da77fb59a5144dffe33f3a46a5711acde2dcaa91f0e8b40ef",  "transactionIndex": 54,  "type": "0x2",  "events": {    "0": {      "address": "0x0000000000000000000000000000000000001010",      "blockNumber": 70361196,      "transactionHash": "0x5ffbeaecca98421da77fb59a5144dffe33f3a46a5711acde2dcaa91f0e8b40ef",      "transactionIndex": 54,      "blockHash": "0x8de7cb8140833f504cb4d31627628049c1300bc9ed6597f3d98f66abf1dbb2b3",      "logIndex": 242,      "removed": false,      "id": "log_132418c2",      "returnValues": {},      "signature": null,      "raw": {        "data": "0x0000000000000000000000000000000000000000000000000001ffa5ac2d918f000000000000000000000000000000000000000000000001b95f2a19a3c4ef94000000000000000000000000000000000000000000001cff33c89d5acababa95000000000000000000000000000000000000000000000001b95d2a73f7975e05000000000000000000000000000000000000000000001cff33ca9d0076e84c24",        "topics": [          "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63",          "0x0000000000000000000000000000000000000000000000000000000000001010",          "0x00000000000000000000000048e31c37a86b206f101c07e064513161d462cb12",          "0x000000000000000000000000ca4793c93a94e7a70a4631b1cece6546e76eb19e"        ]      }    }  } }
    at Object.TransactionError (main.js:34:96084)
    at Object.TransactionRevertedWithoutReasonError (main.js:34:96456)
    at main.js:10:151351

Javasctipt play and pause project

I was making a video play and pause project and I have made it this way, I would like to know opinion of others about my code or any other better way.
Here is my code that I have written ( As a beginner)

const buttonEl = document.querySelector("button");
const video = document.querySelector("video");
let checkPlay = 0;

buttonEl.addEventListener("click", function () {
  if (checkPlay == 0) {
    video.pause();
    buttonEl.innerHTML = '<i class="ri-pause-line"></i>';
    checkPlay++;
  } else {
    video.play();
    buttonEl.innerHTML = '<i class="ri-play-fill"></i>';
    checkPlay = 0;
  }
});

TinyMCE removes content on form submission — empty tags instead of expected for line breaks

TINYMCE 6:

I’m using TinyMCE as a rich text editor inside a Django form, and I’m facing a strange issue: when I submit the form, any new lines in the text are being stripped, and the final content saved looks like this:

<p></p>
<p></p>

When I inspect the editor before submission, the content looks fine with proper paragraphs or
tags, but after submission it gets wiped out or turned into just empty paragraphs.

Here’s my TinyMCE setup:

tinymce.init({
  selector: '#id_description',
  content_style: `
    .mce-content-body p {
      margin-block-start: 0em;
      margin-block-end: 0em;
    }
  `,
  branding: false,
  plugins: 'advlist lists autoresize',
  toolbar: 'bold italic underline | bullist numlist',
  promotion: false,
  menubar: false,
  resize: false,
  min_height: 400,
  statusbar: false,
  formats: {
    underline: { inline: 'u', exact: true }
  },
  invalid_elements: 'span,div,script,img,table,blockquote',
  valid_elements: 'br,p,strong/b,em/i,u,ul,ol,li',
  newlines_to_brs: true,
  forced_root_block: false,
  remove_trailing_brs: true
});

   description = forms.CharField(
        max_length=3000,
        min_length=500,
        widget=TinyMCE(attrs={
            'class': 'w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition duration-200',
            'placeholder': 'Describe the job responsibilities and requirements...',
            'minLength':'500',
            'maxlength': '3000',
            'id': 'id_description',
            'oninput': 'autoResize(this)',
            'style': 'min-height: 8rem; overflow-y: hidden; resize: none;'
        }, ),
        validators=[
            MinLengthValidator(500),  # Ensure the description is at least 50 characters
            MaxLengthValidator(3000)  # Ensure the description does not exceed 2000 characters
        ],
        help_text="Please provide a detailed description (between 50 and 2000 characters).",
        required=True
    )

Why is margin collapsing between parent and child even when `overflow: hidden` is used (BFC)?

I’m trying to understand how margin collapsing behaves when a Block Formatting Context (BFC) is introduced using overflow: hidden.

Here is a minimal reproducible example:

.outer {
  background: lightblue;
}

.inner {
  background: lightgreen;
  overflow: hidden; /* Triggers BFC */
  margin: 30px;
}

p {
  margin-top: 30px;
}
<body>
  <div class="outer">
    <div class="inner">
      <p>Paragraph inside a BFC.</p>
    </div>
  </div>
</body>

From my understanding, setting overflow: hidden on .inner should create a Block Formatting Context, which prevents margin collapsing between .inner and its parent .outer.

However, when I inspect the layout in Chrome DevTools, it appears that the top margin of .inner is still collapsing upward, making it look like .outer has a top margin — even though it doesn’t.

Question:
Why does margin collapsing still occur here even though .inner should be a BFC? Is there something I’m missing?

Why is my HTML canvas appearing blurry after I dynamically set its dimensions in pixels?

I’m trying to create a canvas application which uses a custom-defined responsive coordinate system. Like the viewbox (from SVG). I know canvas inherently uses a pixel based coordinate system.

My coordinate system is basically a 4 value array which defines the minX, maxX, minY, maxY (eg: [0, 0, 1000, 1000]). Just like viewBox.

So if you draw a rectangle at 250, 250, you are guaranteed to have that rectangle render in the top left quadrant of the screen no matter what the size of the window is. And if you define a width for the rectangle, it will change size as the window is resized.

The html of my app is like this:

<div class="canvasContainer">
   <canvas id="canvas1" />
</div>

And the CSS is like this:

.canvasContainer{
    border: 2px dotted purple;
    width: 100%;
    height: 100%;
}

And in my Javascript file, I have a “orientCanvas” function which fires when the page loads or when the user resizes the window.

The orientCanvas function does this:

let canvCont = document.querySelector(".canvasContainer");
let canv = document.getElementById("canvas1");

canv.style.width =  Math.floor(canvCont.getBoundingClientRect().width)  + "px";
canv.style.height = Math.floor(canvCont.getBoundingClientRect().width * 0.5)  + "px";  

I have made the height half the width to preserve aspect ratio.

So as per my understanding, this kind of a setup will first make the canvasContainer div occupy the entire width of the browser window and the height.

And after that loads into the DOM, the Javascript file will dynamically get the height and width of that canvasContainer in terms of pixels and set the width/height of the canvas in pixels.

After doing all this, I find that when I try a

 ctx.strokeRect(100, 100, 5, 5)

The rectangle appears very blurry. I’m having a hard time understanding why though.

I thought blurrines happens when the width/height of a canvas is influenced by relative styling in the CSS file (such as width: 200%, which will stretch the canvas and make 1 pixel appear 2 pixels wide in the final output on the DOM).

But in my project, I am defining the canvas dimensions in terms of pixels. Which means the canvas should not be stretching right? It’s inherent pixel size itself is changing and it is always at its original resolution (neither shrunk nor stretched). So why does it appear blurry?

I have tried changing the height property of my canvasContainer div to 100vh instead of “100%” but it seemed to make no difference.

Attribues in MutationRecord not being set for AddedNodes/Children

I borrowed the code below from MDN, to make it quick, and added my own “watcher”.

If you load the page in your browser with dev tools open you’ll see that, when the new child “P” element is added, no attribute MutationRecords are included.

This is not a huge problem. Just want to confirm that if I want attributes for a new Element then I’ll have to interrogate that element’s attributes/dataset directly? Could be more of a problem for RemovedNodes.

<!DOCTYPE html>
<html>
<style>
body {
  background-color: paleturquoise;
}

button,
input,
pre {
  margin: 0.5rem;
}
</style>
<body>
<button id="toggle">Toggle direction</button><br />
<div id="container">
  <input type="text" id="rhubarb" dir="ltr" data-foo="bar" value="Tofu" />
</div>
<pre id="output"></pre>
<script>
const toggle = document.querySelector("#toggle");
const rhubarb = document.querySelector("#rhubarb");
const observerTarget = document.querySelector("#container");
const output = document.querySelector("#output");

toggle.addEventListener("click", () => {
  rhubarb.dir = rhubarb.dir === "ltr" ? "rtl" : "ltr";
});

const config = {
  subtree: true,
  attributeOldValue: true,
};

const callback = (mutationList) => {
  for (const mutation of mutationList) {
    if (mutation.type === "attributes") {
      output.textContent = `The ${mutation.attributeName} attribute was modified from "${mutation.oldValue}".`;
    }
  }
};

const observer = new MutationObserver(callback);
observer.observe(observerTarget, config);

let watcher = new MutationObserver((mutations, myInstance) => {
    outer:
    for (var i=0; i<mutations.length; i++){
        if (mutations[i].type == "attributes") {
            console.log("Tag = ", mutations[i].target.tagName, mutations[i].attributeName)
        } else {
            if (mutations[i].type != "childList") 
                continue
            let x = mutations[i]
            for (var j=0; j<mutations[i].addedNodes.length; j++) {
                var node = mutations[i].addedNodes[j];
            }
        }
    }
//      myInstance.disconnect();
});
    
watcher.observe(observerTarget, {
    childList: true,
    subtree: true,
    attributes: true,
    attributeOldValue: true,
    characterData: false
})
let y = document.createElement("p")
y.innerHTML = "HELLO"
observerTarget.appendChild(y)
</script>

</body>
</html>

Movie Ticket App using SQLite Issue with Login Triggering ‘User Already Exists

I am building an Android app with a login screen that stores the username and password in an SQLite database. After a successful login, the user is taken to a Movie Ticket Booking screen where they can choose a movie, theatre, and showtime using spinners. I want to save the selected movie booking information in the database as well, tied to the logged-in user.

Currently, the login part works, but I’m not sure how to:

Save the selected spinner values (movie, theatre, time) into the database.

Retrieve and display the previously booked selection when the user logs in again.

How should I structure the database and code to support this?

I implemented the login and registration functionality using SQLiteOpenHelper, and it works — users can register and log in. After login, I created another activity with spinners for movie, theatre, and time selection.

I tried saving the selected spinner values using an updateBooking() method in my database helper, similar to how I saved the grades in a previous app. However, it doesn’t seem to update or retrieve correctly — the booking info is not saved or shown when the user logs in again.

I expected that after logging in and selecting options from the spinners, the data would be saved in the database and shown the next time the user logs in.

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical" android:padding="16dp">

    <EditText android:id="@+id/etUsername"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:hint="Username" />

    <EditText android:id="@+id/etPassword"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:hint="Password" android:inputType="textPassword" />

    <Button android:id="@+id/btnLogin"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:text="Login" />

    <Button android:id="@+id/btnRegister"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:text="Register" />
</LinearLayout>

LoginActivity.java
package com.example.myapplication;


import android.content.Intent;
import android.os.Bundle;
import android.widget.*;
import androidx.appcompat.app.AppCompatActivity;

public class LoginActivity extends AppCompatActivity {
    EditText etUsername, etPassword;
    Button btnLogin, btnRegister;
    DBHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etUsername = findViewById(R.id.etUsername);
        etPassword = findViewById(R.id.etPassword);
        btnLogin = findViewById(R.id.btnLogin);
        btnRegister = findViewById(R.id.btnRegister);
        dbHelper = new DBHelper(this);

        btnRegister.setOnClickListener(v -> {
            String user = etUsername.getText().toString();
            String pass = etPassword.getText().toString();
            if (dbHelper.registerUser(user, pass)) {
                Toast.makeText(this, "User Registered!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "User Exists!", Toast.LENGTH_SHORT).show();
            }
        });

        btnLogin.setOnClickListener(v -> {
            String user = etUsername.getText().toString();
            String pass = etPassword.getText().toString();
            if (dbHelper.loginUser(user, pass)) {
                Intent i = new Intent(this, MainActivity.class);
                i.putExtra("username", user);
                startActivity(i);
                finish();
            } else {
                Toast.makeText(this, "Invalid login", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

activity_booking.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical" android:padding="16dp">

    <TextView android:id="@+id/tvWelcome"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:textSize="18sp" />

    <Spinner android:id="@+id/spMovie"
        android:layout_width="match_parent" android:layout_height="wrap_content" />

    <Spinner android:id="@+id/spTime"
        android:layout_width="match_parent" android:layout_height="wrap_content" />

    <Button android:id="@+id/btnBook"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:text="Book Ticket" />
</LinearLayout>

android manifest
<activity
            android:name=".LoginActivity"
            android:exported="true">


main.java
package com.example.myapplication;

import android.os.Bundle;
import android.widget.*;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    Spinner spMovie, spTime;
    Button btnBook;
    TextView tvWelcome;
    DBHelper dbHelper;
    String username;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_booking);

        spMovie = findViewById(R.id.spMovie);
        spTime = findViewById(R.id.spTime);
        btnBook = findViewById(R.id.btnBook);
        tvWelcome = findViewById(R.id.tvWelcome);

        dbHelper = new DBHelper(this);
        username = getIntent().getStringExtra("username");
        tvWelcome.setText("Welcome, " + username);

        String[] movies = {"Inception", "Interstellar", "Oppenheimer"};
        String[] times = {"10:00 AM", "1:00 PM", "4:00 PM", "7:00 PM"};

        spMovie.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, movies));
        spTime.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, times));

        btnBook.setOnClickListener(v -> {
            String movie = spMovie.getSelectedItem().toString();
            String time = spTime.getSelectedItem().toString();

            if (dbHelper.saveBooking(username, movie, time)) {
                Toast.makeText(this, "Ticket Booked!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "Booking Failed!", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

DBhelpder.java
package com.example.myapplication;


import android.content.*;
import android.database.Cursor;
import android.database.sqlite.*;

public class DBHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "MovieApp.db";

    public DBHelper(Context context) {
        super(context, DB_NAME, null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE users(username TEXT PRIMARY KEY, password TEXT)");
        db.execSQL("CREATE TABLE bookings(username TEXT, movie TEXT, time TEXT)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
        db.execSQL("DROP TABLE IF EXISTS users");
        db.execSQL("DROP TABLE IF EXISTS bookings");
        onCreate(db);
    }

    public boolean registerUser(String username, String password) {
        SQLiteDatabase db = getWritableDatabase();
        Cursor c = db.rawQuery("SELECT * FROM users WHERE username=?", new String[]{username});
        if (c.getCount() > 0) return false;
        ContentValues cv = new ContentValues();
        cv.put("username", username);
        cv.put("password", password);
        return db.insert("users", null, cv) != -1;
    }

    public boolean loginUser(String username, String password) {
        SQLiteDatabase db = getReadableDatabase();
        Cursor c = db.rawQuery("SELECT * FROM users WHERE username=? AND password=?", new String[]{username, password});
        return c.getCount() > 0;
    }

    public boolean saveBooking(String username, String movie, String time) {
        SQLiteDatabase db = getWritableDatabase();
        ContentValues cv = new ContentValues();
        cv.put("username", username);
        cv.put("movie", movie);
        cv.put("time", time);
        return db.insert("bookings", null, cv) != -1;
    }
}


Auth0 login redirect failing with “Network connection was lost” error on Capacitor iOS app

I’m integrating Auth0 login with my Vue SPA using Capacitor for an iOS native app. The app runs on an iOS emulator (iPhone 16 Pro, iOS 16.0+), but login consistently fails at auth0.handleRedirectCallback with a network error:

Error: “The network connection was lost”

Notably, after accessing the Auth0 login domain once, the connection to this specific domain (login.acme.com or staging-login.acme.dev) stops working entirely until the emulator is fully reset. Other websites continue working normally.

Steps to Reproduce

  1. Launch the Capacitor Vue app in the iOS emulator.
  2. Initiate Auth0 login (opens Auth0 URL in browser plugin)
  3. Complete login successfully, Auth0 redirects back to the app using custom URL scheme.
  4. The app handles redirect via handleRedirectCallback.
  5. Observe immediate “Network connection was lost” error at this step.

Environment Setup

  • Vue SPA frontend, using Auth0 SDK: @auth0/auth0-spa-js@^2.1.3
  • Capacitor cli version: 7.2.1
  • iOS Emulator: iPhone 16 Pro, iOS 16+
  • Xcode version: 16.3

Relevant Code

Redirect Callback Handling

const createNewSession = async (redirectUrl?: string): Promise<string | undefined> => {
  console.log(`[Auth0] Creating new session by calling handleRedirectCallback`);
  if (!auth0Client.value) {
    throw new Error('No Auth0 Client');
  }

  const desiredUrl = redirectUrl ?? window.location.href;
  
  try {
    console.log(`[Auth0] handling redirect callback using redirectUrl: ${desiredUrl}`);
    const result = await auth0Client.value.handleRedirectCallback(desiredUrl); // <-- Fails here
    console.log('[Auth0] handleRedirectCallback result', result);
    
    const sessionAuthenticated = await auth0Client.value.checkIfAuthenticated();
    if (sessionAuthenticated) {
      return handleAuthenticatedSession(desiredUrl);
    }
  } catch (err) {
    console.error('[Auth0] Error handling redirect callback. Raw error:', err);
    // Additional error handling...
  }
};

Capacitor Config (capacitor.config.ts)

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.acme.app',
  appName: 'Acme',
  webDir: 'dist',
  server: {
    hostname: 'localhost',
    allowNavigation: ['staging-login.acme.dev'],
  },
  ios: {
    contentInset: 'always',
    limitsNavigationsToAppBoundDomains: false,
  },
  plugins: {
    CapacitorHttp: { enabled: true },
  },
};

export default config;

Redirect URL Generation (Custom Scheme)

const getRedirectUri = (path: string): string => {
  if (Capacitor.isNativePlatform()) {
    const appId = 'com.acme.app'
    const domain = import.meta.env.VITE_DOMAIN
    return `${appId}://${domain}/capacitor/${appId}/${path}`
  } else {
    // Use window.location.origin for web builds/dev server
    return `${window.location.origin}/${path}`
  }
}

###Capacitor URL Listener

App.addListener('appUrlOpen', async (event: URLOpenListenerEvent) => {
  console.log('[Capacitor] App opened with raw URL:', event.url)
  const result = await handleRedirectCallback(event.url)
  console.log('[Capacitor] handleRedirectCallback result', result)
  await Browser.close()
})

Example Redirect URL from logs (anonymized placeholders):

⚡️  [log] - [Capacitor] App opened with raw URL: com.acme.app://login.acme.com/capacitor/com.acme.app/login/callback?code=A_CODE&state=A_STATE_STR

Debugging Info

Safari debug

Already Attempted Solutions

  • Restarting emulator/device solves temporarily but the issue returns after one successful connection.
  • Checked SSL certificates on Auth0 domains

Specific Questions

  • Has anyone faced similar persistent network errors specifically with Capacitor and Auth0?
  • Could this be something to do with App permissions?
  • Any suggestions for further debugging or information gathering.

I need a way to dynamically edit the class of a div on one page from a script on another page

I have an ‘Availability Form’ on my site which allows users to select a date/time they desire to schedule an appointment.

I want to differentiate which dates/times are available (or not) within the Availability form, by using either of two separate CSS ‘class’ variables… ‘available’ or ‘unavailable’.

I’d like to be able to dynamically manage the Availability Form on the ‘Visitor’s Page’ using a mirrored structure on a ‘Manager’s Page’, by toggling the CSS class of a particular selection in the form between ‘avaiable’ or ‘unavailable’and saving the changes.

I am thinking a possible way to achieve this may be an ‘onclick’ javascript function?

But honestly, I am a bit out of my depth on this particular type of coding.
Any advice or help would be greatly appreciated.

I have included a simplified structure below (without any script).

CSS:

.pageContainer {

width: 100%;
max-width: 280px;
margin: auto;
align-items: center;

}

.dayContainer {

float: left;
padding: 10px;
width: 120px;
text-align: center;
margin-bottom: 40px;

}

h1 {

font-family: arial;
text-align: center;

}

.dayHeader {

color: #ffffff;
font-family: arial;
font-weight: bold;
cursor: pointer;
height: 40px; 
line-height: 40px;
background-color: black;    

}

.available {

width: 100%;
color: #ffffff;
font-family: arial;
cursor: pointer;
height: 40px; 
line-height: 40px;
background-color: green;

}

.available:hover {font-weight: bold;}

.unavailable  {

width: 100%;
color: #333333;
font-family: arial;
cursor: pointer;
height: 40px;
line-height: 40px;
background-color: grey;   

} 

.unavailable:hover {font-weight: bold;}

.buttonWrapper {

width:100%;
text-align: center;  

}

VISITOR’S PAGE (Availability Form):

<div class="pageContainer">

<h1>Visitor's Page</h1>

<form action="" method="post" name="availabilityForm">

<div class="dayContainer">
<div class="dayHeader">MONDAY</div>
<button id="VR1-C1" class="available">1:00 PM</button>
<button id="VR2-C1" class="unavailable">2:00 PM</button>
<button id="VR3-C1" class="available">3:00 PM</button>
</div>

<div class="dayContainer">
<div class="dayHeader">TUESDAY</div>
<button id="VR1-C2" class="unavailable">1:00 PM</button>
<button id="VR2-C2" class="available">2:00 PM</button>
<button id="VR3-C2" class="available">3:00 PM</button>
</div>

</form>

</div>

MANAGER’S PAGE

<div class="pageContainer">    

<h1>Manager's Page</h1>

<div class="dayContainer">
<div class="dayHeader">MONDAY</div>
<div id="MR1-C1" class="available" onclick="updateClass">1:00 PM</div>
<div id="MR2-C1" class="unavailable" onclick="updateClass">2:00 PM</div>
<div id="MR3-C1" class="available" onclick="updateClass">3:00 PM</div>
</div>


<div class="dayContainer">
<div class="dayHeader">TUESDAY</div>
<div id="MR1-C2" class="unavailable" onclick="updateClass">1:00 PM</div>
<div id="MR2-C2" class="available" onclick="updateClass">2:00 PM</div>
<div id="MR3-C2" class="available" onclick="updateClass">3:00 PM</div>
</div>

<br><br>

<div class="buttonWrapper"><button>Save Changes</button></div>

</div>

Updating element value prevents change event on mobile

I’m working with an application where some of the input elements are updated in real time using an input event. For some reason, this prevents a change event from firing on my mobile device (running ios 18.3.2). I have tested this on both Chrome and Safari and get the same issue. I have not tested any other mobile devices since I don’t have any.

The below code fires a change event perfectly fine in a desktop browser but I do not get any change event in #input_b on my mobile device.

var input_a = document.getElementById('input_a');
input_a.addEventListener("change", (event) => {
    console.log('#input_a changed');
});

var input_b = document.getElementById('input_b');
input_b.addEventListener("input", (event) => {
    event.target.value = event.target.value.toUpperCase().trim();
});
input_b.addEventListener("change", (event) => {
    console.log('#input_b changed');
});
input_a: <input id="input_a" type="text" autocomplete="off"><br><br>
input_b: <input id="input_b" type="text" autocomplete="off">

Can anyone explain why?

Keeping MediaRecorder alive regardless of user interactions

I’m trying to record audio from a user for an extended period of time, specifically anywhere between 10 mins and 1.5 hours. However, I want the recordings and related resources to stay alive and continue recording even if the user switches to other tabs. I’ve implemented it inside a useContext so that the methods are readily available for lower components

import React, { createContext, useState, useRef, useCallback, useContext, useEffect } from 'react';
import { setup_media_recorder } from '../utils/AudioUtils';
import { AlertContext } from './AlertFlag';

const MicrophoneContext = createContext();
const AudioContext = createContext();

const put_mic_local = (deviceId) => {
  localStorage.setItem("microphone", deviceId);
}

const get_mic_local = () => {
  return localStorage.getItem("microphone");
}

export const AudioProvider = React.memo(({ children }) => {
  const { addAlert } = useContext(AlertContext);
  // Microphone
  const [ selectedMic, setSelectedMic ] = useState(null);
  const [ microphones, setMicrophones ] = useState([]);
  // Audio
  const [ recordingState, setRecordingState ] = useState("mounted");
  const [ recordingTime, setRecordingTime ] = useState(0);
  const recordingTimerRef = useRef(null);

  // Persistent locations
  const audioDeviceRef = useRef(null);
  const mediaRecorderRef = useRef(null);
  const recordedChunksRef = useRef([]);
  const audioCodecs = useRef(null);

  const loadPermissionsAndMicrophones = useCallback(async () => {
    if (recordingState === "initialized") {
      return;
    } else if (recordingState === "ended") {
      restart();
      return;
    } else if (recordingState !== "mounted") {
      throw new Error("Recording state is not mounted.")
    }
    // Grab permissions. If not given, then nothing happens
    try {
      await navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
        stream.getTracks().forEach(track => track.stop());
      });
    }
    catch (error) {
      addAlert("Microphone permission denied", "danger");
      return;
    }
    try {
      await navigator.mediaDevices.enumerateDevices().then(devices => {
        // Ensure there is a deviceId. Otherwise, grabbing a stream from an empty mic id will throw overconstrained
        const audio_devices = devices.filter(device => device.kind === "audioinput" && device.deviceId && device.deviceId !== "");
        const local_mic_id = get_mic_local();
        const selectedLocalMicExists = audio_devices.some(mic => mic.deviceId === local_mic_id);
        
        if (selectedLocalMicExists) {
          setSelectedMic(local_mic_id);
        } else {
          setSelectedMic(audio_devices[0].deviceId);
        }
        setMicrophones(audio_devices);
        setRecordingState("initialized");
      });
    } catch (error) {
      addAlert(error.message, "danger");
      throw new Error(error);
    }
  }, [recordingState]);

  // Swap before recording
  const swapMicrophones = useCallback((deviceId) => {
    const is_acceptable_mic = microphones.some(mic => mic.deviceId === deviceId);
    if (!is_acceptable_mic) {
      addAlert("Microphone is not selectable.", "danger");
      throw new Error("Improper microphone selected");
    }

    setSelectedMic(deviceId);
    put_mic_local(deviceId);
  }, [microphones, recordingState]);

  const startCapture = useCallback(async () => {
    if (recordingState !== "initialized") {
      throw new Error("Recording state is not initialized")
    }

    try {
      if (!selectedMic) {
        addAlert("No microphone selected", "danger");
        throw new Error("No microphone selected");
      }
      // Create source with initial media stream
      const firstAudioStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: selectedMic, echoCancellation: true }});
      audioDeviceRef.current = firstAudioStream;

      const newMediaRecorder = setup_media_recorder(firstAudioStream, (chunk) => { recordedChunksRef.current.push(chunk) })
      mediaRecorderRef.current = newMediaRecorder["media_recorder"];
      audioCodecs.current = newMediaRecorder["audio_codecs"];

      mediaRecorderRef.current.start(5000); // Collect data every second
      setRecordingState('recording');
      recordingTimerRef.current = setInterval(() => {
        setRecordingTime(prev => prev + 1);
      }, 1000);
    } catch (error) {
      // Cleanup if partially initialized
      cleanRecordingStates();
      cleanAudio();
      addAlert("Couldn't begin recording", "danger");
      throw new Error(error)
    }
  }, [recordingState, selectedMic]);


  const pauseCapture = useCallback(() => {
    if (recordingState !== "recording") {
      throw new Error("Cannot pause recording as recording has not started") 
    }

    try {
      mediaRecorderRef.current.pause();
      clearInterval(recordingTimerRef.current);
      setRecordingState('paused');
    }
    catch(error) {
      throw new Error(error);
    }
  }, [recordingState])

  // CHECK IF STREAMS ARE ALIVE AND IF THE RECORDING CAN BE CONTINUED. IF NOT, THEN A FLAG SHOULD BE TRIGGERED TO FORCE USER TO SUBMIT
  const unpauseCapture = useCallback(() => {
    if (recordingState !== "paused") {
      throw new Error("Cannot play recording as recording is not paused");
    }

    try {
      mediaRecorderRef.current.resume();
      recordingTimerRef.current = setInterval(() => {
        setRecordingTime(prev => prev + 1);
      }, 1000);
      setRecordingState('recording');
    } catch (error) {
      throw new Error(error)
    }
  }, [recordingState])

  const stopCapture = useCallback(() => {
    if (recordingState !== "recording" && recordingState !== "paused") {
      throw new Error("Cannot stop recording as recording is not recording or paused")
    }

    try {
      return new Promise((resolve, reject) => {
        mediaRecorderRef.current.onstop = () => {
          let blob;
          if (audioCodecs.current) {
            blob = new Blob(recordedChunksRef.current, {
              type: audioCodecs.current
            });
          } else {
            blob = new Blob(recordedChunksRef.current);
          }
          resolve(blob);
          cleanAudio();
          cleanRecordingStates();
        };
        mediaRecorderRef.current.onerror = (err) => {
          reject(err);
        };
        // This fires final ondataavailable events and triggers `onstop`
        mediaRecorderRef.current.stop();
      });
    } catch (error) {
      throw new Error(error)
    }
  }, [recordingState])

  // Cleanup audio controls and connections
  const cleanAudio = useCallback(() => {
    if (mediaRecorderRef.current) {
      mediaRecorderRef.current.stop();
      mediaRecorderRef.current = null;
    }

    if (audioDeviceRef.current) {
      audioDeviceRef.current.getTracks().forEach((track) => track.stop());
      audioDeviceRef.current = null;
    }
  }, [])

  const cleanRecordingStates = useCallback(() => {
    setRecordingTime(0);

    if (recordingTimerRef.current) {
      clearInterval(recordingTimerRef.current);
    }
    recordedChunksRef.current = [];
    setRecordingState("ended");
  }, [])

  const restart = useCallback(() => {
    if (selectedMic && microphones.length > 0 && recordingState === "ended") {
      setRecordingState("initialized")
    }
  }, [recordingState, microphones, selectedMic])

  useEffect(() => {
    return () => {
      cleanAudio();
      cleanRecordingStates();
    }
  }, [])

  // Exposed contexts
  const microphoneValue = {
    microphones,
    selectedMic,
    loadPermissionsAndMicrophones,
    swapMicrophones,
  };
  
  // Recorder context value
  const recorderValue = {
    recordingState,
    recordingTime,
    audioDeviceRef,
    audioCodecs,
    startCapture,
    pauseCapture,
    unpauseCapture,
    stopCapture,
    restart,
    cleanAudio,
    cleanRecordingStates,
  };
  
  return (
    <MicrophoneContext.Provider value={microphoneValue}>
      <AudioContext.Provider value={recorderValue}>
        {children}
      </AudioContext.Provider>
    </MicrophoneContext.Provider>
  );
})

export const useMicrophone = () => useContext(MicrophoneContext);
export const useRecorder = () => useContext(AudioContext);

export { MicrophoneContext, AudioContext };

However, it seems that browsers will regularly throttle and even kill media streams and resources if they deem that the user has no more need for them. Anyway to prevent the browser from doing that?

It seems to be an edge case scenario, but it’ll happen infrequently where I’m unable to trigger a .stop() event on the mediarecorder and I get an error such as:

InvalidStateError: The MediaRecorder's state cannot be inactive

Other than indicating to the user to stay on the screen, is there another way to keep the streams alive?

Detect employee access to our page across domains

We have 3 (top level) domains. They are a business decision and cannot be changed, as the companies behind them are to be taken as separate entities.

I need to detect internal use of our app at subdomains: maps.example.com, maps.example2.com and maps.example3.com.

A bit more about requirements:

  • We have an internal web app on int.example.com.
  • The app on maps subdomain does not have authentication other than a hash in URL. * It is a free-to-share link. All apps use the same back-end server.
  • The server of all apps is the same NodeJS server. I have only one instance server (no need for clusters)

What I tried:

  • Initially, I used a localStorage property, but it gets deleted every so often, making it unreliable. Also, the manual approach is not a very nice solution, more like a band-aid.
  • Then I was thinking about cookies, but the top-level domains are a problem. Maybe there might be a way to use the internal app to set cookies to all 3 domains.

Do anyone have any suggestions?

Please can someone explain why my javascript code does not work

I want when I click on the button the width of the divs turns to 300px.

function testing() {
  var nbrTry = 5;
  for (let i = 0; i < nbrTry; i++) {
    document.write("<div></div>");
    let div = document.getElementsByTagName('div');
    div[i].setAttribute('id', `div${i}`);
    let v = document.getElementById(`div${i}`);
    v.style.width = '60px';
    v.style.height = '60px';
    v.style.background = 'black';
    v.style.margin = '2px';
    v.style.transition = `2s`;
  }

  document.write("<button></button>");
  let btn2 = document.getElementsByTagName('button');
  btn2[0].setAttribute('id', `btn2`);
  let b = document.getElementById(`btn2`);
  b.innerHTML = "moving the divs";
  b.style.margin = '50px';
}

function movingDivs() {
  var nbrTry = 5;
  for (let i = 0; i < nbrTry; i++) {
    let v = document.getElementById(`div${i}`);
    v.style.width = '300px';
  }
}

let btn = document.getElementById("btn1");
btn.addEventListener('click', function() {
  testing();
});

let btn3 = document.getElementById("btn2");
btn3.addEventListener('click', function() {
  movingDivs();
})
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div styl="height:120px;width:100%;"><button id="btn1" style="margin: 100px;">Create Elements</button></div>
  <script rel="script/javascript" src="main.js"></script>
</body>

</html>

Is there a way to change a ” string in a “ string?

Take this object as exemple

item = {'field': 2};

I have a '${item['field']}' string. This, in JS, is just a string the way it reads, but I actually want the content of the field, so is there a way to make this change?

'${item['field']}' ->  `${item['field']}` 

So that it prints 2 instead of ${item['field']}

Getting error trying to accept payments on my website

I keep getting an error that I just can’t figure out. my website is subscription based, uses a firebase and JavaScript backend and stripe for payments. just deployed and when I try to subscribe I get the error in console:

createSubscription:1              
Failed to load resource: the server responded with a status of 500 ()

I am not a coder so I probably screwed up somewhere. This is my index.js

const functions = require("firebase-functions/v1");
const admin = require("firebase-admin");
const stripe = require("stripe")("your-secret-code-here");
const cors = require("cors")({ origin: "https://thenerdfinder.com" });

admin.initializeApp();

// Create Subscription
exports.createSubscription = functions.https.onRequest((req, res) => {
  cors(req, res, async () => {
    if (req.method === 'OPTIONS') {
      return res.status(204).send('');
    }

    const { email, uid } = req.body;
    if (!email || !uid) {
      console.log("Missing email or uid in request body", req.body);
      return res.status(400).send({ error: 'Email and UID are required.' });
    }

    try {
      console.log("Fetching or creating customer for email:", email);
      const customers = await stripe.customers.list({ email });
      let customer = customers.data.length ? customers.data[0] : await stripe.customers.create({ email });
      console.log("Customer ID:", customer.id);

      console.log("Creating subscription for customer:", customer.id);
      const subscription = await stripe.subscriptions.create({
        customer: customer.id,
        items: [{ price: "price_ID_HERE" }],
        payment_behavior: "default_incomplete",
        trial_period_days: 30,
        expand: ["latest_invoice.payment_intent"]
      });
      console.log("Created subscription:", JSON.stringify(subscription, null, 2));

      await admin.firestore().collection("users").doc(uid).set({
        email,
        stripeCustomerId: customer.id,
        subscriptionId: subscription.id,
        subscriptionStatus: "active",
        createdAt: admin.firestore.FieldValue.serverTimestamp()
      }, { merge: true });
      console.log("Saved subscription info to Firestore for UID:", uid);

      const clientSecret = subscription.latest_invoice.payment_intent?.client_secret;
      if (!clientSecret) {
        console.error("Missing clientSecret in subscription:", subscription);
        throw new Error("Payment intent not found in the subscription.");
      }

      res.status(200).json({ clientSecret });
    } catch (error) {
      console.error("Stripe error:", error);
      res.status(500).send({ error: error.message });
    }
  });
});

// Cancel Subscription
exports.cancelSubscription = functions.https.onRequest((req, res) => {
  cors(req, res, async () => {
    if (req.method !== 'POST') {
      return res.status(405).send({ error: 'Method not allowed' });
    }

    const { subscriptionId } = req.body;

    if (!subscriptionId) {
      return res.status(400).json({ error: 'Subscription ID is required.' });
    }

    try {
      const canceledSubscription = await stripe.subscriptions.del(subscriptionId);

      const userSnapshot = await admin.firestore()
        .collection("users")
        .where("subscriptionId", "==", subscriptionId)
        .get();

      userSnapshot.forEach(async (doc) => {
        await doc.ref.update({
          subscriptionStatus: "canceled",
          subscriptionId: null
        });
      });

      return res.status(200).json({ success: true, canceledSubscription });
    } catch (error) {
      console.error('Error canceling subscription:', error);
      return res.status(500).json({ error: 'Failed to cancel subscription.' });
    }
  });
});        

This is my firebase console log:

C:UsersgavitDesktopNerdFinderFunctions>firebase functions:log
2025-04-15T18:36:41.018392Z ? createSubscription:     server: 'nginx',
2025-04-15T18:36:41.018396Z ? createSubscription:     date: 'Tue, 15 Apr 2025 18:36:41 GMT',
2025-04-15T18:36:41.018399Z ? createSubscription:     'content-type': 'application/json',
2025-04-15T18:36:41.018402Z ? createSubscription:     'content-length': '218',
2025-04-15T18:36:41.018405Z ? createSubscription:     connection: 'keep-alive',
2025-04-15T18:36:41.018409Z ? createSubscription:     'access-control-allow-credentials': 'true',
2025-04-15T18:36:41.018413Z ? createSubscription:     'access-control-allow-methods': 'GET, HEAD, PUT, PATCH, POST, DELETE',
2025-04-15T18:36:41.018416Z ? createSubscription:     'access-control-allow-origin': '*',
2025-04-15T18:36:41.018420Z ? createSubscription:     'access-control-expose-headers': 'Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required',
2025-04-15T18:36:41.018423Z ? createSubscription:     'access-control-max-age': '300',
2025-04-15T18:36:41.018427Z ? createSubscription:     'cache-control': 'no-cache, no-store',
2025-04-15T18:36:41.018431Z ? createSubscription:     'content-security-policy': "base-uri 'none'; default-src 'none'; form-action 'none'; frame-ancestors 'none'; img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'; worker-src 'none'; upgrade-insecure-requests; report-uri https://q.stripe.com/csp-violation?q=5BoLZUJ-9qKTofu7tXwxZG_B3WJANChUyxQ1GVBSIW96Glq-Agjym0q7J_oDcz20oDKMgwBs-UlN6rd0",
2025-04-15T18:36:41.018435Z ? createSubscription:     'idempotency-key': 'stripe-node-retry-62eff8ac-d841-4ef1-b523-9aa98e49ac11',
2025-04-15T18:36:41.018439Z ? createSubscription:     'original-request': 'req_dw8R4bpRVyy7KI',
2025-04-15T18:36:41.018443Z ? createSubscription:     'request-id': 'req_dw8R4bpRVyy7KI',
2025-04-15T18:36:41.018446Z ? createSubscription:     'stripe-should-retry': 'false',
2025-04-15T18:36:41.018449Z ? createSubscription:     'stripe-version': '2025-03-31.basil',
2025-04-15T18:36:41.018452Z ? createSubscription:     vary: 'Origin',
2025-04-15T18:36:41.018456Z ? createSubscription:     'x-stripe-priority-routing-enabled': 'true',
2025-04-15T18:36:41.018459Z ? createSubscription:     'x-stripe-routing-context-priority-tier': 'livemode-critical',
2025-04-15T18:36:41.018462Z ? createSubscription:     'x-wc': 'ABGHI',
2025-04-15T18:36:41.018465Z ? createSubscription:     'strict-transport-security': 'max-age=63072000; includeSubDomains; preload'
2025-04-15T18:36:41.018468Z ? createSubscription:   },
2025-04-15T18:36:41.018471Z ? createSubscription:   requestId: 'req_dw8R4bpRVyy7KI',
2025-04-15T18:36:41.018475Z ? createSubscription:   statusCode: 400,
2025-04-15T18:36:41.018478Z ? createSubscription:   userMessage: undefined,
2025-04-15T18:36:41.018481Z ? createSubscription:   charge: undefined,
2025-04-15T18:36:41.018484Z ? createSubscription:   decline_code: undefined,
2025-04-15T18:36:41.018488Z ? createSubscription:   payment_intent: undefined,
2025-04-15T18:36:41.018491Z ? createSubscription:   payment_method: undefined,
2025-04-15T18:36:41.018494Z ? createSubscription:   payment_method_type: undefined,
2025-04-15T18:36:41.018497Z ? createSubscription:   setup_intent: undefined,
2025-04-15T18:36:41.018500Z ? createSubscription:   source: undefined
2025-04-15T18:36:41.018503Z ? createSubscription: }
2025-04-15T18:36:41.020633398Z D createSubscription: Function execution took 2076 ms, finished with status code: 500