why reset button X not display above selected item value on jQuery after add default option with Arabic and English? [duplicate]

I am currently working with jQuery and have encountered an issue regarding the reset functionality for a dropdown list. Specifically, after adding default options in both Arabic and English, the reset button does not display correctly.

When a value is selected, I want to show a reset button (denoted as “X”). However, if no option is selected, the dropdown should display either “Select port” or “اختر منفذ” without showing the reset button.

Before changing the language to Arabic or English, the reset button appears as expected. Here is the relevant code snippet:

row += "<select id='ddl_Port" + Result.d.P_DISPATCH_DATA[i].DISPATCH_RECID + "' class='form-control chosen-select chosen-rtl' tabindex='1'><option value=''></option>";
var countriesPorts = Result.d.P_PORTS.filter(d => d.COUNTRY_ID == Result.d.P_DISPATCH_DATA[i].PICKUP_COUNTRY_ID);

if (countriesPorts != null) {
  if (countriesPorts.length > 0) {
    for (var j in countriesPorts) {
      row += " <option value='" + countriesPorts[j].PORT_ID + "'>" + countriesPorts[j].PORT_NAME + "</option> ";
    }
    row += " </select></td>";
  }
}

After switching to Arabic or English, the reset button (“X”) does not appear. The code for the dropdown with the default option is as follows:

var defaultOption = MYLang.ReturnLang() == "ar-KW" ? "اختر منفذ" : "select port";

row += "<select id='ddl_Port" + Result.d.P_DISPATCH_DATA[i].DISPATCH_RECID + "' class='form-control chosen-select chosen-rtl' tabindex='1' >" +
  "<option value=''>" + defaultOption + "</option>";

var countriesPorts = Result.d.P_PORTS.filter(d => d.COUNTRY_ID == Result.d.P_DISPATCH_DATA[i].PICKUP_COUNTRY_ID);

if (countriesPorts != null && countriesPorts.length > 0) {
  for (var j in countriesPorts) {
    row += "<option value='" + countriesPorts[j].PORT_ID + "'>" + countriesPorts[j].PORT_NAME + "</option>";
  }
}

Additionally, I would like an image to illustrate the reset button in red on the second row.
show clear button

How to Integrate Draw.io in Custom Web Application: Retrieving XML Data from Canvas via Iframe?

Description

I am working on integrating the Draw.io editor into my custom web application, which is based on html css js. As a data modeler, I know little javascript. I have successfully embedded Draw.io in an iframe and can interact with it to some extent. However, I need help retrieving the designed ERD diagram’s XML data from the canvas and passing it back to my application for further processing and generate SQL DDL script from ERD model. But I am unable to do that and here is my current situation:

Current Setup

  1. Hosting Environment:
    I have deployed the Draw.io editor on my own server using Tomcat, with NGINX as a proxy. The application is accessible via this URL:
    https://app.flingex.com/draw/

  2. Integration with Web App:
    I have embedded the Draw.io editor in an iframe on one of my Web Application using the following code:

    <iframe 
        id="drawio_iframe" 
        src="https://app.flingex.com/draw/" 
        style="width: 100%; height: 500px;">
    </iframe>
    
  3. Objective:
    I want to retrieve the clean XML data of the diagram designed in the Draw.io editor via the iframe using postMessage. The XML data will then be stored in the database for further manipulation and generate SQL DDL script from ERD model .

