AngularJs API post file to the .net core app endpoint file parameter is null

I am using ald angularJs and trying upload file and do API call, API is a .net core app, I can see request using breakpoint in the API but parameter is comes null always.

here is the angularJs code

 vm.uploadMotorFactor = function () {
   let uploadUrl = `/api/Membership/UploadMotorFactor`;

   let fileInput = document.getElementById('motorFactorFile');
   let file = fileInput.files[0];

   if (!file) {
     alert("Please select a CSV file to upload.");
     return;
   }

   let formData = new FormData();
   formData.append('file', file); // Matches the property name in ImportFileDataRequest

   $http.post(uploadUrl, formData, {
     headers: { 'Content-Type': undefined }, // Let the browser set the correct multipart boundary
     transformRequest: angular.identity
   }).then(response => {
     alert('File uploaded successfully!');
     fileInput.value = ''; // Clear the file input after successful upload
   }).catch(error => {
     console.error('Error uploading file:', error);
     alert('File upload failed.');
   });
 };

this is my API endpoint

 [HttpPost]
 public async Task<IActionResult> UploadMotorFactor([FromForm] IFormFile file)
 {
     try
     {
         return file != null ? Ok() : StatusCode(StatusCodes.Status500InternalServerError);
        
     }
     catch (Exception e)
     {
         _logger.LogError(e, "Failed to download Motor factor");
         return StatusCode(StatusCodes.Status500InternalServerError);
     }
 }

I used 'Content-Type', 'multipart/form-data' as well but the result is the same, what I am missing here?

enter image description here

Zoom Meeting SDK: Uncaught TypeError: Cannot read properties of null (reading ‘append’)

I’m trying to develop an HTML and JavaScript website that can join a meeting room using Zoom Meeting SDK. I’m new to Zoom Meeting SDK so I’m quite confused on why I keep getting the error ‘Uncaught TypeError: Cannot read properties of null (reading ‘append’)’. For now I’m using front-end only. Below is the error:

Error Message Appeared

This is my simple code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kiosk Video Call</title>

    <!-- Add Lodash before Zoom SDK -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

    <!-- Load Zoom SDK Dependencies -->
    <script src="https://source.zoom.us/2.15.0/lib/vendor/react.min.js"></script>
    <script src="https://source.zoom.us/2.15.0/lib/vendor/react-dom.min.js"></script>
    <script src="https://source.zoom.us/2.15.0/lib/vendor/redux.min.js"></script>
    <script src="https://source.zoom.us/2.15.0/lib/vendor/redux-thunk.min.js"></script>
    <script src="https://source.zoom.us/2.15.0/zoom-meeting-2.15.0.min.js"></script>

    <style>
        /* Ensure Zoom Meeting UI is properly displayed */
        #zmmtg-root { 
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 1000;
            background-color: white;
        }
        .meeting-app {
            display: none;
        }
        body { text-align: center; font-family: Arial, sans-serif; }
        .btn {
            background-color: #007bff;
            border: none;
            color: white;
            padding: 15px 32px;
            font-size: 16px;
            cursor: pointer;
            margin-top: 20px;
        }
        .input-field {
            margin: 10px;
            padding: 8px;
            width: 80%;
            max-width: 400px;
            display: block;
        }
    </style>
</head>
<body>

    <h1>Test Video Call</h1>

    <div id="zmmtg-root"></div>
    <div id="aria-notify-area"></div>
    <div class="meeting-app"></div>
    
    <input id="meetingNumber" class="input-field" type="text" placeholder="Enter Meeting Number">
    <input id="passWord" class="input-field" type="text" placeholder="Enter Meeting Password">
    <input id="userName" class="input-field" type="text" placeholder="Enter Your Name" value="Kiosk Client">
    <input id="apiKey" class="input-field" type="text" placeholder="Enter API Key">
    <input id="signature" class="input-field" type="text" placeholder="Enter Signature">

    <button id="startSession" class="btn">Start Session</button>

