Why Vite development mode can resolve a module but not a built product?

I am developing a Fastify application with Vite.
My product uses jsonwebtoken package to sign and verify JWT.

While developing, I can use all jsonwebtoken functions with Vite’s development mode. However, after I build the application, although the building process goes well, the built application collapses and produces TypeError: jwt.sign is not a function.

Why the development mode works well but the built product doesn’t?
Is there any way to detect the error at compile time? Or is there any mistakes in my building setting?

Here is a minimum reproduction source code. https://github.com/randyumi/20240203jsonwebtoken-vite-build

  • npm run dev -> curl http://localhost:8080/ -> works well and returns signed JWT.
  • npm run build -> NODE_ENV=production node dist/index.js -> curl http://localhost:8080/ -> not works, says jwt.sign is not a function

I found an issue regarding this problem https://github.com/auth0/node-jsonwebtoken/issues/655

react-router-dom | path=”*” doesn’t work on vercel

I’m currently working on developing an application using React along with React Router Dom, and I’m in the process of deploying it on Vercel. So far, all of my routes are functioning as expected, except for the 404 error route. I’m encountering an issue, and I’m seeking assistance to resolve it.

In my React application, I’ve set up various routes using React Router Dom, and they seem to be working fine. However, the specific route designed to handle 404 errors is not behaving as intended. I would greatly appreciate any help or guidance in troubleshooting and resolving this issue.

App.jxs code:


import './App.css'

import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom"
import { onAuthStateChanged } from "firebase/auth"

// Hooks
import {useState, useEffect} from "react"
import { useAuthentication } from './hooks/useAutentication.jsx'

// Pages
import Home from "./pages/Home/Home.jsx"
import About from "./pages/About/About.jsx"
import CreatePost from './pages/CreatePost/CreatePost.jsx'
import Dashboard from './pages/Dashboard/Dashboard.jsx'
import Login from "./pages/Login/Login.jsx"
import Register from "./pages/Register/Register.jsx"
import Search from './pages/Search/Search.jsx'
import Post from './pages/Post/Post.jsx'
import EditPost from './pages/EditPost/EditPost.jsx'
import NotFound from './pages/NotFound/NotFound.jsx'

// Components
import NavBar from "./components/NavBar.jsx"
import Footer from "./components/Footer.jsx"


//Context
import { AuthProvider } from "./context/AuthContext.jsx"

function App() {
  const [user, setUser] = useState(undefined)
  const {auth} = useAuthentication()

  const loadingUser = user === undefined

  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      setUser(user)
    })
  }, [auth])

  if(loadingUser){
    return <p>Carregando...</p>
  }

  return (
    <div className='w-full'>
      
      <AuthProvider value={{ user }}>
        <BrowserRouter>
          <NavBar />
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
            <Route path="/login" element={!user ? <Login /> : <Navigate to="/" />} />
            <Route path="/register" element={!user ? <Register /> : <Navigate to="/" />} />
            <Route path='/posts/create' element={user ? <CreatePost /> : <Navigate to="/login" />} />
            <Route path='/dashboard' element={user ? <Dashboard /> : <Navigate to="/login" />} />
            <Route path='/search' element={<Search />} />
            <Route path='/posts/:id' element={<Post />} />
            <Route path='/posts/edit/:id' element={user ? <EditPost /> : <Navigate to="/login" />} />
            <Route path='*' element={<NotFound />} />
          </Routes>
          <Footer />
        </BrowserRouter>
      </AuthProvider>
    </div>
  )
}

export default App

i have to modify my App.jsx code, or something on vercel website?

In react.js, a piece of css style that is mysteriously applied to a component; How to find how it is applied, by the help of chrome developer mode?

I have a Material React Table; In the table, 2 columns are almost the same;

They only differ in:

column A has filterVariant: ‘text’;

column B has filterVariant: ‘select’;

So the filter input in column A is a text field for you to type in texts;
the filter input in column B is a select dropdown for you to open the dropdown and click the option you want to select;

However, the two filters are a bit different in UI:
image:

see the gap? the underline of the filter are not at the same level; the second one is a bit higher;

enter image description here

column B’s filter looks more narrow in height;

In Browser developer mode, on inspection,

I found that in column A’s filter:

.css-12pkzps-MuiInputBase-input-MuiInput-input
{
  font: inherit;
  letter-spacing: inherit;
  color: currentColor;
  padding: 4px 0 5px;  // this is the key
  border: 0;
  box-sizing: content-box;
  background: none;
  height: 1.4375em;
  margin: 0;
  -webkit-tap-highlight-color: transparent;
  display: block;
  min-width: 0;
  width: 100%;
  -webkit-animation-name: mui-auto-fill-cancel;
  animation-name: mui-auto-fill-cancel;
  -webkit-animation-duration: 10ms;
  animation-duration: 10ms;
  text-overflow: ellipsis;
}

It has padding: 4px 0 5px;

And I found that in column B’s filter:

.css-y3y8ml-MuiSelect-select-MuiInputBase-input-MuiInput-input.MuiSelect-select
{
  display: grid;
  -webkit-align-items: center;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  padding: 0 0.75rem !important; // this is causing the filter to look thinner!! 
}

.css-y3y8ml-MuiSelect-select-MuiInputBase-input-MuiInput-input
{
  -moz-appearance: none;
  -webkit-appearance: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  border-radius: 0;
  cursor: pointer;
  font: inherit;
  letter-spacing: inherit;
  color: currentColor;
  padding: 4px 0 5px;  // this line is sriked through and greyed out; 
  ...
}

It has the same padding: 4px 0 5px; at first, but then it is over-written by padding: 0 0.75rem !important; above.

However, in the react.js code where the table and the columns are defined, there is no code that applies the padding: 0 0.75rem !important; style.

How can I debug this and find out where this mysterious padding: 0 0.75rem !important; is from?

Capture keyboard shortcut and then enact another shortcut

For a third-party website that I don’t control, there is a keyboard shortcut of command + K (on a Mac) to trigger some functionality (it opens up a command palette to search and perform actions). I would like to explore whether it is possible to create my own custom keyboard shortcut to also enact this command palette functionality. ie. if I press the keyboard character “.” or letters “gg”, to trigger the same functionality as native command + K of the website. I would execute the javascript using a Chrome browser extension when I load the particular website.