What I’ve Tried

  1. Sending postMessage to the Iframe
    I used the following JavaScript to send a message to the iframe:

    const iframe = document.getElementById('drawio_iframe');
    iframe.contentWindow.postMessage(
        { action: 'export', format: 'xml' },
        'https://app.flingex.com'
    );
    
  2. Listening for Messages in the Iframe
    I opened the iframe directly in a new tab (https://app.flingex.com/draw/) and added this listener to debug:

    window.addEventListener('message', function(event) {
        console.log('Message received:', event);
    });
    
  3. Results:

    • The postMessage seems to send successfully, but I don’t see any response or XML data being returned to my application.
    • No messages are logged in the iframe console.

Expected Behavior

  • When I send { action: 'export', format: 'xml' } to the iframe, I expect the iframe to respond with the exported XML data from the Draw.io canvas.

Questions

  1. Is there any additional configuration or API setup required to enable Draw.io to handle postMessage events for exporting XML data?
  2. Are there any permissions, headers, or origin configurations I need to adjust on the server or in the iframe for this to work?
  3. Can someone provide a working example or guide for achieving this integration?

Additional Information

  • Draw.io deployment: Self-hosted (Tomcat + NGINX)
  • Application: APEX (html, css and JavaScript based integration)
  • I am not using embed=1 in the iframe URL, as I want to keep the design tools visible.
  • The URL https://app.flingex.com/draw/ works fine when accessed directly.

What I Need

I’m looking for guidance on how to properly implement the following:

  1. Send a message from my web app to the iframe to trigger the XML export.
  2. Retrieve the exported XML data in the parent application (via postMessage or another method).
  3. Any specific Draw.io settings, scripts, or code snippets needed to enable this functionality.

Thank You!

I appreciate any help or suggestions to solve this issue. Let me know if you need more details or access to any specific code snippets.


**Tags **

  • draw.io
  • iframe
  • postmessage
  • javascript
  • html

Feel free to customize this further to suit your style or include additional details. Let me know if you need further adjustments!

Error generated while creating a NextJS project

Good morning, I am a student in software programming, and this is my last session. We are taking a course on web programming with Next.js. During the installation, I encountered errors, which are shown in the screenshots. The errors are related to missing dependencies and several other issues. The error messages are too long.
This are my versions:

PS C:…DesktopSeesion 4WebServernextjs>
PS C:…DesktopSeesion 4WebServernextjs> npm -v
11.0.0
PS C:…DesktopSeesion 4WebServernextjs> nvm -v
1.2.2
PS C:…DesktopSeesion 4WebServernextjs> node -v
v22.13.0
PS C:…DesktopSeesion 4WebServernextjs> nvm list
22.13.0 (Currently using 64-bit executable)
PS C:UsersabotsDesktopSeesion 4WebServernextjs>

I encountered these warnings and errors during installation:

(node:5052) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
npm WARN peerDependencies The peer dependency typescript@>=3.3.1 included from eslint-config-next will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm WARN peerDependencies The peer dependency eslint-plugin-import-x@* included from eslint-import-resolver-typescript will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm WARN peerDependencies The peer dependency typescript@>=4.8.4 <5.8.0 included from @typescript-eslint/parser will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm WARN peerDependencies The peer dependency ts-node@>=9.0.0 included from postcss-load-config will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.

Please what is the issue?

I tried everything possible, i changed versions, reinstall everything, i spent all my night on it.

Expo-Auth-Session never fullfills promise with Pixelfed login

I am trying to log into a Pixelfed instance, using the expo-auth-session package. I get as far as the pop-up with the code showing after I authorized my app in the pop-up. However, the promise never gets fulfilled. If I close the window, I get to the Dismiss part of the promise, but that was it.

import React, { useState, useEffect } from 'react';
import { View, ActivityIndicator, Platform, Button } from 'react-native';
import { WebView } from 'react-native-webview';
import * as WebBrowser from 'expo-web-browser';
import * as AuthSession from 'expo-auth-session';
import * as Linking from "expo-linking"

export default function OAuthLoginScreen({ route, navigation }) {
  const [syncRunning, setSyncRunning] = useState(false);
  
  const { 
    serverUrl, 
    authUrl, 
    tokenUrl, 
    tmpRedirectUri, 
    clientId, 
    scopes, 
    handleAuth 
  } = route.params;

  const discovery = {
    authorizationEndpoint: authUrl,
    tokenEndpoint: tokenUrl
  };

  if(tmpRedirectUri === undefined || tmpRedirectUri === null){
    redirectUri = AuthSession.makeRedirectUri({
      scheme: 'myapp',
    });
  } else {
    redirectUri = tmpRedirectUri;
  }

  const options = {
    clientId: clientId,
    redirectUri: redirectUri,
    scopes: scopes
  };

  const [request, response, promptAsync] = AuthSession.useAuthRequest(
    options,
    discovery
  );

  if(request && !syncRunning){
    setSyncRunning(true)
    promptAsync()
  }

  useEffect(() => {
    if (response?.type === 'success') {
      const { code } = response.params;
      handleAuth(serverUrl, result.url, navigation);
    }
  }, [response]);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <ActivityIndicator size="large" color="#0000ff" />
    </View>
  );

}

