Call to undefined function readline()

When i try to write
$choice = readline();
it shows me

Fatal error: Uncaught Error: Call to undefined function readline()

But for other readlines, like $title = readline("Enter title: ") it doesn’t show me errors. What is the cause? I’m using php version 8.4.0

How can i fix it without needing to write longer codes (if possible) ?

I tried to make a do..while loop where there are multiple choices – cases, but it doesn’t seem to like it

do {
    echo "nn";
    echo "1 - show all booksn";
    echo "2 - show a bookn";
    echo "3 - add a bookn";
    echo "4 - delete a bookn";
    echo "5 - quitnn";
    $choice = readline();

    switch ($choice) {
        case 1:
            foreach ($books as $id => $book) {
                displayBook($id, $book);
            }

            break;
        case 2:
            $id = readline("Enter book id: ");
            displayBook($id, $books[$id]);

            break;
        case 3:
            addBook($books);
            break;
        case 4:
            deleteBook($books);
            break;
        case 5:
            echo "Goodbye!n";
            $continue = false;
            break;
        case 13:
            print_r($books); // hidden option to see full $books content
            break;
        default:
            echo "Invalid choicen";
    };

} while ($continue == true);

Laravel installer error – Could not scan for classes vendor/sebastian/code-unit-reverse-lookup/src/ which does not appear to be a file [duplicate]

When trying to create a new Laravel project, the Laravel installer throws the following error:

Could not scan for classes inside "/home/aes256/test/vendor/sebastian/code-unit-reverse-lookup/src/" which does not appear to be a file nor a folder
> pre-package-uninstall: IlluminateFoundationComposerScripts::prePackageUninstall
Script IlluminateFoundationComposerScripts::prePackageUninstall handling the pre-package-uninstall event terminated with an exception

In ComposerScripts.php line 66:

  [ErrorException]
  Constant LARAVEL_START already defined

Re-running the Laravel installer with verbose mode shows the following additional info:

Executing async command (CWD): 'rm' '-rf' '/home/aes256/test/vendor/sebastian/code-unit-reverse-lookup'
Could not scan for classes inside "/home/aes256/test/vendor/sebastian/code-unit-reverse-lookup/src/" which does not appear to be a file nor a folder
> pre-package-uninstall: IlluminateFoundationComposerScripts::prePackageUninstall
Script IlluminateFoundationComposerScripts::prePackageUninstall handling the pre-package-uninstall event terminated with an exception

In ComposerScripts.php line 66:

  [ErrorException]
  Constant LARAVEL_START already defined


Exception trace:
  at /home/aes256/test/vendor/laravel/framework/src/Illuminate/Foundation/ComposerScripts.php:66
 IlluminateFoundationBootstrapHandleExceptions->handleError() at /home/aes256/test/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:258
 IlluminateFoundationBootstrapHandleExceptions->{closure:IlluminateFoundationBootstrapHandleExceptions::forwardsTo():257}() at n/a:n/a
 define() at /home/aes256/test/vendor/laravel/framework/src/Illuminate/Foundation/ComposerScripts.php:66
 IlluminateFoundationComposerScripts::prePackageUninstall() at phar:///usr/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:508
 ComposerEventDispatcherEventDispatcher->executeEventPhpScript() at phar:///usr/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:284
 ComposerEventDispatcherEventDispatcher->doDispatch() at phar:///usr/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:158
 ComposerEventDispatcherEventDispatcher->dispatchPackageEvent() at phar:///usr/bin/composer/src/Composer/Installer/InstallationManager.php:369
 ComposerInstallerInstallationManager->executeBatch() at phar:///usr/bin/composer/src/Composer/Installer/InstallationManager.php:322
 ComposerInstallerInstallationManager->downloadAndExecuteBatch() at phar:///usr/bin/composer/src/Composer/Installer/InstallationManager.php:221
 ComposerInstallerInstallationManager->execute() at phar:///usr/bin/composer/src/Composer/Installer.php:839
 ComposerInstaller->doInstall() at phar:///usr/bin/composer/src/Composer/Installer.php:649
 ComposerInstaller->doUpdate() at phar:///usr/bin/composer/src/Composer/Installer.php:298
 ComposerInstaller->run() at phar:///usr/bin/composer/src/Composer/Command/UpdateCommand.php:281
 ComposerCommandUpdateCommand->execute() at phar:///usr/bin/composer/vendor/symfony/console/Command/Command.php:298
 SymfonyComponentConsoleCommandCommand->run() at phar:///usr/bin/composer/vendor/symfony/console/Application.php:1040
 SymfonyComponentConsoleApplication->doRunCommand() at phar:///usr/bin/composer/vendor/symfony/console/Application.php:301
 SymfonyComponentConsoleApplication->doRun() at phar:///usr/bin/composer/src/Composer/Console/Application.php:400
 ComposerConsoleApplication->doRun() at phar:///usr/bin/composer/vendor/symfony/console/Application.php:171
 SymfonyComponentConsoleApplication->run() at phar:///usr/bin/composer/src/Composer/Console/Application.php:137
 ComposerConsoleApplication->run() at phar:///usr/bin/composer/bin/composer:98
 require() at /usr/bin/composer:29