</body>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        console.log("Checking if ZoomMtg is loaded...");
        
        if (typeof ZoomMtg === "undefined") {
            console.error("Zoom SDK failed to load. Check network connection or script URL.");
            return;
        }

        console.log("Zoom SDK Loaded Successfully");

        // Initialize Zoom SDK
        ZoomMtg.setZoomJSLib("https://source.zoom.us/2.15.0/lib", "/av");
        ZoomMtg.preLoadWasm();
        ZoomMtg.prepareWebSDK();
        ZoomMtg.i18n.load('en-US');
        ZoomMtg.i18n.reload('en-US');

        document.getElementById("startSession").addEventListener("click", function () {
            console.log("Start Session button clicked.");

            // Show Zoom Meeting Container
            document.getElementById('zmmtg-root').style.display = 'block';

            // Get User Inputs
            const meetingNumber = document.getElementById("meetingNumber").value.trim();
            const passWord = document.getElementById("passWord").value.trim();
            const userName = document.getElementById("userName").value.trim();
            const apiKey = document.getElementById("apiKey").value.trim();
            const signature = document.getElementById("signature").value.trim(); 

            if (!meetingNumber || !passWord || !userName || !apiKey || !signature) {
                alert("Please fill in all fields before starting the session.");
                return;
            }

            console.log("Initializing Zoom SDK...");

            ZoomMtg.init({
                leaveUrl: window.location.origin + window.location.pathname,
                isSupportAV: true,
                disableInvite: true,
                success: function () {
                    console.log("Zoom SDK Initialized.");
                    ZoomMtg.join({
                        meetingNumber: meetingNumber,
                        userName: userName,
                        signature: signature,
                        apiKey: apiKey,
                        passWord: passWord,
                        success: function () {
                            console.log("Joined Meeting Successfully!");
                        },
                        error: function (error) {
                            console.error("Zoom Join Error:", error);
                            document.getElementById('zmmtg-root').style.display = 'none';
                        },
                    });
                },
                error: function (error) {
                    console.error("Zoom Init Error:", error);
                    document.getElementById('zmmtg-root').style.display = 'none';
                },
            });
        });
    });
</script>

</html>

How to get uid on client rendered pages? (firebase, nextjs)

I’m trying to get my firebase uid on a nextjs client rendered page.

This is my function to get the uid from the session cookie.

import "server-only";    

export async function isUserAuthenticated(session: string | undefined = undefined) {
    const _session = session ?? (await getSession());
    if (!_session) return false;

    try {
        const decodedIdToken = await auth.verifySessionCookie(_session, true);
        return decodedIdToken.uid;
    } catch (error) {
        console.log(error);
        return false;
    }
}

The problem is, for security reasons, I can only run this in server components. verifySessionCookie() is part of the firebase-admin lib (here).

I’d love to pass this down from my layout.tsx but I can’t pass props to {children} and I can’t use context in server components. The only way I can think to do this is to make every single page.tsx a server component and then pass down the uid to as props from there. But this seems horrible, I’d be replicating the same code for every single URL. Is there any other solution besides this?

How to list all posts from Appwrite

I am trying to make a Post Web App using Appwrite. I am able to upload the images but not view them in all posts for anonymous reason.

config.js:



async getPosts(queries = [Query.equal("status", "active")]){

        try {

            return await this.databases.listDocuments(

                conf.appwriteDatabaseId,

                conf.appwriteCollectionId,

                queries,

                



            )

        } catch (error) {

            console.log("Appwrite serive :: getPosts :: error", error);

            return false

        }

    }

All posts.jsx:



import React, {useState, useEffect} from 'react'

import { Container, PostCard } from '../components'

import appwriteService from "../appwrite/config";



function AllPosts() {

    const [posts, setPosts] = useState([])

    useEffect(() => {}, [])

    appwriteService.getPosts([]).then((posts) => {

        if (posts) {

            setPosts(posts.documents)

        }

    })

  return (

    <div className='w-full py-8'>

        <Container>

            <div className='flex flex-wrap'>

                {posts.map((post) => (

                    <div key={post.$id} className='p-2 w-1/4'>

                        <PostCard {...post} />

                    </div>

                ))}

            </div>

            </Container>

    </div>

  )

}



export default AllPosts

I tried to check full appwrite configs but still nothing changed. I also tried ChatGPT but it failed. The length of post is always 0

Multiple Vite processes overwriting each other

I have a Neos CMS project which has a small preact project inside of it. The bundled preact JS code should not always be rendered, but only when a specific element is rendered. For this reason, I can’t bundle all my JavaScript into one and need two Vite processes.