I had the same issue, when I tried to implement it with the expo-web-browser package as well. One issue I believe is that Pixelfed requires urn:ietf:wg:oauth:2.0:oob as value for the redirect uri. Otherwise an Invalid Client error will be shown. Hence, the dance with the tmpRedirectUri as Instagram works with the right uri.

Is it true that a HTTPS development server is needed? If true, how can this be achieved using the metro bundler? The --https flag does not open a https session. I don’t want to go back to webpack, as it seems to be deprecated. I also tried with ǹgrok, which allows for https, but this did not work either.

When the same code is used with the Instagram oauth login flow, it works just as it should.

__dirname and path.resolve not working right in my webpack

Alright, so I’ve never used webpack, but I wanted to bundle multiple js files into 1 singular file for the lower memory size of the finalized project and to simplify the file structure. But when I use __dirname and path.resolve func the resulting bundled file contains MY file url, so for example C:/users/{MYUSERNAME}/etc, even though its supposed to be relative to the pc thats running the file. And of course that doesn’t work on someone else’s system. Thanks in advance!

Honestly, I’ve tried to spam the chatgpt with prompts on how to fix that. But to no avail!

How can you store the contents of a TextBox even after being updated?

So I am quite new to Javascript, and I am trying to create a Cesium map that displays aircraft flying overhead (this is a simplification, but all that’s needed to answer). Everything is working so far, but I would like to place a textbox inside the description that appears when you click on an entity. While this does work, the textbox does not save the value after new information is fetched from the server (about once per second). Also, the cursor is always moved away from the textbox. Here’s a snippet of my code:

var position = Cesium.Cartesian3.fromDegrees(plane.lon, plane.lat, plane.alt_geom);
                    var heading = Cesium.Math.toRadians(plane.track - 90);
                    var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, 0.0, 0.0));

                    var description = `
                        <table>
                            <tr><th>Flight</th><td>${plane.flight}</td></tr>
                            <tr><th>Type</th><td><input type="text" id="${plane.hex}"></td></tr>
                            <tr><th>Altitude</th><td>${plane.alt_geom} ft</td></tr>
                            <tr><th>Speed</th><td>${plane.gs} knots</td></tr>
                            <tr><th>Track</th><td>${plane.track}&deg;</td></tr>
                            <tr><th>Squawk</th><td>${plane.squawk}</td></tr>
                            <tr><th>ICAO</th><td>${plane.hex}</td></tr>
                            <tr><th>Position age</th><td>${plane.seen_pos}</td></tr>
                        </table>
                    `;

This is run about once a second to update the speed, altitude, etc.

Is there a way to disconnect the text box from the rest of the description? I have also tried saving the information and putting it in my text box, but it did not work at all.

Thanks! If you would like to see my whole code, I can send a link.

How to wait all Promise are resolve in a loop?

async function getSomething(parameter) {
  ...
}

function myFunction() {
  const params = [param1, param2, ...]
  const results = []
  let i = 0

  params.forEach((param) => {
    getSomething(param).then((result) => results[i++] = result)
  })
  
  console.log(results)
}

results is empty because the calls in the for are asynchronous and not yet executed.

How can I wait that all Promise in the for loop are resolved ?

Encrypting Passwords in Next.js Without Breaking Search Functionality

Here’s a brief overview of my implementation:

  1. I have a POST API endpoint that receives user data, including a password.
  2. I want to encrypt the password using AES-256-CBC and store it in MongoDB.
  3. I also have a GET API endpoint that retrieves user data, and I want to decrypt the stored passwords before sending the response to the client
  4. Additionally, there is a search bar in my application, but I am facing issues with encrypting and decrypting passwords because it interferes with the search functionality. I previously tried using bcrypt and crypto, but these approaches made it impossible to search for users by their username or other criteria effectively.