Is it something to be concerned about?

Tried a different Linux machine with fresh PHP + Composer install, same error.

edit: trying to create new project using PHPUnit instead of Pest works fine.

Doctrine ORM: Transaction commit fails after rollback in batch loop (Symfony 5.4, PHP 7.4)

I’m running a batch process in Symfony 5.4.48 (PHP 7.4.30, Doctrine ORM 2.20.3) where I need to handle database transactions per iteration. If a business condition fails, I want to rollback the transaction and continue to the next item. However, after a rollback, the next iteration fails with:

Transaction commit failed because the transaction has been marked for rollback only.

Here’s a simplified version of my code:

<?php
foreach ($items as $item) {
    $em = $doctrine->getManager();
    $connection = $em->getConnection();
    $connection->beginTransaction();
    try {
        // ... business logic ...
        if ($shouldRollback) {
            $connection->rollBack();
            $doctrine->resetManager();
            continue;
        }
        $connection->commit();
    } catch (Throwable $e) {
        if ($connection->isTransactionActive()) {
            $connection->rollBack();
        }
        $doctrine->resetManager();
        continue;
    }
}

Even after calling $doctrine->resetManager(), the next $em and $connection seem to be in a “rollback only” state, and commit() fails.

Environment:

  • Symfony: 5.4.48
  • Doctrine ORM: 2.20.3
  • PHP: 7.4.30
  • OS: Windows

What I’ve tried:

  • Resetting the EntityManager with $doctrine->resetManager()
  • Reacquiring the EntityManager and Connection after rollback
  • Checking transaction state with $connection->isRollbackOnly()

Questions:

  • Is this the expected behavior for Doctrine ORM?
  • How can I fully reset the EntityManager/Connection so that the next transaction works?
  • Is there a recommended pattern for batch processing with per-iteration transactions in Doctrine?

What will happen if Node.js cannot read a directory (or a part of a file) due to bad/problematic sectors on disk or corrupted file system?

I want to use the directory- and file-reading functions from 'node:fs' to merge multiple files into one file. For example, I have the following script:

import fs from 'node:fs';
import { readdir, readFile, stat } from 'node:fs/promises';
import { join } from 'node:path';
var myStream = fs.createWriteStream('path/to/output.txt', {flags: 'a'});
var dirPath = 'path/to/mydirectory';
try {
    const entries = await readdir(dirPath, { recursive: true, withFileTypes: true });
    for (const entry of entries) {
        if (entry.isFile()) {
        const myPath = join(entry.parentPath, entry.name);
        const { size } = await stat(myPath);
        const contents = await readFile(myPath);
        myStream.write('<path>' + myPath + '</path>' + '<size>' + size.toString(10) + '</size>n' + contents + 'n');
     }
};
} catch (err) {
    console.error(err);
}; 
myStream.end()