Now the problem: The Vite processes of course don’t know of each other and use the same function and variable names for the minification, which, of course, breaks everything.

Is there any way I can bypass this?

InvalidOperationException: There is already a subscriber to the content with the given section ID ‘System.Object’

I have a blazor app.
In my wwwroot folder I created a folder called JS and created a javascript file called Paginate.js and wrote 2 functions.

In my app.razor I referenced thre js file and the page on my blazor I tried to invoke the function. Now i get the above error. I removed what I did to the last time it worked and I am still getting the same message?

Is there anything that was created in the background or what am I missing?

Thanks

OnAfterRenderAsync{ 
 Await 
JSRuntime.InvokeVoidAsync("pagination")
}

I want to design a web image gallery with css grid in a particular way and I’m stuck

  1. I wanted to have only 6 images under the main-image, but at the same time I want to have more than 6 images / total.. the 1st problem is whenever I add another image is creating a new row, it’s not creating it on the same row – I only want to have 2 rows the one with the main image and the one with the 6 images ( with ONLY six images )

  2. How do I have multiple images in that “slider” underneath, without having to have them all at the same time but to see them gradually as the user clicks through them? I want only 6 images in the slider but more in total so when the user gets to the 6th image, the next 6 images load, while the previous 6 images hide, and when it gets to the last image to go back to the first and vice versa.

I tried added images then hiding them with overflow:hidden (before I get into the js I need to get through this one first).

I’m kind of a beginner so on the 2nd problem I have no clue where to start, but if someone could just point me in the right direction it would be very nice for me.

html {
  font-size: 62.5%;
  box-sizing: border-box;
  /* font-family: "Montserrat", sans-serif; */
}

body {
  margin: 0;
  padding: 0;
  font-family: "Montserrat", sans-serif;
  font-optical-sizing: auto;
  font-weight: 500;
  font-style: normal;
  background-color: #e9e9e9;
}

figure {
  display: block;

  margin: 0;
  padding: 0;

  height: 100%;
  width: 100%;
}

.grid {
  display: grid;

}

.grid__gallery {
  max-width: 100%;

  padding: .5rem;

  margin-left: 2rem;
  margin-right: 2rem;

  column-gap: 0.4rem;
  row-gap: 0.1rem;

  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: auto;

}

.main__image {
  position: relative;
  width: 100%;
  color: white;
  background-color: #444;

  height: 50rem;


  grid-column: 1 / -1;

  /* this will helps changing the photo */
  /* by selecting the url of one of the photos under the  main slide and passing it in the background image of this css */
  background-image: url("");
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

.image {
  max-width: 100%;
  width: 100%;

  cursor: pointer;
  transition: 0.1s ease;


  background-color: #333;
  border: 1px solid green;
  height: 15rem;
}

.slide:active {
  cursor: pointer;
  transform: scale(0.995);
  box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.041);
}

.slider-arrow {
  font-size: 3rem;
  position: absolute;
  cursor: pointer;
  padding: 1rem;
  border-radius: 10%;

  transition: 0.3s ease;
  border: 0.1rem solid transparent;
  outline: none;
}

.slider-arrow:active {
  font-size: 2.8rem;
}

.slider-arrow:hover {
  border: 0.1rem solid #fff;
}

.left-arrow {
  top: 50%;
  left: 5%;
  transform: translateY(-50%);
}

.right-arrow {
  top: 50%;
  right: 5%;
  transform: translateY(-50%);
}
<div class="grid grid__gallery">
  <div class="main__image">
    <div class="left-arrow slider-arrow">&larr;</div>
    <div class="right-arrow slider-arrow">&rarr;</div>
  </div>
  <figure class="image slide__1"><img src="" alt="1" /></figure>
  <figure class="image slide__2"><img src="" alt="2" /></figure>
  <figure class="image slide__3"><img src="" alt="3" /></figure>
  <figure class="image slide__4"><img src="" alt="4" /></figure>
  <figure class="image slide__5"><img src="" alt="5" /></figure>
  <figure class="image slide__6"><img src="" alt="6" /></figure>
</div>

How to stop the selecting first suggestion?

If I don’t select from the options, I want to search by query when I press enter.

I tried html element id keyup event what should i do?

