Звук HowlerJs не работает в производственной сборкеJavascript

Форум по Javascript
Ответить
Anonymous
 Звук HowlerJs не работает в производственной сборке

Сообщение Anonymous »

Я хочу добавить звук нового заказа в свою систему билетов в ресторане. всякий раз, когда будет новый заказ, будет отображаться карточка билета и сработает Звук. Но проблема, когда его звук в производственной сборке не работает (иногда работает).
Технология: React 18, Howler
howler.js:2521 аудиоконтексту не удалось запуститься. его необходимо возобновить (или создать) после жеста пользователя на странице. эти ошибки отображаются, но все равно звучат на сервере разработки. если я его создаю, звук по-прежнему работает, но когда он работает на рабочем сервере, звук иногда работает (максимальное количество раз нет)
Я реализовал множество решений для некоторых звуков с искажениями, в некоторые начальные моменты этого не происходит. не работаю и т. д. и т. п.
Звуковой крючок
// 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;


Код навигационной панели
// 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 ;
};

// 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 (

{/* Left side: Menu toggle + Pagination */}







{/* Right side: Sound settings, Kitchen screens, Departments, Dark mode, Logout */}

{/* Sound Settings Dropdown */}



{getSoundLabel()}



{soundOptions.map((option) => (
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"
}
>


{option.label}


{option.description}



))}



{/* Kitchen Screens Menu */}


{/* Departments Menu */}


{/* Dark Mode Toggle */}

{colorMode === "light" ? (

) : (

)}


{/* Logout */}





);
};

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 (




{sortOrders().map((orders, i) => (

))}



);
};

export default TicketCard;



Подробнее здесь: https://stackoverflow.com/questions/793 ... tion-build
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»