/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; import moment from "moment"; import { IWebBid } from "../system/type"; export function cn(...args: ClassValue[]) { return twMerge(clsx(args)); } export const formatTime = (time: string, patent = "DD/MM/YYYY") => { return moment(time).format(patent); }; export function removeFalsyValues>( obj: T, excludeKeys: (keyof T)[] = [] ): Partial { return Object.entries(obj).reduce((acc, [key, value]) => { if (value || excludeKeys.includes(key as keyof T)) { acc[key as keyof T] = value; } return acc; }, {} as Partial); } export function isValidJSON(str: string): boolean { if (!str || str.length <= 0) return false; try { JSON.parse(str); return true; // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { return false; } } export function copyToClipboard(text: string, onSuccess?: () => void): void { if (!navigator.clipboard) { const textarea = document.createElement("textarea"); textarea.value = text; textarea.style.position = "fixed"; document.body.appendChild(textarea); textarea.focus(); textarea.select(); try { document.execCommand("copy"); if (onSuccess) onSuccess(); } catch (err) { console.error("Không thể copy nội dung: ", err); } document.body.removeChild(textarea); } else { navigator.clipboard .writeText(text) .then(() => { if (onSuccess) onSuccess(); }) .catch((err) => console.error("Lỗi khi copy nội dung: ", err)); } } export function base64ToFile(base64String: string, fileName: string): File { const [header, base64Content] = base64String.split(","); const mimeTypeMatch = header.match(/:(.*?);/); if (!mimeTypeMatch || mimeTypeMatch.length < 2) { throw new Error("Invalid base64 string"); } const mimeType = mimeTypeMatch[1]; const binaryString = atob(base64Content); const byteArray = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { byteArray[i] = binaryString.charCodeAt(i); } return new File([byteArray], fileName, { type: mimeType }); } export function toSlug(str: string, maxLength = 60): string { if (typeof str !== "string") return ""; // Kiểm tra giá trị đầu vào // Kiểm tra nếu môi trường hỗ trợ `normalize` const normalizedStr = str.normalize ? str.normalize("NFD") : str; return normalizedStr .replace(/[\u0300-\u036f]/g, "") // Xóa dấu .replace(/[^a-zA-Z0-9\s-]/g, "") // Chỉ giữ chữ cái, số, khoảng trắng và dấu "-" .trim() // Xóa khoảng trắng đầu/cuối .replace(/\s+/g, "-") // Thay khoảng trắng bằng "-" .replace(/-+/g, "-") // Gộp nhiều dấu "-" thành 1 .toLowerCase() // Chuyển về chữ thường .slice(0, maxLength) // Giới hạn độ dài .replace(/^-+|-+$/g, ""); // Xóa "-" đầu/cuối } export function estimateReadingTimeInSeconds( content: string, wordsPerMinute = 200 ): number { if (!content || typeof content !== "string") return 0; const wordCount = content.trim().split(/\s+/).length; return Math.ceil((wordCount / wordsPerMinute) * 60); } export function extractDomain(url: string): string | null { try { const parsedUrl = new URL(url); return parsedUrl.origin; } catch (error) { return null; } } // Hash chuỗi thành số nguyên export function hashStringToInt(str: string): number { let hash = 0; for (let i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); hash = hash & hash; // convert to 32bit integer } return Math.abs(hash); } // Biến số thành màu HEX export function intToHexColor(int: number): string { const r = (int >> 16) & 0xff; const g = (int >> 8) & 0xff; const b = int & 0xff; return `#${[r, g, b].map((x) => x.toString(16).padStart(2, "0")).join("")}`; } export function stringToColor(str: string): string { const colorPalette = [ "#FF6B6B", "#FFD93D", "#FF9F1C", "#F76C6C", "#6BCB77", "#4ECDC4", "#F7B801", "#FF6F91", "#00C9A7", ]; const hash = hashStringToInt(str); const index = hash % colorPalette.length; return colorPalette[index]; } export function findEarlyLoginTime(webBid: IWebBid): string | null { const now = new Date(); // Bước 1: Lọc ra những bid có close_time hợp lệ const validChildren = webBid.children.filter(child => child.close_time); if (validChildren.length === 0) return null; // Bước 2: Tìm bid có close_time gần hiện tại nhất const closestBid = validChildren.reduce((closest, current) => { const closestDiff = Math.abs(new Date(closest.close_time!).getTime() - now.getTime()); const currentDiff = Math.abs(new Date(current.close_time!).getTime() - now.getTime()); return currentDiff < closestDiff ? current : closest; }); if (!closestBid.close_time) return null; // Bước 3: Tính toán thời gian login sớm const closeTime = new Date(closestBid.close_time); closeTime.setSeconds(closeTime.getSeconds() - (webBid.early_login_seconds || 0)); return closeTime.toISOString(); }