Smooth out the transition

I’ve been trying out the D3 library in a Nextjs app and I am trying to get the zoom and pan working. Now, I’ve somehow managed to get the zoom and pan working. What I’m having trouble with is resetting the chart.

I have this function for a button click that is supposed to reset any zoom or pan on a chart.

  function handleClick() {
    var selection = d3.select(svgRef.current).select(".toZoom");

    selection
      .transition()
      .duration(750)
      .tween("attr.transform", () => {
        var i = d3.interpolateString(
          "scale(1, 1)" + `translate(0,${height - margin.bottom})`,
          "scale(1, 1) translate(0,0)",
        );
        return (t) => {
          selection.attr("transform", i(t));
        };
      });
  }

I managed to get this function to work(most of it is from the docs). Can’t say I know 100% what is going on.
The main problem I have with this implementation is that the chart resets to its original position, however, before doing so, it disappears from the view and floats in from the side.I would like it to seamlessly transition back to its origin without disappearing.

Any help ? Would also appreciate some materials/explanation what tweens and interpolation means in this context.(Did not really understand it from the D3 docs.

React – How best to protect against stale data execution [duplicate]

I’m new to React (and coding in general, as a student).

But I had a (hopefully basic!!) query –

Say I have a React component, and it has the following ref:

const productionMode = useRef<boolean>(true);

lets say I have a function within this component which (simplistic example), says:

if (productionMode) {
    callToProdEnvironment();
}

But my concern is, say I have some async function which changes the value of productionMode to false right after it passes the if.

This would mean that I would be making a call to my production environment, which could potentially be very problematic.

Now. I could totally add a check to callToProdEnvironment which checks once again that productionMode is true, but this seems a little repetitive. Maybe it totally isn’t a bad thing though. Please let me know.

But this one really makes me scratch my head:

Take this example:

const aRef = useRef<MyCustomObject | undefined>(myObj);

if (aRef.current) {
    console.log(aRef.current.aProperty);
}

if (aRef.current) passes.. but due to an async operation that changes aRef’s value (to undefined), then accessing .aProperty on an undefined would not work! And I can’t exactly add extra protection there.

I saw a suggestion about doing something like:

const aRef = useRef<MyCustomObject | undefined>(myObj);

const current = aRef.current;

if (current) {
    console.log(current.aProperty);
}

But to my mind this is an even staler version of aRef.current…

I can’t really get my head around this, and I’m aware it’s probably a very fundamental concern about race-conditions/the issues with async executions. But I am new to all of this, like I say, and I just wanted a little bit of perspective! I’ve spent hours trying to make sense of it. I feel a bit stupid!

How to get my dropdown to populate correctly

Does anyone see what i’m doing wrong here..my first dropdown works just fine but when i put a breakpoint on the second dropdown controller it does not get hit?

This is my controller for the first and second dropdowns. the first controller works great and i put a breakpoint in the GetTemplateByDeptId method never gets hit?

[HttpGet]
public ActionResult HomeView()
{
    var departments = _uow.Repository<Dept>().GetAll().ToList();

    ViewBag.Departments = departments;
 

    return View();
}

[HttpGet]
public JsonResult GetTemplateByDeptId(int id)
{
    return Json(_uow.Repository<Template>().Get(x => x.TemplateID == id));
}

This is my View

@model Fab4Passdown.Data.Dept


<div class="text-center">
<h2>Department Dropdown</h2>
<div class="row form-group p-4 border m-2">
    <div class="col-2">
        Department
    </div>
    <div class="col-4">

        @Html.DropDownList("DeptID", new SelectList(ViewBag.Departments, "DeptID", 
  "Dept_Name"), "--Select--", new { @class = "form-control", @style = "height: 38px", @id = 
  "deptdropdown" })

    </div>
    <div class="col-4">
        Template
    </div>
    <div class="col-4">
        <select id="templatedropdown">
            <option>--Select--</option>
        </select>
    </div>
</div>
</div>

This is my JS

<script>

    $(document).ready(function () {
    getTemplateByDepartmentID;
})

$("#deptdropdown").change(function () {
    getTemplateByDepartmentID;
})

var getTemplateByDepartmentID = function() {
    $.ajax({
        url: "@Url.Action("GetTemplateByDeptId", "Home")",
        type: "Get",
        contentType: "application/json; charset=utf-8",
        data: {
            id: $('#deptdropdown').val(),
        },
        success: function (data) {
            $(data).each(
                function (index, item) {
                    $('#templatedropdown').append('<option value="' + item.DeptID + '">' + 
 item.Dept_Name + '</option>')
                }
            );
        }
})
}

Lazy Loading Images With Vanilla Javascript

I am working on a custom lazy load script with vanilla javascript that I would like to utilize throughout a site I am building. At several points during it’s construction I feel like I have had it successfully completed, but when I start trying to break my code for testing, it really breaks.
Currently I am at the point where I had a basic Vanilla Javascript working model doing what I needed it do Codepen Link

I began customizing it to search for a parent element by a data attribute (data-lazy-mask) then running a for each loop to gather all of those elements then located the img tag inside of it & then load it. Then when the user scrolls the page and the parent containing element is in view on the screen a class (data-lazy-shown) is added to the parent.
I had a working model doing all of these things but it wouldn’t work on any element not shown on the screen during the initial page load process. It does work on elements not shown on the page at time of load in my first version shown above, but once I customized it, it no longer did. This is my javascript code currently.

(() => {
const initLazyMask = () => {
    const isImgInViewport = (img) => {
        const rect = img.getBoundingClientRect();
        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
        );
    }

    const lazyMaskLoader = () => {
        const lazyParents = document.querySelectorAll('[data-lazy-mask]');
        let delay = 0;

        lazyParents.forEach((parent, i) => {
            const img = parent.querySelector('img');
            function add_mask(e, c) {
                m = document.createElement(e);
                m.classList.add(c);
                parent.appendChild(m) ;
            }
            
            if (isImgInViewport(img)) {
                if (img.getAttribute('data-src') !== null) {
                    img.setAttribute('src', img.getAttribute('data-src'));
                    img.removeAttribute('data-src');
                }
                if (img.getAttribute('data-srcset') !== null) {
                    img.setAttribute('srcset', img.getAttribute('data-srcset'));
                    img.removeAttribute('data-srcset');
                }
                
                setTimeout(() => {
                    parent.classList.add('data-lazy-shown');
                    img.classList.add('lazy-img-shown');
                    add_mask('div', 'cs-mask');
                }, delay);

                delay += 100; // Increment the delay for staggering
            }
        });

        // Remove event listeners if all images are loaded
        if (document.querySelectorAll('img[data-src]').length === 0 && document.querySelectorAll('img[data-srcset]').length === 0) {
            window.removeEventListener('DOMContentLoaded', lazyMaskLoader);
            window.removeEventListener('load', lazyMaskLoader);
            window.removeEventListener('resize', lazyMaskLoader);
            window.removeEventListener('scroll', lazyMaskLoader);
        }
    };

    // Add event listeners to images
    window.addEventListener('DOMContentLoaded', lazyMaskLoader);
    window.addEventListener('load', lazyMaskLoader);
    window.addEventListener('resize', lazyMaskLoader);
    window.addEventListener('scroll', lazyMaskLoader);
};

return initLazyMask();
})();

