"use client"; import { useLocal } from "@/lib/utils/use-local"; import { AlertTriangle, Check, Loader2 } from "lucide-react"; import { useEffect } from "react"; import { toast } from "sonner"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, } from "../ui/resize"; import get from "lodash.get"; import { Skeleton } from "../ui/Skeleton"; import { normalDate } from "@/lib/utils/date"; type Local = { data: T | null; submit: () => Promise; render: () => void; }; export const Form: React.FC = ({ children, header, onLoad, onSubmit, onFooter, showResize, mode, className, onInit, afterLoad, }) => { const local = useLocal({ ready: false, data: null as any | null, submit: async () => { toast.info( <> {"Saving..."} ); try { const fieldDate: any = local?.fields; try { const dateFields = Object.values(fieldDate).filter( (field: any) => get(field, "type") === "date" ); if (Array.isArray(dateFields) && dateFields?.length) { dateFields.map((e: any) => { if (e?.name) local.data[e?.name] = normalDate(local.data[e?.name]); }); local.render(); } } catch (ex) {} const fieldRequired = Object.values(fieldDate).filter( (field: any) => field?.required ); let error = {} as any; if (Array.isArray(fieldRequired) && fieldRequired?.length) { fieldRequired.map((e: any) => { const type = e?.type; let keys = e?.name; if (["dropdown-async", "multi-async"].includes(type)) { keys = e?.target || e?.name; } if ( [ "multi-dropdown", "checkbox", "multi-upload", "multi-async", ].includes(type) ) { if ( !Array.isArray(get(local.data, keys)) || !get(local.data, `${keys}.length`) ) { error[e?.name] = `This field requires at least one item.`; } } else { if (!get(local.data, keys)) { error[e?.name] = `Please fill out this field.`; } } }); } local.error = error; local.render(); if (Object.keys(error).length) { throw new Error("please check your input field."); } else { await onSubmit(local); } setTimeout(() => { toast.success(
{ toast.dismiss(); }} >
Record Saved
); }, 100); } catch (ex: any) { const msg = get(ex, "response.data.meta.message") || ex.message; toast.error(
Submit Failed {msg}.
, { dismissible: true, className: css` background: #ffecec; border: 2px solid red; `, } ); } }, reload: async () => { local.ready = false; local.render(); toast.info( <> {"Loading..."} ); local.data = null; local.render(); const res = await onLoad(); local.ready = true; local.data = res; local.render(); if (typeof afterLoad === "function") { afterLoad(local); } setTimeout(() => { toast.dismiss(); }, 100); // if (res instanceof Promise) { // res.then((data) => { // local.ready = true; // local.data = data; // local.render(); // Panggil render setelah data diperbarui // // toast.dismiss(); // // toast.success("Data Loaded Successfully!"); // }); // } else { // local.ready = true; // local.data = res; // local.render(); // Panggil render untuk memicu re-render // toast.dismiss(); // toast.success("Data Loaded Successfully!"); // } }, fields: {} as any, render: () => {}, error: {} as any, onChange: () => {}, mode, }); useEffect(() => { local.onChange(); }, [local.data]); useEffect(() => { const run = async () => { if (typeof onInit === "function") { onInit(local); } local.ready = false; local.render(); toast.info( <> {"Loading..."} ); const res = await onLoad(); local.ready = true; local.data = res; local.render(); // Panggil render setelah data diperbarui if (typeof afterLoad === "function") { await afterLoad(local); } setTimeout(() => { toast.dismiss(); }, 100); }; run(); }, []); // Tambahkan dependency ke header agar reaktif const HeaderComponent = typeof header === "function" ? header(local) : <>; if (!local.ready) return (
); return (
{HeaderComponent}
{showResize ? ( // Resize panels...
{ e.preventDefault(); local.submit(); }} > {local.ready ? ( children(local) ) : (
)}
{typeof onFooter === "function" ? onFooter(local) : null}
) : ( <>
{ e.preventDefault(); local.submit(); }} > {local.ready ? ( children(local) ) : (
)}
{typeof onFooter === "function" ? (
{onFooter(local)}
) : (
)} )}
); };