/** * @fileoverview Utility functions used throughout the application * @description Contains helper functions for common operations * @author Cursor * @version 1.0.0 */ /** * Formats a timestamp string to HH:MM format * @param {string} dateString - ISO timestamp string to format * @returns {string} Formatted time string in HH:MM format * @example * formatTime('2024-01-15T14:30:00Z'); // Returns "14:30" */ export function formatTime(dateString: string): string { const date = new Date(dateString); let hours = date.getHours(); let minutes = date.getMinutes(); const hoursString = hours < 10 ? '0' + hours : hours; const minutesString = minutes < 10 ? '0' + minutes : minutes; return hoursString + ':' + minutesString; } /** * Creates a promise that resolves after a specified delay * @param {number} ms - Delay time in milliseconds * @returns {Promise} Promise that resolves after the delay * @example * await delay(1000); // Wait for 1 second */ export function delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } export function b64(a: Uint8Array): string { // Use chunked approach to avoid "Maximum call stack size exceeded" for large arrays // Process in chunks and use apply to avoid spreading large arrays const chunkSize = 8192; let binary = ''; for (let i = 0; i < a.length; i += chunkSize) { const chunk = a.slice(i, i + chunkSize); binary += String.fromCharCode.apply(null, Array.from(chunk)); } return btoa(binary); } export function ub64(s: string): Uint8Array { const bin = atob(s); const arr = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i); return arr; } export function id(id: string): T { return document.getElementById(id) as unknown as T } /** * Runs the specified callback after `click` or `touchstart` event is triggered. * * @param action The action to perform after interaction * @returns A function to clean up the event listeners. */ export function doAfterInteraction(action?: () => (T | Promise)): Promise { return new Promise((resolve, reject) => { function doAfterInteractionInner() { document.removeEventListener("click", doAfterInteractionInner); document.removeEventListener("touchstart", doAfterInteractionInner); try { const result = action?.(); if (result instanceof Promise) { result.then(resolve); } else { resolve(result as T); } } catch (error) { reject(error); } } document.addEventListener("click", doAfterInteractionInner); document.addEventListener("touchstart", doAfterInteractionInner); setTimeout(reject, 10000); }); }