Here is the link to the current Codepen version I am trying to have work. Current Codepen Example

I need help.

Creating buttons that hide their respective paragraph

I’m a newbie to HTML, CSS and JavaScript and I’d like some help.

Let say I have 3 buttons and 3 paragraphs

<head>
<style>
.hidden {
display: none;
}
</style>
</head>

<body>
<button>A</button>
<button>B</button>
<button>C</button>
<br>
<p>A</p>
<p>B</p>
<p>C</p>
</body>

I want to create a js function that hides all paragraphs except the one with the same letter as the button, using a CSS rule that apply the class “hidden”.

I tried many things but all I can do is to toggle the class hidden to all paragraphs. Can someone explain me how I can do that please?

Thank you!

Here’s the file I was using to test anything I could think of to find a solution

<!doctype html>
<html>
<head>
 <title></title>
 <style>
 .hidden {
 display: none;
 }
 </style>
</head>
<body>
<div class="button">
 <button class="a" onClick="toggle(this,id)">a</button>
 <button class="b" onClick="toggle(this,id)">b</button>
 <button class="c" onClick="toggle(this,id)">c</button>
</div>
<div class="main">
<div class="a text">
 <p>a</p>
</div>
<div class="b text">
 <p>b</p>
</div>
<div class="c text">
 <p>c</p>
</div>
</div>
 <script>
function toggle(clicked,id) {
var el = document.querySelectorAll(".text");
var length = el.length;
for (let i=0; i<length; i++){
el[i].classList.add("hidden");
}
}
 </script>
