From 7c3d24255b802b2080dc2624d29e0b4923bafa47 Mon Sep 17 00:00:00 2001 From: rizky Date: Thu, 5 Sep 2024 00:38:09 -0700 Subject: [PATCH] Dialong Pop, Import, sheet Component --- comps/dialog/Dialog.tsx | 93 ++++++++++++++++++++ comps/import/Import.tsx | 145 ++++++++++++++++++++++++++++++++ comps/import/lib/formatBytes.ts | 8 ++ comps/sheet/sheet.tsx | 125 +++++++++++++++++++++++++++ exports.tsx | 12 +++ 5 files changed, 383 insertions(+) create mode 100755 comps/dialog/Dialog.tsx create mode 100755 comps/import/Import.tsx create mode 100755 comps/import/lib/formatBytes.ts create mode 100755 comps/sheet/sheet.tsx diff --git a/comps/dialog/Dialog.tsx b/comps/dialog/Dialog.tsx new file mode 100755 index 0000000..1ec6143 --- /dev/null +++ b/comps/dialog/Dialog.tsx @@ -0,0 +1,93 @@ +import { useLocal } from "@/utils/use-local"; +import { glb } from "app/lib/goal"; +import { Button } from "lib/comps/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogOverlay, + DialogTitle, + DialogTrigger, +} from "lib/comps/ui/dialog"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; +import { FC, useEffect } from "react"; + +export const Pop: FC<{ + child: any; + PassProp: any; + props: any; + content: any; +}> = ({ child, PassProp, props, content }) => { + const local = useLocal({ + open: false, + }); + return ( + + +
+ { + local.open = true; + local.render(); + }, + close: () => { + local.open = false; + local.render(); + }, + }} + > + {child} + +
+
+ { + local.open = false; + local.render(); + }} + className={cx( + "", + css` + background-color: #00000038 !important; + ` + )} + /> + + { + local.open = false; + local.render(); + }} + className={cx( + "c-absolute c-right-4 c-top-4 c-rounded-sm c-opacity-70 c-ring-offset-background c-transition-opacity hover:c-opacity-100 focus:c-outline-none focus:c-ring-2 focus:c-ring-ring focus:c-ring-offset-2 disabled:c-pointer-events-none data-[state=open]:c-bg-accent data-[state=open]:c-text-muted-foreground", + css` + right: 1rem; + ` + )} + > + + Close + + + + + { + local.open = true; + local.render(); + }, + close: () => { + local.open = false; + local.render(); + }, + }} + > + {content} + + +
+ ); +}; diff --git a/comps/import/Import.tsx b/comps/import/Import.tsx new file mode 100755 index 0000000..bef5221 --- /dev/null +++ b/comps/import/Import.tsx @@ -0,0 +1,145 @@ +import { useLocal } from "@/utils/use-local"; +import { FC, useEffect } from "react"; +import * as XLSX from "xlsx"; + +export const Import: FC<{ + child: any; + PassProp: any; + props: any; + sample: string; + desc: string; + title: string; + task: (e: any) => Promise; + excel: any; + done: (e: any) => void; +}> = ({ child, PassProp, props, title, desc, sample, task, excel, done }) => { + const local = useLocal({ + ready: false, + fase: "start" as "start" | "running" | "end", + data: [] as any[], + progress: 0 as number, + props: { + title, + desc, + sample, + }, + file: { + name: isEditor ? "sample" : (null as any), + size: isEditor ? "sample" : (null as any), + }, + excel: { + failed: { + data: [] as any[], + download: () => { + const ws = XLSX.utils.json_to_sheet(local.excel.failed.data); + // Buat workbook dan tambahkan worksheet + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, "report"); + // Ekspor file + XLSX.writeFile(wb, "failed_import.xlsx"); + } + } + }, + recap: { + success: [] as any[], + failed: [] as any[], + }, + action: { + run: () => { + local.fase = "running"; + local.progress = 0; + local.ready = false; + local.render(); + }, + done: () => { + local.fase = "end"; + local.render(); + } + } + }); + useEffect(() => { + if (local.fase === "start") { + local.ready = false; + local.render(); + } + setTimeout(() => { + local.render(); + }, 1000); + }, [local.fase]); + useEffect(() => { + if (local.ready) { + const callback = () => { + local.fase = "end"; + local.ready =false; + local.render(); + if (typeof done === "function") { + done(local); + } + }; + const sleep = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + const startImport = async ({ + list, + task, + }: { + list: any[]; + task: (e: any) => Promise; + }) => { + let n = 0; + while (n < list.length) { + if (!local.ready) { + await new Promise((resolve) => { + const interval = setInterval(() => { + if (local.ready) { + clearInterval(interval); + resolve([]); + } + }, 100); + }); + } + + await task(list[n]); + await sleep(100); + n++; + } + }; + let idx = 0; + if (local.progress <= 0) { + const res = startImport({ + list: local.data, + task: async (e) => { + if (typeof task === "function") { + const result = await task({data: e, excel}); + if (typeof result === "boolean") { + if (!result) { + local.recap.failed.push(e); + local.excel.failed.data.push(e); + } else { + local.recap.success.push(e); + } + } else { + local.recap.success.push(e); + } + } + idx++; + local.progress = (idx / local.data.length) * 100; + local.render(); + }, + }); + + if (res instanceof Promise) res.then(callback); + else callback(); + } + } + }, [local.ready]); + return ( +
+ + {child} + +
+ ); +}; diff --git a/comps/import/lib/formatBytes.ts b/comps/import/lib/formatBytes.ts new file mode 100755 index 0000000..56411e1 --- /dev/null +++ b/comps/import/lib/formatBytes.ts @@ -0,0 +1,8 @@ +export const formatBytes = (bytes: number, decimals = 2) => { + if (bytes === 0) return "0 Bytes"; + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; +}; diff --git a/comps/sheet/sheet.tsx b/comps/sheet/sheet.tsx new file mode 100755 index 0000000..9e5d8ea --- /dev/null +++ b/comps/sheet/sheet.tsx @@ -0,0 +1,125 @@ +import { useLocal } from "@/utils/use-local"; +import * as SheetPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; +import { FC, useEffect } from "react"; +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetOverlay, + SheetTitle, + SheetTrigger, +} from "lib/comps/ui/sheet"; + +export const SheetCn: FC<{ + child: any; + PassProp: any; + props: any; + content: any; + header: string; + open: string; +}> = ({ child, PassProp, props, content, header, open }) => { + const local = useLocal({ + open: false, + }); + useEffect(() => { + if (isEditor) { + let op = open === "y" ? true : false; + if (local.open !== op) { + local.open = op; + local.render(); + } + } + }, [open]); + return ( + + +
+ { + local.open = true; + local.render(); + setTimeout(() => { + document.body.style.pointerEvents = "auto"; + }, 1000); + }, + close: () => { + local.open = false; + local.render(); + }, + }} + > + {child} + +
+
+ { + local.open = false; + local.render(); + }} + className={cx( + "", + css` + background-color: #00000038 !important; + z-index: 1; + ` + )} + /> + + { + local.open = false; + local.render(); + }} + className={cx( + "c-absolute c-right-4 c-top-4 c-rounded-sm c-opacity-70 c-ring-offset-background c-transition-opacity hover:c-opacity-100 focus:c-outline-none focus:c-ring-2 focus:c-ring-ring focus:c-ring-offset-2 disabled:c-pointer-events-none data-[state=open]:c-bg-accent data-[state=open]:c-text-muted-foreground", + css` + right: 1rem; + ` + )} + > + + Close + + + {header} + + { + local.open = true; + local.render(); + setTimeout(() => { + document.body.style.pointerEvents = "auto"; + }, 1000); + }, + close: () => { + local.open = false; + local.render(); + }, + }} + > + {content} + + +
+ ); +}; diff --git a/exports.tsx b/exports.tsx index 0128d9b..3794f6f 100755 --- a/exports.tsx +++ b/exports.tsx @@ -15,6 +15,7 @@ export const Dialog = lazify( async () => (await import("@/comps/ui/dialog")).Dialog ); + export const Typeahead = lazify( async () => (await import("@/comps/ui/typeahead")).Typeahead ); @@ -94,7 +95,18 @@ export const ScrollArea = lazify( export const KeyValue = lazify( async () => (await import("@/comps/form/field/type/KeyValue")).KeyValue ); +export const Pop = lazify( + async () => (await import("@/comps/dialog/Dialog")).Pop +); +export const Import = lazify( + async () => (await import("@/comps/import/Import")).Import +); + +export const Sheet = lazify( + async () => (await import("@/comps/sheet/sheet")).SheetCn +); +export {formatBytes} from "@/comps/import/lib/formatBytes" export { fetchLinkParams } from "@/comps/form/field/type/TypeLink"; export { FieldLoading, Spinner } from "@/comps/ui/field-loading"; export { lang } from "lib/lang";