I have implemented the following code:

import { NextApiRequest, NextApiResponse } from "next";

impor

import { NextApiRequest, NextApiResponse } from "next";
import connectMongo from "../../lib/mongoose";
import { form } from "../../models/Form";
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "GET") {
    try {
      await connectMongo();
      const forms = await form.find(
        {},
        { name: 1, username: 1, password: 1, notes: 1, url: 1, _id: 0 }
      );
      res.status(200).json({ success: true, data: forms });
    } catch (error) {
      console.error(error);
      res.status(500).json({ success: false, error: "Failed to fetch data" });
    }
  } else {
    res.status(405).json({ message: "Method not allowed" });
  }
}
import { NextApiRequest, NextApiResponse } from "next";
import connectMongo from "../../lib/mongoose";
import { form } from "../../models/Form";
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "POST") {
    // Handle POST request to save data
    const { name, username, password, notes, url } = req.body;

    try {
      await connectMongo();
      const newForm = await form.create({
        name,
        username,
        password,
        notes,
        url,
      });
      res.status(201).json({ success: true, data: newForm });
    } catch (error) {
      console.error(error);
      res.status(500).json({ success: false, error: "Failed to save data" });
    }
  }
}

and this is the main page that contains the passwords :

"use client";
import React, { useState, useEffect } from "react";
import Image from "next/image";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";

interface FormData {
  name: string;
  username: string;
  password: string;
  notes: string;
  url: string;
}

const Passwords = ({ search }: { search: string }) => {
  const [selectedItem, setSelectedItem] = useState<FormData | null>(null);
  const [forms, setForms] = useState<FormData[]>([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`/api/get`);
        const result = await response.json();

        if (result.success) {
          const filteredData = search
            ? result.data.filter(
                (item: { username: string }) => item.username === search
              )
            : result.data;
          setForms(filteredData);
        } else {
          console.error("Failed to fetch data:", result.error);
        }
      } catch (error) {
        console.error("Error fetching data:", error);
      }
    };

    fetchData();
  }, [search]);

  const handleItemClick = (item: FormData) => {
    setSelectedItem(item); // Set clicked item's data
  };

  const handleBack = () => {
    setSelectedItem(null); // Reset selectedItem to null to show the list
  };

  return (
    <section className="main-wrapper">
      {selectedItem ? (
        // Render selected item's details
        <div className="item-info">
          <form>
            <label htmlFor="name">Name</label>
            <Input
              placeholder="Name"
              id="name"
              name="name"
              value={selectedItem.name}
              readOnly
            />

            <label htmlFor="username">Username</label>
            <Input
              placeholder="Username"
              id="username"
              name="username"
              value={selectedItem.username}
              readOnly
            />

            <label htmlFor="password">Password</label>
            <Input
              placeholder="Password"
              id="password"
              name="password"
              value={selectedItem.password}
              readOnly
            />

            <label htmlFor="notes">Notes</label>
            <Textarea
              placeholder="Notes"
              id="notes"
              name="notes"
              value={selectedItem.notes}
              readOnly
            />

            <label htmlFor="url">URL</label>
            <Input
              placeholder="URL"
              id="url"
              name="url"
              value={selectedItem.url}
              readOnly
            />
            <div className="flex gap-2">
              <Button type="submit">
                Edit
                <Image
                  src={"/magicpen.svg"}
                  width={20}
                  height={20}
                  alt="icon"
                />
              </Button>
              <Button onClick={handleBack}>Back</Button>
            </div>
          </form>
        </div>
      ) : (
        // Render the list of items
        <div className="list">
          {forms.map((form, index) => (
            <div key={index} className="preview">
              <div className="name">
                <Image
                  src={"/passport.svg"}
                  alt="icon"
                  width={32}
                  height={32}
                />
                <div className="data">
                  <p className="title">{form.name}</p>
                  <p className="email">{form.username}</p>
                </div>
              </div>
              <Button
                className="edit"
                onClick={() => {
                  handleItemClick(form);
                }}>
                <Image
                  src={"/edit.svg"}
                  alt="edit icon"
                  width={24}
                  height={24}
                />
              </Button>
            </div>
          ))}
        </div>
      )}
    </section>
  );
};