</body>
</html>

To avoid switching from different files I wrote all the CSS and JS in the HTML file.

“Uncaught ReferenceError: msal is not defined”

index.html

  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
    <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.35.0/js/msal-browser.min.js" defer></script>
    <script src="./pages/index/index.js" defer type="module"></script>
    <title>Homepage</title>
  </head>

./pages/index/index.js

const myMSALObj = new msal.PublicClientApplication(msalConfig);

I’m using @msal/browser via CDN. Can anyone explain why msal is not defined and how to solve it?
More than 3 hours now … i still don’t know what’s going on

SvelteKit cookies.set(…) not setting persistent cookie

I am setting a Cookie using the SvelteKits’ integrated cookies.set inside a server action for OAuth reasons.

twitter: async ({ locals, cookies }) => {
        const provider = (await locals.pb.collection("users").listAuthMethods()).authProviders.find((p) => p.name === "twitter");

        cookies.set("provider", JSON.stringify(provider), {
            path: "/",
            httpOnly: true
        });
        console.log(cookies.get("provider"));

        await new Promise(resolve => setTimeout(resolve, 1000));

        const redirectUrl = provider?.authUrl + env.REDIRECT_URL + provider?.name;
        throw redirect(303, redirectUrl);
    },

The console.log(cookies.get("provider")); actually prints out the whole cookie, just as intended. However, when observing the browser console (hence the delay so I got more time to check) there is no cookie actually being set. After the redirect to Twitters’ OAuth service has taken place and I’m being redirected back to my callback url, there is no cookie available which I need to access the providers’ state (for CSRF reasons apparently).

For completeness, here is the code of the endpoint that’s being redirected to as my callback url:

export const GET = async ({ url, locals, cookies }) => {
    const provider = JSON.parse(cookies.get("provider") || "{}");
    console.log(provider)

    if (url.searchParams.get("error")) {
        throw new Error(url.searchParams.get("error"));
    }

    if (provider.state !== url.searchParams.get("state")) {
        throw new Error("State parameters don't match.");
    }

    .....
};

Since the cookie is not avaiable, the providers’ state is always !== the state returned by twitter through the callback url.

moment JS returning NaN on common date

I’m trying to get thisDate in milliseconds using moment.js and I’m getting NaN when I run the valueOf() method. I’m honestly clueless as to why this isn’t working considering my date is a pretty standard date.

const thisDate = '18/07/2023'
  
console.log(moment(thisDate).valueOf())
<script src="https://momentjs.com/downloads/moment.js"></script>

I’ve tried the same with multiple other dates and the result is random, some dates will output the value in milliseconds correctly others will just return NaN.

What am I doing wrong?

Why does click only work for every other li?

So im creating a simple to do list, when you type the todo and click submit, it adds an li to the ul. when you click on the text of the li it will put a linethrough the words. However when two or more lis are appended to the ul, only every other li will respect this line-through action. can someone point out why and solve this problem?

———————————The html—————————–

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel ='stylesheet' href = 'todo.css'>
    </head>
    <body>
        <h1>To do list!</h1>
        <form>
            <input type ='text'>
            <input type = 'submit' placeholder = 'Add to do'>
        </form>
    
        <ul>

        </ul>



        <script src = 'todo.js'></script>
    </body>
    </html>

———————————The javascript——————————-

    const ul = document.querySelector('ul')
    const submitTodo = document.querySelector('input[type="submit"]')
    const addTodo = document.querySelector('input[type="text"]')


    submitTodo.addEventListener('click', function(e){
        e.preventDefault()
        let newTodo = document.createElement('li')
        newTodo.innerText = addTodo.value 
    
        let newTodoRemove = document.createElement('button')
        newTodoRemove.innerText = 'Remove To-do'
    
    
    
        ul.appendChild(newTodo)
        newTodo.appendChild(newTodoRemove)

        const allLis = document.querySelectorAll('li')
        console.log(allLis)

        for(let li of allLis){
    
            li.addEventListener('click', function(e){
                if(e.target.style.textDecoration == 'line-through'){
                    e.target.style.textDecoration = 'none'
                }else{
                    e.target.style.textDecoration = 'line-through'
                }
            
            })
        }
    


    })

VisualStudios php code for website not connecting to database properly(Booking form)

So, I have been trying to connect a database to a booking form for a restaurant with some code i have generated with some AI tools and hard coded, i have no idea why there is a problem, i am new to coding. Any assistance would help. Apparently there is an error on line 311 of the html file.I have also gone through the naming conventions of my database and everything seems to be in line.

