From 398282b3bf4e0667a98cbb7bbc10e576973c7883 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 23 Dec 2025 16:09:29 +0700 Subject: [PATCH] feat(FE-316): Add Uniformity page components --- .../pages/uniformity/UniformityChart.tsx | 164 ++++++++++++++++++ .../uniformity/UniformityPageWrapper.tsx | 59 +++++++ .../pages/uniformity/UniformityStat.tsx | 93 ++++++++++ .../pages/uniformity/UniformityTable.tsx | 49 ++++++ 4 files changed, 365 insertions(+) create mode 100644 src/components/pages/uniformity/UniformityChart.tsx create mode 100644 src/components/pages/uniformity/UniformityPageWrapper.tsx create mode 100644 src/components/pages/uniformity/UniformityStat.tsx create mode 100644 src/components/pages/uniformity/UniformityTable.tsx diff --git a/src/components/pages/uniformity/UniformityChart.tsx b/src/components/pages/uniformity/UniformityChart.tsx new file mode 100644 index 00000000..576e47d8 --- /dev/null +++ b/src/components/pages/uniformity/UniformityChart.tsx @@ -0,0 +1,164 @@ +import { + Bar, + BarChart, + Rectangle, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; +import Card from '@/components/Card'; + +interface Payload { + value?: number; + name?: string; + dataKey?: string | number; +} + +interface CustomTooltipProps { + active?: boolean; + payload?: readonly Payload[]; + label?: string | number; +} + +const UniformityChart = () => { + // #region Sample data + const data = [ + { + name: '48-52', + uv: 80, + }, + { + name: '52-56', + uv: 120, + }, + { + name: '56-60', + uv: 160, + }, + { + name: '60-64', + uv: 200, + }, + { + name: '64-68', + uv: 160, + }, + { + name: '68-72', + uv: 120, + }, + { + name: '72-76', + uv: 80, + }, + { + name: '76-80', + uv: 120, + }, + { + name: '84-88', + uv: 160, + }, + { + name: '88-92', + uv: 200, + }, + { + name: '92-96', + uv: 160, + }, + ]; + + const margin = { + top: 20, + right: 30, + left: 20, + bottom: 5, + }; + // #endregion + + function getIntroOfPage(label: string): string { + if (label === 'Page A') { + return "Page A is about men's clothing"; + } + if (label === 'Page B') { + return "Page B is about women's dress"; + } + if (label === 'Page C') { + return "Page C is about women's bag"; + } + if (label === 'Page D') { + return 'Page D is about household goods'; + } + if (label === 'Page E') { + return 'Page E is about food'; + } + if (label === 'Page F') { + return 'Page F is about baby food'; + } + return ''; + } + + function CustomTooltip({ payload, label, active }: CustomTooltipProps) { + if (active && payload && payload.length && label !== undefined) { + const labelStr = String(label); + return ( +
+

{`${labelStr} : ${payload[0].value}`}

+

{getIntroOfPage(labelStr)}

+

+ Anything you want can be displayed here. +

+
+ ); + } + + return null; + } + + return ( +
+ +
+ + + + + + + } + /> + + +
+
+ +
+ Weekly Performance Content +
+
+
+ ); +}; + +export default UniformityChart; diff --git a/src/components/pages/uniformity/UniformityPageWrapper.tsx b/src/components/pages/uniformity/UniformityPageWrapper.tsx new file mode 100644 index 00000000..4141d094 --- /dev/null +++ b/src/components/pages/uniformity/UniformityPageWrapper.tsx @@ -0,0 +1,59 @@ +'use client'; + +import { usePathname, useRouter } from 'next/navigation'; +import Drawer from '@/components/Drawer'; +import React, { ReactNode } from 'react'; +import UniformityTable from '@/components/pages/uniformity/UniformityTable'; +import { useUiStore } from '@/stores/ui/ui.store'; + +export default function UniformityPageWrapper({ + children, +}: { + children: ReactNode; +}) { + const pathname = usePathname(); + const router = useRouter(); + const toggleValidate = useUiStore((s) => s.toggleValidate); + + const isAdd = pathname.includes('/add'); + const isEdit = pathname.includes('/detail/edit'); + const isDetail = pathname.includes('/detail'); + + const isOpen = isAdd || isEdit || isDetail; + + const handleBackdropClick = () => { + const unsub = useUiStore.getState().subscribeIsValid((isValid) => { + if (isValid) { + router.push('/uniformity'); + } + }); + + toggleValidate(); + + setTimeout(() => { + unsub?.(); + }, 100); + }; + + return ( + <> +
+ !isOpen && router.push('/uniformity')} + /> +
+ + { + if (!v) router.push('/uniformity'); + }} + closeOnBackdropClick={isDetail ? true : false} + onBackdropClick={handleBackdropClick} + variant='right' + zIndex='99999' + sidebarContent={isOpen &&
{children}
} + /> + + ); +} diff --git a/src/components/pages/uniformity/UniformityStat.tsx b/src/components/pages/uniformity/UniformityStat.tsx new file mode 100644 index 00000000..e7603e16 --- /dev/null +++ b/src/components/pages/uniformity/UniformityStat.tsx @@ -0,0 +1,93 @@ +import Badge from '@/components/Badge'; +import Card from '@/components/Card'; +import { Icon } from '@iconify/react'; +import { formatNumber } from '@/lib/helper'; + +const UniformityStat = () => { + const statisticsData = [ + { + title: 'Total Population', + value: 1908978, + icon: 'heroicons-outline:inbox-stack', + change: '15.5%', + changeType: 'increase', + }, + { + title: 'Total Uniformity', + value: 954489, + icon: 'heroicons-outline:scale', + change: '50%', + changeType: 'decrease', + }, + { + title: 'Total Depletion', + value: 954489, + icon: 'heroicons-outline:inbox-stack', + change: '15.5%', + changeType: 'increase', + }, + { + title: 'Total Production', + value: 2534, + icon: 'heroicons-outline:inbox-stack', + change: '15.5%', + changeType: 'increase', + }, + ]; + + return ( +
+ {statisticsData.map((stat, index) => ( + +
+ + From last month + + + + {stat.change} + +
+ + } + > +
+
+ +
+
+ {stat.title} + + {formatNumber(stat.value)} + +
+
+
+ ))} +
+ ); +}; + +export default UniformityStat; diff --git a/src/components/pages/uniformity/UniformityTable.tsx b/src/components/pages/uniformity/UniformityTable.tsx new file mode 100644 index 00000000..d5caa220 --- /dev/null +++ b/src/components/pages/uniformity/UniformityTable.tsx @@ -0,0 +1,49 @@ +'use client'; + +import Button from '@/components/Button'; +import UniformityChart from '@/components/pages/uniformity/UniformityChart'; +import UniformityStat from '@/components/pages/uniformity/UniformityStat'; +import { Icon } from '@iconify/react'; + +const UniformityTable = ({ refresh }: { refresh?: () => void }) => { + return ( + <> +
+ + +
+ + + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
Uniformity Table Component
+
+ + ); +}; + +export default UniformityTable;