import switchSound from "../assets/sounds/ui/switch.mp3"; import popup from "../assets/sounds/ui/popup_open.mp3"; import notification from "../assets/sounds/ui/notification.mp3"; export function getSoundFileName(name: string) { const sounds: Record = { switch: switchSound, popup: popup, notification: notification, }; return sounds[name] ?? null; } const randomChars = () => { const uppercaseAsciiStart = 65; const letterIndex = Math.floor(Math.random() * 26); const letter = String.fromCharCode(uppercaseAsciiStart + letterIndex); return letter; }; const generateNumberPlate = () => { const numberPlateLetters = new Array(4); const characters: string[] = []; for (let index = 0; index <= numberPlateLetters.length; index++) { const letter = randomChars(); characters.push(letter); } const number = Math.floor(Math.random() * 99); characters.splice(2, 0, number + " "); const numberPlate = characters.join(""); return numberPlate; }; export const generateNumberPlateList = (numberofSightings = 5) => { const numberPlates = []; for (let i = 0; i <= numberofSightings; i++) { numberPlates.push(generateNumberPlate()); } return numberPlates; }; export const formatNumberPlate = (plate: string) => { const splittedPlate = plate?.split(""); splittedPlate?.splice(4, 0, " "); const formattedPlate = splittedPlate?.join(""); return formattedPlate; }; export const BLANK_IMG = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; export function capitalize(s?: string) { return s ? s.charAt(0).toUpperCase() + s.slice(1) : ""; } export function formatAge(tsMillis: number) { const ms = Date.now() - tsMillis; const seconds = 5 * Math.floor(ms / 5000); // quantize to 5s like the original const d = Math.floor(seconds / (3600 * 24)); const h = Math.floor((seconds % (3600 * 24)) / 3600); const m = Math.floor((seconds % 3600) / 60); const s = Math.floor(seconds % 60); if (d > 0) return `${d}d ago`; if (h > 0) return `${h}h ago`; if (m > 0) return `${m}m ago`; return `${s}s ago`; } export function drawRects( canvas: HTMLCanvasElement, imageEl: HTMLImageElement, rects: [number, number, number, number][], color: string ) { const ctx = canvas.getContext("2d"); if (!ctx) return; // Ensure canvas size matches displayed image size const w = imageEl.clientWidth || imageEl.naturalWidth; const h = imageEl.clientHeight || imageEl.naturalHeight; if (canvas.width !== w) canvas.width = w; if (canvas.height !== h) canvas.height = h; ctx.imageSmoothingEnabled = false; ctx.lineWidth = 1; ctx.strokeStyle = color; rects.forEach((r) => { const [x, y, rw, rh] = r; ctx.beginPath(); ctx.rect( Math.round(x * w), Math.round(y * h), Math.round(rw * w), Math.round(rh * h) ); ctx.stroke(); }); } // setSelectedRef(data?.ref); //setItems(data); // const selected = useMemo( // () => // selectedRef == null // ? null // : items.find((x) => x?.ref === selectedRef) ?? null, // [items, selectedRef] // ); // const effectiveSelected = selected ?? mostRecent ?? null; // useEffect(() => { // let delay = pollMs; // let dead = false; // const controller = new AbortController(); // async function tick() { // try { // // Pause when tab hidden to save CPU/network // if (document.hidden) { // setTimeout(tick, Math.max(delay, 2000)); // return; // } // if (obj && typeof obj.ref === "number" && obj.ref > -1) { // setItems((prev) => { // const next = [obj, ...prev].slice(0, limit); // // maintain selection if still present; otherwise select newest if allowed // const stillExists = // selectedRef != null && next.some((x) => x?.ref === selectedRef); // if (autoSelectLatest && !stillExists) { // setSelectedRef(obj.ref); // } // return next; // }); // setMostRecent(obj); // mostRecentRef.current = obj.ref; // delay = pollMs; // reset backoff on success // } // } catch { // // exponential backoff (max 10s) // delay = Math.min(delay * 2, 10000); // } finally { // if (!dead) setTimeout(tick, delay); // } // } // const t = setTimeout(tick, pollMs); // return () => { // dead = true; // controller.abort(); // clearTimeout(t); // }; // }, [baseUrl, limit, pollMs, autoSelectLatest, selectedRef]);