HTML for BOOKING

Booking - Your Restaurant Name
 



    <!-- Include the same header as your main page -->


<main>
    <section id="booking">
        <h2>Book Your Table</h2>
        <form id="booking-form" method="POST" action="Booking.php"> 
             <div>
                <label for="guests">Number of Guests:</label>
                <input type="number" id="guests" name="guests" min="1" max="8" required>
            </div>
            <div>
                <label for="karaoke">Karaoke:</label>
                <input type="checkbox" id="karaoke" name="karaoke" value="yes">
                <label for="karaoke">Yes</label>
            </div>
            <p id="karaoke-message" style="display: none;">Please select at least 4 guests if you wish to book the karaoke table.</p> 
            <div>
                <label for="date">Date:</label>
                <input type="date" id="date" name="date" min="2024-05-14" required>
            </div>
             <div>
                <label for="time">Time:</label>
                <select id="time" name="time">
                    <!-- Time options will be dynamically added here -->
                </select>
            </div>
            <div>
                <label for="table">Table:</label>
                <select id="table" name="table">
                    <option value="">Select a Table</option>  <!-- Default empty option -->
                    <option value="Table S1">Table S1</option>
                    <option value="Table S2">Table S2</option>
                    <option value="Table S3">Table S3</option>
                    <option value="Table S4">Table S4</option>
                    <option value="Table S5">Table S5</option>
                    <option value="Table M1">Table M1</option>
                    <option value="Table M2">Table M2</option>
                    <option value="Table M3">Table M3</option>
                    <option value="Table M4">Table M4</option>
                    <option value="Table M5">Table M5</option>
                    <option value="Table M6">Table M6</option>
                    <option value="Table L1">Table L1</option>
                    <option value="Table L2">Table L2</option>
                    <option value="Table L3">Table L3</option>
                    <option value="Table K1">Table K1</option>
                </select>
            </div>     
            <div class="Floorplan-image">
            <img src="" alt="Floorplan Image">
           </div>

            <div>
                <label for="name">Name:</label>
                <input type="text" id="name" name="name" required>
            </div>
            <div>
                <label for="surname">Surname:</label>
                <input type="text" id="surname" name="surname" required>
            </div>
            <div>
                <label for="phone">Telephone Number:</label>
                <input type="tel" id="phone" name="phone" required>
            </div>
            <div>
                <label for="email">Email Address:</label>
                <input type="email" id="email" name="email" required>
            </div>
            <button type="submit">Make Booking</button>
        </form>
    </section>
</main>

<footer>
    <!-- Include the same footer as your main page -->
</footer>