There seems to be many ways to capture a custom shortcut combination and then call subsequent code:

Detect double Ctrl keypress in JS

But then the problem arises, is it possible to trigger a keyboard shortcut that is specific to that website (and not an OS shortcut etc.)?

This implies that calling a shortcut such as an OS shortcut would not be possible: Javascript to trigger keyboard shortcut (CMD+SHIFT+4) on Mac

But is there an option to trigger a website-specific keyboard shortcut?

Synchronizing two interfaces in real-time [closed]

I am currently developing a web application dedicated to online quiz management using php and java script & mysql. In this application, hosts will have the ability to create their own quizzes, while participants can engage in them. However, I am facing a challenge: I want participants to be unable to navigate between questions when viewing the quiz. This responsibility should be delegated to the host.
To address this issue, I have designed a single page that appears with two distinct interfaces. The interface for the host will be displayed on a projector and accessible via the link:

<?php echo "<a href="jueuser.php?code_quiz=" . $row['code'] . "&role_user=" . $role_user . "&id_animateur=" . $id_animateur . ""> 'lancer le quiz</a>

This way, the host can manage the progression of questions.

Simultaneously, the same page will serve as the participant interface, accessible via the link:

header("location:jueuser.php?code_quiz=$code_quiz&id=$user_id&pseudo=$pseudo&role_user=$role_user&quiz_user_id=$quiz_user_id");

This version of the page, tailored for participants using mobile phones, will disable the ability to navigate between questions, thus reserving this function exclusively for the host. However, I know how to implement it; here’s my jueuser.php code:

<!-------jueuser.php--------------->
<?php
include_once "connexion.php";
$role_user = isset($_GET['role_user']) ? mysqli_real_escape_string($con, $_GET['role_user']) : '';
$roleUserJson = json_encode($role_user);
$id_animateur = isset($_GET['id_animateur']) ? mysqli_real_escape_string($con, $_GET['id_animateur']) : '';
$code_quiz = isset($_GET['code_quiz']) ? mysqli_real_escape_string($con, $_GET['code_quiz']) : '';
$user_id = isset($_GET['user_id']) ? mysqli_real_escape_string($con, $_GET['user_id']) : '';
$id = isset($_GET['quiz_user_id']) ? mysqli_real_escape_string($con, $_GET['quiz_user_id']) : '';

if ($code_quiz || ($type_animateur && $id_animateur)) {
    $quiz = mysqli_query($con, "SELECT id_quiz , titre FROM quiz WHERE code='$code_quiz'");
    $quiz_row = mysqli_fetch_assoc($quiz);
    $id_quiz = $quiz_row['id_quiz'];
    $titre_quiz = $quiz_row['titre'];
} else {
    echo "Erreur : Paramètres manquants pour afficher les questions du quiz.";
    exit();
}
$question = mysqli_query($con, "SELECT id_question, numero,type_question, contenu , path_file FROM questions WHERE quiz_id=$id_quiz");
$totalQuestions = mysqli_num_rows($question);
?>

<!DOCTYPE html>
<html lang="fr">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="hallo.css" rel="stylesheet">
    <title>Quiz App</title>
</head>

<body>
    <main class="main">
        <div class="container">
            <section class="quiz-section">
                <div class="quiz-box">
                    <h1><?php echo strtoupper($titre_quiz); ?></h1>
                    <div class="quiz-header">
                        <span>Quiz Web Site </span>
                    </div>
                    <form id="quizForm" method="POST" action="reponse.php" enctype="multipart/form-data">
                        <?php
                        $questionActuelle = 1;

                        while ($question_row = mysqli_fetch_assoc($question)) {
                            $id_question = $question_row['id_question'];
                            $numero_question = $question_row['numero'];
                            $contenu_question = $question_row['contenu'];
                            $type_question = $question_row['type_question'];

                        ?>
                            <div class="questionContainer question-text" data-questionid="<?php echo $id_question; ?>" data-type="<?php echo $type_question; ?>">
                                <?php if (in_array($type_question, ['image', 'video', 'audio'])) { ?>
                                    <div class="question_text">
                                        <?php if ($question_row['type_question'] == 'image') { ?>
                                            <div class="img" id="img">
                                                <img height="150px" src="files2/<?= $question_row['path_file'] ?>" width="250px" alt="image" />
                                            </div>
                                            <div class="question_text"><?php echo ucfirst($contenu_question); ?></div>
                                        <?php } elseif ($question_row['type_question'] == 'video') { ?>
                                            <div class="video" id="video">
                                                <video controls width="320" height="240" >
                                                    <source src="files2/<?= $question_row['path_file'] ?>" type="video/webm"/>
                                                </video>
                                            </div>
                                            <div class="question_text"><h3><?php echo ucfirst($contenu_question); ?></h3></div>
                                        <?php } elseif ($question_row['type_question'] == 'audio') { ?>
                                            <div class="question_text audio" id="audio">
                                                <audio controls>
                                                    <source src="files2/<?= $question_row['path_file'] ?>" type="audio/mp3"/>
                                                    <source src="files2/<?= $question_row['path_file'] ?>" type="audio/m4a"/>
                                                </audio>
                                            </div>
                                            <div class="question_text"><h3><?php echo ucfirst($contenu_question); ?></h3></div>
                                        <?php } ?>
                                    </div>
                                <?php } else { ?>
                                    <div class="question_text"><h3><?php echo ucfirst($contenu_question); ?></h3></div>
                                <?php } ?>
                                    <?php
                                    $proposition = mysqli_query($con, "SELECT id, numero_pro, contenu_pro FROM propositions WHERE question_id='$id_question'");
                                    while ($pro_row = mysqli_fetch_assoc($proposition)) {
                                        $numero_pro = $pro_row['numero_pro'];
                                        $contenu_pro = $pro_row['contenu_pro'];
                                    ?>
                                        <div class="option-list">
                                                <div class="option" id="option" >
                                                    <input type="radio" style="display:none" name="question_<?php echo $id_question; ?>" value="<?php echo $contenu_pro; ?>">
                                                    <span class="span"><?php echo $contenu_pro; ?></span>
                                                </div>
                                        </div>
                                    <?php
                                    }
                                    ?>
                                <input type="hidden" name="id" value="<?php echo $user_id; ?>">
                                <input type="hidden" name="quiz_user_id" value="<?php echo $quiz_user_id; ?>">
                                <input type="hidden" name="question_id[]" value="<?php echo $id_question; ?>">
                            </div>
                        <?php
                        }
                        ?>
                        <div class="quiz-footer">
                            <button type="button" id="nextButton" name="nextButton" class="next-btn">Suivant</button>
                            <button type="submit" id="submitButton" name="submitButton" class="next-btn">Valider</button>
                        </div>
                    </form>
                </div>
            </section>
        </div>
    </main>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            var questionContainers = document.querySelectorAll('.questionContainer');
            var nextButton = document.getElementById('nextButton');
            var currentQuestionIndex = 0;
            let roleUser = JSON.parse('<?php echo $roleUserJson; ?>');
            
            var opTions = document.querySelectorAll('.option');

           opTions.forEach(function (opTion) {
           opTion.addEventListener('click', function () {
            // Remove 'active' class from all opTions
            opTions.forEach(function (otherOpTion) {
                otherOpTion.classList.remove('active');
            });

            // Add 'active' class to the clicked opTion
            opTion.classList.add('active');
            });
            });
            function showQuestion(index) {
                questionContainers.forEach(function (container, i) {
                    container.style.display = i === index ? 'block' : 'none';
                });
            }

            function updateButton() {
                var submitButton = document.getElementById('submitButton');
                if (currentQuestionIndex < questionContainers.length - 1) {
                    nextButton.style.display = (roleUser === 'animateur') ? 'block' : 'none';
                    submitButton.style.display = 'block';
                } else {
                    nextButton.style.display = 'none';
                    submitButton.style.display = (roleUser === 'participant') ? 'block' : 'none';
                }
            }   
            function nextQuestion() {
                if (currentQuestionIndex < questionContainers.length - 1) {
                    currentQuestionIndex++;
                    showQuestion(currentQuestionIndex);
                    updateButton();
                }
            }

            nextButton.addEventListener('click', nextQuestion);

            showQuestion(currentQuestionIndex);
            updateButton();
        });
    </script>