export default Passwords;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>

How to use a single QR code on T-shirts to redirect to unique user pages?

I’m designing T-shirts with a QR code on the back. The goal is that when someone scans the QR code, it redirects them to a unique web page corresponding to the individual wearing the T-shirt (e.g., a personal profile or portfolio). However, I want to avoid printing a different QR code for each T-shirt, as it would make production complex.

Instead, I want to use the same QR code on all the T-shirts, but the system should dynamically redirect the scanner to the unique page for each person.

How can I implement this?

Is there a way to change the tab title in private mode?

I want to make a custom landing page for when I open a new private tab.
Manage to do it in normal tab with a custom extension:

{
  "manifest_version": 3,
  "name": "Black Background New Tab",
  "version": "1.0",
  "description": "Changes the background color of new tabs to black.",
  "permissions": ["tabs", "activeTab", "storage"],
  "chrome_url_overrides": {
    "newtab": "newtab.html"
  },
  "host_permissions": ["<all_urls>"],
  "incognito": "spanning"
}

newtab.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>────────────────────────────────────────────</title>
  <style>
    <-- some style here
  </style>
</head>
<body>
  <-- some code here
</body>
</html>

But I cannot make it work in private windows/tabs.

how to I make a radio button which switches background color in bootstrap and js?

enter image description here

I’d like to make a idea note like bulletin board to use bootstrap and Javascript. So I make a input-group include send button, enter or click message add like a stack. But I don’t know how to use when onclick two function which is setting background-color and send message at the same time. In radio button, when I check the button, Can I change the color code in bootstrap?

The radio button which switch card-header’s background color Pink or Gray can change card-header’s color when I checked color and enter the message. Depending on the checked radio button, the color of the header part where the message was pressed must be changed.

function addMessage() {
  const input = document.getElementById('messageInput');
  const messageText = input.value.trim();
  if (messageText !== '') {
    const messageHTML = `
<div class="card mb-3 shadow-sm">
  <div class="card-header bg-primary">
    <div class="text-muted">
      Posted by ${getCurrentUser()} at ${formatDateTime()}
    </div>
  </div>
  <div class="card-body">
    <div class="d-flex justify-content-between align-items-top">
      <div class="flex-grow-1">
        <div class="message-text">${messageText}</div>
      </div>
      <button class="btn btn-danger btn-sm ms-2" onclick="this.closest('.card').remove()">Delete</button>
    </div>
  </div>
</div>`;

  }
}
<!-- Input group -->
<div class="d-flex justify-content mb-5">
  <div class="input-group">
    <input type="text" class="form-control" id="messageInput" placeholder="Text input">
    <button type="button" class="btn btn-primary" onclick='addMessage()'>Send</button>
  </div>
</div>

<div class="message-board" id="messageBoard"></div>

Why does my Shadow DOM button (tabindex=”0″) get focus after the regular button (tabindex=”10″) and how can I fix it?

I’m trying to ensure that a button inside a Shadow DOM gets tab focus before a regular button in the main DOM. one button have tabindex=”0″, and the other one is 10 but the regular button outside the shadow is always focused first.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        button{
            padding: 1%;
            border-radius: 10px;
            width: 100px;
            height: 50px;   
            
        }
        button:focus {
        background-color: red;
        }

    </style>
</head>
<body>
      
        <div id="shdow">
            
        </div>

        <button  tabindex="10">focus me </button>


        <script>
            // set shadow root with button taindex 0
            document.querySelector('#shdow').attachShadow({mode: 'open'}).innerHTML = `
                <style>
        button{
            padding: 1%;
            border-radius: 10px;
            width: 100px;
            height: 50px;   
            
        }
        button:focus {
        background-color: green;
        }

    </style>
            <button tabindex="0">focus me </button>`;

        </script>

</body>
</html>

when run UT on loopback application getting node-preload not found error