<script>
    const bookingForm = document.getElementById('booking-form');
    const guestsInput = document.getElementById('guests');
    const tableSelect = document.getElementById('table');
    const karaokeCheckbox = document.getElementById('karaoke');
    const karaokeMessage = document.getElementById('karaoke-message');
    const dateInput = document.getElementById('date');
    const timeSelect = document.getElementById('time');

    // Time slots for 1-hour intervals
    const oneHourTimeSlots = [
      "11:00",
      "12:00",
      "13:00",
      "14:00",
      "15:00",
      "16:00",
      "17:00",
      "18:00",
      "19:00",
      "20:00",
      
    ];

    // Time slots for 2-hour intervals
    const twoHourTimeSlots = [
      "11:00",
      "13:00",
      "15:00",
      "17:00",
      "19:00",
      `your text`
    ];

    function updateTableOptions() {
      const numGuests = parseInt(guestsInput.value);
      const tableOptions = tableSelect.options;
      const karaokeSelected = karaokeCheckbox.checked;

      // Reset options to include all tables initially
      for (let i = 0; i < tableOptions.length; i++) {
        tableOptions[i].disabled = false;
        tableOptions[i].style.display = 'block';
      }

      // Enable/disable tables based on guest count
      if (numGuests >= 1 && numGuests <= 2) {
        // Allow S1-S5
        for (let i = 0; i < tableOptions.length; i++) {
          if (
            !tableOptions[i].value.startsWith('Table S') ||
            tableOptions[i].value === 'Table S6' ||
            tableOptions[i].value === 'Table S7' ||
            tableOptions[i].value === 'Table S8'
          ) {
            tableOptions[i].disabled = true;
            tableOptions[i].style.display = 'none';
          }
        }
      } else if (numGuests >= 3 && numGuests <= 4) {
        // Allow M1-M4
        for (let i = 0; i < tableOptions.length; i++) {
          if (
            !tableOptions[i].value.startsWith('Table M') ||
            tableOptions[i].value === 'Table M5' ||
            tableOptions[i].value === 'Table M6'
          ) {
            tableOptions[i].disabled = true;
            tableOptions[i].style.display = 'none';
          }
        }
      } else if (numGuests >= 5 && numGuests <= 6) {
        // Allow M5-M6
        for (let i = 0; i < tableOptions.length; i++) {
          if (
            !tableOptions[i].value.startsWith('Table M') ||
            tableOptions[i].value === 'Table M1' ||
            tableOptions[i].value === 'Table M2' ||
            tableOptions[i].value === 'Table M3' ||
            tableOptions[i].value === 'Table M4'
          ) {
            tableOptions[i].disabled = true;
            tableOptions[i].style.display = 'none';
          }
        }
      } else if (numGuests >= 7 && numGuests <= 8) {
        // Allow L1-L3
        for (let i = 0; i < tableOptions.length; i++) {
          if (
            !tableOptions[i].value.startsWith('Table L') ||
            tableOptions[i].value === 'Table L4' ||
            tableOptions[i].value === 'Table L5' ||
            tableOptions[i].value === 'Table L6'
          ) {
            tableOptions[i].disabled = true;
            tableOptions[i].style.display = 'none';
          }
        }
      }

      // If karaoke is selected AND at least 4 guests, only allow Table K1
      if (karaokeSelected && numGuests >= 4) {
        for (let i = 0; i < tableOptions.length; i++) {
          if (tableOptions[i].value !== 'Table K1') {
            tableOptions[i].disabled = true;
            tableOptions[i].style.display = 'none';
          }
        }
        // Make sure Table K1 is visible and enabled
        tableSelect.querySelector('option[value="Table K1"]').style.display = 'block';
        tableSelect.querySelector('option[value="Table K1"]').disabled = false;
        karaokeMessage.style.display = 'none'; // Hide the message
      } else if (karaokeSelected && numGuests < 4) {
        karaokeMessage.style.display = 'block'; // Show the message
      }
    }

    // Add event listener to the guests input
    guestsInput.addEventListener('change', updateTableOptions);

    // Add event listener to the karaoke checkbox
    karaokeCheckbox.addEventListener('change', updateTableOptions);

    // Call the updateTableOptions function initially
    updateTableOptions();

    // Date Validation
    function validateDate() {
      const today = new Date();
      const tomorrow = new Date(today);
      tomorrow.setDate(today.getDate() + 1); // Get tomorrow's date

      const tomorrowFormatted = tomorrow.toISOString().split('T')[0]; // Format tomorrow's date

      dateInput.min = tomorrowFormatted; // Set minimum date to tomorrow

      // Prevent selecting Tuesdays
      const date = new Date(dateInput.value);
      const day = date.getDay();
      if (day === 2) {
        // Tuesday is 2 in getDay()
        dateInput.value = '';
        alert('Bookings are not available on Tuesdays.');
      }
    }

    // Call validateDate initially and whenever the date input changes
    validateDate();
    dateInput.addEventListener('change', validateDate);

    // Update the time options based on the number of guests
    function updateTimeOptions() {
      const numGuests = parseInt(guestsInput.value);
      const timeOptions = timeSelect.options;

      // Clear existing options
      timeOptions.length = 0;

      // Generate new options based on guest count
      if (numGuests <= 3) {
        oneHourTimeSlots.forEach(time => {
          const option = document.createElement('option');
          option.value = time;
          option.text = time;
          timeOptions.add(option);
        });
      } else {
        twoHourTimeSlots.forEach(time => {
          const option = document.createElement('option');
          option.value = time;
          option.text = time;
          timeOptions.add(option);
        });
      }
    }

    // Call updateTimeOptions initially and when the number of guests changes
    updateTimeOptions(); 
    guestsInput.addEventListener('change', updateTimeOptions);

    bookingForm.addEventListener('submit', async (event) => {
      event.preventDefault();

      // Get values from the form
      const table = document.getElementById('table').value;
      const time = document.getElementById('time').value;
      const guests = document.getElementById('guests').value;
      const date = document.getElementById('date').value;
      const karaoke = document.getElementById('karaoke').checked ? 'yes' : 'no'; // Get karaoke value
      const name = document.getElementById('name').value;
      const surname = document.getElementById('surname').value;
      const phone = document.getElementById('phone').value;
      const email = document.getElementById('email').value;

      
      fetch('Booking.php', {
method: 'POST',
headers: {
  'Content-Type': 'application/x-www-form-urlencoded',
},
body: `table=${table}&time=${time}&guests=${guests}&date=${date}&karaoke=${karaoke}&name=${name}&surname=${surname}&phone=${phone}&email=${email}`,}).then((response) => {// Handle server responseif (response.ok) {// If the response is OK (status code 200), parse as JSONreturn response.json();} else {}
})
.then(data => {
  if (typeof data === 'object' && data.bookingId) { 
    // If we successfully parsed JSON data with a bookingId
    displayConfirmationModal(data.bookingId, email); 
  } else {
    // Handle errors
    alert(data); // Display the error message from the server 
  }
})
.catch((error) => {
  console.error('Error:', error);
  alert('An error occurred. Please try again later.');
});});

    // Function to display a modal for confirmation
    function displayConfirmationModal(bookingId, email) {
        const modal = document.createElement('div');
        modal.id = 'confirmationModal';
        modal.classList.add('modal'); // Add a class for modal styling
        modal.innerHTML = `
            <div class="modal-content">
                <span class="close" onclick="closeModal()">&times;</span>
                <h2>Booking Successful!</h2>
                <p>Your Booking ID: ${bookingId}</p>
                <p>An email confirmation will be sent to: ${email}</p>
                <button onclick="window.location.href='index.html'">Continue</button>
            </div>
        `;
        document.body.appendChild(modal);
    }

    // Function to close the modal
    function closeModal() {
        const modal = document.getElementById('confirmationModal');
        if (modal) {
            document.body.removeChild(modal);
        }
    }

   
    document.addEventListener('click', function(event) {
        if (event.target.classList.contains('close')) {
            closeModal();
        }
    });