</body>

</html>

Synchronizing two interfaces in real-time

useEffect running multiple times causing journal multiple entry creations and deletions

I’m facing an issue where the useEffect in my React component is running 8-9 times, resulting in the creation and deletion of multiple journal entries. I have tried using useCallback for each function within the useEffect as suggested in other posts, but it leads to an infinite loop. I’m not sure what I am doing wrong. Am I using the cleanup function properly?

Things I have tried that havent worked:
  • Using use callback for the functions in the use effect
  • Getting rid of the cleanup function to find the root cause
  • Avoid updating states from local storage.
  • n number of changes to the overall to useEffect function.

I would appreciate any help in resolving this issue.

Here’s the code for my component:

import Editor from '../components/text-editor/Editor';
import Layout from '../containers/Layout';
import { useUser } from '../contexts/UserContext';
import {
    getJournalEntryById,
    updateJournalEntry,
    createJournalEntry,
    deleteJournalEntry,
} from '../services/journalEntryService';
import { useParams } from 'react-router-dom';
import { useMenu } from '../contexts/NavDrawerContext';

// Get the journal ID from local storage

const Journal = () => {
    const { userID, toggleDarkMode } = useUser();
    const [initialContent, setInitialContent] = useState([]);
    const [selectedBlocks, setSelectedBlocks] = useState([]);
    const [isSelectionActive, setIsSelectionActive] = useState(false);
    const [isFocused, setIsFocused] = useState(false);
    const [isPromptDisplayVisible, setIsPromptDisplayVisible] = useState(false);
    const [currentMood, setCurrentMood] = useState('happy');
    const [isFocusModeOn, setIsFocusModeOn] = useState(false);
    const [journalID, setJournalID] = useState('');

    const [isTextEditorMenuCollapsed, setIsTextEditorMenuCollapsed] =
        useState(false);
    const containerRef = useRef(null);

    // Function to scroll to the bottom of the editor
    const scrollToBottom = () => {
        if (containerRef.current) {
            containerRef.current.scrollTop = containerRef.current.scrollHeight;
        }
    };

    const updateJournalID = (id) => {
        setJournalID(id);
        localStorage.setItem('journalID', id);
    };

    const resetJournalID = () => {
        setJournalID('');
        localStorage.removeItem('journalID');
    };

    // number of times the useEffect hook is called
    let effectCountRef = useRef(0);



    useEffect(() => {
        const journalIDFromLocalStorage = localStorage.getItem('journalID');
        if (journalIDFromLocalStorage) {
            setJournalID(journalIDFromLocalStorage);
        }
        console.log(`useEffect hook called ${effectCountRef.current} times`);
        effectCountRef.current++;

        const fetchAndUpdateJournalStates = async (id) => {
            try {
                if (id?.length) {
                    const journalEntry = await getJournalEntryById(id);

                    if (journalEntry) {
                        const { content, mood, _id } = journalEntry;
                        const blocks = JSON.parse(content);
                        setInitialContent(blocks);
                        setCurrentMood(mood);
                        updateJournalID(_id);
                    }
                } else {
                    const response = await createJournalEntry(
                        initialContent,
                        currentMood
                    );
                    updateJournalID(response._id);
                }
            } catch (error) {
                console.error(
                    'Error fetching or creating journal entry:',
                    error
                );
                resetJournalID();
            }
        };

        fetchAndUpdateJournalStates(journalID);

        return () => {
            const deleteJournalIfEmpty = async (id) => {
                try {
                    if (!id) return;

                    const response = await getJournalEntryById(id);

                    const content = JSON.parse(response.content);

                    if (content.length === 0) {
                        await deleteJournalEntry(id);
                        console.log('Journal entry deleted');
                    }
                } catch (error) {
                    console.error(
                        'Error deleting journal entry if empty:',
                        error
                    );
                }
            };

            deleteJournalIfEmpty(journalID);
        };
    }, [journalID]);

    const handleJournalUpdate = useCallback(
        async (editor) => {
            // Update the content state and scroll to the bottom of the editor
            const newContent = editor.topLevelBlocks;
            captureSelectedBlocks(editor);
            scrollToBottom();

            if (newContent?.length && journalID?.length) {
                try {
                    await updateJournalEntry(journalID, 'content', newContent);
                } catch (error) {
                    console.error('Failed to update journal entry:', error);
                }
            }
        },
        [journalID]
    );

    const handleMoodChange = (mood) => {
        setCurrentMood(mood);
    };

    // Function to reset journal from navigation
    const resetJournal = () => {
        setInitialContent([]);
        resetJournalID();
        setCurrentMood('happy');
    };

    // Function to capture selected blocks
    const captureSelectedBlocks = useCallback(
        (editor) => {
            const currentSelectedBlocks = editor.getSelection()?.blocks;
            const currentActiveBlock = editor.getTextCursorPosition().block;

            if (currentSelectedBlocks) {
                setSelectedBlocks(currentSelectedBlocks);
                setIsSelectionActive(true);
            } else {
                isSelectionActive && setIsSelectionActive(false);
                setSelectedBlocks([currentActiveBlock]);
            }
        },
        [selectedBlocks, isSelectionActive]
    );

    return (
        <Layout
            currentMood={currentMood}
            handleMoodChange={handleMoodChange}
            isFocusModeOn={isFocusModeOn}
            setIsFocusModeOn={setIsFocusModeOn}
            setIsPromptDisplayVisible={setIsPromptDisplayVisible}
            setIsTextEditorMenuCollapsed={setIsTextEditorMenuCollapsed}
            toggleDarkMode={toggleDarkMode}
            showFocusModeAndMoodDropdown={true}
            handleJournalUpdate={handleJournalUpdate}
            journalID={journalID}
            resetJournal={resetJournal}
        >
            <Editor
                initialContent={initialContent}
                userID={userID}
                journalID={journalID}
                handleJournalUpdate={handleJournalUpdate}
                selectedBlocks={selectedBlocks}
                setSelectedBlocks={setSelectedBlocks}
                captureSelectedBlocks={captureSelectedBlocks}
                currentMood={currentMood}
                setCurrentMood={setCurrentMood}
                isTextEditorMenuCollapsed={isTextEditorMenuCollapsed}
                setIsTextEditorMenuCollapsed={setIsTextEditorMenuCollapsed}
                isFocusModeOn={isFocusModeOn}
                setIsFocusModeOn={setIsFocusModeOn}
                isPromptDisplayVisible={isPromptDisplayVisible}
                setIsPromptDisplayVisible={setIsPromptDisplayVisible}
                isFocused={isFocused}
                setIsFocused={setIsFocused}
                containerRef={containerRef}
                isSelectionActive={isSelectionActive}
                setIsSelectionActive={setIsSelectionActive}
            />
        </Layout>
    );
};

