Width of notifications from mantine in react app

So, I have problem with notifications width, despite using lines from mantine docs, with of notifications is 100% all the time.
App.tsx:

<MantineProvider defaultColorScheme="dark">
            <Notifications containerWidth="50" />
            <BrowserRouter>
                <Routing/>
            </BrowserRouter>

notifications.ts:

export const LoginFailedNotification = ()=>{
    notifications.show({
        position: 'bottom-right',
        withCloseButton: true,
        autoClose: 5000,
        title: "You've been compromised",
        message: 'Leave the building immediately',
        color: 'red',
        icon: React.createElement(IconX),
    });
}

mantine docs: https://mantine.dev/x/notifications/?t=props

I tried things described in mantine docs, i would expect that notification width would be 50px

How to get height of children inside component?

I make a wrapper for the content

import cls from './ContentWrapper.module.css';
import { classNames } from '../../lib/classNames/classNames.ts';
import { ReactNode, useContext, useEffect, useRef } from 'react';
import { ScrollContext } from '@/app/providers/ScrollProvider/ScrollProvider.tsx';
import { useLocation } from 'react-router';

interface ContentWrapperProps {
    className?: string;
    width?: '60' | '80' | '100';
    children?: ReactNode;
}
export const ContentWrapper = (props: ContentWrapperProps) => {
    const { className, children, width = '100%' } = props;
    const { scrolls, setScroll } = useContext(ScrollContext);
    const { pathname } = useLocation();
    const onScroll = () => {
        const scroll = Math.round(window.scrollY);
        setScroll?.(pathname, scroll);
    };
    const ref = useRef<HTMLDivElement | null>(null);

    useEffect(() => {
        console.log('renderWrapper');
        console.log(ref.current?.scrollHeight);
    });

    return (
        <div
            className={classNames([
                className,
                cls.contentWrapper,
                [cls['size_' + width]],
            ])}
            id="contentBlockId"
            onScroll={onScroll}
            ref={ref}
        >
            {children}
        </div>
    );
};

Inside the wrapper I have a render, for example – a publication feed. When the feed is loaded, it changes height and goes beyond the window.

import cls from './PublicationsList.module.css';
import { classNames } from '@/shared/lib/classNames/classNames.ts';
import { useAllPublications } from '../../api/publicationApi.ts';
import { Publication } from '../../model/types/publication.ts';
import { Loader } from '@/shared/ui/Loader/Loader.tsx';
import { PublicationTapeItem } from '../PublicationTapeItem/PublicationTapeItem.tsx';
import { useEffect, useRef } from 'react';

interface PublicationsListProps {
    className?: string;
}
export const PublicationsList = (props: PublicationsListProps) => {
    const { className } = props;
    const { data, isLoading, error } = useAllPublications();
    const ref = useRef<HTMLDivElement | null>(null);

    useEffect(() => {
        console.log('renderContent');
        console.log(ref.current?.scrollHeight);
    });

    if (isLoading) {
        return <Loader />;
    }

    if (error) {
        throw new Error(error.toString());
    }

    return (
        <div
            className={classNames([className, cls.publicationsList], {})}
            ref={ref}
        >
            {data.map((publication: Publication) => (
                <PublicationTapeItem
                    key={publication.id}
                    publication={publication}
                />
            ))}
        </div>
    );
};

How can I find out the height of the feed block from the wrapper?

I get it in console
enter image description here

i try add useeffect without dependencies for get element ref every render

Fetching keys and values of api

const url = "http://universities.hipolabs.com/search?name=";

let btn = document.querySelector("#college");

btn.addEventListener("click", async () => {
  let input = document.querySelector("input").value;
  let colArr = await fetchData(input);
  show(colArr);
});

function show(colArr) {
  let list = document.querySelector("#list");
  list.innerText = "";
  for (col of colArr) {
    console.log(col.name);
    let li = document.createElement("li");
    li.innerText = col.name;
    list.appendChild(li);
  }
}

async function fetchData(input) {
  try {
    let res = await axios.get(url + input);
    return res.data;
  } catch (e) {
    console.log("Error: ", e);
    return [];
  }
}
 <h1>Get cat facts</h1>
    <!-- <button>Get Facts</button> -->
     <input type="text">
    <ul id="list"></ul>
    <button id="college">Show Colleges</button> <br>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>

/// Here I am extracting data from an api of colleges. My code is running for query string when user enters a country all universities are showing in that country, but I want to modify it by adding country name in the url example => India ; and when user enters the state only the college which is list in that state should be printed.data extracted in printing but the key state-province is not accessible when I add col.state-province.