</script>
<style>
    /* Modal styles */
    .modal {
        display: none; /* Hidden by default */
        position: fixed; /* Stay in place */
        z-index: 1; /* Sit on top */
        left: 0;
        top: 0;
        width: 100%; /* Full width */
        height: 100%; /* Full height */
        overflow: auto; /* Enable scroll if needed */
        background-color: rgb(0,0,0); /* Black with opacity */
        background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
        padding-top: 60px;
    }

    .modal-content {
        background-color: #fefefe;
        margin: 5% auto; /* 5% from the top and centered */
        padding: 20px;
        border: 1px solid #888;
        width: 80%; /* Could be more or less, depending on your design */
    }

    .close {
        color: #aaa;
        float: right; /* Add this line to float the close button to the right */
        font-size: 28px;
        font-weight: bold;
        cursor: pointer;
    }

    .close:hover,
    .close:focus {
        color: black;
    }
</style>

PHP FOR BOOKING

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Database connection details (from login.php)
$host = "localhost";
$dbname = "movedb"; 
$username = "root";
$password = "";

try {
    $dsn = "mysql:host=$host;dbname=$dbname";
    $pdo = new PDO($dsn, $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    // Return a JSON error if the database connection fails
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Database connection failed.']);
    exit;
}

// Check if the booking form is submitted
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // Get booking details from the form
    $bookingDate = $_POST['date'];
    $bookingTime = $_POST['time'];
    $tableId = $_POST['table'];
    $custFname = $_POST['name'];
    $custLname = $_POST['surname'];
    $custEmail = $_POST['email'];
    $custCell = $_POST['phone'];
    $noOfGuests = $_POST['guests']; 

    // Validate inputs (add more validation as needed)
    if (empty($bookingDate) || empty($bookingTime) || empty($tableId) || empty($custFname) || empty($custLname) || empty($custEmail) || empty($custCell) || empty($noOfGuests)) {
        // Return a JSON error response if any required field is missing
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Please fill in all required fields.']);
        exit;
    }

    // Retrieve table details
    $sqlTable = "SELECT * FROM Table WHERE TableID = :table";
    $stmtTable = $pdo->prepare($sqlTable);
    $stmtTable->bindParam(':tableId', $tableId);
    $stmtTable->execute();
    $tableDetails = $stmtTable->fetch(PDO::FETCH_ASSOC);

    // Check if table is active
    if ($tableDetails['TableStatus'] !== 'Active') {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Table is not active.']);
        exit;
    }

    // Insert the customer data
    $sqlCustomer = "INSERT INTO Customer (CustFName, CustLName, CustEmail, CustCell) 
                    VALUES (:custFname, :custLname, :custEmail, :custCell)";
    $stmtCustomer = $pdo->prepare($sqlCustomer);
    $stmtCustomer->bindParam(':custFname', $custFname);
    $stmtCustomer->bindParam(':custLname', $custLname);
    $stmtCustomer->bindParam(':custEmail', $custEmail);
    $stmtCustomer->bindParam(':custCell', $custCell);

    try {
        $stmtCustomer->execute();
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Error inserting customer data: ' . $e->getMessage()]);
        exit;
    }

    // Get the newly created customer ID
    $newCustomerId = $pdo->lastInsertId();

    // Insert the booking data
    $sqlBooking = "INSERT INTO Booking (BookingDate, BookingTime, BookingStatus, Karaoke, NoOfGuests, CustType, CustCell, TableID, ReceptionistID, CustomerID)
                   VALUES (:date, :time, :bookingStatus, :karaoke, :guests, :customerType, :phone, :table, :receptionistId, :customerId)";
    $stmtBooking = $pdo->prepare($sqlBooking);
    $stmtBooking->bindParam(':date', $bookingDate);
    $stmtBooking->bindParam(':time', $bookingTime);
    $stmtBooking->bindParam(':bookingStatus', 'Active');
    $stmtBooking->bindParam(':karaoke', isset($_POST['karaoke']) ? 1 : 0); 
    $stmtBooking->bindParam(':guests', $noOfGuests);
    $stmtBooking->bindParam(':customerType', 'Online');
    $stmtBooking->bindParam(':phone', $custCell);
    $stmtBooking->bindParam(':table', $tableId);
    // Get a receptionist ID (you'll need to implement logic to get this from your system)
    $receptionistId = 1; // Replace with actual receptionist ID logic
    $stmtBooking->bindParam(':receptionistId', $receptionistId);
    $stmtBooking->bindParam(':customerId', $newCustomerId); // Bind the new customer ID

    try {
        $stmtBooking->execute();
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Error inserting booking data: ' . $e->getMessage()]);
        exit;
    }

    // Get the new booking ID 
    $newBookingId = $pdo->lastInsertId();

    // Send email confirmation (replace with your actual email logic)
    $to = $custEmail;
    $subject = "Your Booking Confirmation";
    $message = "Your booking (ID: " . $newBookingId . ") has been confirmed. nn" .
               "Booking Date: " . $bookingDate . "n" .
               "Booking Time: " . $bookingTime . "n" .
               "Table: " . $tableDetails['TableNo'] . "n" .
               "Number of Guests: " . $noOfGuests . "nn" .
               "Thank you for booking with us!";
    $headers = 'From: [email protected]' . "rn"; 
    mail($to, $subject, $message, $headers);

    // Return JSON response with the booking ID
    header('Content-Type: application/json');
    echo json_encode(['bookingId' => $newBookingId]);
    exit; // Stop further execution

}
?>