<UInputMenu
            v-model="query"
            size="lg"
            :search="search"
            class="border-[#CECECE] rounded-lg bg-[#F5F5F5] sm:w-[263px] placeholder:text-[#A8A8A8] absolute flex items-center justify-center"
            :class="
              userProfile?.id ? 'w-[calc(100%-80px)]' : 'w-[calc(100%-210px)]'
            "
            placeholder="search product..."
            selected-icon=""
            :ui="{
              icon: {
                trailing: {
                  pointer: '',
                  padding: {
                    lg: '!px-1',
                  },
                },
              },
            }"
            @update:model-value="handleSearch"
          >
            <template #trailing>
              <UButton
                icon="i-heroicons-magnifying-glass"
                variant="soft"
                class="min-w-14 justify-center"
                @click="handleSearch(query)"
              />
            </template>
          </UInputMenu>

Prestashop Controllers and Hooks

I created a form and I want to handle the hook hookDisplayAdminProductsMainStepLeftColumnMiddle directly from the controller in /controllers/admin/AjaxSeoScore.php. The view to be displayed is located in /views/templates/admin/test.tpl

 public function hookDisplayAdminProductsMainStepLeftColumnMiddle($params)
{
    $controller = new AdminAjaxSeoScore();
    return $controller->display();
} 

and then my controller

class AdminAjaxSeoScore extends ModuleAdminController
{
    public function __construct()
    {
        // Chiamata al costruttore della classe base
        parent::__construct();

        // Setta il template per la visualizzazione
        $this->template = 'seoscore_header.tpl';
    }

    // Funzione per la visualizzazione dell'hook
    public function display()
    {
        // Aggiungi variabili da passare al template se necessario
        $this->context->smarty->assign(array(
            'some_variable' => 'Some value', // Esempio di variabile da assegnare
        ));

        // Visualizza il template
        parent::display();
    }
} 

Is this the correct way to work? I can’t visualize anything. How do I pass for example the product id to the controller?

How do I scroll a slide within a vertical slide and have it snap to the next slide and fade with Swiper.js?

As the title says, how do I scroll through a slide that has 500vh and then snap to the next slide and fade with Swiper.js?

https://codepen.io/Echo1017/pen/NPWrBGq?editors=1010

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>I want to scroll within a vertical slide and fade to the next slide!</title>
    <link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">
    <style>
        html, body {
            position: relative;
            height: 100%;
        }
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #fff;
        }
        .swiper {
            width: 100%;
            height: 100%;
        }
        .swiper-slide {
            text-align: center;
            font-size: 18px;
            display: flex;
            justify-content: center;
            align-items: center;
            scroll-snap-align: start;
        }
        .swiper-slide:first-child {
            height: 500vh;
            overflow: auto; 
            background: linear-gradient(blue, pink);
            scroll-snap-type: y mandatory; 
            scroll-snap-stop: always; 
        }
        .swiper-slide:nth-child(2) {
            background-color: #98fb98; 
        }
        .swiper-slide:nth-child(3) {
            background-color: #87cefa; 
        }
    </style>
</head>
<body>
    <div class="swiper">
        <div class="swiper-wrapper">
            <div class="swiper-slide"><h1>SLIDE 1 <br/>When I scroll down this 500vh slide to the bottom, I want it to snap and fade to show the next slide.</h1></div>
            <div class="swiper-slide"><h1>SLIDE 2</h1></div>
            <div class="swiper-slide"><h1>SLIDE 3</h1></div>
        </div>
    </div>
    
    <script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
    <script>
        var swiper = new Swiper('.swiper', {
            effect: 'fade',
            fadeEffect: {
                crossFade: true
            },
            direction: 'vertical',
            mousewheel: true,
            pagination: {
                el: '.swiper-pagination',
                clickable: true,
            },
            slidesPerView: 'auto',
            speed: 1000,
        });
    </script>
</body>
</html>

I want to keep the behaviour as it is and allow the first slide to be scrollable.
I have tried free mode, but after a little scrolling it goes back to the top of the slide.

Remote window in webrtc won’t display

I am trying to setup this web rtc video call function for a site i am building, the call will only be connected if the admin has in the function the same name as the client side’s name, in my server in the logs i get

Forwarding candidate for admin Received message: { type:
‘client_join’, name: ‘admin’ } Client trying to join: admin Client
successfully connected: admin Connection closed New connection
established

But the remoteVideo in each side won’t load, i dont know what more to try