Description Image – Here I have extracted the data of colleges

Validating a Form using Javascript

Trying to validate a simple form to make sure the correct code is entered.

<form name="codeForm" method="post" onSubmit="validateForm();">
  <label for="code">Code:</label><br>
  <input type="text" id="code" name="code"><br>
  <input type="submit" value="Submit" onclick="test()">
</form>

var session = document.getElementById("session");
var code = document.forms["codeForm"]["code"].value;

function validateForm(){
    if(code==="ACBD2025"){
        session.style.display="block";
        
    } else {
        alert("Please enter a Valid Code");
    }
}

Does node.js use a call stack for local variables like C and Java? [duplicate]

The context I’m interested in is an HTTP server where calls may be suspended for a period of time due to IO operations before returning a response. In the meantime other HTTP requests may arrive.

I’m new to node.js and there doesn’t seem to be a readily apparent answer to this. Does one have to code in a special way to prevent local variables from being overwritten by subsequent calls?

Npm installation issues

Whenever I try to install any npm package I always get some errors like 16 vulnerabilities and some critical errors which is so much annoying that every time I work everything goes wrong I really don’t know what to do I have tried the mpn audit functions as well as all the fix functions clean the kj and all things still it is having the same issue.
enter image description here.

I did try to clean the cache files of MPM and try to reinstall all the things that I have been running on but still having the same problem and it doesn’t resolve.

I am currently building a shopping site in Html & Js for an project, but there seems to be an error with my Cart

If I add an item to my cart (set the quantity above 0), I have this weird errror where only the first object is having an image and the others don´t. I dont know how to fix this and where my error was.