My question is: what will happen if a directory cannot be opened or some part of a file cannot be read (due to bad/problematic sectors on disk, corrupted file system, etc.)? Will the program just freeze, so I will need to terminate it manually? Or only the corresponding file/directory will be skipped? Will the program skip a file in its entirety or only the unreadable part of it? What type of error, if any, will the program report? I have not found any information on this topic. Would it be possible to use Node.js to make the full list of problematic directories and files that are located in a given directory?

How to persist uploaded photos in a multi-step React form across page refresh?

I’m building a multi-step form in React where users can upload photos along with other inputs.

Currently:

I store all the form values in a formData state object.

To persist progress across refreshes, I save formData in localStorage.

Problem:

Uploaded photos are stored using URL.createObjectURL(file).

These object URLs don’t survive a page refresh, so the images are lost even though the rest of the form data is restored from localStorage.

Question:

Is there a way to persist uploaded photos across page refreshes without just dumping everything into localStorage?

What are the common patterns for handling this in React multi-step forms?

Should I use IndexedDB for files?

Should I upload files immediately to a temporary backend storage (and store only the reference in localStorage)?

Or is there another best practice for this use case?

Render Issues within animated PNG inside a SVG

I saw this tutorial that teaches how to do complex multilayer parallax scrolls and implemented on my website. While prototyping I found some weird lines that would appear while manipulating the PNG’s (I know the file size is big, I will fix it later). I thought it could be just some white pixels that just needed to be cleaned, but after cleaning all edges the problem persisted. Any idea why browsers are with this render issue?

https://codepen.io/Ramoses-Hofmeister-Ferreira/pen/wBMWBvZ

I was trying to manipulate some images inside an SVG so I could have a responsive multilayer parallax scroll, yet browsers are rendering strange white lines on the edge of the PNG’s that are inside of the SVG.

HTML:

<body>
    <div class="banner">
        <div id="mountain"></div>
    </div>
</body>

CSS:

body {
    margin: 0;
    background-color: #000000;
}

#mountain {
    width: 100%;
    height: 100vh;
    overflow: hidden;
}

#mountain svg {
    width: 100%;
    height: 100%;
    object-position: center;
}

JS:

function loadSVG() {
    fetch("https://raw.githubusercontent.com/astronaut954/pedro/main/img/parallax_scroll.svg")
        .then(res => res.text())
        .then(svg => {
            const mountain = document.getElementById("mountain");
            mountain.innerHTML = svg;

            const svgEl = mountain.querySelector("svg");
            svgEl.setAttribute("preserveAspectRatio", "xMidYMid slice");

            createWrapper("#layer_1");
            createWrapper("#layer_2");

            setAnimationScroll();
            setCloudAnimation();

        });
}

function createWrapper(layerId) {
    const layer = document.querySelector(`#mountain svg ${layerId}`);
    if (!layer) return;

    const wrapper = document.createElementNS("http://www.w3.org/2000/svg", "g");
    wrapper.setAttribute("id", `${layerId.slice(1)}_wrapper`);

    layer.parentNode.insertBefore(wrapper, layer);
    wrapper.appendChild(layer);
}


loadSVG();

function setAnimationScroll() {
    gsap.registerPlugin(ScrollTrigger);

    let runAnimation = gsap.timeline({
        scrollTrigger: {
            trigger: ".banner",
            start: "top top",
            end: "+=1000",
            scrub: true,
            pin: true
        }
    });

    runAnimation.add([
        gsap.to("#cloud10_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud9_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud8_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud7_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud6_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud5_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud4_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud3_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud2_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud1_fixed", { y: -1500, duration: 2 }),
        gsap.to("#cloud2b", { y: -1500, duration: 2 }),
        gsap.to("#cloud1b", { y: -1500, duration: 2 }),
        gsap.to("#cloud10", { y: -1500, duration: 2 }),
        gsap.to("#cloud9", { y: -1500, duration: 2 }),
        gsap.to("#cloud8", { y: -1500, duration: 2 }),
        gsap.to("#cloud7", { y: -1500, duration: 2 }),
        gsap.to("#cloud6", { y: -1500, duration: 2 }),
        gsap.to("#cloud5", { y: -1500, duration: 2 }),
        gsap.to("#cloud4", { y: -1500, duration: 2 }),
        gsap.to("#cloud3", { y: -1500, duration: 2 }),
        gsap.to("#cloud2", { y: -1500, duration: 2 }),
        gsap.to("#cloud1", { y: -1500, duration: 2 })
    ])
    .add([
        gsap.to("#layer_1", {
            scale: 1.4,
            x: -250,
            y: 0,
            transformOrigin: "50% 0%",
            duration: 2
        }),
        gsap.to("#layer_2", {
            scale: 1.2,
            transformOrigin: "50% 0%",
            duration: 2
        })
    ]);
}