Server.js:

const WebSocket = require("ws");

const wss = new WebSocket.Server({ port: 3000 });
let activeCalls = {};

wss.on("connection", (ws) => {
    console.log("New connection established");

    ws.on("message", (message) => {
        const data = JSON.parse(message);
        console.log("Received message:", data);

        if (data.type === "admin_join") {
            if (activeCalls[data.name]) {
                console.log(`Admin already in another call: ${data.name}`);
                ws.send(JSON.stringify({ type: "admin_busy" }));
                return;
            }
            activeCalls[data.name] = { admin: ws, client: null };
            console.log(`Admin joined the call: ${data.name}`);
        }

        if (data.type === "client_join") {
            console.log(`Client trying to join: ${data.name}`);

            if (!activeCalls[data.name]) {
                console.log(`No admin call for ${data.name}. Client rejected.`);
                ws.send(JSON.stringify({ type: "waiting", name: data.name }));
                return;
            }

            if (activeCalls[data.name].client) {
                console.log(`Another client is already in call with admin: ${data.name}`);
                ws.send(JSON.stringify({ type: "admin_busy" }));
                return;
            }

            activeCalls[data.name].client = ws;
            ws.send(JSON.stringify({ type: "client_joined", name: data.name }));
            activeCalls[data.name].admin.send(JSON.stringify({ type: "client_joined", name: data.name }));
            console.log(`Client successfully connected: ${data.name}`);
        }

        if (data.type === "offer" || data.type === "answer" || data.type === "candidate") {
            console.log(`Forwarding ${data.type} for ${data.name}`);

            if (activeCalls[data.name] && activeCalls[data.name].client && activeCalls[data.name].admin) {
                const target = data.type === "offer" ? activeCalls[data.name].client : activeCalls[data.name].admin;
                if (target && target.readyState === WebSocket.OPEN) {
                    target.send(JSON.stringify(data));
                }
            }
        }

        if (data.type === "leave") {
            console.log(`${data.name} left the call`);
            if (activeCalls[data.name]) {
                if (activeCalls[data.name].client) activeCalls[data.name].client.send(JSON.stringify({ type: "leave", name: data.name }));
                if (activeCalls[data.name].admin) activeCalls[data.name].admin.send(JSON.stringify({ type: "leave", name: data.name }));
                delete activeCalls[data.name];
            }
        }
    });

    ws.on("close", () => {
        console.log("Connection closed");
    });
});

console.log("WebSocket server running on ws://localhost:3000");

Client side:

  <section>
    <script>
        const name = "<?php echo $_SESSION['name']; ?>";
        console.log("Client is:", name);

        const videoCallSection = document.createElement("div");
        document.body.appendChild(videoCallSection);

        videoCallSection.innerHTML = `
            <h1>Client Video Call: ${name}</h1>
            <video id="localVideo" autoplay playsinline style="display: none;"></video>
            <video id="remoteVideo" autoplay playsinline style="display: none;"></video>
            <button id="joinCall" style="margin-top:10px; padding:10px; background:green; color:white; border:none; cursor:pointer;">Join Call</button>
            <button id="leaveCall" style="margin-top:10px; padding:10px; background:red; color:white; border:none; cursor:pointer; display:none;">Leave Call</button>
            <p id="statusMessage" style="color: red; font-weight: bold;"></p>
        `;

        const localVideo = document.getElementById("localVideo");
        const remoteVideo = document.getElementById("remoteVideo");
        const joinButton = document.getElementById("joinCall");
        const leaveButton = document.getElementById("leaveCall");
        const statusMessage = document.getElementById("statusMessage");

        const peerConnection = new RTCPeerConnection({
            iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
        });

        const socket = new WebSocket("ws://localhost:3000");
        let localStream;

        joinButton.addEventListener("click", async () => {
            joinButton.style.display = "none";
            leaveButton.style.display = "block";
            localVideo.style.display = "block";
            remoteVideo.style.display = "block";

            socket.send(JSON.stringify({ type: "client_join", name }));

            navigator.mediaDevices.getUserMedia({ video: true, audio: true })
                .then(stream => {
                    localStream = stream;
                    localVideo.srcObject = stream;
                    stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
                })
                .catch(error => console.error("Error accessing media devices.", error));
        });

        socket.onmessage = async (message) => {
            const data = JSON.parse(message.data);

            console.log("Received message:", data);

            if (data.name !== name) {
                statusMessage.innerText = "This call is not for you!";
                return;
            }

            if (data.type === "admin_busy") {
                statusMessage.innerText = "Admin is in another call.";
                return;
            }

            if (data.type === "waiting") {
                statusMessage.innerText = "Waiting for admin to start the call.";
                return;
            }

            if (data.type === "client_joined") {
                statusMessage.innerText = "Call connected!";
            }

            if (data.type === "offer") {
                await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
                const answer = await peerConnection.createAnswer();
                await peerConnection.setLocalDescription(answer);
                socket.send(JSON.stringify({ type: "answer", answer, name }));
            } else if (data.type === "candidate") {
                await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
            } else if (data.type === "leave") {
                endCall();
            }
        };

        function endCall() {
            if (localStream) {
                localStream.getTracks().forEach(track => track.stop());
            }
            if (peerConnection) {
                peerConnection.close();
            }
            socket.send(JSON.stringify({ type: "leave", name }));
            socket.close();
            videoCallSection.innerHTML = "";
        }

        leaveButton.addEventListener("click", endCall);
    </script>