export default Journal;

DOMException: Failed to set remote answer sdp: Called in wrong state: stable

When a 3rd user enters the video conference, i get the following error : “DOMException: Failed to set remote answer sdp: Called in wrong state: stable”

I saw here that its probably because peers are made to be connected to one peer only and therefor i need to create a new webRTC connection each time a new user enters if i want more than 2 users in the conference but thats what i did !
Have a look here :

socket.on("user-joined", (id, clients, username, email) => {
      console.log(`Utilisateur rejoint: ${username}, ID: ${id}`);
  

      if (id !== socketId) {
        this.getSources(); // ce salaud j'ai dû le metre ici aussi car en mode prod il faut le relancer quand un autre peer se connecte
        message.success({
          content: `${username} a rejoint la conférence.`,
          className: "custom-message",
          duration: 3,
        })
        // si l'id qui vient d'arriver ne correspond pas à mon socketId (moi) alors je play le sound de cette maniere,
        //seul les utilisateurs déjà présents dans la room entendront le son si un new user arrive dans la room
      }


      clients.forEach((socketListId) => {
        connections[socketListId] = this.createPeerConnection(socketListId); // HERE I CREATE A NEW USER FOR EACH NEW CONNECTION !

        // c'est ici que j'initialise la connection P2P avec webRTC
        console.log("Current state of connections:", connections);

        // je collecte mes iceCandidates
        connections[socketListId].onicecandidate = function (event) {
          if (event.candidate != null) {
            socket.emit(
              "signal", // je spread mes icecandidate via "signal"
              socketListId,
              JSON.stringify({ ice: event.candidate })
            )
          }
        }
 
        // je check si un nouveau user (nouveau videoElement du coup) arrive dans la room
        connections[socketListId].onaddstream = (event) => {
          // c un event de webRTC go voir : https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addstream_event

          let searchVideo = document.querySelector(
            `[data-socket="${socketListId}"]`
          )


          if (!searchVideo) {              
            console.log(`Creating new video element for socketListId: ${socketListId}`);

            videoElements = clients.length // videoElements = nbr de client connectés à la  room..
            console.log("videoElements: ", videoElements) // test adaptCSS
            let main = document.getElementById("main")
            let cssMesure = this.adaptCSS(main)


            let video = document.createElement("video")

            let css = {
              minWidth: cssMesure.minWidth,
              minHeight: cssMesure.minHeight,
              maxHeight: "100%",
              margin: "10px",
              borderStyle: "solid",
              borderColor: "#bdbdbd",
              objectFit: "fill",
              backgroundImage: `url(${backgroundBlck})`,
              backgroundSize: 'cover', 
              backgroundPosition: 'center', 
              backgroundRepeat: 'no-repeat' 
            };
          
            for (let i in css) video.style[i] = css[i]
          
            video.style.setProperty("width", cssMesure.width)
            video.style.setProperty("height", cssMesure.height)
            video.setAttribute("data-socket", socketListId)
            video.style.borderRadius = "25px"
            video.srcObject = event.stream
            video.autoplay = true
            video.playsinline = true
            video.onclick = this.handleVideoClick
            const videoId = "video_" + socketListId;
            video.setAttribute("id", videoId);
            // video.classList.add("video-with-username");
            // video.setAttribute("data-username", username);
            video.srcObject = event.stream;
            main.appendChild(video)
      
            this.adaptCSS(main);

          }else{
            console.log(`Updating existing video element for socketListId: ${socketListId}`);

            searchVideo.srcObject = event.stream;

          }

        }
          
        if (window.localStream instanceof MediaStream) {
          // Ajout du stream à RTCPeerConnection..
          console.log(`Adding stream to connection for user ${socketListId}`);
          console.log("Current state of connections:", connections);

          connections[socketListId].addStream(window.localStream);
        } else {
          message.error('Votre caméra n'est pas disponible !!');
        }        
      })

      if (id === socketId) {
        console.log("Local user has joined. Initiating offer creation logic.");
    }
     // Ici, je vais gérer le scénario au cas où un user se co à une salle avec des utilisateurs déjà présents.
     //Cet utilisateur va envoyer son offre à tous les utilisateurs déjà présents dans la salle.        

      if (id === socketId) { // dans cette condition je veux être sûr que celui qui va envoyer son offer à tout lmonde est l'user qui vient de se connecter (genre moi localement quoi)
        
        for (let otherUserId in connections) {  // je loop à travers les autres utilisateurs dans la room
          if (otherUserId === socketId) continue 
      
          let connection = connections[otherUserId];
          console.log('ajout du stream à la connection pour user : ' + otherUserId);
      
          try {
            connection.addStream(window.localStream);
          } catch (e) {
            console.error('Erreur ajout stream à la co :', e);
            continue; // Skip l'itérration pour passer à la suivante si erreur
          }
      
          console.log('Stream bien ajouté. Creation de l offre pour user : ' + otherUserId);
      
          connection
            .createOffer()
            .then((description) => {
              console.log('Offre creee avec succes!. Je set la local description pour user : ' + otherUserId);
              connection.setLocalDescription(description);
            })
            .then(() => {
              console.log('Local description -> OK . envoi du signal pour user ' + otherUserId);
              socket.emit(
                "signal",
                otherUserId,
                JSON.stringify({ sdp: connections[id].localDescription })
              );
            })
            .catch((e) => console.error('Erreur durant création offer ou localdescription ): ', e));
        }
      }

here you have a bigger part of my component :

const server_url =
  process.env.NODE_ENV === "production" 
    ? "https://zakaribel.com:4001"
    : "http://localhost:4001"

let connections = {}
let socket = null
let socketId = null
let videoElements = 0

const peerConnectionConfig = {
  iceServers: [
    { urls: "stun:stun.services.mozilla.com" },
    { urls: "stun:stun.l.google.com:19302" },

    // Serveur TURN (si un user est derrière un nat restrictif ou un pare feu chiant, un serveur TURN prendra le relais)
    {
      urls: "turn:turn.anyfirewall.com:443?transport=tcp",
      credential: "webrtc",
      username: "webrtc",
    },
  ],
}

class Main extends Component {
  constructor(props) {
    super(props)
    this.myVideo = React.createRef()
    this.iceCandidatesQueue = {}
    this.videoAvailable = false
    this.audioAvailable = false

    this.state = {
      video: false,
      audio: false,
      screen: false,
      showModal: false,
      screenAvailable: false,
      socketId: '',
      messages: [],
      message: "",
      newmessages: 0,
      askForUsername: true,
      username: "",
      usernames: {},
      isSidebarOpen: false,
      requestingSpeech: false,
      speechRequestMessage: "",
      password: "",
      authorizedUsers: [],
      connectedEmails: [],
      currentUserEmail: "",
      isAdmin: false,
      loadingCamera: true,      
    }
    
    axios
    .get(`${server_url}/users`, { withCredentials: true } )
      .then((response) => {
        this.setState({ authorizedUsers: response.data })
      })
      .catch((error) => {
        console.error(
          "Erreur lors de la récupération des utilisateurs :",
          error
        )
      })

    this.sourcesPermissions()
  }


  sourcesPermissions = async () => {
    try {
      const videoStream = await navigator.mediaDevices.getUserMedia({
        video: true,
      })
      const audioStream = await navigator.mediaDevices.getUserMedia({
        audio: true,
      })

      const screenAvailable = !!navigator.mediaDevices.getDisplayMedia
      this.setState({ screenAvailable })

      if (videoStream || audioStream) {
        window.localStream = videoStream || audioStream // je recupere le flux autorisé par l'user dans window.localStream
        this.myVideo.current.srcObject = window.localStream // j'affiche ce flux dans mon element video
        this.setState({ loadingCamera: false })
      }

      this.videoAvailable = !!videoStream // videoAvailable à true si videoStream est true et vis versa
      this.audioAvailable = !!audioStream // meme délire
      this.screenAvailable = screenAvailable
    } catch (error) {
      console.error(error)
      this.setState({ loadingCamera: false })
    }
  }

  getMediasAndInitConnection = () => {
    this.setState(
      {
        video: this.videoAvailable, // videoAvailable = acces video autorisé par user donc this.state.video sera true
        audio: this.audioAvailable, // ...
      },
      () => {
        this.getSources()  // llorsque l'utilisateur arrivera dans la room sa camera/son audio sera activée ou désactivée en fonction des permissions 
        this.serverConnection() // ensuite jenclenche la logique de connexion server notamment en recuperant l'username, l'email, signal pour SDP/iceCandidates etc....
      }
    )
  }
  
  getSources = () => {
    if ((this.state.video && this.videoAvailable) || (this.state.audio && this.audioAvailable)) {
      navigator.mediaDevices.getUserMedia({ video: this.state.video, audio: this.state.audio })
        .then((stream) => {
          this.getSources_Success(stream);
        })
        .catch((e) => console.log(e));
    } else {
      try {
        if (this.myVideo.current && this.myVideo.current.srcObject) {
          let tracks = this.myVideo.current.srcObject.getTracks();
          tracks.forEach((track) => track.stop());
        }
      } catch (e) {
        console.log(e);
      }
    }
  };
  

  getSources_Success = (stream) => {
    window.localStream = stream
    this.myVideo.current.srcObject = stream
    
    for (let id in connections) {
      if (id === socketId) continue // la jdis que si dans la liste des sockets ya une id qui correspond à MA socketId(moi)

      connections[id].addStream(window.localStream)

      // et ce sera envoyé aux autres users
      connections[id]
        .createOffer()
        .then((description) => connections[id].setLocalDescription(description))
        .then(() => {
          // du coup j'envoie tout ça via une websocket..
          // mon emission "signal" contiendra mon offer pour que tous les autres users puisse la receptionner
          // createOffer qui va creer une SDP est un processus OBLIGATOIRE pour établir une connexion WebRTC
          // c'est comme si t'allais à la banque pour ouvrir un compte et tu signes aucun papiers..
          socket.emit(
            "signal",
            id,
            JSON.stringify({ sdp: connections[id].localDescription })
          )
        })
        .catch((e) => console.log(e))
    }
  }

  

  // ici je vais réceptionner tout ce qui est SDP/iceCandidates
  signalFromServer = (fromId, body) => {
    let signal = JSON.parse(body);
  
    if (fromId !== socketId) {
      if (signal.sdp) {
        connections[fromId]
          .setRemoteDescription(new RTCSessionDescription(signal.sdp))
          .then(() => {
            console.log(`Remote description set successfully for ${fromId}`);
            
            if (signal.sdp.type === "offer") {
              connections[fromId]
                .createAnswer()
                .then((description) => {
                  console.log(`Answer created successfully for ${fromId}`);
                  
                  connections[fromId]
                    .setLocalDescription(description)
                    .then(() => {
                      console.log(`Local description set successfully for ${fromId}`);
                      
                      socket.emit(
                        "signal",
                        fromId,
                        JSON.stringify({
                          sdp: connections[fromId].localDescription,
                        })
                      );
                    })
                    .catch((e) => console.error(`Error setting local description for ${fromId}:`, e));
                })
                .catch((e) => console.error(`Error creating answer for ${fromId}:`, e));
            }
  
            if (this.iceCandidatesQueue[fromId]) {
              this.iceCandidatesQueue[fromId].forEach((candidate) => {
                connections[fromId]
                  .addIceCandidate(new RTCIceCandidate(candidate))
                  .catch((e) => console.error(`Error adding ice candidate for ${fromId}:`, e));
              });
              delete this.iceCandidatesQueue[fromId];
            }
          })
          .catch((e) => console.error(`Error setting remote description for ${fromId}:`, e));
      }
  
      if (signal.ice) {
        let iceCandidate = new RTCIceCandidate(signal.ice);
        if (connections[fromId].remoteDescription) {
          connections[fromId]
            .addIceCandidate(iceCandidate)
            .catch((e) => console.error(`Error adding ice candidate for ${fromId}:`, e));
        } else {
          if (!this.iceCandidatesQueue[fromId]) {
            this.iceCandidatesQueue[fromId] = [];
          }
          this.iceCandidatesQueue[fromId].push(iceCandidate);
        }
      }
    }
  };
  

serverConnection = () => {
  socket = io.connect(server_url, { secure: true })

  // demande de parole
  socket.on("speech-requested", ({ username }) => {
    message.warning({
      content: `${username} souhaite prendre la parole.`,
      className: "custom-message",
      duration: 3,
    })
  })

  socket.on("signal", this.signalFromServer)

  socket.on("connect", () => {

    socket.on("redirectToMainPage", () => {
     this.stopTracks()
    });

  socket.emit(
    "joinCall",
    window.location.href,
    this.state.username,
    this.state.currentUserEmail
  )
  socketId = socket.id
  this.setState({ socketId });

  socket.on("update-user-list", (users) => {
    if (users) {
      // si j'fais pas ça il va mdire undefined blablabla
      let updatedUsernames = {}
      users.forEach((user) => {    
        updatedUsernames[user.id] = user.username
      })
      this.setState({ usernames: updatedUsernames })
    } else {
      console.log(
        "Pas encore de user ici.."
      )
    }
  })

    socket.on("chat-message", this.addMessage) // je recupere les messages emit coté serveur pour les display 

    socket.on("userLeft", (id) => {


    
      let video = document.querySelector(`[data-socket="${id}"]`)
      let username = this.state.usernames[id] 

       // J'update l'array usernames quand un user quitte la room "...this.state.usernames" 
       //car je creer une sorte de copie pour effectuer mon delete ensuite jenvoie cette copie à ma vraie state
  const updatedUsernames = { ...this.state.usernames };
  delete updatedUsernames[id]; // du coup je supprime l'utilisateur en supprimant son index id

  this.setState({ usernames: updatedUsernames });
    
    
      if (id !== socketId )  {
        this.playUserDisconnectedSound()
        message.info({
          content: `${username} a quitté la conférence.`,
          className: "custom-message",
          duration: 3,
        })
      }

      if (video !== null) {
        videoElements--
        video.parentNode.removeChild(video)

        let main = document.getElementById("main")
        this.adaptCSS(main)
      }
    })


    socket.on("user-joined", (id, clients, username, email) => {
      console.log(`Utilisateur rejoint: ${username}, ID: ${id}`);
  

// seul l'user qui s'est fait kick va listen " user-kicked" car c'est emit depuis server spécifiquement à la personne kicked et le reste jte fais pas un dessin       
      socket.on("user-kicked", () => {
        window.location.href = "/";  
        socket.disconnect();
      });

      if (id !== socketId) {
        this.getSources(); // ce salaud j'ai dû le metre ici aussi car en mode prod il faut le relancer quand un autre peer se connecte
        message.success({
          content: `${username} a rejoint la conférence.`,
          className: "custom-message",
          duration: 3,
        })
        // si l'id qui vient d'arriver ne correspond pas à mon socketId (moi) alors je play le sound de cette maniere,
        //seul les utilisateurs déjà présents dans la room entendront le son si un new user arrive dans la room
      }

      
      this.setState((prevState) => ({
        usernames: {
          ...prevState.usernames,
          [id]: username,
        },
      }))

      this.setState((prevState) => ({
        connectedEmails: [...prevState.connectedEmails, email],
      }))
      console.log("Current state of connections:", connections);

      clients.forEach((socketListId) => {
        connections[socketListId] = this.createPeerConnection(socketListId);

        // c'est ici que j'initialise la connection P2P avec webRTC
        console.log("Current state of connections:", connections);

        // je collecte mes iceCandidates
        connections[socketListId].onicecandidate = function (event) {
          if (event.candidate != null) {
            socket.emit(
              "signal", // je spread mes icecandidate via "signal"
              socketListId,
              JSON.stringify({ ice: event.candidate })
            )
          }
        }
 
        // je check si un nouveau user (nouveau videoElement du coup) arrive dans la room
        connections[socketListId].onaddstream = (event) => {
          // c un event de webRTC go voir : https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addstream_event

          let searchVideo = document.querySelector(
            `[data-socket="${socketListId}"]`
          )


          if (!searchVideo) {              
            console.log(`Creating new video element for socketListId: ${socketListId}`);

            videoElements = clients.length // videoElements = nbr de client connectés à la  room..
            console.log("videoElements: ", videoElements) // test adaptCSS
            let main = document.getElementById("main")
            let cssMesure = this.adaptCSS(main)


            let video = document.createElement("video")

            let css = {
              minWidth: cssMesure.minWidth,
              minHeight: cssMesure.minHeight,
              maxHeight: "100%",
              margin: "10px",
              borderStyle: "solid",
              borderColor: "#bdbdbd",
              objectFit: "fill",
              backgroundImage: `url(${backgroundBlck})`,
              backgroundSize: 'cover', 
              backgroundPosition: 'center', 
              backgroundRepeat: 'no-repeat' 
            };
          
            for (let i in css) video.style[i] = css[i]
          
            video.style.setProperty("width", cssMesure.width)
            video.style.setProperty("height", cssMesure.height)
            video.setAttribute("data-socket", socketListId)
            video.style.borderRadius = "25px"
            video.srcObject = event.stream
            video.autoplay = true
            video.playsinline = true
            video.onclick = this.handleVideoClick
            const videoId = "video_" + socketListId;
            video.setAttribute("id", videoId);
            // video.classList.add("video-with-username");
            // video.setAttribute("data-username", username);
            video.srcObject = event.stream;
            main.appendChild(video)
      
            this.adaptCSS(main);

          }else{
            console.log(`Updating existing video element for socketListId: ${socketListId}`);

            searchVideo.srcObject = event.stream;

          }

        }
          
        if (window.localStream instanceof MediaStream) {
          // Ajout du stream à RTCPeerConnection..
          console.log(`Adding stream to connection for user ${socketListId}`);
          console.log("Current state of connections:", connections);

          connections[socketListId].addStream(window.localStream);
        } else {
          message.error('Votre caméra n'est pas disponible !!');
        }        
      })

      if (id === socketId) {
        console.log("Local user has joined. Initiating offer creation logic.");
    }
     // Ici, je vais gérer le scénario au cas où un user se co à une salle avec des utilisateurs déjà présents.
     //Cet utilisateur va envoyer son offre à tous les utilisateurs déjà présents dans la salle.        

      if (id === socketId) { // dans cette condition je veux être sûr que celui qui va envoyer son offer à tout lmonde est l'user qui vient de se connecter (genre moi localement quoi)
        
        for (let otherUserId in connections) {  // je loop à travers les autres utilisateurs dans la room
          if (otherUserId === socketId) continue 
      
          let connection = connections[otherUserId];
          console.log('ajout du stream à la connection pour user : ' + otherUserId);
      
          try {
            connection.addStream(window.localStream);
          } catch (e) {
            console.error('Erreur ajout stream à la co :', e);
            continue; // Skip l'itérration pour passer à la suivante si erreur
          }
      
          console.log('Stream bien ajouté. Creation de l offre pour user : ' + otherUserId);
      
          connection
            .createOffer()
            .then((description) => {
              console.log('Offre creee avec succes!. Je set la local description pour user : ' + otherUserId);
              connection.setLocalDescription(description);
            })
            .then(() => {
              console.log('Local description -> OK . envoi du signal pour user ' + otherUserId);
              socket.emit(
                "signal",
                otherUserId,
                JSON.stringify({ sdp: connections[id].localDescription })
              );
            })
            .catch((e) => console.error('Erreur durant création offer ou localdescription ): ', e));
        }
      }
      
    })
  })
}

  
createPeerConnection = () =>   {
  let peerConnection = new RTCPeerConnection(peerConnectionConfig);

  return peerConnection;
}

I tried adding a new connection for each new peer entering the room ! It didnt change anything i still get the same error..

Next.js – Create public API using params and Prisma for database

I have a question, how to use Prisma on a page (ex api/blog/[id]/[slug2]).

I tested what Prisma offers with Next.js on their site, but I get this as an error:

Prisma doc used: https://www.prisma.io/nextjs#nextjs-tabs

Error: 
  x "getStaticProps" is not supported in app/. Read more: https://nextjs.org/docs/app/building-your-application/data-fetching
  | 
  | 
    ,-[/vercel/path0/src/app/api/blog/[id]/[slug2]/page.tsx:10:1]

My code currently :

"use client"

import { PrismaClient } from "@prisma/client"

type Props = {
  params: {
    id: string
    slug2: boolean
  }
  blogsLists: []
}

export async function getStaticProps() {
  const prisma = new PrismaClient()
  const blogsLists = await prisma.blogsList.findMany()

  return {
    props: { blogsLists },
  }
}

export default function BlogData({ params, blogsLists }: Props) {
  return (
    <p>
      Test : {params.id}/{params.slug2}
      {blogsLists.map((bloginfo) => (
        <li key={bloginfo}>{bloginfo.id}</li>
      ))}
    </p>
  )
}

Getting the distance between cities [closed]

There was a task, the essence:
The starting and ending points (city X and city Y) were given. It is necessary to calculate the distance between two cities, the distance is not along a geographical straight line, but along roads. There are API Yandex Maps, Google and others, but there is a limit queries (this is not suitable).

Appendix: Based on the distance, the cost of transportation is calculated in dollars per mile.
JavaScript is used/
What solution would you use?

I looked at different APIs (from Google, Bing and others), there are restrictions on requests everywhere.

Compound calculator

I found a compound calculator for wordpress but it calculates the interest on a annual interest, I would like it to calculate on a monthly compounding on the input instead, can someone help.

Code:

(function(){
    var due = 0,
        A = fieldname5,   /* Payment */
        P = fieldname1,   /* Start Amount */
        r = fieldname2,   /* Annual Interest Rate 5% */
        n = fieldname3,   /* Compound Frequency */
        t = fieldname4,   /* Years of Growth */
        p = fieldname6,   /* Payment Frequency */

        rate = Math.pow(1+r/n,n/p)-1,
        nper = p * t,
        F = (P+(due ? A : 0))*Math.pow(1+rate, nper) + A*( (Math.pow(1+rate,nper) - 1)/rate ) - (due ? A : 0);
    return PREC(F,2);
})()

I want it to work as this one:
https://tackletrading.com/tools/compounding-gains-calculator/?fbclid=IwAR3E3iZD85fY6I478-e2hmFk4qbiYoLOSUP110DS6mKJ6_tTklsmEq55gOU

I tried to get Chatgpt to help but not working.

JSON response is cut off, when the disk is full

Information

I have a Node JS/Express server that queries the DB and returns big amount of JSON data to the client that is making the request to that API. The server is running on Ubuntu 22.04 LTS on AWS EC2 instance. The server is also generating big amount of logs. When the disk becomes full because of log files, the response to this API (that returns big amount of JSON) gets truncated and only one half is being returned to client, which causes browser to issue an error. We got this issue today and after clearing logs, it got fixed. I know about different techniques and ideas of solving this issue (like pagination, getting data chunk by chunk, etc.).

Question

What is the actual reason for the response being cut off when disk space is running low and how this process happens (OS, NodeJS Server, Express)?

[Edit] If I rephrase the question: What is the correlation of returned JSON and disk space?

I have used functions to change the background color when selected in the bootstrap dropdown menu. But the color blinks and goes back to white

Themes

  • Blue
  • Yellow
  • Pink
  • //These were the functions

    const changeblue=()=>{

      document.body.style.backgroundColor='blue';
      showAlert("Blue mode has been enabled", "success");
    

    }
    const changepink=()=>{

      document.body.style.backgroundColor='pink';
      showAlert("Pink mode has been enabled", "success");
    

    }
    const changeyellow=()=>{

      document.body.style.backgroundColor='yellow';
      showAlert("Yellow mode has been enabled", "success");
    

    }

    get text selection JS

    I’m creating a module for editing text, and I’d like to retrieve the text that is selected in the toggleBold() function, but I have the impression that when I select the text, clicking on the bold button deselects the text, so no text is returned, and I don’t know how to manage this.

    I tried saving the selection in a variable

    here my code

    // Module my_wysiwyg.js
    
    export class MyWysiwyg {
            constructor(textareaElement, options) {
                    this.element = textareaElement;
                    this.options = options;
    
                    
                    this.setupToolbar();
            }
    
            setupToolbar() {
                   
                    this.toolbar = document.createElement("div");
                    this.toolbar.classList.add("wysiwyg-toolbar");
    
                   
                    if (this.options && this.options.buttons) {
                            this.options.buttons.forEach(buttonName => {
                                    const button = document.createElement("button");
                                    button.textContent = buttonName;
    
                                    // Ajout d'un écouteur d'événements au bouton "bold"
                                    if (buttonName === "bold") {
                                            button.addEventListener("click", (event) => {
                                                    this.toggleBold(event); 
                                            });
                                    }
                                    if(buttonName === "italic"){
                                            button.addEventListener("click", () => {
                                                    this.toggleItalic();
                                            })
                                    }
    
                            
                                    this.toolbar.appendChild(button);
                            });
                    }
    
                    
                    this.element.parentNode.insertBefore(this.toolbar, this.element);
            }
            //my function fog get text selection
            toggleBold(event) {
                    event.preventDefault();
                    const selection = window.getSelection();
                    const selectedText = selection.toString();
    
    
                    console.log(selectedText);
    
            }
           
    }
    

    React Js – Not understanding the render and re-renders for this code in react

    import { useState,useReducer } from 'react'
    
    const countReducer = (state,newState)=>({...state,...newState})
    
    function Counter({initialCount = 0, step = 1}) {
    
      const [me,setMe] = useState('ABc');
    
      const [state, setState] = useReducer(countReducer,{
        count:initialCount
      })
    
      const count = state.count
    
      let i=5;
      console.log('i->'+i)
        const changeVal = ()=>{
        console.log('curre val '+me)
        console.log('i val inside**'+i)
        i=i+1
        setMe('pqrts'+i)
      }
      console.log('i->after '+i)
      console.log('next val '+me)
    
    
      const increment = () => setState({count:count+step})
      return <>
      <button onClick={changeVal}>Change the alphabets: {me}</button>
      <button onClick={increment}>{count}</button>
      </>
    }
    

    I am calling the Counter function in App component. When I click on the change the alphabets first time, I am getting ‘pqrts6’, then when I click on the button 2 times, I will get ‘pqrts7’, then if i again click , i will get the ‘pqrts6’

    I have tried adding console logs but I’m still unable to understand the behavior.

    If my understanding is correct, react should persist the values of local variables and I should always get ‘pqrts6’
    `

    My todo web works completely fine on local host but gives me error on VERCEL when i am trying to sign in and sign up

    I created a MERN Todo app that works just fine on localhost (I can sign in and sign up easily), but when I try to sign in and sign up on Vercel, the console gives me an error, and I really don’t know how to resolve it.

    The Error:
    https://i.stack.imgur.com/EOTmE.png

    Also, everywhere I have given axios.post(${window.location.origin}/api/v1/register) like this.

    My local host is posting on HTTP, but Vercel is posting on HTTPS. I don’t know if this is the issue or not, but I am just stating it here.

    The Site:
    https://todo-new-ochre.vercel.app

    For Signin:
    Use this email as this is saved on my MongoDB database:

    Email: hypelabel
    Password: h
    

    Repo Link:
    https://github.com/samarth-6/TODO_new

    I tried everything that I know of. I tried googling the error, but I still could not get anything to resolve it. ChatGPT was of no help either.