How can I detect when the AG Grid filter dialog closes?

I have an AG Grid, implemented in React/Typescript. It automatically updates with new data, and the columns have filters. When new data comes in, the grid reloads with the changes, which closes the filter dialog if it’s open. That’s not ideal. It seems like a viable solution would be to track when the dialog is open, and hold off on updates while it’s open. I can track when the filter dialog opens (onFilterOpened), or when it changes (onFilterChanged), but I’m not certain how to detect closing the dialog without making a change by clicking off of it so that I can resume changes.

Here’s the event code (which is basically just console logs right now) based on what an AI model suggested:

const onFilterOpened = () => {
  console.log("Filter opened.");
  setIsFilterDialogOpen(true);
};

const onSortChanged = () => {
  if (gridApiRef.current) {
    columnState.current = gridApiRef.current.getColumnState();
  }
};

const onFilterChanged = (event: { api: GridApi; }) => {
  if (
    event.api.getFilterModel() &&
    Object.keys(event.api.getFilterModel()).length > 0
  ) {
    console.log("Filter dialog is opened");
    setIsFilterDialogOpen(true);
  } else {
    console.log("Filter closed.");
    setIsFilterDialogOpen(false);
  }

  console.log("Filter changed");
};

And set up here:

<AgGridReact  
  className={"ag-theme-astro"}  
  columnDefs={colDefGrouped}  
  defaultColDef={defaultColDef}  
  rowData={groupedRowData}  
  domLayout="autoHeight"  
  pagination={true}  
  paginationPageSize={20}  
  isFullWidthRow={isFullWidthRow}  
  fullWidthCellRenderer={fullWidthCellRenderer}  
  getRowHeight={getRowHeight}  
  onGridReady={onGridReady}  
  onFilterChanged={onFilterChanged}
  onFilterOpened={onFilterOpened}
  data-testid="groupedGrid"
/>

I get the “Filter opened” message when it opens, and “Filter dialog is opened” as I type in changes in the filter. But nothing when it closes.

unable to get a hard-coded svg line on d3 chart

I’m trying to just get a simple line on a D3 chart without using an array of data (that will be the next step).

The x-axis is years from 2007 to 2023. The y-axis is numbers from 0.00 to 0.50.

I assume the data pairs I’ll need will be x in a time formatted year and y as a number.

But when I put in the code to draw a line from one point to the other on the chart, nothing appears and I get no error message.

<div id="container"></div>
<script type="module">

const width = 1140;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 50;
const marginLeft = 70;

//x-axis is years
const x = d3.scaleUtc()
    .domain([new Date("2007-01-01"), new Date("2023-01-01")])
    .range([marginLeft, width - marginRight]);

//y-axis is numbers between 0 and .5
const y = d3.scaleLinear()
    .domain([0, .5])
    .range([height - marginBottom, marginTop]);

const svg = d3.create("svg")
    .attr("width", width)
    .attr("height", height);

svg.append("g")
    .attr("transform", `translate(0,${height - marginBottom})`)
    .call(d3.axisBottom(x)
        .ticks(d3.utcYear.every(1))
);
    
svg.append("text") //label
    .attr("class", "x label")
    .attr("text-anchor", "end")
    .attr("x", width/2)
    .attr("y", height - 6)
    .text("Year");

