import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } export function formatDate( date: Date | string | number, locale: string = "en-US", opts: Intl.DateTimeFormatOptions = {}, includeTime: boolean = false ) { const dateObj = new Date(date); // 한국 로케일인 경우 하이픈 포맷 사용 if (locale === "ko-KR" || locale === "KR" || locale === "kr") { const year = dateObj.getFullYear(); const month = String(dateObj.getMonth() + 1).padStart(2, "0"); const day = String(dateObj.getDate()).padStart(2, "0"); let result = `${year}-${month}-${day}`; // 시간 포함 옵션이 활성화된 경우 if (includeTime) { const hour = String(dateObj.getHours()).padStart(2, "0"); const minute = String(dateObj.getMinutes()).padStart(2, "0"); const second = String(dateObj.getSeconds()).padStart(2, "0"); result += ` ${hour}:${minute}:${second}`; } return result; } // 다른 로케일은 기존 방식 유지 return new Intl.DateTimeFormat(locale, { month: opts.month ?? "long", day: opts.day ?? "numeric", year: opts.year ?? "numeric", // Add time options when includeTime is true ...(includeTime && { hour: opts.hour ?? "2-digit", minute: opts.minute ?? "2-digit", second: opts.second ?? "2-digit", hour12: opts.hour12 ?? false, // Use 24-hour format by default }), ...opts, // This allows overriding any of the above defaults }).format(dateObj); } // formatDateTime 함수도 같은 방식으로 수정 export function formatDateTime( date: Date | string | number | null | undefined, locale: string = "en-US", opts: Intl.DateTimeFormatOptions = {} ) { if (date === null || date === undefined || date === '') { return ''; // 또는 '-', 'N/A' 등 원하는 기본값 반환 } const dateObj = new Date(date); // 한국 로케일인 경우 하이픈 포맷 사용 if (locale === "ko-KR" || locale === "KR" || locale === "kr") { const year = dateObj.getFullYear(); const month = String(dateObj.getMonth() + 1).padStart(2, "0"); const day = String(dateObj.getDate()).padStart(2, "0"); const hour = String(dateObj.getHours()).padStart(2, "0"); const minute = String(dateObj.getMinutes()).padStart(2, "0"); const second = String(dateObj.getSeconds()).padStart(2, "0"); return `${year}-${month}-${day} ${hour}:${minute}:${second}`; } // 다른 로케일은 기존 방식 유지 return new Intl.DateTimeFormat(locale, { month: opts.month ?? "long", day: opts.day ?? "numeric", year: opts.year ?? "numeric", hour: opts.hour ?? "2-digit", minute: opts.minute ?? "2-digit", second: opts.second ?? "2-digit", hour12: opts.hour12 ?? false, ...opts, }).format(dateObj); } export function toSentenceCase(str: string) { return str .replace(/_/g, " ") .replace(/([A-Z])/g, " $1") .toLowerCase() .replace(/^\w/, (c) => c.toUpperCase()) .replace(/\s+/g, " ") .trim() } /** * @see https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx */ export function composeEventHandlers( originalEventHandler?: (event: E) => void, ourEventHandler?: (event: E) => void, { checkForDefaultPrevented = true } = {} ) { return function handleEvent(event: E) { originalEventHandler?.(event) if ( checkForDefaultPrevented === false || !(event as unknown as Event).defaultPrevented ) { return ourEventHandler?.(event) } } } /** * 바이트 단위의 파일 크기를 사람이 읽기 쉬운 형식으로 변환합니다. * (예: 1024 -> "1 KB", 1536 -> "1.5 KB") * * @param bytes 변환할 바이트 크기 * @param decimals 소수점 자릿수 (기본값: 1) * @returns 포맷된 파일 크기 문자열 */ export const formatFileSize = (bytes: number, decimals: number = 1): string => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; // 로그 계산으로 적절한 단위 찾기 const i = Math.floor(Math.log(bytes) / Math.log(k)); // 단위에 맞게 값 계산 (소수점 반올림) const value = parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)); return `${value} ${sizes[i]}`; }; export function formatCurrency( value: number, currency: string | null | undefined = "KRW", locale: string = "ko-KR" ): string { return new Intl.NumberFormat(locale, { style: "currency", currency: currency ?? "KRW", // null이나 undefined면 "KRW" 사용 // minimumFractionDigits: 0, // maximumFractionDigits: 2, }).format(value) }