let cart = [
    {id: 1, name:"Ryzen 7 7800X3D", price:455, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 2, name:"r9_9900X", price:470, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 3, name:"r9_9800X3D", price:760, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 4, name:"r5_7500f", price:122, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 5, name:"rx_7900XTX", price:910, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 6, name:"Herr Dreier", price:69420, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 7, name:"rx_7700XT", price:540, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
    {id: 8, name:"r7_7800X3D", price:455, quantity:0, finalprice: 0, img:"graphics/r7x3d.png",},
];

function addCartItem(img, Names, price, id) {
    cartList = document.querySelector("#cart ul"); 
    li = document.createElement("li");
    li.innerHTML = `
    <div class="item" id="${price}">
     <img src="${img}" alt="">
    <p id="1me">${Names}</p>
    <label for="Quantity">Quantity</label>
    <select name="Quantity" id="${id}" onchange="update_quantity(this.value, ${id})">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    </select>
    <p>${price}</p>
    <button type="button" onclick="remove_item();"><i class="fa-solid fa-xmark"></i></button>
    </div>
`;
    cartList.appendChild(li);
};

function cart_loader() {
    load_cart();
    x = 0;
    while(x < cart.length) {
    price_calc(x);
    if(cart[x].quantity >=1) {
    addCartItem(cart[x].img, cart[x].name, cart[x].finalprice+"€", cart[x].id)
};
x++;
};
total_price();
};
cart_loader();

Short description of what I did:
At first I coded both functions, I added the first object to cart, everything worked, but as soon I added a second item only the first one had an Image, but I wanted both to have one. I tried rewriting the cart_loader(); but that didn´t work. I tried loading another Image, it didn´t work and I tried to find the error with printing everything out in the debug console.

how can i remove an event from web page at specific view point

I am trying to remove the event from some items at 993px viewpoint and above which was added at 992px and below. How to go about it?

HTML

<div class="sidebar_button d-flex d-lg-none justify-content-center align-items-center z-3">
   <span class="close_left active p-2 py-3 rounded-circle" title="Close_left">&times;</span>
   <span class="dis_left p-2 py-3 rounded-circle" title="Dis_left">&#8827;</span>
</div>

JavaScript code

if (sidebarbtn_div.style.display=='flex') {
  const changesidebarbtn=()=>{
    sidebarbtn.forEach(item=>{
      item.classList.remove('active')
    })
  };
  sidebarbtn.forEach(disbtn => {
    disbtn.addEventListener('click', () => {
      changesidebarbtn();
      if(disbtn.classList.contains('close_left')) {
        document.querySelector('.dis_left').classList.add('active');
        document.querySelector('#class_middle').style.width='96vw';
        sidebar.style.display='none'
      } else if(disbtn.classList.contains('dis_left')) {
        document.querySelector('.close_left').classList.add('active');
        document.querySelector('#class_middle').style.width='100%';
        sidebar.style.display='block'
      };
    })
  })
} else if (sidebarbtn_div.style.display=='none') {
  document.querySelector('#class_middle').style.width='100%';
  sidebar.style.display='block'
}

Swagger not showing documentation with Koa annotations

I have a simple rest API that works with Koa and MySQL and now I want to add some swagger documentation, I have done the first part of the api-docs route works however it doesn’t seem to be able to load the options I defined.

I expect it to load the option and the annotations I defined

Thanks a lot in advance and a happy new year 😀

**login.ts**

import { verifyLogin, verifyCaptcha } from "../middlewares/login.middleware"
import LoginController from "../controller/login.controller"

const KoaRouter = require('@koa/router')

const loginRouter = new KoaRouter({
    prefix: '/login'
})


/**
 * @swagger
 * /login:
 *    post:
 *      description: User Login
 *      responses:
 *        '200':
 *          description: Successfully login
 *        '500':
 *          description: Bad Request
 *    parameters:
 *      - name: username
 *        in: body
 *        required: true
 *        schema:
 *          type: string
 *          format: string
 *      - password: password
 *        in: body
 *        required: true
 *        schema:
 *          type: string
 *          format: string
 *      - code: code
 *        in: body
 *        required: true
 *        schema:
 *          type: string
 *          format: string
 */
loginRouter.post('/', verifyLogin, verifyCaptcha, LoginController.generateToken)


export default loginRouter
**swagger.ts**

const path = require('path');
const KoaRouter = require('@koa/router')
const swaggerJsdoc = require('swagger-jsdoc');
import { koaSwagger } from 'koa2-swagger-ui';

const options = {
    swaggerDefinition: {
        openapi: '3.0.0',
        info: {
          title: 'My API',
          version: '1.0.0',
          description: 'This is a sample server',
        },
    },
    apis: [path.join(__dirname, '../router/*.ts')],
};

const swaggerDocs = swaggerJsdoc(options);

const docsRouter = new KoaRouter({
    prefix: '/api'
})

docsRouter.get('/docs', koaSwagger({ routePrefix: false, swaggerOptions: { swaggerDocs } }))


export default docsRouter

This is what happens when the console prints

enter image description here

transform and padding do not works together

I have drop-down menu, I do not want to change it width min-width: 200px;. But I want to add padding from the right.

what i want to do

Also I can’t understand how to make it’s opening not to right, but to left, but padding now main problem.

<nav>
    <ul class="nav-menu">

        <li class="dropdown">
            <a href="#" data-toggle="dropdown">About</a>
            <ul class="dropdown-menu">
              <li><a href="/foo.html">Foo</a></li>
              <li><a href="/bar.html">Bar</a></li>
            </ul>
       </li>

    </ul>
</nav>
 nav {
   width: 200px;  
   position: relative;
 }
   

.nav-menu {
   background-color: orange;
   
   display: flex;
   flex-direction: row;    

 }
 
 .dropdown {
  position: relative;
  }
   
  
  a[data-toggle="dropdown"] {
    display: flex;
    align-items: center;
    background: transparent;
    color: blue;
    padding: 10px 15px;
    border-radius: 4px;
    transition: background 0.3s ease;
    white-space: nowrap;
  }
  
  a[data-toggle="dropdown"]:hover {
    color: black;
  }

.nav-menu {
    gap: 10px;
    list-style-type: none;
    padding: 0;
    margin: 0;
    align-items: center;
    width: 100%;
}

.dropdown-menu {
    list-style: none;
    padding: 10px 15px;
    margin: 0;
    position: absolute;
    top: 100%;
    left: 0;
    /* min-width: 200px; */
    width: auto;
    box-sizing: border-box;
    background: #ffffff;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
    border-radius: 6px;
    overflow: hidden;
    transform: scaleY(0);
    transform-origin: top;
    opacity: 0;
    transition: transform 0.3s ease, opacity 0.3s ease;
    z-index: 1000;
  }
  
.dropdown-menu.show {
    transform: scaleY(1);
    opacity: 1;
  }
  
.dropdown-menu:before {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    clip-path: inset(0 0 0 0);
  }
document.querySelectorAll('.dropdown').forEach((dropdown) => {
  const button = dropdown.querySelector('a[data-toggle="dropdown"]');
  const menu = dropdown.querySelector('.dropdown-menu');

  button.addEventListener('click', (event) => {
    event.preventDefault();
    document.querySelectorAll('.dropdown-menu.show').forEach((openMenu) => {
      if (openMenu !== menu) {
        openMenu.classList.remove('show');
      }
    });
    const buttonWidth = button.offsetWidth;
    menu.style.width = `${buttonWidth}px`;
    menu.classList.toggle('show');
  });
});

// to close the dropdown when clicked anywhere else on the page
document.addEventListener('click', (event) => {
  if (!event.target.closest('.dropdown')) {
    document.querySelectorAll('.dropdown-menu.show').forEach((menu) => {
      menu.classList.remove('show');
    });
  }
});

https://jsfiddle.net/4y0vq17m/1/

I tried to add padding-right to .dropdown-menu but it do not works as I expect.

Does chrome.webRequest capture the “requestBody” of PATCH?

I’m developing a chrome extension to capture the parameters and it’s values from a web application. So far I have been successfully able to capture the requestBody of POST calls through the chrome.webRequest API. But when testing the same for an update action (PATCH) the “requestBody” returns as null

I’ve tried adding log statements to my function and come to a conclusion that it might be a limitation in the chrome.webRequest API itself.

// Capture the request body before the request is sent 
chrome.webRequest.onBeforeRequest.addListener(   
(details) => {     
if (isCapturing && ["POST", "PUT", "PATCH"].includes(details.method)) { 
      const requestBody = details.requestBody;       
       let rawBody = "";       
console.log(Request details: ${JSON.stringify(details)}`);  
`
if (requestBody) {
    console.log(`Request body exists for ${details.method} request to ${details.url}`);
    if (requestBody.raw && requestBody.raw.length) {
      rawBody = String.fromCharCode.apply(
        null,
        new Uint8Array(requestBody.raw[0].bytes)
      );
      console.log(`Raw body extracted for ${details.method} request to ${details.url}`);
    } else {
      console.log(`Request body raw is empty for ${details.method} request to ${details.url}`);
    }
  } else {
    console.log(`Request body is null for ${details.method} request to ${details.url}`);
  }
  const url = new URL(details.url);
  const postmanUrl = {
    raw: details.url,
    protocol: url.protocol.replace(":", ""),
    host: url.hostname.split("."),
    path: url.pathname.split("/").filter(Boolean),
  };

  // Push the request with the body
  capturedRequests.push({
    name: details.url,
    request: {
      method: details.method,
      header: [], // Will be added in onCompleted
      body: rawBody,
    },
  });
}
}, 
{ urls: ["<all_urls>"] }, 
["requestBody"] );

I need to know if there is any workaround for this to make it work for both POST and PATCH.

I’ve logged the header details and found out that the tag “requestBody” is available in POST and not in PATCH. This could mean that there is a limitation. I need to know if there is any known workaround for this.

Any help would be appreciated!

Axios request “pending” in Chrome Dev Tool

In my project I’m doing a GET request (axios) and I’m getting the data I need.

My problem: In Chrome Dev Tools (Network tab) the status of the request is always “pending”. On the other hand, when I console.log the status of the response, it’s 200 (code below).

Any ideas what is wrong here?

await axios({
      method: "get",
      url: `https://nominatim.openstreetmap.org/search?city=${city}&country=${country}&limit=1&format=json`,
      headers: {
          "Content-Type": "application/json; charset=utf-8",
        },
    })
    .then(function (response) {
        console.log(response.data);
        console.log(response.status);
        console.log(response.statusText);
      });

Why does it only work correctly when I use the await keyword?

        try {
            const review = await Review.create({
                user: user.userid,
                place_id: pid,
                stars: stars,
                content: content,
            });

            /* await */ User.findByIdAndUpdate(user.userid, {
                $push: {reviews: review._id}
            });

            res.status(200).json(returnResponse(false, "reviewWritten", "-"));

            return;
        } catch (error) {
            console.error(error);

            res.status(500).json(returnResponse(true, "errorAtReviewWriting", "-"));

            return;
        }

I have written the code as shown above.

I thought that since I don’t need the return value of User.findByIdAndUpdate, I don’t have to use the await keyword and let it run asynchronously. Why does it only work correctly when I use the await keyword?

When I don’t use the await keyword, It’s not updated at all. Literally.

I have verified that the data has not been edited at all by findById() method after saving.

And, error didn’t occur since the returned response code was 200.

Use Javascript to alter a text file

I am attempting to remove the vowel points from Hebrew language. The following code is successful at removing the vowel points:

function removeVowels(text) {
    return text.replace(/[u0591-u05C7]/g, "");
}

const originalText =
    "אָדָ֛ם בְּצַלְמֵ֖נוּ כִּדְמוּתֵ֑נוּ וְיִרְדּ";

const vowelsRemoved = removeVowels(originalText);

// print out the results

console.log(vowelsRemoved); 

Returning:

אדם בצלמנו כדמותנו וירד

However, I would like to do things differently:

  1. Instead of entering the Hebrew into the .js file, I would like this function to change the text of a whole document called ‘hebrew.txt’.
  2. Instead of printing the result in terminal, I would like it to overwrite the content of ‘hebrew.txt’, with a console message telling me when it has finished.

Do I need to use fs.writeFile somehow?
Much appreciated.

Edit: If it makes any difference, I am using Linux.

TypeError: Cannot read properties of null when saving data in PHP web app

I’m working on a PHP web app where users input data, validate fields, preview images, and then save the data to MySQL. When submitting the form, I encounter the error:

TypeError: Cannot read properties of null (reading ‘value’)

This happens when I try to access form field values. How can I fix this issue?

function populateReviewSection() {
            const reviewContent = document.getElementById('reviewContent');
            reviewContent.innerHTML = ''; // Clear previous content

            // Helper function to format dates (if applicable)
            const formatDate = (dateStr) => {
                const date = new Date(dateStr);
                if (isNaN(date.getTime())) return 'Not provided';
                return date.toLocaleDateString(); // You can customize this format as needed
            };

            // Retrieve form data
            const firstname = document.getElementById('firstname').value;
            const surname = document.getElementById('surname').value;
            const email = document.getElementById('email').value;
            const dob = formatDate(document.getElementById('dob').value); // Format DOB
            const gender = document.querySelector('input[name="gender"]:checked')?.value || 'Not selected';
            const ridersImagePreview = document.getElementById('ridersImagePreview').src;
            const ridersImageName = document.getElementById('ridersImageName').textContent || 'No image selected';

            // Retrieve fields for GPS address, employment status, and nationality
            const gpsAddress = document.getElementById('riders_gpsAddress').value || 'Not provided';
            const employmentStatus = document.getElementById('employment_status').value || 'Not selected';
            const nationality = document.getElementById('nationality').value || 'Not selected';
            const homeTown = document.getElementById('home_town').value || 'Not provided';
            const phoneNumber = document.getElementById('phone_number').value || 'Not provided';
            const address = document.getElementById('address').value || 'Not provided';
            const stationId = document.getElementById('station_id').value || 'Not selected';

            // Step 2: Retrieve form data from Step 2
            const idCardType = document.getElementById('id_card_type').value || 'Not selected';
            const idCardNumber = document.getElementById('id_card_number').value || 'Not provided';
            const idCardExpiry = formatDate(document.getElementById('id_card_expiry').value); // Format ID card expiry
            const idCardImagePreview = document.getElementById('idCardImagePreview').src;
            const idCardBackImagePreview = document.getElementById('idCardBackImagePreview').src;

            const isRiderHavingLicense = document.getElementById('isRiderHavingLicense').value || 'Not selected';
            const licenseNumber = document.getElementById('license_number').value || 'Not provided';
            const licenseExpiryDate = formatDate(document.getElementById('license_expiry_date').value); // Format license expiry
            const licenseImagePreview = document.getElementById('licenseImagePreview').src;
            const licenseBackImagePreview = document.getElementById('licenseBackImagePreview').src;

            // Get values for the radio button groups
            const yearsAsRider = document.querySelector('input[name="years_as_rider"]:checked')?.value || 'Not selected';
            const ownMotorbike = document.querySelector('input[name="own_motorbike"]:checked')?.value || 'Not selected';
            const workingForPay = document.querySelector('input[name="working_for_pay"]:checked')?.value || 'Not selected';
            const business_model = document.getElementById('business_model').value || 'Not provided';
            const shareBike = document.querySelector('input[name="share_bike"]:checked')?.value || 'Not selected';

            // Populate the reviewContent div with the collected data
            reviewContent.innerHTML = `

                <!-- Rider's Image displayed above the text -->
                <div class="image-preview" style="text-align: center; margin-bottom: 20px;">
                    <h6><strong>Rider's Image</strong></h6>
                    <img src="${ridersImagePreview}" alt="Rider's Image" style="max-width: 300px; height: auto; display: block; margin-left: auto; margin-right: auto; border-radius: 8px;">
                    <p><strong>Image Name:</strong> ${ridersImageName}</p>
                </div>

                <div class="review-section">
                    <h6><strong>Personal Information</strong></h6>
                    <table class="table table-bordered">
                        <tr>
                            <th>First Name</th>
                            <td>${firstname}</td>
                        </tr>
                        <tr>
                            <th>Surname</th>
                            <td>${surname}</td>
                        </tr>
                        <tr>
                            <th>Email</th>
                            <td>${email}</td>
                        </tr>
                        <tr>
                            <th>Date of Birth</th>
                            <td>${dob}</td>
                        </tr>
                        <tr>
                            <th>Gender</th>
                            <td>${gender}</td>
                        </tr>
                    </table>
                </div>

                <div class="review-section">
                    <h6><strong>Rider's Details</strong></h6>
                    <table class="table table-bordered">
                        <tr>
                            <th>GPS Address</th>
                            <td>${gpsAddress}</td>
                        </tr>
                        <tr>
                            <th>Employment Status</th>
                            <td>${employmentStatus}</td>
                        </tr>
                        <tr>
                            <th>Nationality</th>
                            <td>${nationality}</td>
                        </tr>
                        <tr>
                            <th>Home Town</th>
                            <td>${homeTown}</td>
                        </tr>
                        <tr>
                            <th>Phone Number</th>
                            <td>${phoneNumber}</td>
                        </tr>
                        <tr>
                            <th>Address</th>
                            <td>${address}</td>
                        </tr>
                        <tr>
                            <th>Station</th>
                            <td>${stationId}</td>
                        </tr>
                    </table>
                </div>


                <div class="review-section">
                    <h6><strong>ID Card Information</strong></h6>
                    <table class="table table-bordered">
                        <tr>
                            <th>ID Card Type</th>
                            <td>${idCardType}</td>
                        </tr>
                        <tr>
                            <th>ID Card Number</th>
                            <td>${idCardNumber}</td>
                        </tr>
                        <tr>
                            <th>ID Card Expiry</th>
                            <td>${idCardExpiry}</td>
                        </tr>
                        <tr>
                            <th>ID Card Front</th>
                            <td><img src="${idCardImagePreview}" alt="ID Card Front" style="max-width: 200px; max-height: 200px;"></td>
                        </tr>
                        <tr>
                            <th>ID Card Back</th>
                            <td><img src="${idCardBackImagePreview}" alt="ID Card Back" style="max-width: 200px; max-height: 200px;"></td>
                        </tr>
                    </table>
                </div>

                <div class="review-section">
                    <h6><strong>License Information</strong></h6>
                    <table class="table table-bordered">
                        <tr>
                            <th>Has a License</th>
                            <td>${isRiderHavingLicense}</td>
                        </tr>
                        ${isRiderHavingLicense === 'Yes' ? `
                            <tr>
                                <th>License Number</th>
                                <td>${licenseNumber}</td>
                            </tr>
                            <tr>
                                <th>License Expiry</th>
                                <td>${licenseExpiryDate}</td>
                            </tr>
                            <tr>
                                <th>License Front</th>
                                <td><img src="${licenseImagePreview}" alt="License Front" style="max-width: 200px; max-height: 200px;"></td>
                            </tr>
                            <tr>
                                <th>License Back</th>
                                <td><img src="${licenseBackImagePreview}" alt="License Back" style="max-width: 200px; max-height: 200px;"></td>
                            </tr>
                        ` : ''}
                    </table>
                </div>

                <div class="review-section">
                    <h6><strong>Rider's Experience</strong></h6>
                    <table class="table table-bordered">
                        <tr>
                            <th>Number of Years as a Rider</th>
                            <td>${yearsAsRider} years</td>
                        </tr>
                        <tr>
                            <th>Do you own the motorbike?</th>
                            <td>${ownMotorbike}</td>
                        </tr>
                        <tr>
                            <th>Are you working for work and pay?</th>
                            <td>${workingForPay}</td>
                        </tr>
                        <tr>
                            <th>Your business model if not work and pay</th>
                            <td>${business_model}</td>
                        </tr>
                        <tr>
                            <th>Do you share the bike with another rider?</th>
                            <td>${shareBike}</td>
                        </tr>
                    </table>
                </div>

            `;
        }

        // Add a submit button to your HTML in the review step
        document.querySelector('#submit-form').addEventListener('click', function(e) {
            e.preventDefault();

            // Show SweetAlert2 confirmation dialog
            Swal.fire({
                title: 'Are you sure?',
                text: "You want to submit this rider information?",
                icon: 'question',
                showCancelButton: true,
                confirmButtonColor: '#3085d6',
                cancelButtonColor: '#d33',
                confirmButtonText: 'Yes, submit it!'
            }).then((result) => {
                if (result.isConfirmed) {
                    // Disable the submit button to prevent double submission
                    this.disabled = true;

                    // Show loading state
                    $(this).html('<i class="fas fa-spinner fa-spin"></i> Submitting...');

                    // Call the save function
                    saveRiderData();
                }
            });
        });

        // Update the saveRiderData function to properly collect all form data
        function saveRiderData() {
            // Create a data object instead of FormData
            const data = {
                firstname: document.getElementById('firstname').value,
                surname: document.getElementById('surname').value,
                email: document.getElementById('email').value,
                dob: document.getElementById('dob').value,
                gender: document.querySelector('input[name="gender"]:checked').value,
                gpsAddress: document.getElementById('riders_gpsAddress').value,
                employmentStatus: document.getElementById('employmentStatus').value,
                nationality: document.getElementById('nationality').value,
                homeTown: document.getElementById('home_town').value,
                phoneNumber: document.getElementById('phone_number').value,
                address: document.getElementById('address').value,
                stationId: document.getElementById('station_id').value
            };

            // Handle image files - convert to base64
            const promises = [];

            // Function to convert file to base64
            const fileToBase64 = (file) => {
                return new Promise((resolve, reject) => {
                    const reader = new FileReader();
                    reader.readAsDataURL(file);
                    reader.onload = () => resolve(reader.result);
                    reader.onerror = error => reject(error);
                });
            };

            // Add riders image
            const ridersImage = document.getElementById('ridersImage').files[0];
            if (ridersImage) {
                promises.push(
                    fileToBase64(ridersImage).then(base64 => {
                        data.ridersImagePreview = base64;
                    })
                );
            }

            // Add ID card images
            const idCardImage = document.getElementById('id_card_image').files[0];
            if (idCardImage) {
                promises.push(
                    fileToBase64(idCardImage).then(base64 => {
                        data.idCardImagePreview = base64;
                    })
                );
            }

            const idCardBackImage = document.getElementById('id_card_back_image').files[0];
            if (idCardBackImage) {
                promises.push(
                    fileToBase64(idCardBackImage).then(base64 => {
                        data.idCardBackImagePreview = base64;
                    })
                );
            }

            // License information
            data.isRiderHavingLicense = document.getElementById('isRiderHavingLicense').value;
            if (data.isRiderHavingLicense === 'Yes') {
                data.licenseNumber = document.getElementById('license_number').value;
                data.licenseExpiryDate = document.getElementById('license_expiry_date').value;

                const licenseImage = document.getElementById('license_image').files[0];
                if (licenseImage) {
                    promises.push(
                        fileToBase64(licenseImage).then(base64 => {
                            data.licenseImagePreview = base64;
                        })
                    );
                }

                const licenseBackImage = document.getElementById('license_back_image').files[0];
                if (licenseBackImage) {
                    promises.push(
                        fileToBase64(licenseBackImage).then(base64 => {
                            data.licenseBackImagePreview = base64;
                        })
                    );
                }
            }

            // Experience information
            data.yearsAsRider = document.querySelector('input[name="years_as_rider"]:checked').value;
            data.ownMotorbike = document.querySelector('input[name="own_motorbike"]:checked').value;
            data.workingForPay = document.querySelector('input[name="working_for_pay"]:checked').value;
            data.businessModel = document.getElementById('business_model').value;
            data.shareBike = document.querySelector('input[name="share_bike"]:checked').value;

            // Wait for all file conversions to complete
            Promise.all(promises)
                .then(() => {
                    // Send the data using fetch
                    return fetch('../API/save_rider_data.php', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify(data)
                    });
                })
                .then(response => response.json())
                .then(data => {
                    console.log('Response data:', data);
                    if (data.status === 'success') {
                        Swal.fire({
                            icon: 'success',
                            title: 'Success!',
                            text: 'Rider information saved successfully!',
                            timer: 1500
                        }).then(() => {
                            window.location.href = 'riders_list.php';
                        });
                    } else {
                        throw new Error(data.message || 'Failed to save rider information');
                    }
                })
                .catch(error => {
                    console.error('Error:', error);
                    Swal.fire({
                        icon: 'error',
                        title: 'Error',
                        text: error.message
                    });
                    document.querySelector('#submit-form').disabled = false;
                    document.querySelector('#submit-form').innerHTML = 'Submit';
                });
        }


<?php
header('Content-Type: application/json');

// Include database connection
require 'connection.php';

// Start transaction
mysqli_begin_transaction($conn);

try {
    // Function to handle file upload
    function uploadFile($base64String, $uploadPath)
    {
        if (strpos($base64String, 'data:image') === 0) {
            $base64Image = explode(',', $base64String)[1];
            $imageData = base64_decode($base64Image);
            $fileName = uniqid() . '.jpg';
            $filePath = $uploadPath . $fileName;

            if (file_put_contents($filePath, $imageData)) {
                return $fileName;
            }
        }
        return null;
    }

    // Validate required fields
    $requiredFields = ['firstname', 'surname', 'email', 'dob', 'nationality', 'employment_status', 'phone_number'];
    $data = json_decode(file_get_contents('php://input'), true);

    foreach ($requiredFields as $field) {
        if (empty($data[$field])) {
            throw new Exception("Required field $field is missing");
        }
    }

    // Generate unique registration number
    $registrationNumber = 'RDR' . date('Y') . sprintf('%06d', rand(1, 999999));

    // Insert into Riders table
    $stmt = $conn->prepare("INSERT INTO Riders (
        registration_number, first_name, surname, home_town, nationality,
        employment_status, dob, gender, email, phone_number, gps_address,
        address, station_id, user_id
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

    $stmt->bind_param(
        "ssssssssssssii",
        $registrationNumber,
        $data['firstname'],
        $data['surname'],
        $data['homeTown'],
        $data['nationality'],
        $data['employmentStatus'],
        $data['dob'],
        $data['gender'],
        $data['email'],
        $data['phoneNumber'],
        $data['gpsAddress'],
        $data['address'],
        $data['stationId'],
        $data['userId']
    );

    $stmt->execute();
    $riderId = $stmt->insert_id;

    // Upload and save passport picture
    if (!empty($data['ridersImagePreview'])) {
        $passportPicture = uploadFile($data['ridersImagePreview'], '../uploads/passport_pictures/');
        if ($passportPicture) {
            $stmt = $conn->prepare("INSERT INTO PassportPictures (rider_id, passport_picture) VALUES (?, ?)");
            $stmt->bind_param("is", $riderId, $passportPicture);
            $stmt->execute();
        }
    }

    // Insert ID Card information
    if (!empty($data['idCardType'])) {
        $idCardFront = uploadFile($data['idCardImagePreview'], '../uploads/id_cards/');
        $idCardBack = uploadFile($data['idCardBackImagePreview'], '../uploads/id_cards/');

        $stmt = $conn->prepare("INSERT INTO IDCards (
            rider_id, id_card_type, id_card_number, id_card_expiry,
            id_card_front_image, id_card_back_image
        ) VALUES (?, ?, ?, ?, ?, ?)");

        $stmt->bind_param(
            "isssss",
            $riderId,
            $data['idCardType'],
            $data['idCardNumber'],
            $data['idCardExpiry'],
            $idCardFront,
            $idCardBack
        );
        $stmt->execute();
    }

    // Insert License information
    $hasLicense = $data['isRiderHavingLicense'] === 'Yes';
    if ($hasLicense) {
        $licenseFront = uploadFile($data['licenseImagePreview'], '../uploads/licenses/');
        $licenseBack = uploadFile($data['licenseBackImagePreview'], '../uploads/licenses/');

        $stmt = $conn->prepare("INSERT INTO Licenses (
            rider_id, license_number, license_expiry_date, has_license,
            license_front_image, license_back_image
        ) VALUES (?, ?, ?, ?, ?, ?)");

        $stmt->bind_param(
            "ississ",
            $riderId,
            $data['licenseNumber'],
            $data['licenseExpiryDate'],
            $hasLicense,
            $licenseFront,
            $licenseBack
        );
        $stmt->execute();
    }

    // Insert Rider Experience
    $stmt = $conn->prepare("INSERT INTO RiderExperience (
        rider_id, years_as_rider, owns_motorbike, works_for_pay, shares_bike
    ) VALUES (?, ?, ?, ?, ?)");

    $stmt->bind_param(
        "issss",
        $riderId,
        $data['yearsAsRider'],
        $data['ownMotorbike'],
        $data['workingForPay'],
        $data['shareBike']
    );
    $stmt->execute();

    // Commit transaction
    mysqli_commit($conn);

    echo json_encode([
        'status' => 'success',
        'message' => 'Rider information saved successfully',
        'rider_id' => $riderId,
        'registration_number' => $registrationNumber
    ]);
} catch (Exception $e) {
    // Rollback transaction on error
    mysqli_rollback($conn);
    echo json_encode([
        'status' => 'error',
        'message' => $e->getMessage()
    ]);
}

// Close database connection
mysqli_close($conn);