I tried changing some of the JSON issues but they just reappear for line 311
booking.html:311 Error:
SyntaxError: Unexpected token ‘<‘, “
“… is not valid JSON
This is the apparent error, but i am sure there might be more wrong.
This is all i really know, help would be awesome.

Datepicker issue after upgrade

If datepicker on field, stopped working & in console log showing error :Refused to execute script from ‘http://localhost:52025/locA.locB.Reports.Web/Reports1/Reports1/~/Scripts/Reports2Refund.js’ because its MIME type (‘text/html’) is not executable, and strict MIME type checking is enabled.In this case how to work on the issue?

It showed error & datepicker is not working

How to randomize the order of a large array in Javascript (efficiently) [duplicate]

In a banner I am showing an image and some data on a country. The banner then auto-rotates to show info of all countries in the world. I want to randomize the order of the countries, so the website looks different each time you visit the website.
I have now randomized the array with all the country-data in php, but problem of that is that I have a page-cache, so users still see the same until the cache gets flushed.
So, therefor I want to do the randomization in javascript.

What I have:
var COUNTRY_DATA = [];
COUNTRY_DATA[“Austria”] = [“https://www.takeyourbackpack.com/CONTENT/countries/Austria/….”, “Australia”, “Canberra, ….];
COUNTRY_DATA[“Brazil” = [” https://www.takeyourbackpack.com/CONTENT/countries/Brazil/….”, “South America”, ….];
etc (184 countries).

How can I reshuffle this multi-dimensional array in an efficient way. I’d rather not reshuffle all the array values around, as that may not be most efficient. Thinking about making a new array with only the indices, which are shuffled so I can use COUNTRY_DATA[shuffled_index[1]] and then COUNTRY_DATA[shuffled_index[2]], but struggling how to generate this shuffled_index array.

To get an idea of what I want to achieve, have a look at takeyourbackpack.com.

OpenAI API key with “proj-” prefix not working when read from .env file

I’m working on a Next.js/React/TypeScript project that integrates with the OpenAI API. I’ve encountered an issue with the new Project-based API keys feature.
Previously, I successfully used this setup:

typescriptCopyconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, });

My .env file contained:

OPENAI_API_KEY=sk-xxxxx

However, with the new Project-based API keys (format: sk-proj-xxxxx), this setup no longer works. I’m receiving an invalid_api_key error.

I’ve noticed that process.env.OPENAI_API_KEY seems to strip the proj- part from the API key when reading it from the .env file.

Oddly enough, using the key as a plain string works fine:
const openai = new OpenAI({ apiKey: "sk-proj-xxxxx", });

I’ve scoured the OpenAI documentation and googled the hell out of it but haven’t found any solutions. The closest relevant information I found was in the OpenAI Authentication documentation.

Has anyone encountered this problem? Any insights or solutions would be greatly appreciated! 🙂

My route.ts:

import { auth } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";
import OpenAI from "openai";

const openai = new OpenAI({
  apiKey: "process.env.OPENAI_API_KEY", //this seems to be the issue
});

const instructionMessage = {
  role: "system",
  content: `blah blah instructions`,
};

async function POST(req: Request) {
  try {
    const { userId } = auth();
    const body = await req.json();
    const { messages } = body;
    const lastMessage = messages[messages.length - 1];

    if (!userId) {
      return new NextResponse("Unauthorized", { status: 401 });
    }

    if (!openai.apiKey) {
      return new NextResponse("OpenAi Api Key not configured"), { status: 500 };
    }

    if (!messages || messages.length === 0) {
      return new NextResponse("Input Required", { status: 400 });
    }

    const response = await openai.chat.completions.create({
      model: "gpt-4o-mini",
      messages: [instructionMessage, lastMessage],
    });

    return NextResponse.json(response.choices[0].message);
  } catch (error) {
    console.log("[CODE_ERROR]", error);
    return new NextResponse("Internal error", { status: 500 });
  }
}

export { POST };

Returning Object Values in Javascript

Maybe I’m overthinking this. Will probably end up getting the answer if I just take a break from it for a second but I can’t get my head around it at the moment. Doing Javascript basics, and the problem question relates to amending objects in a function.

Will add the code below.
Sorry if I miss any details out – this is my first time seeking support on this community forum!

The question essentially presents you with object ‘Kitchen’ but with a few ‘issues’ that need sorting to make it read better. I’ve ‘passed’ 6 but failing the 7th requirement.

Requirements are:

  1. is a function – DONE
  2. should return a kitchen with the correct keys (hasFridge, favouriteAppliance, food, petName, totalShelves) – DONE
  3. should change each string to lower case in the object item – DONE
  4. should delete the hoover property, if present in the object – DONE
  5. should return the correct total number of shelves (5) – DONE
  6. should return the correct total number of shelves if only one shelf key is present

✕ AssertionError: expected 5 to equal 3

  1. should remove other shelf keys – DONE

The object:

let kitchen = {
  hasFridge: true, 
  favouriteAppliance: "KeTtlE",
  drinks: "lemoNAdE",
  food: "eGgS",
  shelvesInCupboards: 3,
  shelvesNotInCupboards: 2,
  petName: "RhuBarB",
  hoover: "DysOn" 
};

My code:

function sortTheKitchen(kitchen) {
    console.log(kitchen);
    delete kitchen.shelvesNotInCupboards
      const kitchenItems = {
        hasFridge: true,
        favouriteAppliance: 'kettle',
        food: 'eggs',
        petName: 'rhubarb',
        drinks: 'lemonade',
        shelvesInCupboards: 3
      };
      for (const key in kitchenItems) {
          for (const key1 in kitchen) {
            if (key === key1) {
              kitchen[key1] = kitchenItems[key]
            }
            if (key1 === 'hoover') {
              delete kitchen[key1]
            }
          }
      }
    delete kitchen.shelvesInCupboards
    kitchen.totalShelves = 5 
    return kitchen;
}