svg.append("text") //label
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("x", -height/3)
    .attr("y", 6)
    .attr("dy", ".75em")
    .attr("transform", "rotate(-90)")
    .text("Percent");

svg.append("g")
    .attr("transform", `translate(${marginLeft},0)`)
    .call(d3.axisLeft(y));

const parseTime = d3.utcFormat("%Y");

svg.append("line")          // nothing appears
.style("stroke", "black")  
.attr("x1", parseTime(new Date("2007")))     // x position of the first end of the line
.attr("y1", 0.50)      // y position of the first end of the line
.attr("x2", parseTime(new Date("2008")))      // x position of the second end of the line
.attr("y2", 0.40);

container.append(svg.node());

Data from html disappears and doesn’t not post using rest api call. When submit button is selected the form clears and data is not submitted

I have a basic HTML form that submits data to a SharePoint list. There are no errors in the code, nor do I receive anything that would cause the form not to submit to the SharePoint list. I am using basic HTML, some CSS, and AngularJS. The angular code uses a basic rest api call to post the data when the button is selected.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
    <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css">
    <link rel="stylesheet" href="calendar.css">
    <!-- <title>Document</title> -->
</head>
<body>

    <div class="container">
    <div class="row">
      <div class="col-md-8 col-md-offset-2">
        <div class="form-container">
          <h2 class="text-center" style="font-weight: bold;">Tour Request Form</h2>
          <form action="#" method="post" enctype="multipart/form-data">
            <div class="form-group">
                <div ng-controller="calendarController as calendar">
              <label for="tourRequest">Tour Request</label>
                    <input type="text" class="form-control" id="tourRequest" name="tourRequest" required>
                    <input class="btn-primary" type="submit" value="add">


            </div>
            </div>
          </form>
        </div>
      </div>
    </div>
    </div>
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="calendar.js"></script>
</body>
</html>
angular.module('mcalendarapp', [])
  .controller('myController', function($scope, $http) {
    $scope.newItem = {
      Title: $scope.tourRequest, // Example: A field in your SharePoint list
     // Description: '' // Example: Another field
    };

    $scope.addItem = function() {
      var listName = 'TourRequest'; // Replace with your list name
      var apiUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('" + listName + "')/items";

      var dataPayload = {
        '__metadata': {
          'type': 'SP.Data.' + listName + 'ListItem' // Adjust if your list name has spaces or special characters
        },
        'Title': $scope.newItem.Title,
       // 'Description': $scope.newItem.Description
      };

      $http({
        method: 'POST',
        url: "/_api/web/lists/getByTitle('mylist')/items",
        headers: {
          'Accept': 'application/json; odata=verbose',
          'Content-Type': 'application/json; odata=verbose',
          'X-RequestDigest': jQuery('#__REQUESTDIGEST').val() // Get the request digest
        },
        data: JSON.stringify(dataPayload)
      }).then(function(response) {
        // Success handling
        alert('Item added successfully!');
        $scope.newItem = {}; // Clear the form
      }).catch(function(error) {
        // Error handling
        console.error('Error adding item:', error);
        alert('Failed to add item. Check console for details.');
      });
    };
  });

Assistance with code and reasoning behind the api call failing

image map with random image on page load

Alright so this is the code i’m using for this section.

<div class="center">
<div class="imgcenter">
 <img id= "myRandomImg" usemap="#map" width="100%" height="100%">

<map name="map">
    <area shape="rect" coords="952,428,1203,657" alt="recent release" href="https://www.google.com">
</map>

<script>
myarray = ["webite1.png", "webite2.png", "webite3.png", "webite4.png", "webite5.png", "webite6.png"]
window.onload = function(){
 var randomNum = Math.floor(Math.random() * 6);
 var randomImgSrc =document.getElementById("myRandomImg").src = myarray[randomNum]; 
 console.log(randomNum)
}
</script>


How to set this image map on the photos being generated when the page loads?

All of the photos are the same size. I’m pretty new to this.

Trouble embedding SSRS report in iframe – scripts fail to load from correct origin