I am using loopback Nodejs framework in my project and Mocha and Chai for unit testing when I do npm run fulltest for run Ut it giving me error node-preload module not found.
Node-preload is build in package inside node-module it’s present in node-module still I am getting this error in my system only getting this error( don’t know why) in my colleague system it’s working fine. what can be the issue.

Method I tried to resolving the issue

  1. reinstall the node-modules
  2. degrade the node version using same version which my colleague using
  3. cleared cache, clone the application again
  4. get zip node-modules from my colleague

still getting same issue

How I can resolve this issue?

HowlerJs Sound not working on production build

So i want to implement new order sound on my restaurant ticket system. whenever there will be a new order it will show a ticket card and Sound will happen. But the issue when its on production build sound not working (sometimes work).

Technology: react 18, Howler

howler.js:2521 the audiocontext was not allowed to start. it must be resumed (or created) after a user gesture on the page. this errors shows but still it make sound on development server. if I build it then start still sound working but when its on production server sound sometimes working (maximum times not)

I have implemented many solution for some sound have distortion , some initial time doesn’t work etc etc

Sound Hook

// src/hooks/useSoundEffect.js

import { useEffect, useRef } from "react";
import { useKdsContext } from "../contexts/KdsProvider";
import { getSecondsDifference } from "../utils";

const useSoundEffect = (items, thresholdSeconds = 2, cooldownMs = 300) => {
  const { soundOption, getActiveHowl } = useKdsContext();
  
  const triggeredOrdersRef = useRef(new Set());
  
  const lastSoundTimeRef = useRef(0);
  
  useEffect(() => {
    if (!items || items.length === 0) return;
    
    const newItems = items.filter((item) => {
      const diff = getSecondsDifference(item.OrderDateTime);
      return diff < thresholdSeconds;
    });
    

    const mapByOrderNumber = newItems.reduce((acc, item) => {
      if (!acc[item.OrderNumber]) {
        acc[item.OrderNumber] = [];
      }
      acc[item.OrderNumber].push(item);
      return acc;
    }, {});
    
    Object.keys(mapByOrderNumber).forEach((orderNumber) => {
      const alreadyTriggered = triggeredOrdersRef.current.has(orderNumber);
      if (!alreadyTriggered) {
        const now = Date.now();
        if (now - lastSoundTimeRef.current < cooldownMs) {

          return;
        }
        
        lastSoundTimeRef.current = now;
        
        triggeredOrdersRef.current.add(orderNumber);
        
        if (soundOption !== "No_Sound") {
          const howl = getActiveHowl();
          if (howl) {
            if (howl.state() === "loaded") {
              howl.stop();
              howl.play();
            } else {
              howl.once("load", () => {
                howl.stop();
                howl.play();
              });
            }
          }
        }
      }
    });
  }, [items, thresholdSeconds, cooldownMs, soundOption, getActiveHowl]);
};

export default useSoundEffect;

Navbar code

// src/components/KitchenDisplay/Content/ContentTop.js

import React from "react";
import {
  HStack,
  Icon,
  useColorMode,
  Menu,
  MenuButton,
  MenuList,
  MenuItem,
  Button,
  Text,
} from "@chakra-ui/react";
import { IoMdMenu } from "react-icons/io";
import {
  MdOutlineLogout,
  MdBrightness4,
  MdBrightness7,
  MdVolumeOff,
  MdVolumeUp,
  MdMusicNote,
} from "react-icons/md";
import { useNavigate } from "react-router-dom";
import { Howler } from "howler";

import KitchenScreensMenu from "./KitchenScreensMenu";
import Pagination from "./Pagination";
import CustomIcon from "../../../components/CustomIcon";
import DepartmentsMenu from "./DepartmentsMenu";
import useColors from "../../../hooks/useColors";
import { useKdsContext } from "../../../contexts/KdsProvider";

