Files
simrsx-fe/app/lib/utils.ts

164 lines
4.5 KiB
TypeScript

import type { ClassValue } from 'clsx'
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { toast } from '~/components/pub/ui/toast'
export interface SelectOptionType<_T = string> {
value: string
label: string
code?: string
}
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export function mapToComboboxOptList(items: Record<string, string>): SelectOptionType<string>[] {
if (!items) {
return []
}
const result: SelectOptionType<string>[] = []
Object.keys(items).forEach((item) => {
result.push({
label: items[item] as string,
value: item,
code: item,
})
})
return result
}
/**
* 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`
}
}
/**
* 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<string, any>): 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',
})
}