</section>

Admin side:

  function showvideo(name) {
    console.log("Admin wants to call:", name);

    const videoCallSection = document.getElementById("videocall");
    videoCallSection.style.display = "block";

    videoCallSection.innerHTML = `
        <h1>Admin Video Call: ${name}</h1>
        <video id="localVideo" autoplay playsinline></video>
        <video id="remoteVideo" autoplay playsinline></video>
        <button id="leaveCall" style="margin-top:10px; padding:10px; background:red; color:white; border:none; cursor:pointer;">Leave Call</button>
        <p id="statusMessage" style="color: red; font-weight: bold;"></p>
    `;

    const localVideo = document.getElementById("localVideo");
    const remoteVideo = document.getElementById("remoteVideo");
    const leaveButton = document.getElementById("leaveCall");
    const statusMessage = document.getElementById("statusMessage");

    const peerConnection = new RTCPeerConnection({
        iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
    });

    const socket = new WebSocket("ws://localhost:3000");
    let localStream;
    let inCall = false;
    let connectedClient = null;

    // Start local video only if user is valid
    navigator.mediaDevices.getUserMedia({ video: true, audio: true })
        .then(stream => {
            localStream = stream;
            localVideo.srcObject = stream;
            stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
        })
        .catch(error => console.error("Error accessing media devices:", error));

    peerConnection.ontrack = event => {
        remoteVideo.srcObject = event.streams[0];
    };

    socket.onmessage = async (message) => {
        const data = JSON.parse(message.data);
        console.log("Received message:", data);

        if (data.type === "admin_busy") {
            statusMessage.innerText = "Admin is in another call.";
            return;
        }

        if (data.type === "waiting") {
            statusMessage.innerText = "Waiting for client to join...";
            return;
        }

        if (data.type === "client_joined") {
            if (data.name !== name) {
                statusMessage.innerText = "Client name mismatch!";
                return;
            }
            connectedClient = data.name;
            statusMessage.innerText = "Call connected!";
        }

        if (data.type === "offer") {
            if (data.name !== name) {
                statusMessage.innerText = "Wrong client trying to connect!";
                return;
            }
            await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
            const answer = await peerConnection.createAnswer();
            await peerConnection.setLocalDescription(answer);
            socket.send(JSON.stringify({ type: "answer", answer, name }));
        } else if (data.type === "answer") {
            await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer));
        } else if (data.type === "candidate") {
            if (data.name !== name) return;
            await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
        } else if (data.type === "leave") {
            endCall();
        }
    };

    peerConnection.onicecandidate = event => {
        if (event.candidate) {
            socket.send(JSON.stringify({ type: "candidate", candidate: event.candidate, name }));
        }
    };

    socket.onopen = () => {
        socket.send(JSON.stringify({ type: "admin_join", name }));
    };

    async function startCall() {
        if (inCall) {
            statusMessage.innerText = "Admin is already in another call.";
            return;
        }

        const offer = await peerConnection.createOffer();
        await peerConnection.setLocalDescription(offer);
        socket.send(JSON.stringify({ type: "offer", offer, name }));
        inCall = true;
    }

    function endCall() {
        if (localStream) localStream.getTracks().forEach(track => track.stop());
        if (peerConnection) peerConnection.close();
        socket.send(JSON.stringify({ type: "leave", name }));
        socket.close();
        videoCallSection.innerHTML = "";
        inCall = false;
    }

    leaveButton.addEventListener("click", endCall);
    setTimeout(startCall, 1000);
}