I’m having trouble embedding an SSRS report in an from an external application. The app calls the report server URL, and we’ve already configured CORS and switched to basic authentication.

We pass the credentials in the request using JavaScript, and it seems to work — the report loads the parameter header without prompting for login. However, the page fails to load completely because the Sys scripts throw errors. The issue is that the loaded page tries to fetch scripts from the iframe’s origin (http://192.168.1.101:8081) instead of the SSRS server (http://192.168.1.101), resulting in Uncaught ReferenceError: Sys.

Interestingly, if I embed the iframe without passing credentials and manually authenticate when prompted by the browser, the report loads perfectly.
Below is the JavaScript code used to embed the iframe and the error message. Any suggestions or workarounds would be greatly appreciated!

<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Report Viewer</title>
<style>
    body, html {
        margin: 0;
        padding: 0;
        height: 100%;
    }
    iframe {
        width: 100%;
        height: 100%;
        border: none;
    }
</style>
</head>
<body>
<iframe id="reportFrame"></iframe>

<script>
    const username = "user";
    const password = "password";

    const reportUrl = "http://192.168.1.101:80/ReportServer/Pages/ReportViewer.aspx?/MyReport&rs:Embed=True&rc:LinkTarget=main";

    const credentials = btoa(username + ":" + password);

    fetch(reportUrl, {
        method: "GET",
        headers: {
            "Authorization": "Basic " + credentials,
            "Upgrade-Insecure-Requests": "1",
            "Cache-Control":"max-age=0",
            
            "Access-Control-Allow-Origin":"http://192.168.1.101:8081",
            "Access-Control-Allow-Credentials":"true",
            "Access-Control-Allow-Methods":"GET, PUT, POST, PATCH, DELETE",
            "Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept, Authorization",
        }
    })
    .then(response => response.text())
    .then(html => {
        const iframe = document.getElementById("reportFrame");
        const blob = new Blob([html], { type: "text/html" });
        iframe.src = URL.createObjectURL(blob);
    })
    .catch(error => {
        console.error("Error to load the report:", error);
    });
</script>

Browser Error

We’re using the latest PBI Reporting Server.

unable to adjust d3 y-axis label position

I want to vertically center the y-axis label on a d3 graph. Right now, I have the label at the top of the y-axis. When I try to adjust the y or dy attributes, the label moves horizontally, not vertically. I suspect this has to do with the label being rotated, but when I comment out the rotation, the label disappears.

<div id="container"></div>
<script type="module">

const width = 1140;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 50;
const marginLeft = 70;

const x = d3.scaleUtc()
    .domain([new Date("2007-01-01"), new Date("2023-01-01")])
    .range([marginLeft, width - marginRight]);

const y = d3.scaleLinear()
    .domain([0, .5])
    .range([height - marginBottom, marginTop]);

const svg = d3.create("svg")
    .attr("width", width)
    .attr("height", height);

svg.append("g")
    .attr("transform", `translate(0,${height - marginBottom})`)
    .call(d3.axisBottom(x)
        .ticks(d3.utcYear.every(1))
);
    
svg.append("text")
    .attr("class", "x label")
    .attr("text-anchor", "end")
    .attr("x", width/2)
    .attr("y", height - 6)
    .text("Year");

svg.append("text")
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("y", 6) //if I change this value, the label moves horizontally
    .attr("dy", ".75em") //if I change this value, the label moves horizontally
    .attr("transform", "rotate(-90)") //if I comment this out, the label disappears
    .text("Percent");

svg.append("g")
    .attr("transform", `translate(${marginLeft},0)`)
    .call(d3.axisLeft(y));

container.append(svg.node());

Over riding a forms Submit button with Javascript

I have a login form with a submit button to submit the form. it ‘Fetches’ a PHP page that sets some SESSION Variables and returns to the login screen.
on completion I hide the Login Name and Password inputs and change the value of the Login button to ‘Logout’. I have a JQuery .click function to ‘Fetch’ a PHP page to unset the SESSION vars. However, now the form doesn’t submit. I assume the .click() function on the button is causing this?
How can I successfully overide the submit?

code below:

HTML

    <input
        class="btn"
        id="loginBtn"
        type="submit"
        value="Login"
    />

Javascript:

$("#loginBtn").click(function () {
    if ($("#loginBtn").value != "Logout") {
    return;
    }
    else {
        fetch("./logout.php")
        .then((response) => response.text())
        .then(window.location.replace("./login.html"))
        .catch((error) => console.error("Error:", error));
        }
});

Ive searched high and low but can’t understand a solution.
I could create a new button outside of the form and make that visible when required but thats giving in….

SVG Javascript Animated Arrows Missing

I am trying to animate a series of arrows between text boxes in a html file. The text boxes are receiving json strings sent via API calls. That part is working perfectly. However I am trying to animate four arrows between the boxes to illustrate and syncronize with the data exchanges and I cannot get my arrows to appear. There are no error messages in Chrome inspector and I can see the arrows becoming active and inactive but none appear, which makes me think it is a simple problem, perhaps an opacity switch somewhere. The literature is unclear on possible solutions. What is the problem with the js code that the arrows will not appear or animate? Any assistance would be gratefully received. I have enclosed the relevant html and js of my page.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Privacy API Exchange Flow</title>
<style>

  body { font-family: sans-serif; background: #f8f8f8; padding: 1rem;}
  h1 { text-align: center; }
  .buttons { text-align: center; margin: 1rem 0; }
  
  button {
    margin: 0.3rem; padding: 0.5rem 1rem; font-size: 1rem;
    border-radius: 4px; cursor: pointer;
  }
  
  #statusLine {
    text-align: center; font-weight: bold; font-size: 1.1rem;
    margin-bottom: 0.5rem; color: #1976d2;
  }
  .container { position: relative; width: 100%; }
  .boxes {
    display: flex; justify-content: space-around; margin-top: 1rem;
    position: relative; z-index: 2;
  }
  .box {
    width: 28%; background: white; border: 2px solid #444;
    border-radius: 6px; padding: 0.5rem;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
  }
  .title { font-weight: bold; text-align: center; margin-bottom: 0.5rem;}
  
  pre {
    background: #f0f0f0; height: 200px; overflow: auto;
    padding: 0.5rem; border-radius: 4px; font-size: 0.8rem;
  }

  /* Arrow styling */
  svg.arrow {
     position: absolute; top: 290px; width: 100%; height: 50px; 
     overflow: visible; z-index: 1;
  }
  
  svg.arrow path {
    transition: stroke-dashoffset 1s ease-in-out;
    stroke: #1976d2; stroke-width: 3; fill: none;
    marker-end: url(#arrowhead);    
    opacity: 1; /* hidden until animated */
  }
  
  path.active {
    stroke: #4CAF50; 
    stroke-width: 2px;
    stroke-dasharray: 300; 
    stroke-dashoffset: 300;
    opacity: 1; 
    animation: draw 1s forwards;
  }
  
  @keyframes draw {
    to { stroke-dashoffset: 0; }
  }
  
</style>
</head>
<body>

<h1>API Exchange</h1>

<div class="buttons">
  <button id="runDemo">Run Demo</button>
  <button id="resetDemo">Reset Demo</button>
</div>

<div id="statusLine">Ready to start</div>

<div class="container">

  <svg id="arrow1" class="arrow" width="100" height="50" viewBox="0 0 100 50">
  <path
    d= "M 20 50 L 20 20"
    fill="none"
    stroke="black"
    stroke-width="1"
  />
</svg>

<svg id="arrow2" class="arrow" width="100" height="50" viewBox="0 0 100 50">
  <path
    d= "M 50 20 L 20 20"
    fill="none"
    stroke="black"
    stroke-width="1"
  />
</svg>

<svg id="arrow3" class="arrow" width="100" height="50" viewBox="0 0 100 50">
  <path
    d= "M 80 30 L 50 30"
    fill="none"
    stroke="black"
    stroke-width="1"
  />
</svg>

<svg id="arrow4" class="arrow" width="100" height="50" viewBox="0 0 100 50">
  <path
    d= "M 50 40 L 80 40"
    fill="none"
    stroke="black"
    stroke-width="1"
  />
</svg>

  <svg class="arrow">
    <defs>
      <marker id="arrowhead" markerWidth="10" markerHeight="7"
              refX="10" refY="3.5" orient="auto">
        <polygon points="0 0, 10 3.5, 0 7" fill="#1976d2" />
      </marker>
    </defs>
  </svg>

 
  <div class="boxes">
    <div class="box">
      <div class="title">User</div>
      <pre id="userBox">// waiting…</pre>
    </div>
    <div class="box">
      <div class="title">Service Provider</div>
      <pre id="spBox">// waiting…</pre>
    </div>
    <div class="box">
      <div class="title">Trusted Third Party</div>
      <pre id="ttpBox">// waiting…</pre>
    </div>
  </div>
</div>

<script >
const sp_base = "http://localhost:8080";
const ttp_base = "http://localhost:8090";

const delay = ms => new Promise(res => setTimeout(res, ms));

function show(id, data) {
  document.getElementById(id).textContent =
    (typeof data === "string" ? data : JSON.stringify(data, null, 2));
}
function setStatus(text) {
  document.getElementById("statusLine").textContent = text;
}

function resetDemo() {
  show("userBox", "// waiting…");
  show("spBox", "// waiting…");
  show("ttpBox", "// waiting…");
  setStatus("Ready to start");
  document.querySelectorAll("svg.arrow path").forEach(p => p.classList.remove("active"));
  console.log("Demo Reset");
}

function animateArrow(id) {
  const path = document.getElementById(id);
  console.log("Arrow animated");
  if (!path) {
    console.error(`Arrow with id "${id}" not found!`);
    return;
  }

  //Reset Animation

 path.style.strokeDashoffset = "300"; 
 void path.offsetWidth; // Force reflow
 console.log("Animation Restart");

  //trigger animation
  path.classList.add("active");
  console.log("Animation Triggered");

  //remove active status after animation finish
  setTimeout(() => path.classList.remove("active"), 1000);
}


// Ensure DOM is ready
document.addEventListener("DOMContentLoaded", () => {
  document.getElementById("runDemo").onclick = async () => {
    resetDemo();
    setStatus("Step 1: User → Service Provider");
    show("userBox", "Running demo..."); 
    //await delay(5000);

  try {
    // Step 1
    animateArrow("arrow1");
    
    await delay(5000);
    //this logic is working only the animation is missing
    const uidResp = await fetch(`${sp_base}/UID/issue`, {
      method: "POST",
      headers: {"Content-Type": "application/json"},
      body: JSON.stringify({ dln: dln, sh: shx, audience: "sp"})
    }).then(r=>r.json());
    show("spBox", uidResp);

    await delay(5000);

    // Step 2
    setStatus("Step 2: Service Provider → User (UID issued)");
    animateArrow("arrow2");
    show("userBox", { message: "Received signed UID from SP", uid: uidResp });

    await delay(5000);

    // Step 3
    setStatus("Step 3: User → TTP (send UID)");
    animateArrow("arrow3");
    const ttpResp = await fetch(`${ttp_base}/token/issue`, {
      method: "POST",
      headers: {"Content-Type": "application/json"},
      body: JSON.stringify({
        uid: uidResp.uid,
        signature: uidResp.signature,
        signer: uidResp.signer
      })
    }).then(r=>r.json());
    show("ttpBox", ttpResp);

    await delay(5000);

    // Step 4
    setStatus("Step 4: TTP → User (note issued)");
    animateArrow("arrow4");
    show("userBox", {
      message: "Received note from TTP after verification",
      token: ttpResp
    });

    setStatus("Demo complete ✅");

  } catch (err) {
    console.error(err);
    show("userBox", { error: err.message });
    setStatus("Error: " + err.message);
  }
};
});
document.getElementById("resetDemo").onclick = resetDemo;

</script>

</body>
</html>