const ContentTop = () => {
  const {
    toggleSidebar,
    soundOption,
    setSoundOption,
    newOrderHowlRef,
    pleaseHowlRef,
    alertHowlRef,
  } = useKdsContext();

  const navigate = useNavigate();
  const { toggleColorMode, colorMode } = useColorMode();
  const { alpha100 } = useColors();

  const handleLogout = () => {
    localStorage.removeItem("token");
    navigate("/login");
  };

  // Sound options configuration
  const soundOptions = [
    {
      value: "No_Sound",
      label: "No Sound",
      icon: MdVolumeOff,
      description: "Mute",
    },
    {
      value: "New_Order",
      label: "New Order",
      icon: MdMusicNote,
      description: "Play",
    },
    {
      value: "Please",
      label: "Please",
      icon: MdMusicNote,
      description: "Play",
    },
    {
      value: "Alert",
      label: "Alert",
      icon: MdMusicNote,
      description: "Play",
    },
  ];

  /**
   * Called when a user selects a sound option from the dropdown.
   * 1) If "No_Sound", just set it and return.
   * 2) Otherwise, that click is a user-gesture, so we can resume Howler’s AudioContext.
   * 3) Immediately stop + play the chosen sound as a preview.
   */
  const handleSoundSelect = (optionValue) => {
    setSoundOption(optionValue);

    // If user picked "No_Sound", do nothing more
    if (optionValue === "No_Sound") {
      return;
    }

    // Because the user physically clicked the menu item, 
    // we can resume the audio context if it's suspended.
    const audioCtx = Howler.ctx;
    if (audioCtx && audioCtx.state === "suspended") {
      audioCtx.resume().then(() => {
        // Once resumed, play the chosen sound
        playSelectedSound(optionValue);
      });
    } else {
      // If audio context wasn't suspended, just play right away
      playSelectedSound(optionValue);
    }
  };

  // Helper function: stop + play the chosen sound
  const playSelectedSound = (optionValue) => {
    const soundMap = {
      New_Order: newOrderHowlRef.current,
      Please: pleaseHowlRef.current,
      Alert: alertHowlRef.current,
    };

    const soundInstance = soundMap[optionValue];
    if (soundInstance) {
      if (soundInstance.state() === "loaded") {
        soundInstance.stop();
        soundInstance.play();
      } else {
        soundInstance.once("load", () => {
          soundInstance.stop();
          soundInstance.play();
        });
      }
    }
  };

  // Display the icon for the current sound option
  const getSoundIcon = () => {
    const currentOption = soundOptions.find((opt) => opt.value === soundOption);
    return <Icon as={currentOption?.icon || MdVolumeUp} boxSize="18px" />;
  };

  // Display the label for the current sound option
  const getSoundLabel = () => {
    const currentOption = soundOptions.find((opt) => opt.value === soundOption);
    return currentOption?.label || "New Order Sound";
  };

  return (
    <HStack justifyContent="space-between" alignItems="center" w="full">
      {/* Left side: Menu toggle + Pagination */}
      <HStack gap="5">
        <CustomIcon
          fontSize="28px"
          onClick={toggleSidebar}
          cursor="pointer"
          _hover={{ color: "gray.600" }}
        >
          <IoMdMenu />
        </CustomIcon>

        <Pagination />
      </HStack>

      {/* Right side: Sound settings, Kitchen screens, Departments, Dark mode, Logout */}
      <HStack gap="5" alignItems="center">
        {/* Sound Settings Dropdown */}
        <Menu closeOnSelect>
          <MenuButton
            as={Button}
            leftIcon={getSoundIcon()}
            variant="ghost"
            size="md"
            px={4}
            py={2}
            transition="all 0.2s"
            borderRadius="md"
            borderWidth="2px"
            borderColor={alpha100}
            _hover={{
              bg: colorMode === "light" ? "gray.100" : "whiteAlpha.200",
            }}
            _expanded={{
              bg: colorMode === "light" ? "gray.100" : "whiteAlpha.200",
            }}
            _focus={{ boxShadow: "outline" }}
          >
            <Text as="span" fontSize="sm" fontWeight="medium">
              {getSoundLabel()}
            </Text>
          </MenuButton>
          <MenuList>
            {soundOptions.map((option) => (
              <MenuItem
                key={option.value}
                icon={<Icon as={option.icon} boxSize="18px" />}
                onClick={() => handleSoundSelect(option.value)}
                position="relative"
                py={3}
                px={4}
                _hover={{
                  bg: colorMode === "light" ? "gray.50" : "whiteAlpha.200",
                }}
                bg={
                  soundOption === option.value
                    ? colorMode === "light"
                      ? "gray.50"
                      : "whiteAlpha.200"
                    : "transparent"
                }
              >
                <HStack spacing={2}>
                  <Text
                    fontWeight={
                      soundOption === option.value ? "medium" : "normal"
                    }
                  >
                    {option.label}
                  </Text>
                  <Text
                    fontSize="xs"
                    color={colorMode === "light" ? "gray.500" : "gray.400"}
                  >
                    {option.description}
                  </Text>
                </HStack>
              </MenuItem>
            ))}
          </MenuList>
        </Menu>

        {/* Kitchen Screens Menu */}
        <KitchenScreensMenu />

        {/* Departments Menu */}
        <DepartmentsMenu />

        {/* Dark Mode Toggle */}
        <CustomIcon
          onClick={toggleColorMode}
          cursor="pointer"
          _hover={{ color: "gray.600" }}
        >
          {colorMode === "light" ? (
            <Icon as={MdBrightness4} boxSize="25px" title="Dark Mode" />
          ) : (
            <Icon as={MdBrightness7} boxSize="25px" title="Light Mode" />
          )}
        </CustomIcon>

        {/* Logout */}
        <CustomIcon
          onClick={handleLogout}
          cursor="pointer"
          _hover={{ color: "gray.600" }}
        >
          <Icon as={MdOutlineLogout} boxSize="25px" title="Log Out" />
        </CustomIcon>
      </HStack>
    </HStack>
  );
};

