Dialong Pop, Import, sheet Component

This commit is contained in:
rizky 2024-09-05 00:38:09 -07:00
parent cec4fefeaf
commit 7c3d24255b
5 changed files with 383 additions and 0 deletions

93
comps/dialog/Dialog.tsx Executable file
View File

@ -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 (
<Dialog open={local.open}>
<DialogTrigger asChild>
<div {...props} className={cx(props.className, "")}>
<PassProp
pop={{
open: () => {
local.open = true;
local.render();
},
close: () => {
local.open = false;
local.render();
},
}}
>
{child}
</PassProp>
</div>
</DialogTrigger>
<DialogOverlay
onClick={() => {
local.open = false;
local.render();
}}
className={cx(
"",
css`
background-color: #00000038 !important;
`
)}
/>
<DialogContent className="sm:s-max-w-[425px]">
<DialogPrimitive.Close
onClick={() => {
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;
`
)}
>
<X className="c-h-4 c-w-4" />
<span className="c-sr-only">Close</span>
</DialogPrimitive.Close>
<DialogHeader className="c-hidden">
<DialogTitle></DialogTitle>
</DialogHeader>
<PassProp
pop={{
open: () => {
local.open = true;
local.render();
},
close: () => {
local.open = false;
local.render();
},
}}
>
{content}
</PassProp>
</DialogContent>
</Dialog>
);
};

145
comps/import/Import.tsx Executable file
View File

@ -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<any>;
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<void>;
}) => {
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 (
<div {...props} className={cx(props.className, "")}>
<PassProp
li={local}
>
{child}
</PassProp>
</div>
);
};

View File

@ -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];
};

125
comps/sheet/sheet.tsx Executable file
View File

@ -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 (
<Sheet open={local.open}>
<SheetTrigger asChild>
<div {...props} className={cx(props.className, "")}>
<PassProp
sheet={{
open: () => {
local.open = true;
local.render();
setTimeout(() => {
document.body.style.pointerEvents = "auto";
}, 1000);
},
close: () => {
local.open = false;
local.render();
},
}}
>
{child}
</PassProp>
</div>
</SheetTrigger>
<SheetOverlay
onClick={() => {
local.open = false;
local.render();
}}
className={cx(
"",
css`
background-color: #00000038 !important;
z-index: 1;
`
)}
/>
<SheetContent
className={cx(
"sm:s-max-w-[425px]",
css`
z-index: 2;
`
)}
>
<SheetPrimitive.Close
onClick={() => {
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;
`
)}
>
<X className="c-h-4 c-w-4" />
<span className="c-sr-only">Close</span>
</SheetPrimitive.Close>
<SheetHeader
className={cx(
css`
padding: 0px 0px 0px 10px;
`
)}
>
<SheetTitle>{header}</SheetTitle>
</SheetHeader>
<PassProp
sheet={{
open: () => {
local.open = true;
local.render();
setTimeout(() => {
document.body.style.pointerEvents = "auto";
}, 1000);
},
close: () => {
local.open = false;
local.render();
},
}}
>
{content}
</PassProp>
</SheetContent>
</Sheet>
);
};

View File

@ -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";