Files
simrsx-fe/app/lib/utils.ts
hasyim_kai f6ae61849d Squashed commit of the following:
commit 8e3ea9e8d1d7e3b06bc6e53e0b97f62222276171
Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
Date:   Thu Nov 20 16:14:03 2025 +0700

    Feat: UI control letter history

commit f11f97f936447bdb225918abb43313f8db540d67
Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
Date:   Thu Nov 20 15:18:25 2025 +0700

    Squashed commit of the following:

    commit dab6adc4a9
    Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
    Date:   Tue Nov 18 11:19:48 2025 +0700

        Fix: add role authorization in Resume

    commit c28fc8f7aa
    Merge: 7ed1cc8 bcfb4c1
    Author: Muhammad Hasyim Chaidir Ali <68959522+Hasyim-Kai@users.noreply.github.com>
    Date:   Tue Nov 18 09:02:16 2025 +0700

        Merge branch 'dev' into feat/resume-81

    commit 7ed1cc83bf
    Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
    Date:   Mon Nov 17 15:04:01 2025 +0700

        Feat: add doc preview in Resume List

    commit bcfb4c1456
    Merge: 1cbde57 975c87d
    Author: Munawwirul Jamal <57973347+munaja@users.noreply.github.com>
    Date:   Mon Nov 17 11:15:14 2025 +0700

        Merge pull request #147 from dikstub-rssa/feat/surat-kontrol-135

        Feat: Integration Rehab Medik - Surat Kontrol

    commit 15ab43c1b1
    Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
    Date:   Mon Nov 17 10:38:21 2025 +0700

        Feat: add verification capthca and form adjustment

    commit 53bd8e7f6e
    Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
    Date:   Fri Nov 7 08:55:23 2025 +0700

        Fix: refactor rehab medik - Resume UI

    commit fc308809b8
    Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
    Date:   Wed Oct 29 14:57:19 2025 +0700

        Feat: add UI Rehab Medik > Proses > Resume

    commit 9b383a5437
    Merge: a4dc7d7 831749a
    Author: Muhammad Hasyim Chaidir Ali <68959522+Hasyim-Kai@users.noreply.github.com>
    Date:   Wed Oct 29 13:32:47 2025 +0700

        Merge pull request #139 from dikstub-rssa/dev

        Update branch feat/resume-81

commit 2b7bea70d66e8472220a2a2406889fc489cc1ebd
Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
Date:   Tue Nov 18 11:20:51 2025 +0700

    Fix: Typo in Control Letter

commit 808e91527cf95de2a47387bb792a3af2e16d907b
Author: hasyim_kai <muhammad.hasyim.c.a@gmail.com>
Date:   Tue Nov 18 10:59:50 2025 +0700

    Fix: add role authorization in Control Letter
2025-11-25 14:09:25 +07:00

163 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',
})
}