Chrome extension only working after a refresh of the page

Im making my first ever chrome extension, the idea is: when a table in my salesforce cases contain any word i give in, it goes in a color i chose for that word.

The whole things works like i want to, the only problem im having is that i first need te press refresh when i open a new tab. After clicking refresh once, it keeps working in that tab.

This is my content.js:

 chrome.storage.local.get(['preferences'], function (result) {
  const preferences = result.preferences || [];
  console.log('Opgeslagen voorkeuren:', preferences);

  if (preferences.length === 0) {
    console.log('Geen voorkeuren ingesteld.');
    return;
  }

  // Functie om Shadow DOM te doorzoeken
  const traverseShadowDOM = (node, callback) => {
    if (node.nodeType === Node.ELEMENT_NODE) {
      if (node.shadowRoot) {
        callback(node.shadowRoot);
        node.shadowRoot.childNodes.forEach(child => traverseShadowDOM(child, callback));
      }
      node.childNodes.forEach(child => traverseShadowDOM(child, callback));
    }
  };

  // Pas kleuren toe op rijen, inclusief Shadow DOM
  const applyColorsToRows = () => {
    let rows = [];
    traverseShadowDOM(document.body, (root) => {
      const found = root.querySelectorAll('tr[data-row-key-value]');
      rows = rows.concat(Array.from(found));
    });

    if (rows.length > 0) {
      console.log('Case-rijen gevonden, toepassing gestart.');
      rows.forEach(row => {
        const statusCell = row.querySelector('td[data-label="Status"]');
        const statusSpan = statusCell?.querySelector('span[title]');
        if (statusCell && statusSpan) {
          preferences.forEach(preference => {
            if (statusSpan.textContent.trim() === preference.status) {
              if (preference.applyTo === 'column') {
                statusCell.style.backgroundColor = preference.bgColor;
                statusCell.style.color = preference.textColor;
              } else {
                row.style.backgroundColor = preference.bgColor;
                row.style.color = preference.textColor;
              }
            }
          });
        }
      });
    }
  };

  // Verbeterde retry-logica met backoff
  let retries = 0;
  const maxRetries = 10; // Maximaal 5 seconden (10 * 500ms)
  const retryInterval = setInterval(() => {
    applyColorsToRows();
    if (retries >= maxRetries) clearInterval(retryInterval);
    retries++;
  }, 500);

  // MutationObserver voor toekomstige wijzigingen
  const observer = new MutationObserver(applyColorsToRows);
  observer.observe(document.body, { childList: true, subtree: true });
});

This is manifest.js:

{
"manifest_version": 3,
"name": "BetterBetterLists for Salesforce",
"version": "1.0",
"permissions": [
  "storage"
],
"background": {
  "service_worker": "background.js"
},
"content_scripts": [
  {
    "matches": ["https://rogiers.lightning.force.com/lightning/o/Case/*"],
    "js": ["content.js"],
    "all_frames": true, 
    "run_at": "document_idle"
  }
],
"action": {
  "default_popup": "popup.html",
  "default_icon": {
    "16": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  }
}

}

my background.js:

chrome.runtime.onInstalled.addListener(() => {
    console.log('BetterLists for Salesforce is geinstalleerd!');
  });
  
  // Service worker ontvangt berichten van content scripts of popup
  chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === 'getPreferences') {
      chrome.storage.local.get(['status', 'color'], function(result) {
        sendResponse(result);
      });
      return true;  // Om te wachten op de async reactie
    }
  });

Then i have a html page for the popup when its clicked, but i wont share that bcs its not important i think.

If anyone would be able to help i would be really greatful!

Thank you for your time!

Robbe

Date FNS module of Chart Js axis is displaying improperly

This is my chart

Here is my code I am using the date-fns module with chart js, the x axis fails to display some months and the spacing between the bars are also weirdly off centered.:

var expenseChartElement = document.getElementById('expenseGraph')

