From f98c4cd87146a67c239219977fa10fc3eaa1aa7d Mon Sep 17 00:00:00 2001 From: faisolavolut Date: Thu, 6 Feb 2025 07:20:05 +0700 Subject: [PATCH] update 7 files --- components/form/Field.tsx | 2 +- components/form/Form.tsx | 124 +++++++++++++++------------- components/form/field/TypeInput.tsx | 3 - components/tablelist/TableList.tsx | 2 +- components/ui/bar.tsx | 31 +++++++ components/ui/card.tsx | 48 +++++++---- components/ui/progress-chart.tsx | 75 +++++++++++++++++ helpers/user.ts | 3 +- package.json | 2 + 9 files changed, 212 insertions(+), 78 deletions(-) create mode 100644 components/ui/bar.tsx create mode 100644 components/ui/progress-chart.tsx diff --git a/components/form/Field.tsx b/components/form/Field.tsx index 13ed06e..6b22b6c 100644 --- a/components/form/Field.tsx +++ b/components/form/Field.tsx @@ -154,7 +154,7 @@ export const Field: React.FC = ({ css` height: 2.13rem; `, - is_disable ? "" : "" + is_disable ? "bg-gray-200/50 " : "bg-gray-200/50 " )} > {before} diff --git a/components/form/Form.tsx b/components/form/Form.tsx index ed7bb2e..31088ef 100644 --- a/components/form/Form.tsx +++ b/components/form/Form.tsx @@ -1,7 +1,7 @@ "use client"; import { useLocal } from "@/lib/utils/use-local"; import { AlertTriangle, Check, Loader2 } from "lucide-react"; -import { ReactNode, useEffect, useState } from "react"; +import { useEffect } from "react"; import { toast } from "sonner"; import { ResizableHandle, @@ -71,7 +71,7 @@ export const Form: React.FC = ({ ); - }, 1000); + }, 100); } catch (ex: any) { const msg = get(ex, "response.data.meta.message") || ex.message; toast.error( @@ -117,22 +117,26 @@ export const Form: React.FC = ({ ); local.data = null; local.render(); - const res = onLoad(); - 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!"); - } + const res = await onLoad(); + local.ready = true; + local.data = res; + local.render(); + toast.dismiss(); + // 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: () => {}, @@ -144,48 +148,56 @@ export const Form: React.FC = ({ local.onChange(); }, [local.data]); useEffect(() => { - if (typeof onInit === "function") { - onInit(local); - } - local.ready = false; - local.render(); - toast.info( - <> - { + if (typeof onInit === "function") { + onInit(local); + } + local.ready = false; + local.render(); + toast.info( + <> + - {"Loading..."} - - ); - const res = onLoad(); - 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 { + ` + )} + /> + {"Loading..."} + + ); + const res = await onLoad(); + local.ready = true; local.data = res; - local.render(); // Panggil render untuk memicu re-render + local.render(); // Panggil render setelah data diperbarui toast.dismiss(); - toast.success("Data Loaded Successfully!"); - } + // 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!"); + // } + }; + run(); }, []); // Tambahkan dependency ke header agar reaktif diff --git a/components/form/field/TypeInput.tsx b/components/form/field/TypeInput.tsx index 425794c..22d0845 100644 --- a/components/form/field/TypeInput.tsx +++ b/components/form/field/TypeInput.tsx @@ -69,9 +69,6 @@ export const TypeInput: React.FC = ({ } else if (type === "time") { if (fm.data?.[name]) fm.data[name] = convertToTimeOnly(fm.data[name]); fm.render(); - console.log({ - data: fm.data, - }); } else { setRating(value ? value - 1 : value); } diff --git a/components/tablelist/TableList.tsx b/components/tablelist/TableList.tsx index 1e833c9..0c5d57d 100644 --- a/components/tablelist/TableList.tsx +++ b/components/tablelist/TableList.tsx @@ -139,7 +139,7 @@ export const TableList: React.FC = ({ setData(res); setTimeout(() => { toast.dismiss(); - }, 1000); + }, 100); } }, }); diff --git a/components/ui/bar.tsx b/components/ui/bar.tsx new file mode 100644 index 0000000..26c0368 --- /dev/null +++ b/components/ui/bar.tsx @@ -0,0 +1,31 @@ +import { FC } from "react"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, + ChartOptions, + ChartData, +} from "chart.js"; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend +); + +const BarChart: FC<{ data: ChartData<"bar">; option: ChartOptions<"bar"> }> = ({ + data, + option, +}) => { + return ; +}; + +export default BarChart; diff --git a/components/ui/card.tsx b/components/ui/card.tsx index 65ee89d..95e2789 100644 --- a/components/ui/card.tsx +++ b/components/ui/card.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "@/lib/utils/utils" +import { cn } from "@/lib/utils/utils"; const Card = React.forwardRef< HTMLDivElement, @@ -14,8 +14,8 @@ const Card = React.forwardRef< )} {...props} /> -)) -Card.displayName = "Card" +)); +Card.displayName = "Card"; const CardHeader = React.forwardRef< HTMLDivElement, @@ -26,8 +26,8 @@ const CardHeader = React.forwardRef< className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} /> -)) -CardHeader.displayName = "CardHeader" +)); +CardHeader.displayName = "CardHeader"; const CardTitle = React.forwardRef< HTMLDivElement, @@ -38,8 +38,8 @@ const CardTitle = React.forwardRef< className={cn("font-semibold leading-none tracking-tight", className)} {...props} /> -)) -CardTitle.displayName = "CardTitle" +)); +CardTitle.displayName = "CardTitle"; const CardDescription = React.forwardRef< HTMLDivElement, @@ -50,16 +50,16 @@ const CardDescription = React.forwardRef< className={cn("text-sm text-muted-foreground", className)} {...props} /> -)) -CardDescription.displayName = "CardDescription" +)); +CardDescription.displayName = "CardDescription"; const CardContent = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
-)) -CardContent.displayName = "CardContent" +)); +CardContent.displayName = "CardContent"; const CardFooter = React.forwardRef< HTMLDivElement, @@ -70,7 +70,25 @@ const CardFooter = React.forwardRef< className={cn("flex items-center p-6 pt-0", className)} {...props} /> -)) -CardFooter.displayName = "CardFooter" +)); -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } +const CardBetter: React.FC = ({ children, className }) => { + return ( + + + {children} + + + ); +}; +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardBetter, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/components/ui/progress-chart.tsx b/components/ui/progress-chart.tsx new file mode 100644 index 0000000..c00ce4f --- /dev/null +++ b/components/ui/progress-chart.tsx @@ -0,0 +1,75 @@ +import { FC } from "react"; +import { Doughnut } from "react-chartjs-2"; +import { + Chart as ChartJS, + ArcElement, + Title, + Tooltip, + Legend, + ChartOptions, + Chart as ChartInstance, + Plugin, +} from "chart.js"; + +ChartJS.register(ArcElement, Title, Tooltip, Legend); + +interface ProgressChartProps { + percentage: number; + color?: string; + backgroundColor?: string; + options: ChartOptions<"doughnut">; +} + +const ProgressChart: FC = ({ + percentage, + options, + color = "#6366F1", + backgroundColor = "#E0E7FF", +}) => { + const data = { + datasets: [ + { + data: [percentage, 100 - percentage], + backgroundColor: [color, "transparent"], + borderWidth: 0, + borderRadius: [10, 0], + cutout: "70%", + }, + ], + }; + const backgroundCircle: Plugin<"doughnut"> = { + id: "backgroundCircle", + beforeDatasetsDraw(chart: ChartInstance, args: any, pluginOptions: any) { + const { ctx } = chart; + ctx.save(); + + const meta = chart.getDatasetMeta(0); + if (!meta || meta.data.length === 0) return; + + const arc = meta.data[0] as any; // Pastikan ini adalah elemen arc + const xCoor = arc.x; + const yCoor = arc.y; + const innerRadius = arc.innerRadius || 0; + const outerRadius = arc.outerRadius || 0; + const width = outerRadius - innerRadius; + const angle = Math.PI / 180; + + ctx.beginPath(); + ctx.lineWidth = width; + ctx.strokeStyle = backgroundColor; + ctx.arc(xCoor, yCoor, outerRadius - width / 2, 0, angle * 360, false); + ctx.stroke(); + ctx.restore(); + }, + }; + return ( +
+ +
+ +{percentage}% +
+
+ ); +}; + +export default ProgressChart; diff --git a/helpers/user.ts b/helpers/user.ts index ea90603..e97b83d 100644 --- a/helpers/user.ts +++ b/helpers/user.ts @@ -12,8 +12,7 @@ export const userToken = async () => { `${process.env.NEXT_PUBLIC_API_PORTAL}/api/check-jwt-token` ); const jwt = res.data.data; - console.log({ jwt }); - if (!jwt) return; + if (!jwt) return navigate(`${process.env.NEXT_PUBLIC_API_PORTAL}/login`); try { await api.post(process.env.NEXT_PUBLIC_BASE_URL + "/api/cookies", { token: jwt, diff --git a/package.json b/package.json index c2bfc30..12b1447 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@types/lodash.uniqby": "^4.7.9", "autoprefixer": "^10.4.20", "axios": "^1.7.8", + "chart.js": "^4.4.7", "class-variance-authority": "^0.7.1", "classnames": "^2.5.1", "clsx": "^2.1.1", @@ -52,6 +53,7 @@ "lucide-react": "^0.462.0", "next": "15.0.3", "react-beautiful-dnd": "^13.1.1", + "react-chartjs-2": "^5.3.0", "react-colorful": "^5.6.1", "react-icons": "^5.3.0", "react-resizable": "^3.0.5",