Change an image on HTML Canvas after every refresh

I am learning how to use HTML and JavaScript and am fairly new/beginner. I have learned recently through my class being able to create a canvas an to draw images or shapes. I created the below but one of the tasks is to create a randomness within the canvas, I decided to try and change the heart image to different ones but am unable to try to apply the math code, I know you may need to use math floor and math random but am unsure how to go about placing the code on the canvas, any help would be greatly appreciated.
The ones I have googled through show arrays as well and I even found the below, but its for background images, and what I am trying to do is change an image placed on the canvas:

Below is my code, I have shortened as it has other elements:

var myCanvas = document.getElementById("canvas1");
var myContext = myCanvas.getContext("2d");
var obstacle = new Image();
obstacle.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Heart_coraz%C3%B3n.svg/160px-Heart_coraz%C3%B3n.svg.png";
obstacle.onload = function() {
  myContext.drawImage(obstacle, 50, 50);
}

function changeBackgroundImage() {
  const images = [
    "url('https://placehold.co/600x400/orange/white')",
    "url('https://placehold.co/600x400/yellow/teal')",
    "url('https://placehold.co/600x400/red/green')"
  ];
  const randomIndex = Math.floor(Math.random() * images.length);
  document.body.style.backgroundImage = images[randomIndex];
}
window.onload = changeBackgroundImage;
<canvas id="canvas1" width="1000" height="900" style="border: dotted 3px #001219;background-color:#E9D8A6;">Your browser does not support canvas></canvas>

Facing JavaScript heap out of memory with react typescript Project(CRA) during build

I am facing JavaScript heap out of memory during build in my react typescript applications. We used create-react-app to build the application.
When we bypass the type checking build is working fine. Looks like issue happens with the type checking.
I have increase the memory size upto

–max-old-space-size=8192

Tried increased the memory limit using ForkTsCheckerWebpackPlugin

new ForkTsCheckerWebpackPlugin({
    typescript: {
       memoryLimit: 4096, // Increase the memory limit (in MB)
    },
}),

Nothing worked for me.

Here is my tsconfig.json

{
    "extends": "./tsconfig.paths.json",
    "compilerOptions": {
        "baseUrl": "./src/",
        "target": "es5",
        "typeRoots": ["./src/"],
        "lib": ["dom", "dom.iterable", "esnext"],
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": false,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "noImplicitAny": false,
        "noFallthroughCasesInSwitch": true
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "build", "dist"]
}

Error

<--- Last few GCs --->

[63135:0x160008000]   169406 ms: Mark-sweep (reduce) 2044.6 (2084.2) -> 2043.4 (2084.5) MB, 580.8 / 0.0 ms  (average mu = 0.207, current mu = 0.036) allocation failure; scavenge might not succeed
[63135:0x160008000]   170002 ms: Mark-sweep (reduce) 2044.6 (2084.5) -> 2042.9 (2084.5) MB, 590.6 / 0.0 ms  (average mu = 0.116, current mu = 0.011) allocation failure; scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x102889770 node::Abort() [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 2: 0x102889954 node::ModifyCodeGenerationFromStrings(v8::Local<v8::Context>, v8::Local<v8::Value>, bool) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 3: 0x1029e01a8 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 4: 0x102b8ab30 v8::internal::EmbedderStackStateScope::EmbedderStackStateScope(v8::internal::Heap*, v8::internal::EmbedderStackStateScope::Origin, cppgc::EmbedderStackState) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 5: 0x102b8e71c v8::internal::Heap::CollectSharedGarbage(v8::internal::GarbageCollectionReason) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 6: 0x102b8b730 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GarbageCollectionReason, char const*, v8::GCCallbackFlags) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 7: 0x102b88a30 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 8: 0x102b7d56c v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
 9: 0x102b7ddb0 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