const rawExpense= JSON.parse('{{user["expenses"] | tojson}}')

// console.log(data["income1"]["amt"])
const dates = []



for (let expense in rawExpense){
    let parsedDate = new Date(rawExpense[expense]["date"]); // Ensure correct date parsing
    dates.push({ x: parsedDate, y: parseFloat(rawExpense[expense]["amt"]) });
}


console.log(dates)

    


const data = {
    datasets : [{
        label:"Expense Amount $",
        data : dates,
        backgroundColor:'rgba(54, 162, 235, 0.6)',
    }]

}


const config = {
    type:'bar',
    data,
    options: {
        scales:{
            x:{
                type:'time',
                time : {
                    unit : 'week'
                },
                
            },
            y:{
                beginAtZero:true
            }
        }
    }
};

expenseGraph = new Chart(expenseChartElement,config)

I tried offsetting the timezone, everything is in the right format but nothing works. Please Help. Thanks.

Declaring object.prototype in js – VueRouter it automatically calls a method

I declared an extension method for objects by creating my own function. However, I do not call or import it anywhere. As a result, I get an exception. How can I fix this? I don’t recall such behavior in VUE 2.

Object.prototype.mergeObjXXXX = function(obj2){
     console.log(this);
     console.log(obj2);
}

vue 3.5.13
vue-router: 4.5.0

main.js:38 TypeError: Cannot convert undefined or null to object
    at Object.assign (<anonymous>)
    at Object.mergeObjXXXX (ext.js:20:9)
    at extractComponentsGuards (vue-router.js?v=ea680b7e:1465:32)
    at vue-router.js?v=ea680b7e:2484:16

Service Worker how to load index.html from cache only when offline, if online from network

I’m trying to implement a network strategy for index.html where it is always fetched from the network but falls back to the cache only when offline.

The reason for this approach is that my index.html contains the entry points for the JavaScript and CSS files, which include a hash in their filenames. When I push an update, these hashes change, meaning the service worker won’t find the old .js and .css files in the cache. By always fetching index.html from the network, the app will instantly load the latest version without requiring a manual click to the reload prompt.

However, I still want the app to work offline, so if there’s no internet connection, index.html should be served from the cache.

I’m using vite-plugin-pwa with injectManifest, and my current service worker caches everything, including HTML, CSS, JS, PNG, ICO, and SVG files.

Here’s my initial service worker setup:

/// <reference lib="webworker" />
import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching';
import { NavigationRoute, registerRoute } from 'workbox-routing';

declare let self: ServiceWorkerGlobalScope;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting();
});

// self.__WB_MANIFEST is the default injection point
precacheAndRoute(self.__WB_MANIFEST);

// clean old assets
cleanupOutdatedCaches();

registerRoute(new NavigationRoute(createHandlerBoundToURL('index.html')));

I’ve been trying to modify it so that index.html is always fetched from the network, falling back to the cache only when offline. However, index.html still seems to be served from the cache every time.

Here’s what I’ve tried:

/// <reference lib="webworker" />
import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching';
import { NavigationRoute, registerRoute } from 'workbox-routing';
import { NetworkFirst } from 'workbox-strategies';
import { cacheNames } from 'workbox-core';

declare let self: ServiceWorkerGlobalScope;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting();
});

// self.__WB_MANIFEST is the default injection point
precacheAndRoute(self.__WB_MANIFEST);

// clean old assets
cleanupOutdatedCaches();

// Retrieve the precache cache name dynamically
const precacheCacheName = cacheNames.precache;

registerRoute(
  ({ request }) => request.mode === 'navigate' || request.url.endsWith('/index.html'),
  new NetworkFirst({
    cacheName: precacheCacheName,
    plugins: [
      {
        fetchDidFail: async ({ request }) => {
          console.warn('Network request failed, serving from cache:', request.url);
        },
      },
    ],
  })
);

registerRoute(new NavigationRoute(createHandlerBoundToURL('index.html')));

What am I doing wrong?

Does my approach make sense fetching index.html from the network to always serve the latest version of the app?
I understand that the reload prompt will still appear because the service worker enters a waiting state. However, this strategy ensures that if I make backend changes, the newly fetched JavaScript will work immediately instead of failing with API errors until the user manually reloads. This way, the app stays functional without waiting for the reload prompt to take effect.

Thanks