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 (
+
+ );
+};
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 (
+
+ );
+};
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";