10: 0x102b63d30 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
11: 0x102f04490 v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
12: 0x10325110c Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
13: 0x10884a540 
14: 0x109597f94 
15: 0x108877044 
16: 0x109598c38 
17: 0x109598074 
18: 0x108877044 
19: 0x108ce1428 
20: 0x108255e68 
21: 0x1090d5a10 
22: 0x1090d5d60 
23: 0x109315650 
24: 0x1091bbea0 
25: 0x1095baae0 
26: 0x108291834 
27: 0x1090f89e0 
28: 0x108cf1460 
29: 0x1090cba8c 
30: 0x1090c8eec 
31: 0x1095d7248 
32: 0x1090e4f34 
33: 0x1081bade8 
34: 0x108cf0a2c 
35: 0x1088254bc 
36: 0x10882ff7c 
37: 0x108ce37b0 
38: 0x1086f7854 
39: 0x1082387dc 
40: 0x1080d6394 
41: 0x108ace978 
42: 0x1086daa44 
43: 0x10931e278 
44: 0x1080d6394 
45: 0x1091b8998 
46: 0x1096ee5d0 
47: 0x1091a7e6c 
48: 0x1091b61a8 
49: 0x1082317b0 
50: 0x1081b3340 
51: 0x10930ea3c 
52: 0x1091a71cc 
53: 0x108b0e80c 
54: 0x1080f6614 
55: 0x108b0d19c 
56: 0x10952b4bc 
57: 0x1087e50ec 
58: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
59: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
60: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
61: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
62: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
63: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
64: 0x1032100d0 Builtins_GeneratorPrototypeNext [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
65: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
66: 0x10329ac88 Builtins_PromiseConstructor [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
67: 0x1031d9914 Builtins_JSBuiltinsConstructStub [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
68: 0x1032e6cb8 Builtins_ConstructHandler [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
69: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
70: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
71: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
72: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
73: 0x1032100d0 Builtins_GeneratorPrototypeNext [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
74: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
75: 0x10329ac88 Builtins_PromiseConstructor [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
76: 0x1031d9914 Builtins_JSBuiltinsConstructStub [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
77: 0x1032e6cb8 Builtins_ConstructHandler [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
78: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
79: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
80: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
81: 0x10323cb00 Builtins_SetPrototypeForEach [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
82: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
83: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
84: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
85: 0x1031dc198 Builtins_InterpreterEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
86: 0x1031da4d0 Builtins_JSEntryTrampoline [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
87: 0x1031da164 Builtins_JSEntry [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
88: 0x102b0c928 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
89: 0x102b0be68 v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
90: 0x1029fc048 v8::Function::Call(v8::Local<v8::Context>, v8::Local<v8::Value>, int, v8::Local<v8::Value>*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
91: 0x1027ccd08 node::InternalCallbackScope::Close() [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
92: 0x1027ccfd0 node::InternalMakeCallback(node::Environment*, v8::Local<v8::Object>, v8::Local<v8::Object>, v8::Local<v8::Function>, int, v8::Local<v8::Value>*, node::async_context) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
93: 0x1027e2484 node::AsyncWrap::MakeCallback(v8::Local<v8::Function>, int, v8::Local<v8::Value>*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
94: 0x10293d7b0 node::StreamBase::CallJSOnreadMethod(long, v8::Local<v8::ArrayBuffer>, unsigned long, node::StreamBase::StreamBaseJSChecks) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
95: 0x10293ecb0 node::EmitToJSStreamListener::OnStreamRead(long, uv_buf_t const&) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
96: 0x102942d94 node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
97: 0x102943500 node::LibuvStreamWrap::ReadStart()::$_1::__invoke(uv_stream_s*, long, uv_buf_t const*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
98: 0x1031c6950 uv__stream_io [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
99: 0x1031cea84 uv__io_poll [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
100: 0x1031bc9a0 uv_run [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
101: 0x1027cd6e0 node::SpinEventLoop(node::Environment*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
102: 0x1028c5e1c node::NodeMainInstance::Run() [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
103: 0x10285630c node::LoadSnapshotDataAndRun(node::SnapshotData const**, node::InitializationResult const*) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
104: 0x1028565c4 node::Start(int, char**) [/Users/gtm/.nvm/versions/node/v18.20.4/bin/node]
105: 0x18db9b154 start [/usr/lib/dyld]
RpcIpcMessagePortClosedError: Process 63135 exited [SIGABRT].
Issues checking service aborted - probably out of memory. Check the `memoryLimit` option in the ForkTsCheckerWebpackPlugin configuration.
If increasing the memory doesn't solve the issue, it's most probably a bug in the TypeScript or EsLint.
RpcIpcMessagePortClosedError: Process 63135 exited [SIGABRT].
Issues checking service aborted - probably out of memory. Check the `memoryLimit` option in the ForkTsCheckerWebpackPlugin configuration.
If increasing the memory doesn't solve the issue, it's most probably a bug in the TypeScript or EsLint.

How to fix this heap memory issue?

Page break issue with html2pdf.js

I am using html2pdf.js for pdf previewing the dynamic html code from the text editor in angular v17.
Here is the code I am using for previewing the pdf

generatePDF() {    
    this.replacetext = this.replacetext.replaceAll('text-align: right','text-align: right !important')
    this.replacetext = this.replacetext.replaceAll('text-align: center','text-align: center !important')
    this.replacetext = this.replacetext.replaceAll('text-align: left','text-align: left !important')
    const element = document.createElement('div');
    //element.innerHTML = this.replacetext;
    element.innerHTML = `
    <style>
      .page-break {
        page-break-before: always;
      }
  
      .avoid-page-break {
        page-break-inside: avoid;
      }
  
      .scale-down-height {
        height: auto;
      }
  
      .scale-down-height tr {
        line-height: 0.75 !important; /* Adjust the scale as needed */
        font-size: 0.4em !important; /* Adjust the scale as needed */
      }

      #scorecardtablemodal {
        border-collapse: collapse !important;
        width: 100% !important;
        page-break-inside: avoid !important;
        border-top: none !important; /* Remove top border */
      }      

      #scorecardtablemodal, #scorecardtablemodal th, #scorecardtablemodal td {
        border: 0.5px solid black !important; /* Solid border color for specific table */
      }       
     
    </style>
    ${this.replacetext}
  `;
  
    
    // Append the element to the body to measure its dimensions
    document.body.appendChild(element);
  
    // Apply scaling to large tables
    const tables = element.querySelectorAll('table');
    tables.forEach(table => {      
      if (table.offsetHeight > 900) { // Adjust the height threshold as needed        
        table.classList.add('scale-down-height');        
      }      
    });
  
    // Remove the element from the body after measuring
    document.body.removeChild(element);
  
    const options = {
      margin: 0.2,
      filename: 'document.pdf',
      image: { type: 'jpeg', quality: 0.98 },
      html2canvas: { scale: 2 },
      jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' },
      pagebreak: { mode: ['avoid-all', 'css', 'legacy'] }
    };
  
    html2pdf().from(element).set(options).toPdf().get('pdf').then((pdf) => {
      const totalPages = pdf.internal.getNumberOfPages();
      for (let i = 1; i <= totalPages; i++) {
        pdf.setPage(i);
        pdf.setFontSize(5);
        pdf.setTextColor(150);
        pdf.text(`Page ${i} of ${totalPages}`, pdf.internal.pageSize.getWidth() - 0.38, pdf.internal.pageSize.getHeight() - 0.2);
  
        const pdfType = (this.newReview.lastReviewDt != '' && this.newReview.lastReviewDt != null) ? 'APPROVED' : 'DRAFT';
        pdf.setFontSize(40);
        pdf.setTextColor(150);        
        // Save the current graphics state
        pdf.saveGraphicsState();
  
        // Translate and rotate the context
        pdf.setTextColor(150);
        pdf.setFontSize(15);
        pdf.setFont("arial", "bold");
        pdf.setGState(pdf.GState({ opacity: 0.3 }));        
        pdf.text(pdfType, pdf.internal.pageSize.getWidth() - 0.7, pdf.internal.pageSize.getHeight() - 0.2, {
          angle: 0,
          align: 'right'
        });       
  
        // Restore the graphics state
        pdf.restoreGraphicsState();
      }
    }).output('blob').then((pdfBlob) => {
      const pdfUrl = URL.createObjectURL(pdfBlob);   
      const iframe = document.createElement('iframe');
      iframe.style.width = '100%';
      iframe.style.height = '100%';
      iframe.src = pdfUrl;    
  
      
      this.modalService.open(this.srtpreview, { ariaLabelledBy: 'modal-basic-title', size: 'srt' }).result.then((result) => {
        this.closeResult = `Closed with: ${result}`;
      }, (reason) => {
        this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
      });
  
      // Delay to ensure the modal is fully rendered
      setTimeout(() => {
        const previewContainer = document.getElementById('pdfoutput');
        
        if (previewContainer) {
          previewContainer.innerHTML = '';
          previewContainer.appendChild(iframe);
          console.log('Iframe appended to preview container');
        } else {
          console.error('Preview container not found');
        }
      }, 500); 
    });
  } 

My goal is to ensure that the tables and other contents like image, screenshots not to be cut between the pages by using the pagebreak option

pagebreak: { mode: ['avoid-all', 'css', 'legacy'] 

But the issue I am facing is the top part of the table(like border) is getting cut and going to the previous page.

Here is the screenshot below

enter image description here

And the intensity of the line is getting increased when the content is pushed to further pages(like the table content is getting cut between pages)

enter image description here

I have tried multiple ways but not able to fix this issue.
Please let me know how to address this issue.

Why does the browser not send referer when using egg’s ctx.redirect?

I used egg to start two services, which can be accessed at test1.com and test2.com respectively.
test1.com redirects to test2.com via ctx.redirect.

// test1 egg
router.get('/render', controller.home.render);

async render() {
    const { ctx } = this;
    ctx.redirect('https://test2.moomoo.com');
}

// test2 egg
async render() {
    const { ctx } = this;
    console.log('ctx.header.referer', ctx.header.referer);
    await this.ctx.render('/index.html', {
      data: 'test2',
    });
}

I found that the browser will not display referer at this time.
The values ​​of ctx.header.referer and document.referrer are both empty

Why is this?

But when I redirect via window.location, referer is displayed

I wish when I use ctx.redirect to redirect to test2, referer will show test1

How to extract the directory (e.g., es/ or pt/) from the pathname to dynamically update the heading in a custom web component?

I am working on a custom web component and want to dynamically manipulate the heading in my Carousel component based on the directory in the URL pathname (e.g., es/ for Spanish or pt/ for Portuguese).

class Carousel extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = `
      <div class="Carousel-Sec">
        <p class="trusted-brands-heading">
          <!-- Heading template -->
        </p>
        <!-- Image template -->
      </div>
    `;
  }
}

Get the current active slide of a google slide embedded in an iframe using javascript

I have a embedded google slides into an iframe. I want to know is it possible to get the current active slide number in iframe using javascript or any other way? If yes is it also possible for me to track it whenever the slide is changing inside an iframe?

I know I can use #slide as a query parameter to the embed url and change it accordingly but that is just reloading the slides so the transitions that happen while changing will not work.

cookies can only be modified in a server action or route handler next js

here is my singout action file code:

'use server'
import { revalidatePath } from "next/cache";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export const signout = async () => {
    cookies().delete("access_token");
    cookies().delete("refresh_token");
    cookies().delete("user");
    revalidatePath("/", "layout");
    redirect("/");
}

and here is my order action

"use server";
import axiosInstance from "@/components/axios";
import { signout } from "./signout_action";
import { returnCustomError } from "@/utilities/utils";

export const getOrders = async (pageNumber, query, filter) => {
    try {
        const res = await axiosInstance.get(
            `/api/reseller/orders/?page=${pageNumber}&search=${query}&status=${filter}`
        );
        return res?.data;
    } catch (error) {
        if (error.message === "Unauthorized") {
            signout();
        } else return [];
    }
};

now when user is unauthorized it run singout funtin and clear cookies in development mode and go to home page but ini the production it gives an error “cookies can only be modified in a server action or route handler next js” in the vercel logs

and show application error: a client side exceptions occured (see browser console)

this type of error shows on the screen

how to solve this in next js 14 app router

How do I make the template reactive to changes in property attributes?

Consider this very basic calculator (try it here):

import {html, css, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';

@customElement('simple-calc')
export class SimpleCalc extends LitElement {
  @property()
  value1 = 3
      
  @property()
  value2 = 0

  render() {
    return html`
        <input type="number"
          .value=${this.value1}
          @change=${(e) => this.value1 = e.target.value}>
        <input type="number"
          .value=${this.value2}
          @change=${(e) => this.value2 = e.target.value}>
        <p>Difference: ${this.value1 - this.value2}</p>`;
  }
}

It works as intended, the difference is updated whenever the value of either of the input changes. Now I would like to do the same thing, but with value1 and value2 not being “direct” properties of the LitElement, but rather attributes of a property, ie (try it here):

  @property()
  obj = {value1: 3, value2: 0}

  render() {
    return html`
        <input type="number"
          .value=${this.obj.value1}
          @change=${(e) => this.obj.value1 = e.target.value}>
        <input type="number"
          .value=${this.obj.value2}
          @change=${(e) => this.obj.value2 = e.target.value}>
        <p>Difference: ${this.obj.value1 - this.obj.value2}</p>`;
  }

But in this case, the difference is not updated “live”. How do I make this work?

Is .then() chaining faster than await? [duplicate]

I am wondering if there are any performance difference between these two styles:

async function test() {
  const a = await fetch();
  const b = await a.run();
  return b + 1;
}

vs.

async function test() {
  return fetch()
         .then((a) => a.run())
         .then((b) => b+1);
}

That is, is it better to chain promises with .then vs. waiting them out with await, or does it make no difference (as I expect)?

Home page goes to login if loaded from URL

Setup:

I installed React (Vite) and I developed a home page that should appear only if user is authenticated. If not, the page should go to the login page.

npm create vite@latest my-app --template react
npm install
npm install react-router-dom
npm run dev

The backend is Django and Reacts uses

user/api/user-auth-status

to know if the user is authenticated.
The header is also shown only to the authenticated user. The footer shown to everyone.


Problem

The problem is that if I login from the login page, the home page is shown fine. But if I go to home page / from the header or from the URL bar in my browser, I would be navigated to the login page again.

I am very new to React. I do not understand what is the problem and whether my state user is updated properly or not.


Codes

App.jsx

import './App.css';
import Footer from './Footer';
import Header from './Header';
import Home from './Home';
import Login from './Login';
import React, { useEffect, useState } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import ProtectedRoute from './ProtectedRoute';
import PageNotFound from './PageNotFound';

function App() {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchUserStatus = async () => {
            try {
                const response = await fetch(`${import.meta.env.VITE_API_URL}user/api/user-auth-status`);
                if (!response.ok) {
                    throw new Error('Failed to fetch user status');
                }
                const data = await response.json();
                setUser(data.user);
            } catch (err) {
                setError(err.message);
                console.error('Error fetching user status:', err);
            } finally {
                setLoading(false);
            }
        };

        fetchUserStatus();
    }, []);

    const handleLogin = (userData) => {
        setUser(userData);
    };

    if (loading) {
        return <div>Loading...</div>;
    }

    if (error) {
        return <div>Error: {error}</div>;
    }

    return (
        <BrowserRouter>
            <div className="App">
                {user && user.is_authenticated && <Header user={user} />}
                <div className="body">
                    <Routes>
                        <Route
                            path="/login"
                            element={<Login onLogin={handleLogin} />}
                        />
                        <Route
                            path="/"
                            element={
                                <ProtectedRoute user={user}>
                                    <Home />
                                </ProtectedRoute>
                            }
                        />
                        <Route path="*" element={<PageNotFound />} />
                    </Routes>
                </div>
                <Footer />
            </div>
        </BrowserRouter>
    );
}

export default App;


ProtectedRoute.jsx

import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';


function ProtectedRoute({ children, user }) {
    const navigate = useNavigate();

    useEffect(() => {
        if (!user || !user.is_authenticated) {
            navigate('/login');
        }
    }, [user, navigate]);

    if (user && user.is_authenticated) {
        return <>{children}</>;
    }

    return null;
}

export default ProtectedRoute;


Login.jsx

import './Login.css';
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';

const getCSRFToken = () => {
    const match = document.cookie.match(/csrftoken=([w-]+)/);
    return match ? match[1] : '';
};

function Login({ onLogin }) {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [error, setError] = useState(null);
    const navigate = useNavigate();

    const handleSubmit = (e) => {
        e.preventDefault();

        const csrfToken = getCSRFToken();

        fetch(`${import.meta.env.VITE_API_URL}user/api/login`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': csrfToken,
            },
            credentials: 'include',  // Send cookies with the request
            body: JSON.stringify({
                username: username,
                password: password,
            }),
        })
        .then((response) => response.json())
        .then((data) => {
            if (data.detail === 'Login successful!') {
                onLogin({ username, is_authenticated: true });
                navigate('/');
            } else {
                alert('Login failed: ' + data.detail);
            }
        })
        .catch((error) => {
            alert('Error: ' + error.message);
        });
    };

    return (
        <div className="login-container">
            <h2>Login</h2>
            {error && <div className="error-message">{error}</div>}
            <form onSubmit={handleSubmit}>
                <div className="form-group">
                    <label htmlFor="username">Username</label>
                    <input
                        type="text"
                        id="username"
                        value={username}
                        onChange={(e) => setUsername(e.target.value)}
                        required
                    />
                </div>
                <div className="form-group">
                    <label htmlFor="password">Password</label>
                    <input
                        type="password"
                        id="password"
                        value={password}
                        onChange={(e) => setPassword(e.target.value)}
                        required
                    />
                </div>
                <button type="submit" className="login-button">
                    Login
                </button>
            </form>
        </div>
    );
}

export default Login;

Header.jsx

import React from 'react';
import './Header.css';
import MenuButton from './MenuButton';


function UserBox({user}) {
    if(user && user.is_authenticated)
        return (<>
                user: { user.username }<br/>
                <a href="/logout"><button>Logout</button></a>
            </>);
    else
        return (<>
                  <a href="/login"><button>Login</button></a>
            </>);
}


function Header({user}) {
    const debug = import.meta.env.VITE_DEBUG === 'true';
    const headerLinks = [
        { href: '/', label: 'Home' },
        { href: '/about/', label: 'About' },
        { href: '/contact/', label: 'Contact' },
    ];
  return (
    <div className="App-header">
        <div className="header" style={{ backgroundColor: debug ? '#feffd3' : '#dfffe0' }}>
            {headerLinks.map((link, index) => (
                <MenuButton key={index} url={link.href} text={link.label} />
            ))}
            <div style={{ padding: '10px', margin: '10px', display: 'inline-block' }}>
                <UserBox user={user} />
            </div>
        </div>
    </div>
  );
}

export default Header;

MenuButton.jsx

import React from 'react';
import './MenuButton.css';



function MenuButton({url, text}) {
    return (
        <div className="header-button">
            <a href={url}>{text}</a>
        </div>
    );
}

export default MenuButton;

Changing an input’s value programmatically doesn’t change the value

I’m making a bookmarklet for myself, to provide custom behavior on a website I use often. It’s not my website, so I’m basically running my code externally.

I’ve run an issue where an input doesn’t change its value on submit, no matter what I do to change it programmatically. It will change visually and in the inspector (though different methods of changing alter either one or the other), however, editing the other value in the form causes the input element value to revert to the previous value.
(So far I’ve run into this on two of 10 websites).

  1. prior to edit
  2. programmatic edit
  3. after changing another element’s value

I can change the value of the input, but it doesn’t actually change the value in the inspector (and when it is submitted via a network request, it uses the old value). It does change on the webpage, though.

I have tried

input.value = '10/04/1966';
$(input).prop("value",'10/04/1966');
$(input).attr("value",'10/04/1966');
input.setAttribute("value",'10/04/1966');
setNativeValue(input,'10/04/1966');
input.dispatchEvent(new Event('input'), { bubbles: true, cancelable: true });
input.dispatchEvent(new Event('change'), { bubbles: true, cancelable: true });
$(input).trigger("input");
$(input).trigger("change");

input.value    // 10/04/1966
$(input).val() // 10/04/1966


// fn used above
function setNativeValue(element, value) {
   const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
   const prototype = Object.getPrototypeOf(element);
   const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
 
    if (valueSetter && valueSetter !== prototypeValueSetter) {
      prototypeValueSetter.call(element, value);
   } else {
      valueSetter.call(element, value);
   }
}

innerHTMl is “” before and after, and defaultValue shows the 10/04/1966 after using the code above. However, when submitting the form…it sends the old value.

I’m not certain what framework they’re using, but I don’t see “ng” everywhere, so I’m thinking not Angular, nor is there “shadow” everywhere, so probably not React. Doesn’t narrow it down by much, though. All the source files are minified, so no hints there, either. (maybe something with C#?)

I’ve searched around a bit, but I’m not finding any hints at all. Thanks in advance.

Related research:
jQuery .val change doesn’t change input value
jQuery .val change doesn’t change input value
Can’t programmatically change <input>’s value

How to get the event div position in daypilot

I am using daypilot calendar scheduler. I want, when i click an event a pop up box come near of it left align. For this i need its div position on the browser. How can i get it?. The things i want is concept of google calendar. I want to implement their viewing, editing and deleting event features.

onEventClick: async function (args) {

    const eventData = args.e.data;
    console.log(eventData);
}

this is my event click function inside calendar object.

I tried the method we use in java script, but it is not working. I tried writing html in modal. its also not work as i trying to do.

The guests variable is not getting updated with the value of the guests select dropdown

I am implementing a booking feature for a website, I noticed that if I tried selecting the guests before picking dates, it works I see the console logs and the guests value gets updated. But on selecting dates, and if I try to select the guests, nothing happens and I don’t see any console logs. I have tried different solutions like making the guests variable global, but nothing is working. I really hope to get this solved fast. Thank you.

import { options, accessToken } from "./config.js";

document.addEventListener("DOMContentLoaded", function () {
  const urlParams = new URLSearchParams(window.location.search);
  const propertyId = urlParams.get("id"); // Get the property ID from the URL parameter

  let propertyName = "";

  const url = `${hostawayData.pluginUrl}hostaway-server/proxy.php?endpoint=listings/${propertyId}`;

  fetch(url, options)
    .then(res => res.json())
    .then(data => {
      propertyName = data.result.name;
    })
    .catch(err => console.error(err));

  const max_guests = 4;
  const dateRange = {
    from: new Date(),
    to: new Date(new Date().setDate(new Date().getDate() + 1)),
  };
  let guests = 1;
  let quote = null;
  let amount = 0;
  let loading = false;
  let errMsg = "";
  let successMsg = "";
  let disable = true;
  let hasCoupon = false;
  let coupon = "";
  let availabilityCache = null;
  let isFetchingAvailability = false;

  function getDate(date) {
    if (!date) return "N/A";
    return date.toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric",
    });
  }

  function getDaysBetweenDates(date1, date2) {
    const oneDay = 24 * 60 * 60 * 1000; // milliseconds
    const differenceInTime = date2.getTime() - date1.getTime();
    return Math.round(differenceInTime / oneDay);
  }

  function formatPrice(amount) {
    return `$${amount.toLocaleString("en-US", {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
    })}`;
  }

  function calculateDaysDifference(start, end) {
    const startDate = new Date(start);
    const endDate = new Date(end);
    const timeDiff = endDate - startDate;
    const dayDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
    return dayDiff;
  }

  function calculateTotalAmount(response) {
    // Extract data from the API response
    const ratePlan = response.rates.ratePlans[0].ratePlan;
    const fareAccommodation = ratePlan.money.fareAccommodation;
    const fareCleaning = ratePlan.money.fareCleaning;
    const totalTaxes = ratePlan.money.totalTaxes;

    // Calculate total amount
    const subtotalPrice = fareAccommodation + fareCleaning;
    const totalAmount = subtotalPrice + totalTaxes;

    return totalAmount;
  }

  window.setQuote = function (newQuote) {
    quote = newQuote;
    render();
  };

  window.checkAvailability = function () {
    console.log("Current guests before check:", guests);
    errMsg = "";
    successMsg = "";
    loading = true;
    render();

    const listingId = propertyId; // Replace with actual listing ID
    const fromDate = dateRange.from.toISOString().split("T")[0];
    const toDate = dateRange.to.toISOString().split("T")[0];

    const endpoint = `listings/${listingId}/calendar?startDate=${fromDate}&endDate=${toDate}`;
    console.log(endpoint);
    const url = `${hostawayData.pluginUrl}hostaway-server/proxy.php?endpoint=${encodeURIComponent(endpoint)}`;


    fetch(url, options)
      .then((res) => res.json())
      .then((res) => {
        console.log(res);

        const nights = getDaysBetweenDates(dateRange.from, dateRange.to);
        const minimumStay = res.result[0].minimumStay; // Assuming minimumStay is the same for all days

        if (nights < minimumStay) {
          errMsg = `Minimum stay is ${minimumStay} nights.`;
          loading = false;
          render();
        } else {
          const allAvailable = res.result.every((day) => day.status === "available");
          if (allAvailable) {
            errMsg = "";
            successMsg = "Available";
            render();
            createReservationQuote(
              guests,
              dateRange.from,
              dateRange.to,
              propertyId
            );
          } else {
            successMsg = "";
            errMsg =
              "Some of the selected days are not available. Please change your selections";
            loading = false;
            render();
          }
        }
      })
      .catch((err) => {
        console.error(err);
        // Handle the error as needed
        successMsg = "";
        errMsg = "An Error Occured, Try Again!";
        loading = false;
        render();
        document.getElementById("start-date").value = dateRange.from
          .toLocaleDateString()
          .split("T")[0];
        document.getElementById("start-date").style.fontWeight = "700";
        document.getElementById("end-date").value = dateRange.to
          .toLocaleDateString()
          .split("T")[0];
        document.getElementById("end-date").style.fontWeight = "700";
      })
      .finally(() => {
        document.getElementById("start-date").value = dateRange.from
          .toLocaleDateString()
          .split("T")[0];
        document.getElementById("start-date").style.fontWeight = "700";
        document.getElementById("end-date").value = dateRange.to
          .toLocaleDateString()
          .split("T")[0];
        document.getElementById("end-date").style.fontWeight = "700";
      });
  };

  window.createReservationQuote = function (
    guestsCount,
    checkInDate,
    checkOutDate,
    listingId
  ) {
    console.log("Creating Reservation Quote");
    console.log("Guests Count:", guestsCount);
    console.log("Current Global Guests:", guests);
    console.log(
      "Request Data:",
      guestsCount,
      checkInDate,
      checkOutDate,
      listingId
    );

    const postOptions = {
      method: "POST",
      headers: {
        accept: "application/json; charset=utf-8",
        "content-type": "application/json",
        authorization: `Bearer ${accessToken}`,
      },
      body: JSON.stringify({
        numberOfGuests: guestsCount,
        startingDate: checkInDate.toISOString().split("T")[0],
        endingDate: checkOutDate.toISOString().split("T")[0],
        version: 2,
      }),
    };

    // listings/90632/calendar/priceDetails"

    fetch(
      `${hostawayData.pluginUrl}hostaway-server/proxy.php?endpoint=listings/${listingId}/calendar/priceDetails`,
      postOptions
    )
      .then((response) => {
        if (!response.ok) {
          return response.json().then((error) => {
            throw new Error(`Error: ${error.error}`);
          });
        }
        return response.json();
      })
      .then((data) => {
        console.log("API Response:", data);
        if (data.status == "success") {
          const totalAmount = data.result.totalPrice;
          // Prepare reservation data
          const reservationData = {
            listingId: listingId,
            title: propertyName,
            checkIn: checkInDate.toISOString().split("T")[0],
            checkOut: checkOutDate.toISOString().split("T")[0],
            guests: guests,
            night: calculateDaysDifference(checkInDate, checkOutDate),
            subTotalPrice: totalAmount,
            totalAmount: totalAmount,
          };

          console.log("Reservation created successfully!");
          setQuote(reservationData);
          loading = false;
          render();
          console.log(reservationData);
        } else {
          successMsg = "";
          errMsg = "Failed to get Reservation Quote for this Listing";
          loading = false;
          render();
        }

        return data;
      })
      .catch((err) => {
        console.error("Error:", err);
        successMsg = "";
        errMsg = err.message;
        loading = false;
        render();
      });
  };

  function render() {
    const nights = getDaysBetweenDates(dateRange.from, dateRange.to);
    const bookingModal = document.getElementById("booking-modal");

    if (quote) {
      bookingModal.innerHTML = `
            <div class="flex flex-col gap-4">
              <h3 class="text-lg font-playfair font-medium">${quote.title}</h3>
              <aside class="flex gap-2 justify-between">
                <div class="flex flex-col gap-1">
                  <span class="text-xs font-normal">Check In</span>
                  <p class="text-xs font-medium text-[#242428] font-opensans">${getDate(
        dateRange.from
      )}</p>
                </div>
                <div class="flex flex-col gap-1">
                  <span class="text-xs font-normal">Check Out</span>
                  <p class="text-xs font-medium text-[#242428] font-opensans">${getDate(
        dateRange.to
      )}</p>
                </div>
                <div class="flex flex-col gap-1">
                  <span class="text-xs font-normal">Nights</span>
                  <p class="text-xs font-medium text-[#242428] font-opensans">${nights}</p>
                </div>
                <div class="flex flex-col gap-1">
                  <span class="text-xs font-normal">Guests</span>
                  <p class="text-xs font-medium text-[#242428] font-opensans">${quote.guests || guests}</p>
                </div>
              </aside>
              <div class="separator"></div>
              <aside class="flex flex-col gap-4">
                <div class="flex items-center gap-2">
                  <input type="checkbox" id="coupon" class="p-0" ${hasCoupon ? "checked" : ""
        } onchange="toggleCoupon(this.checked)" />
                  <label for="coupon" class="text-sm font-medium leading-none">I have a Coupon</label>
                </div>
                ${hasCoupon
          ? `<input type="text" value="${coupon}" placeholder="Enter Coupon Code" class="w-full" oninput="setCoupon(this.value)" />`
          : ""
        }
                <div class="flex justify-between text-sm font-medium">
                  <p class="font-medium">Subtotal</p>
                  <p>${formatPrice(quote.subTotalPrice)}</p>
                </div>
              </aside>
              <div class="separator"></div>
              <aside class="flex flex-col gap-8">
                <div class="flex justify-between text-lg font-medium">
                  <p>Total</p>
                  <p>${formatPrice(quote.totalAmount)}</p>
                </div>
                <div class="flex gap-2 mt-2 w-full">
                  <button class="border border-[#0B2846] rounded-[2px] p-3 flex items-center justify-center max-w-11 cursor-pointer" onclick="setQuote(null)" ${loading ? "disabled" : ""
        }>
                    <svg fill="#0B2846" width="12" height="12" class="min-w-3"><path d="M10 6L2 6M2 6L6 2M2 6L6 10" stroke="#0B2846" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                  </button>
                  
                  <button type="button" style="background-color: #0B2846;" class="bg-[#0B2846] text-white text-sm rounded-[2px] p-3 w-fit h-[46px] grow" ${loading ? "disabled" : ""
        } onclick="window.location.href='${window.location.origin}/hostawayweb/checkout?id=${quote.listingId}&start=${quote.checkIn}&end=${quote.checkOut}&numberOfGuests=${quote.guests}'">
                    Create Reservation
                  </button>
                </div>
              </aside>
            </div>
          `;
    } else {
      bookingModal.innerHTML = `<div class="flex flex-col gap-4 max-w-md mx-auto bg-white p-4 shadow-md rounded-lg">
    <!-- Date Picker -->
    <aside class="border border-[#EBE3D7] justify-between flex items-center gap-4 lg:min-h-16 w-full rounded">
      <span class="p-3 border-r border-[#EBE3D7]">
        <svg width="24px" height="24px" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
          <path d="M3.5 0V5M11.5 0V5M1.5 2.5H13.5C14.0523 2.5 14.5 2.94772 14.5 3.5V13.5C14.5 14.0523 14.0523 14.5 13.5 14.5H1.5C0.947716 14.5 0.5 14.0523 0.5 13.5V3.5C0.5 2.94772 0.947715 2.5 1.5 2.5Z" stroke="#000000"></path>
        </svg>
      </span>
      <div class="flex w-full px-2 justify-between items-center gap-1 overflow-hidden">
        <input type="text" name="date" id="start-date" class="text-xs py-2 px-4 text-[#242428] font-light  p-2 w-full rounded" placeholder="Start date" style="border: none; outline: none;" />
        <span>-</span>
        <input type="text" name="date" id="end-date" class="text-xs py-2 px-4 text-[#242428] font-light p-2 w-full rounded" placeholder="End date" style="border: none; outline: none;"/>
      </div>
    </aside>

    <!-- Guest Selection -->
    <div class="border border-[#EBE3D7] flex w-full rounded">
      <span class="p-3 border-r border-[#EBE3D7]">
        <svg width="24" height="24" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7.5 0.875C5.49797 0.875 3.875 2.49797 3.875 4.5C3.875 6.15288 4.98124 7.54738 6.49373 7.98351C5.2997 8.12901 4.27557 8.55134 3.50407 9.31167C2.52216 10.2794 2.02502 11.72 2.02502 13.5999C2.02502 13.8623 2.23769 14.0749 2.50002 14.0749C2.76236 14.0749 2.97502 13.8623 2.97502 13.5999C2.97502 11.8799 3.42786 10.7206 4.17091 9.9883C4.91536 9.25463 6.02674 8.87499 7.49995 8.87499C8.97317 8.87499 10.0846 9.25463 10.8291 9.98831C11.5721 10.7206 12.025 11.8799 12.025 13.5999C12.025 13.8623 12.2376 14.0749 12.5 14.0749C12.7623 14.075 12.975 13.8623 12.975 13.6C12.975 11.72 12.4778 10.2794 11.4959 9.31166C10.7244 8.55135 9.70025 8.12903 8.50625 7.98352C10.0187 7.5474 11.125 6.15289 11.125 4.5C11.125 2.49797 9.50203 0.875 7.5 0.875ZM4.825 4.5C4.825 3.02264 6.02264 1.825 7.5 1.825C8.97736 1.825 10.175 3.02264 10.175 4.5C10.175 5.97736 8.97736 7.175 7.5 7.175C6.02264 7.175 4.825 5.97736 4.825 4.5Z" fill="#000000"></path>
        </svg>
      </span>
      <div class="px-2 flex items-center justify-center w-full">
        
          <select class="w-full border-none" name="guests" id="guests" onchange="setGuests(this.value)">
            <option value="1">1 Guest</option>
            <option value="2">2 Guests</option>
            <option value="3">3 Guests</option>
            <option value="4">4 Guests</option>
            <option value="5">5 Guests</option>
            <option value="6">6 Guests</option>
          </select>
       
      </div>
    </div>
    ${errMsg
          ? `<span style="color: red;" class="text-sm text-red-600">${errMsg}</span>`
          : ""
        } 
        ${successMsg
          ? `<span style="color: green;" class="text-sm text-green-600">${successMsg}</span>`
          : ""
        } 
    <!-- Check Availability Button -->
    <button
        class="p-3 bg-[#0B2846] text-white text-xs border-none" onclick="checkAvailability()" ${loading ? "disabled" : ""
        }>
      ${loading ? "Checking..." : "Check availability"}
    </button>
  </div>`;

      // Initialize datepicker asynchronously
      initializeDatepicker().catch(console.error);
    }
  }

  // Disable the datepicker input field initially
  document.querySelectorAll("input[name='date']").disabled = true;

  //fetch availability
  async function fetchAvailability() {
    // Return cached data if available
    if (availabilityCache) {
      return availabilityCache;
    }

    // Prevent multiple simultaneous fetches
    if (isFetchingAvailability) {
      return null;
    }

    try {
      isFetchingAvailability = true;
      const startDate = new Date();
      const endDate = new Date();
      endDate.setFullYear(endDate.getFullYear() + 3);

      const endpoint = `listings/${propertyId}/calendar?startDate=${startDate.toISOString().split("T")[0]}&endDate=${endDate.toISOString().split("T")[0]}`;
      const url = `${hostawayData.pluginUrl}hostaway-server/proxy.php?endpoint=${encodeURIComponent(endpoint)}`;
      const response = await fetch(url);
      const data = await response.json();

      // Cache the result
      availabilityCache = data.result;
      return availabilityCache;
    } catch (error) {
      console.error('Error fetching availability:', error);
      return null;
    } finally {
      isFetchingAvailability = false;
    }
  }

  function getUnavailableDates(data) {
    const unavailableDates = new Set();
    data.forEach(item => {
      if (item.status !== 'available') {
        unavailableDates.add(new Date(item.date).toLocaleDateString());
      }
    });
    return unavailableDates;
  }

  async function initializeDatepicker() {
    try {
      // Show initial loading state
      const bookingModal = document.getElementById("booking-modal");
      const loadingDiv = document.createElement("div");
      loadingDiv.textContent = "Loading calendar...";
      loadingDiv.style.textAlign = "center";
      loadingDiv.style.padding = "10px";
      bookingModal.appendChild(loadingDiv);

      // Fetch availability data first
      const availabilityData = await fetchAvailability();
      const unavailableDates = getUnavailableDates(availabilityData);

      // Remove loading indicator
      loadingDiv.remove();

      // Initialize flatpickr with disabled dates
      const fp = flatpickr("input[name='date']", {
        mode: "range",
        minDate: "today",
        dateFormat: "Y-m-d",
        maxDate: new Date().fp_incr(365 * 3),
        disable: [
          function (date) {
            return unavailableDates.has(date.toLocaleDateString());
          }
        ],
        onChange: function (selectedDates, dateStr, instance) {
          if (selectedDates.length === 1) {
            dateRange.from = selectedDates[0];
            document.getElementById("start-date").value = dateRange.from
              .toLocaleDateString()
              .split("T")[0];
            document.getElementById("start-date").style.fontWeight = "700";
          } else if (selectedDates.length === 2) {
            dateRange.from = selectedDates[0];
            dateRange.to = selectedDates[1];
            document.getElementById("start-date").value = dateRange.from
              .toLocaleDateString()
              .split("T")[0];
            document.getElementById("end-date").value = dateRange.to
              .toLocaleDateString()
              .split("T")[0];
            render();
            document.getElementById("start-date").value = dateRange.from
              .toLocaleDateString()
              .split("T")[0];
            document.getElementById("start-date").style.fontWeight = "700";
            document.getElementById("end-date").value = dateRange.to
              .toLocaleDateString()
              .split("T")[0];
            document.getElementById("end-date").style.fontWeight = "700";
          }
        }
      });

      window.datePickerInstance = fp;

      // Enable the datepicker input
      document.querySelector("input[name='date']").disabled = false;

    } catch (error) {
      console.error('Error initializing datepicker:', error);
      // Handle error state
      const errorDiv = document.createElement("div");
      errorDiv.textContent = "Error loading calendar. Please try again.";
      errorDiv.style.color = "red";
      document.getElementById("booking-modal").appendChild(errorDiv);
    }
  }

  window.toggleCoupon = function (checked) {
    hasCoupon = checked;
    render();
  };

  function setCoupon(value) {
    coupon = value;
  }

  render();

});


function setDate(value) {
  dateRange.from = value ? value.from : null;
  dateRange.to = value ? value.to : null;
  render();
}

document.addEventListener("DOMContentLoaded", function () {
  const guestsSelect = document.getElementById("guests");

  if (guestsSelect) {
    // Ensure the event listener is added directly
    guestsSelect.addEventListener("change", function (e) {
      const selectedValue = parseInt(e.target.value, 10);

      console.log("Guests dropdown change event triggered");
      console.log("Selected guests value:", selectedValue);

      // Update global guests variable
      guests = selectedValue;

      // Update the select element's style
      e.target.style.fontWeight = "700";

      // Force re-render to update the UI
      render();

      console.log("Current guests after update:", guests);
    });
  }

  // Modify the global setGuests function to ensure it works in all scenarios
  window.setGuests = function (value) {
    const selectedValue = parseInt(value, 10);

    console.log("setGuests function called with value:", selectedValue);

    // Update global guests variable
    guests = selectedValue;

    // Update the select element if it exists
    const guestsSelect = document.getElementById("guests");
    if (guestsSelect) {
      guestsSelect.value = selectedValue;
      guestsSelect.style.fontWeight = "700";
    }

    // Force re-render to update the UI
    render();

    console.log("Guests updated to:", guests);
  };
});

How to I call a Vanillas JS function that is within a another Vanillas JS function, in React?

I have a React component that is sitting within a normal web page (so not a SPA).

There is a Vanilla JS function, within another JS function, on this webpage I wish to call from within my React component. This function looks like:

const getInfo = (() => {
  const updateInfo = (dataId) => {
    //Do something
  }
  const showInfo = (dataId) => {
    //Do something
  }
  return {updateInfo, showInfo}
})();

And they’re called on the (normal) webpages like:

getInfo.updateInfo("1324");

Now, I want to include this in my React component. So, I created a helper function, simply copying the above.

const getInfo = (() => {
  const updateInfo = (dataId) => {
    //Do something
  }
  const showInfo = (dataId) => {
    //Do something
  }
  return {updateInfo, showInfo}
})();

And calling it from within another helper function, as normal:

const calculate = () => {
   getInfo.updateInfo("1324");
   // Other React helper function stuff
}

However, when I try to compile I get the error

getInfo.updateInfo is not a function

Would anyone know how I can use getInfo.updateInfo(); within my React component’s helper functions?

Is it possible to play the audio file, without user interaction, after receiving user’s permissions to play audio?

I am trying to play audio without any user interaction and getting error:

Uncaught (in promise) DOMException: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.`

Here is my code:

<audio id="beep">
    <source src="~/Content/Sounds/beep.mp3" type="audio/mp3">
</audio>

<script>
var playAudio = $("#beep")[0];
playAudio.play();
</script>

As I understand its denied by current browsers to play audio without explicit user interaction. Is it possible somehow when the page is loaded ask user for permission to play audio and only after user’s explicit permission load the page, then call this code in JS whenever I need it?