export default ContentTop;

TicketCard.jsx

// src/components/KitchenDisplay/Content/Tickets/TicketCard.js

import React, { useMemo } from "react";
import { Stack, useColorModeValue } from "@chakra-ui/react";
import useColors from "../../../hooks/useColors";
import TicketCardHeader from "./TicketCardHeader";
import Orders from "./Orders";
import { getSecondsDifference } from "../../../utils";
// Updated import to reflect the new, revised version of the hook:
import useSoundEffect from "../../../hooks/useSoundEffect";

const TicketCard = ({ items }) => {
  const { componentBg } = useColors();
  const boxShadowColor = useColorModeValue("#828282", "#3d4b5c");


  useSoundEffect(items, 2, 5000);

  const isAnyItemUnderTwenty = useMemo(
    () => items.some((item) => getSecondsDifference(item.OrderDateTime) < 20),
    [items]
  );

  const { Department, TableName, TicketNumber, NoOfGuests, OrderDateTime, OrderId } = items[0];

  const orderWiseItems = items.reduce((acc, curr) => {
    const found = acc.find(
      (grouped) => grouped[0].OrderNumber === curr.OrderNumber
    );
    if (!found) {
      acc.push(items.filter((i) => i.OrderNumber === curr.OrderNumber));
    }
    return acc;
  }, []);

  function sortOrders() {
    const served = [];
    const notServed = [];

    orderWiseItems.forEach((o) => {
      if (o.every((i) => i.TicketStatus === "Served")) {
        served.push(o);
      } else {
        notServed.push(o);
      }
    });

    // Sort descending by OrderNumber
    const sortFn = (a, b) => b[0].OrderNumber - a[0].OrderNumber;
    return [...notServed.sort(sortFn), ...served.sort(sortFn)];
  }

  return (
    <Stack
      bg={componentBg}
      borderRadius="md"
      boxShadow={`0 6px 25px -3px ${boxShadowColor}, 0 1px 10px -1px ${boxShadowColor}`}
      maxH="450px"
      overflow="auto"
      position="relative"
      borderColor="primary.400"
      // Apply "newTicket" class if any item is within 20 seconds
      className={isAnyItemUnderTwenty ? "newTicket" : ""}
    >
      <TicketCardHeader data={items[0]} />

      <Stack pb="5" px="5" minH="150px">
        {sortOrders().map((orders, i) => (
          <Orders key={i} items={orders} />
        ))}
      </Stack>
    </Stack>

      );
};

export default TicketCard;