import type { ClassValue } from 'clsx' import { clsx } from 'clsx' import { format } from 'date-fns' import { twMerge } from 'tailwind-merge' import { toast } from '~/components/pub/ui/toast' export interface SelectOptionType<_T = string> { value: string label: string code?: string } export interface CheckItem { id: string label: string } export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } export function mapToComboboxOptList(items: Record): SelectOptionType[] { if (!items) { return [] } const result: SelectOptionType[] = [] Object.keys(items).forEach((item) => { result.push({ label: items[item] as string, value: item, code: item, }) }) return result } export function mapToCheckItems, K extends keyof T & string>( items: T, ): { id: K; label: T[K] }[] { return Object.entries(items).map(([key, value]) => ({ id: key as K, label: value as T[K], })) } /** * Mengkonversi string menjadi title case (huruf pertama setiap kata kapital) * @param str - String yang akan dikonversi * @returns String dalam format title case */ export function toTitleCase(str: string): string { return str.toLowerCase().replace(/\b\w/g, (char) => char.toUpperCase()) } /** * Menghitung umur berdasarkan tanggal lahir * @param birthDate - Tanggal lahir dalam format Date atau string * @returns String umur dalam format "X tahun Y bulan" atau "X bulan" untuk bayi */ export function calculateAge(birthDate: Date | string | null | undefined): string { if (!birthDate) { return '-' } let birth: Date // Konversi ke Date object if (typeof birthDate === 'string') { birth = new Date(birthDate) } else { birth = birthDate } // Validasi tanggal if (isNaN(birth.getTime())) { return '-' } const today = new Date() const birthYear = birth.getFullYear() const birthMonth = birth.getMonth() const birthDay = birth.getDate() const currentYear = today.getFullYear() const currentMonth = today.getMonth() const currentDay = today.getDate() // Hitung tahun let years = currentYear - birthYear let months = currentMonth - birthMonth // Adjust jika bulan atau hari belum lewat if (months < 0 || (months === 0 && currentDay < birthDay)) { years-- months += 12 } if (currentDay < birthDay) { months-- } // Pastikan months tidak negatif if (months < 0) { months += 12 } // Format output if (years === 0) { if (months === 0) { // Hitung hari untuk bayi baru lahir const diffTime = today.getTime() - birth.getTime() const days = Math.floor(diffTime / (1000 * 60 * 60 * 24)) return days <= 30 ? `${days} hari` : '1 bulan' } return `${months} bulan` } else if (months === 0) { return `${years} tahun` } else { return `${years} tahun ${months} bulan` } } export function formatDateToDatetimeLocal(inputDate: Date) { const formattedString = format(inputDate, "yyyy-MM-dd'T'HH:mm") return formattedString } /** * Converts a plain JavaScript object (including File objects) into a FormData instance. * @param {object} data - The object to convert (e.g., form values). * @returns {FormData} The new FormData object suitable for API submission. */ export function toFormData(data: Record): FormData { const formData = new FormData(); for (const key in data) { if (Object.prototype.hasOwnProperty.call(data, key)) { const value = data[key]; // Handle File objects, Blobs, or standard JSON values if (value !== null && value !== undefined) { // Check if the value is a File/Blob instance if (value instanceof File || value instanceof Blob) { // Append the file directly formData.append(key, value); } else if (typeof value === 'object') { // Handle nested objects/arrays by stringifying them (optional, depends on API) // Note: Most APIs expect nested data to be handled separately or passed as JSON string // For simplicity, we stringify non-File objects. formData.append(key, JSON.stringify(value)); } else { // Append standard string, number, or boolean values formData.append(key, value); } } } } return formData; } export function printFormData(formData: FormData) { console.log("--- FormData Contents ---"); // Use the entries() iterator to loop through key/value pairs for (const [key, value] of formData.entries()) { if (value instanceof File) { console.log(`Key: ${key}, Value: [File: ${value.name}, Type: ${value.type}, Size: ${value.size} bytes]`); } else { console.log(`Key: ${key}, Value: "${value}"`); } } console.log("-------------------------"); } export function unauthorizedToast() { toast({ title: 'Unauthorized', description: 'You are not authorized to perform this action.', variant: 'destructive', }) }