From 34f93f8dcccba81677783debee4d15a723bac18c Mon Sep 17 00:00:00 2001 From: randy-ar Date: Wed, 28 Jan 2026 17:54:55 +0700 Subject: [PATCH 1/7] fix(FE): refactor UI Dashboard pixel perfect figma --- src/components/Card.tsx | 7 +- src/components/Navbar.tsx | 6 +- src/components/helper/ButtonFilter.tsx | 12 +- .../pages/dashboard/DashboardProduction.tsx | 298 +++++++++++++----- .../dashboard/chart/DashboardLineChart.tsx | 138 +++++--- .../pages/dashboard/chart/DashboardStats.tsx | 57 ++-- .../DashboardExportCharts.tsx} | 14 +- .../dashboard/export/DashboardExportStats.tsx | 201 ++++++++++++ .../pages/dashboard/export/DashboardPDF.ts | 58 ++-- .../skeleton/DashboardLineChartSkeleton.tsx | 138 ++++---- src/stores/ui/slices/navbar.slice.ts | 22 ++ src/stores/ui/ui.store.ts | 2 + src/types/stores.d.ts | 12 +- 13 files changed, 716 insertions(+), 249 deletions(-) rename src/components/pages/dashboard/{chart/DashboardAllCharts.tsx => export/DashboardExportCharts.tsx} (97%) create mode 100644 src/components/pages/dashboard/export/DashboardExportStats.tsx create mode 100644 src/stores/ui/slices/navbar.slice.ts diff --git a/src/components/Card.tsx b/src/components/Card.tsx index e04fa4c7..c78766e1 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -22,6 +22,7 @@ export interface CardProps onCollapsedChange?: (collapsed: boolean) => void; className?: { wrapper?: string; + wrapperContent?: string; image?: string; body?: string; title?: string; @@ -144,6 +145,10 @@ const Card = ({ return cn('border-t border-base-300 mt-4 pt-4', className?.footer); }; + const getWrapperContentClasses = () => { + return cn('space-y-4', className?.wrapperContent); + }; + const renderCardContent = () => { const hasContent = children || actions || footer; @@ -177,7 +182,7 @@ const Card = ({ ); const cardContent = ( -
+
{children} {actions &&
{actions}
} {footer &&
{footer}
} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 4998ca66..ce17f6b8 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -12,6 +12,7 @@ import PopoverContent from '@/components/popover/PopoverContent'; import { useAuth } from '@/services/hooks/useAuth'; import { AuthApi } from '@/services/api/auth'; import { isResponseError } from '@/lib/api-helper'; +import { useUiStore } from '@/stores/ui/ui.store'; interface NavbarProps { toggleSidebar?: () => void; @@ -21,6 +22,7 @@ const Navbar = ({ toggleSidebar }: NavbarProps) => { const { setUser } = useAuth(); const router = useRouter(); const pathname = usePathname(); + const navbarActions = useUiStore((state) => state.navbarActions); const logoutClickHandler = async () => { const logoutRes = await AuthApi.logout(); @@ -53,7 +55,9 @@ const Navbar = ({ toggleSidebar }: NavbarProps) => {
-
+
+ {/* Page-specific actions */} + {navbarActions &&
{navbarActions}
} void; }; +// 'bg-gradient-to-t from-blue-50 to-blue-100 border-blue-500 text-blue-600 hover:from-blue-100 hover:to-blue-200 + const ButtonFilter = ({ values, onClick, ...props }: ButtonFilterProps) => { return ( + } + className={{ + content: 'w-full', + }} + > + + + + +
+ ); + }, [formik.values, exporting, setNavbarActions]); + + // Cleanup only on unmount + useEffect(() => { + return () => { + clearNavbarActions(); + }; + }, [clearNavbarActions]); + if (isLoadingDashboardProductionData) { return (
@@ -210,48 +273,59 @@ const DashboardProduction = () => { return ( <> -
-
-
- -
- filterModal.openModal()} - /> - - - Export - - - } - className={{ - content: 'w-full', - }} - > - - - - -
+
+
+ openFilterModalRef.current()} + /> + + + Export +
+ +
+ + } + className={{ + content: 'w-full', + }} + > + + + +
- {/* Dashboard Stats */} -
+
{/* Use DashboardLineChart component or skeleton */} -
+
{isLoadingDashboardProductionData ? ( ) : dashboardProductionData && @@ -287,28 +361,46 @@ const DashboardProduction = () => { {/* Hidden container for all charts (used for PDF export in OVERVIEW mode) */} {dashboardProductionData && ( -
- + {/* Export Stats Charts */} +
+ +
+ + {/* Export ALL Charts */} +
+ -
+ } + /> +
+ )}
@@ -319,30 +411,32 @@ const DashboardProduction = () => { modalBox: 'p-0 rounded-xl', }} > -
+
{/* Modal Header */} -
-
+
+

Filter Data

{/* Rentang Waktu */} -
- +
+
{ errorMessage={formik.errors.startDate} onChange={formik.handleChange} className={{ - inputWrapper: 'rounded-lg', + inputWrapper: + 'rounded-[8px] px-[12px] py-[10px] text-sm border-[#18181B]/10', }} isError={ Boolean(formik.errors.startDate) && Boolean(formik.touched.startDate) } /> -
+
+ — +
{ errorMessage={formik.errors.endDate} onChange={formik.handleChange} className={{ - inputWrapper: 'rounded-lg', + inputWrapper: + 'rounded-[8px] px-[12px] py-[10px] text-sm border-[#18181B]/10', }} isError={ Boolean(formik.errors.endDate) && @@ -377,8 +475,10 @@ const DashboardProduction = () => {
{/* Analysis Mode */} -
- +
+ { }} color='primary' className={{ - wrapper: 'w-full my-6 font-semibold text-neutral-500', + wrapper: + 'w-full flex flex-row items-center min-h-[45px] font-medium text-[#18181B]/50', }} > {
{formik.values.analysisMode === 'COMPARISON' && ( -
+
{ Boolean(formik.errors.comparisonType) && Boolean(formik.touched.comparisonType) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} />
)} {/* Location */} -
+
{comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'FARM' ? ( @@ -465,6 +570,10 @@ const DashboardProduction = () => { Boolean(formik.errors.location) && Boolean(formik.touched.location) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} /> ) : ( { Boolean(formik.errors.location) && Boolean(formik.touched.location) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} /> )}
@@ -505,7 +618,7 @@ const DashboardProduction = () => { formik.values.comparisonType === 'KANDANG' ) ) && ( -
+
{comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'FLOCK' ? ( @@ -530,6 +643,10 @@ const DashboardProduction = () => { Boolean(formik.errors.flock) && Boolean(formik.touched.flock) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} /> ) : ( { Boolean(formik.errors.flock) && Boolean(formik.touched.flock) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} /> )}
@@ -563,7 +684,7 @@ const DashboardProduction = () => { formik.values.analysisMode === 'COMPARISON' && !(formik.values.comparisonType === 'KANDANG') ) && ( -
+
{comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'KANDANG' ? ( @@ -588,6 +709,10 @@ const DashboardProduction = () => { Boolean(formik.errors.kandang) && Boolean(formik.touched.kandang) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} /> ) : ( { Boolean(formik.errors.kandang) && Boolean(formik.touched.kandang) } + className={{ + label: 'mb-[8px] text-xs font-semibold', + select: 'rounded-[8px] text-sm border-[#18181B]/10', + }} /> )}
@@ -621,16 +750,19 @@ const DashboardProduction = () => {
{/* Action Buttons */} -
+
-
diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index f2449795..6a419cb4 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -151,7 +151,7 @@ const DashboardLineChart = ({ }} variant='bordered' > -
+
Performance{' '} setOpen(!open)} > {chartTypeLabels[chartData]}{' '} -
- +
+ +
} className={{ - content: 'w-52 mt-3', + content: '', }} controlled={open} > { setChartData('body_weight'); setOpen(!open); @@ -192,6 +194,7 @@ const DashboardLineChart = ({ /> { setChartData('performance'); setOpen(!open); @@ -199,6 +202,7 @@ const DashboardLineChart = ({ /> { setChartData('fcr'); setOpen(!open); @@ -206,6 +210,7 @@ const DashboardLineChart = ({ /> { setChartData('quality_control'); setOpen(!open); @@ -213,6 +218,7 @@ const DashboardLineChart = ({ /> { setChartData('deplesi'); setOpen(!open); @@ -248,8 +254,8 @@ const DashboardLineChart = ({ .includes('std'); return ( - + ); }); })()} @@ -335,20 +343,54 @@ const DashboardLineChart = ({ { // Calculate dynamic domain based on visible data let seriesData: DashboardChartsSeries[] = []; @@ -399,14 +441,12 @@ const DashboardLineChart = ({ })()} ticks={(() => { // Calculate dynamic ticks based on domain - let seriesData: DashboardChartsSeries[] = []; let dataset: DashboardChartsDataset[] = []; if ( analysisMode === 'OVERVIEW' && isOverviewCharts(data.charts) ) { - seriesData = data.charts[chartData]?.series || []; dataset = data.charts[chartData]?.dataset || []; } else if ( analysisMode === 'COMPARISON' && @@ -416,7 +456,6 @@ const DashboardLineChart = ({ data.charts.farm || data.charts.flock || data.charts.kandang; - seriesData = comparisonChart?.series || []; dataset = comparisonChart?.dataset || []; } @@ -436,6 +475,20 @@ const DashboardLineChart = ({ const minValue = Math.min(...allValues); const maxValue = Math.max(...allValues); + + // Handle edge case where min equals max + if (minValue === maxValue) { + const value = Math.round(minValue); + const padding = Math.max(10, Math.abs(value) * 0.2); + return [ + Math.floor(value - padding), + Math.floor(value - padding / 2), + value, + Math.ceil(value + padding / 2), + Math.ceil(value + padding), + ]; + } + const padding = (maxValue - minValue) * 0.1; const domainMin = Math.floor(Math.max(0, minValue - padding)); const domainMax = Math.ceil(maxValue + padding); @@ -444,13 +497,16 @@ const DashboardLineChart = ({ const range = domainMax - domainMin; const step = range / 4; - return [ + // Use Set to ensure unique values + const tickSet = new Set([ domainMin, Math.round(domainMin + step), Math.round(domainMin + step * 2), Math.round(domainMin + step * 3), domainMax, - ]; + ]); + + return Array.from(tickSet).sort((a, b) => a - b); })()} /> `Week ${value}`} content={(props) => { return ( -
-

+

+

{analysisMode === 'OVERVIEW' ? selectedKandang ? selectedKandang.label || 'Overview Performance' @@ -506,12 +562,12 @@ const DashboardLineChart = ({ return (

  • -

    +

    Week {props.label}

    @@ -598,7 +654,7 @@ const DashboardLineChart = ({ return ( {/* Chart icon */} -
    - +
    +
    + +
    {/* Empty state text */} diff --git a/src/components/pages/dashboard/chart/DashboardStats.tsx b/src/components/pages/dashboard/chart/DashboardStats.tsx index dcb0707f..13167ba3 100644 --- a/src/components/pages/dashboard/chart/DashboardStats.tsx +++ b/src/components/pages/dashboard/chart/DashboardStats.tsx @@ -48,7 +48,7 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { icon: isPositive ? 'heroicons:arrow-trending-up' : 'heroicons:arrow-trending-down', - color: isPositive ? 'text-success' : 'text-error', + color: isPositive ? 'text-[#008000]' : 'text-[#FF3A3A]', value: Math.abs(percent), }; }; @@ -60,14 +60,16 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { {prefix} {formatNumber(value)} {suffix && ( - {suffix} + + {suffix} + )} ); }; return ( -
    +
    {CARD_CONFIG.map((config) => { // Find matching data from API const cardData = data.find((item) => item.label === config.key); @@ -78,35 +80,42 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { -
    +
    +
    From last month
    -
    +
    Filter Required
    } > -
    - +
    +
    -

    +

    {config.key}

    -

    +

    ********

    @@ -121,17 +130,21 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { -
    +
    +
    From last month
    {trend.value}% @@ -143,15 +156,15 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { - +
    -

    +

    {cardData.label}

    -

    +

    {formatValue(cardData.value, config.prefix, config.suffix)}

    diff --git a/src/components/pages/dashboard/chart/DashboardAllCharts.tsx b/src/components/pages/dashboard/export/DashboardExportCharts.tsx similarity index 97% rename from src/components/pages/dashboard/chart/DashboardAllCharts.tsx rename to src/components/pages/dashboard/export/DashboardExportCharts.tsx index fe0db0a7..c89014d8 100644 --- a/src/components/pages/dashboard/chart/DashboardAllCharts.tsx +++ b/src/components/pages/dashboard/export/DashboardExportCharts.tsx @@ -17,12 +17,12 @@ import { YAxis, } from 'recharts'; -type DashboardAllChartsProps = { +type DashboardExportChartsProps = { data: Dashboard; analysisMode: string; }; -export type DashboardAllChartsRef = { +export type DashboardExportChartsRef = { getChartRefs: () => { key: string; ref: HTMLDivElement | null; @@ -99,9 +99,9 @@ const chartTypeLabels: Record = { deplesi: 'Deplesi', }; -const DashboardAllCharts = forwardRef< - DashboardAllChartsRef, - DashboardAllChartsProps +const DashboardExportCharts = forwardRef< + DashboardExportChartsRef, + DashboardExportChartsProps >(({ data, analysisMode }, ref) => { // Create refs for charts - use string keys for flexibility const chartRefs = useRef<{ @@ -338,6 +338,6 @@ const DashboardAllCharts = forwardRef< ); }); -DashboardAllCharts.displayName = 'DashboardAllCharts'; +DashboardExportCharts.displayName = 'DashboardExportCharts'; -export default DashboardAllCharts; +export default DashboardExportCharts; diff --git a/src/components/pages/dashboard/export/DashboardExportStats.tsx b/src/components/pages/dashboard/export/DashboardExportStats.tsx new file mode 100644 index 00000000..9d783313 --- /dev/null +++ b/src/components/pages/dashboard/export/DashboardExportStats.tsx @@ -0,0 +1,201 @@ +import Alert from '@/components/Alert'; +import Card from '@/components/Card'; +import { formatNumber } from '@/lib/helper'; +import { + DashboardOverviewCharts, + DashboardStatisticsData, +} from '@/types/api/dashboard/dashboard'; +import { Icon } from '@iconify/react'; +import { forwardRef, useImperativeHandle, useRef } from 'react'; +interface DashboardStatsProps { + data: DashboardStatisticsData[]; +} +export type DashboardExportStatsRef = { + getStatsRefs: () => { + key: string; + ref: HTMLDivElement | null; + label: string; + }[]; + getContainerRef: () => HTMLDivElement | null; +}; + +// Konfigurasi untuk setiap kartu +const CARD_CONFIG = [ + { + key: 'HPP Global', + icon: 'heroicons:banknotes', + alertColor: 'warning' as const, + suffix: ' /Kg', + prefix: 'RP ', + }, + { + key: 'Avg. Selling Price', + icon: 'heroicons:document-currency-dollar', + alertColor: 'success' as const, + suffix: ' /Kg', + prefix: '', + }, + { + key: 'FCR', + icon: 'heroicons:clipboard-document-list', + alertColor: 'info' as const, + suffix: '', + prefix: '', + }, + { + key: 'Mortality', + icon: 'heroicons:exclamation-triangle', + alertColor: 'error' as const, + suffix: ' %', + prefix: '', + }, +]; + +const DashboardExportStats = forwardRef< + DashboardExportStatsRef, + DashboardStatsProps +>(({ data }, ref) => { + const containerRef = useRef(null); + // Helper to get trend icon and color + const getTrendDisplay = (percent: number) => { + const isPositive = percent >= 0; + return { + icon: isPositive + ? 'heroicons:arrow-trending-up' + : 'heroicons:arrow-trending-down', + color: isPositive ? 'text-[#008000]' : 'text-[#FF3A3A]', + value: Math.abs(percent), + }; + }; + + // Helper to format value + const formatValue = (value: number, prefix: string, suffix: string) => { + return ( + <> + {prefix} + {formatNumber(value)} + {suffix && ( + + {suffix} + + )} + + ); + }; + + // Expose container ref through imperative handle + useImperativeHandle(ref, () => ({ + getStatsRefs: () => [], + getContainerRef: () => containerRef.current, + })); + + return ( +
    + {CARD_CONFIG.map((config) => { + // Find matching data from API + const cardData = data.find((item) => item.label === config.key); + + if (!cardData) { + // Show placeholder card for missing data (FCR & Mortality) + return ( + +
    + From last month +
    +
    + Filter Required +
    +
    + } + > +
    + + + +
    +

    + {config.key} +

    +

    + ******** +

    +
    +
    + + ); + } + + const trend = getTrendDisplay(cardData.percent_last_month); + + return ( + +
    + From last month +
    +
    + + {trend.value}% +
    +
    + } + > +
    + + + +
    +

    + {cardData.label} +

    +

    + {formatValue(cardData.value, config.prefix, config.suffix)} +

    +
    +
    + + ); + })} +
    + ); +}); + +DashboardExportStats.displayName = 'DashboardExportStats'; + +export default DashboardExportStats; diff --git a/src/components/pages/dashboard/export/DashboardPDF.ts b/src/components/pages/dashboard/export/DashboardPDF.ts index 17c5bde4..8b4c7e6a 100644 --- a/src/components/pages/dashboard/export/DashboardPDF.ts +++ b/src/components/pages/dashboard/export/DashboardPDF.ts @@ -3,18 +3,19 @@ import { toPng } from 'html-to-image'; import toast from 'react-hot-toast'; import { formatDate } from '@/lib/helper'; import { DashboardFilterType } from '@/components/pages/dashboard/filter/DashboardProductionFilter.schema'; -import { DashboardAllChartsRef } from '@/components/pages/dashboard/chart/DashboardAllCharts'; +import { DashboardExportChartsRef } from '@/components/pages/dashboard/export/DashboardExportCharts'; +import { DashboardExportStatsRef } from '@/components/pages/dashboard/export/DashboardExportStats'; interface DashboardPDFExportParams { filterValues: DashboardFilterType; - statsRef: React.RefObject; - allChartsRef: React.RefObject; + allStatsRef: React.RefObject; + allChartsRef: React.RefObject; setExporting: (value: boolean) => void; } export const generateDashboardPDF = async ({ filterValues, - statsRef, + allStatsRef, allChartsRef, setExporting, }: DashboardPDFExportParams): Promise => { @@ -168,31 +169,34 @@ export const generateDashboardPDF = async ({ yPosition += 10; // Capture and add stats if available - if (statsRef.current) { - const statsImage = await toPng(statsRef.current, { - quality: 1, - pixelRatio: 2, - }); - const statsImgProps = pdf.getImageProperties(statsImage); - const statsWidth = pageWidth - 2 * margin; - const statsHeight = - (statsImgProps.height * statsWidth) / statsImgProps.width; + if (allStatsRef.current) { + const statsContainer = allStatsRef.current.getContainerRef(); + if (statsContainer) { + const statsImage = await toPng(statsContainer, { + quality: 1, + pixelRatio: 2, + }); + const statsImgProps = pdf.getImageProperties(statsImage); + const statsWidth = pageWidth - 2 * margin; + const statsHeight = + (statsImgProps.height * statsWidth) / statsImgProps.width; - // Check if we need a new page - if (yPosition + statsHeight > pageHeight - margin) { - pdf.addPage(); - yPosition = margin; + // Check if we need a new page + if (yPosition + statsHeight > pageHeight - margin) { + pdf.addPage(); + yPosition = margin; + } + + pdf.addImage( + statsImage, + 'PNG', + margin, + yPosition, + statsWidth, + statsHeight + ); + yPosition += statsHeight + 10; } - - pdf.addImage( - statsImage, - 'PNG', - margin, - yPosition, - statsWidth, - statsHeight - ); - yPosition += statsHeight + 10; } if (allChartsRef.current) { diff --git a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx index b479eced..d2999544 100644 --- a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx +++ b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx @@ -3,94 +3,104 @@ import { DashboardMeta } from '@/types/api/dashboard/dashboard'; const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { return ( -
    +
    {/* Header with title skeleton */} -
    +
    Performance{' '}
    {/* Chart area with axes skeleton */} -
    - {/* Main chart container */} -
    - {/* Y-axis skeleton (left side) */} -
    - {[1, 2, 3, 4, 5, 6].map((item) => ( -
    - ))} -
    - - {/* Chart content area */} -
    - {/* Empty state centered in chart area */} -
    - {!meta?.filters && ( - <> - {/* Filter icon */} -
    - +
    + {/* Chart content area */} +
    + {/* Empty state centered in chart area */} +
    + {!meta?.filters && ( + <> + {/* Filter icon */} +
    +
    +
    + +
    +
    - {/* Empty state text */} -

    - No Filters Selected -

    -

    - Please choose filters to narrow down your results and make - your search easier. -

    - - )} - {meta?.filters && ( - <> - {/* Filter icon */} -
    + {/* Empty state text */} +

    + No Filters Selected +

    +

    + Please choose filters to narrow down your results and make + your search easier. +

    + + )} + {meta?.filters && ( + <> + {/* Filter icon */} +
    +
    +
    - {/* Empty state text */} -

    - Data Not Yet Available -

    -

    - Please change your filters to get the data. -

    - - )} + {/* Empty state text */} +

    + Data Not Yet Available +

    +

    + Please change your filters to get the data. +

    + + )} +
    + +
    +
    +
    - - {/* Placeholder for chart height */} -
    - - {/* X-axis skeleton (bottom) */} -
    - {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((item) => ( +
    + {[1, 2, 3, 4].map((item) => (
    + className='flex items-center w-full h-[16px] gap-[16px]' + > +
    +
    +
    ))}
    + + {/* X-axis skeleton (bottom) */} +
    + {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((item) => ( +
    + ))} +
    +
    +
    +
    diff --git a/src/stores/ui/slices/navbar.slice.ts b/src/stores/ui/slices/navbar.slice.ts new file mode 100644 index 00000000..2db6f547 --- /dev/null +++ b/src/stores/ui/slices/navbar.slice.ts @@ -0,0 +1,22 @@ +'use client'; + +import { ReactNode } from 'react'; +import { StateCreator } from 'zustand'; +import { UIStore } from '@/types/stores'; + +type NavbarActionsSlice = { + navbarActions: ReactNode | null; + setNavbarActions: (actions: ReactNode) => void; + clearNavbarActions: () => void; +}; + +export const createNavbarActionsSlice: StateCreator< + UIStore, + [], + [], + NavbarActionsSlice +> = (set) => ({ + navbarActions: null, + setNavbarActions: (actions) => set({ navbarActions: actions }), + clearNavbarActions: () => set({ navbarActions: null }), +}); diff --git a/src/stores/ui/ui.store.ts b/src/stores/ui/ui.store.ts index 05adbb9b..46c70283 100644 --- a/src/stores/ui/ui.store.ts +++ b/src/stores/ui/ui.store.ts @@ -7,6 +7,7 @@ import { UIStore } from '@/types/stores'; import { createMainUiSlice } from '@/stores/ui/slices/main.slice'; import { createDrawerUISlice } from '@/stores/ui/slices/drawer.slice'; import { createTableUISlice } from '@/stores/ui/slices/table.slice'; +import { createNavbarActionsSlice } from '@/stores/ui/slices/navbar.slice'; export const useUiStore = create()( devtools( @@ -15,6 +16,7 @@ export const useUiStore = create()( ...createMainUiSlice(...args), ...createDrawerUISlice(...args), ...createTableUISlice(...args), + ...createNavbarActionsSlice(...args), }), { name: 'ui-cache', diff --git a/src/types/stores.d.ts b/src/types/stores.d.ts index 5b0be6f3..47d2c1fd 100644 --- a/src/types/stores.d.ts +++ b/src/types/stores.d.ts @@ -32,7 +32,17 @@ type TableUISlice = { resetSearchValue: () => void; }; -export type UIStore = MainUiSlice & DrawerUISlice & TableUISlice; +// Navbar Actions Slice +type NavbarActionsSlice = { + navbarActions: ReactNode | null; + setNavbarActions: (actions: ReactNode) => void; + clearNavbarActions: () => void; +}; + +export type UIStore = MainUiSlice & + DrawerUISlice & + TableUISlice & + NavbarActionsSlice; type ProductionStandardFormSlice = { formData: { From 46cfc2539eb8930ac11da3432c86aede8de6d847 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Wed, 28 Jan 2026 17:55:57 +0700 Subject: [PATCH 2/7] fix(FE): remove unused import --- src/components/pages/dashboard/DashboardProduction.tsx | 5 +---- .../pages/dashboard/export/DashboardExportStats.tsx | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 3631d4ca..c3cfaf52 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -4,10 +4,7 @@ import Button from '@/components/Button'; import { Icon } from '@iconify/react'; import Modal, { useModal } from '@/components/Modal'; import DateInput from '@/components/input/DateInput'; -import SelectInput, { - OptionType, - useSelect, -} from '@/components/input/SelectInput'; +import { OptionType, useSelect } from '@/components/input/SelectInput'; import { useState, useEffect, useRef, useCallback } from 'react'; import useSWR from 'swr'; import { DashboardApi } from '@/services/api/dashboard'; diff --git a/src/components/pages/dashboard/export/DashboardExportStats.tsx b/src/components/pages/dashboard/export/DashboardExportStats.tsx index 9d783313..3f452d9c 100644 --- a/src/components/pages/dashboard/export/DashboardExportStats.tsx +++ b/src/components/pages/dashboard/export/DashboardExportStats.tsx @@ -1,10 +1,7 @@ import Alert from '@/components/Alert'; import Card from '@/components/Card'; import { formatNumber } from '@/lib/helper'; -import { - DashboardOverviewCharts, - DashboardStatisticsData, -} from '@/types/api/dashboard/dashboard'; +import { DashboardStatisticsData } from '@/types/api/dashboard/dashboard'; import { Icon } from '@iconify/react'; import { forwardRef, useImperativeHandle, useRef } from 'react'; interface DashboardStatsProps { From dce913815e485e83121d126b0c65329023294e76 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Thu, 29 Jan 2026 10:23:58 +0700 Subject: [PATCH 3/7] chore: adjust styling in Dashboard related components --- .../pages/dashboard/DashboardProduction.tsx | 13 +++++-------- .../pages/dashboard/chart/DashboardStats.tsx | 17 ++++++++--------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index c3cfaf52..7339e831 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -441,10 +441,6 @@ const DashboardProduction = () => { value={formik.values.startDate} errorMessage={formik.errors.startDate} onChange={formik.handleChange} - className={{ - inputWrapper: - 'rounded-[8px] px-[12px] py-[10px] text-sm border-[#18181B]/10', - }} isError={ Boolean(formik.errors.startDate) && Boolean(formik.touched.startDate) @@ -568,7 +564,6 @@ const DashboardProduction = () => { Boolean(formik.touched.location) } className={{ - label: 'mb-[8px] text-xs font-semibold', select: 'rounded-[8px] text-sm border-[#18181B]/10', }} /> @@ -742,9 +737,11 @@ const DashboardProduction = () => {
    )} -
    - -
    + {formErrorList.length > 0 && ( +
    + +
    + )} {/* Action Buttons */}
    diff --git a/src/components/pages/dashboard/chart/DashboardStats.tsx b/src/components/pages/dashboard/chart/DashboardStats.tsx index 13167ba3..f17e18b0 100644 --- a/src/components/pages/dashboard/chart/DashboardStats.tsx +++ b/src/components/pages/dashboard/chart/DashboardStats.tsx @@ -130,8 +130,7 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { { }} variant='bordered' footer={ -
    -
    +
    +
    From last month
    {trend.value}% @@ -156,15 +155,15 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { -
    -

    +
    +

    {cardData.label}

    -

    +

    {formatValue(cardData.value, config.prefix, config.suffix)}

    From 6c2baca807484f13846ef77539367a66c1407550 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 29 Jan 2026 14:50:16 +0700 Subject: [PATCH 4/7] fix(FE): fixing classname using dynamic value --- .../pages/dashboard/DashboardProduction.tsx | 489 +++++++++--------- .../dashboard/chart/DashboardLineChart.tsx | 80 +-- .../pages/dashboard/chart/DashboardStats.tsx | 29 +- .../export/DashboardExportCharts.tsx | 3 +- .../dashboard/export/DashboardExportStats.tsx | 39 +- .../skeleton/DashboardLineChartSkeleton.tsx | 49 +- 6 files changed, 350 insertions(+), 339 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 7339e831..b2149771 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -211,7 +211,7 @@ const DashboardProduction = () => { useEffect(() => { setNavbarActions( -
    +
    { variant='outline' color='none' className={cn( - 'padding-[12px] rounded-[8px] max-h-[40px] font-semibold text-[14px] gap-[6px]', + 'p-2 rounded-lg font-semibold text-sm gap-1.5', 'text-sm text-base-content/50 border border-base-content/10 shadow-button-soft' )} > Export -
    +
    } className={{ - content: 'w-full', + content: 'w-full mt-1 p-0', }} > - + @@ -270,8 +272,8 @@ const DashboardProduction = () => { return ( <> -
    -
    +
    +
    { variant='outline' color='none' className={cn( - 'padding-[12px] rounded-[8px] max-h-[40px] font-semibold text-[14px] gap-[6px]', + 'p-2 rounded-lg font-semibold text-sm gap-1.5', 'text-sm text-base-content/50 border border-base-content/10 shadow-button-soft' )} > @@ -296,18 +298,21 @@ const DashboardProduction = () => { icon='heroicons:cloud-arrow-down' /> Export -
    +
    } className={{ - content: 'w-full', + content: + 'w-full mt-1 p-0 shadow-button-soft border border-base-content/10 rounded-lg', }} > - + @@ -405,107 +410,106 @@ const DashboardProduction = () => { ref={filterModal.ref} className={{ modal: 'p-0', - modalBox: 'p-0 rounded-xl', + modalBox: 'p-0 rounded-[14px]', }} > -
    +
    {/* Modal Header */} -
    -
    +
    +
    -

    Filter Data

    +

    Filter Data

    - {/* Rentang Waktu */} -
    - -
    - -
    - — +
    + {/* Rentang Waktu */} +
    + +
    + +
    +
    -
    -
    - {/* Analysis Mode */} -
    - - { - formik.handleChange(e); - setAnalysisMode(e.target.value as 'OVERVIEW' | 'COMPARISON'); - // Reset all dependent fields when analysis mode changes - formik.setFieldValue('location', []); - formik.setFieldValue('flock', []); - formik.setFieldValue('kandang', []); - formik.setFieldValue('comparisonType', ''); - setSelectedLocationIds([]); - }} - color='primary' - className={{ - wrapper: - 'w-full flex flex-row items-center min-h-[45px] font-medium text-[#18181B]/50', - }} - > - + + { + formik.handleChange(e); + setAnalysisMode( + e.target.value as 'OVERVIEW' | 'COMPARISON' + ); + // Reset all dependent fields when analysis mode changes + formik.setFieldValue('location', []); + formik.setFieldValue('flock', []); + formik.setFieldValue('kandang', []); + formik.setFieldValue('comparisonType', ''); + setSelectedLocationIds([]); + }} color='primary' - value='OVERVIEW' - label='Performance Overview' - /> - - -
    + className={{ + wrapper: + 'w-full flex flex-row items-center font-medium text-base-content/50', + radioWrapper: 'w-full grid grid-cols-2 gap-0 p-0', + }} + > + + + +
    - {formik.values.analysisMode === 'COMPARISON' && ( -
    + {formik.values.analysisMode === 'COMPARISON' && ( { Boolean(formik.touched.comparisonType) } className={{ - label: 'mb-[8px] text-xs font-semibold', - select: 'rounded-[8px] text-sm border-[#18181B]/10', + select: 'rounded-lg text-sm border-base-content/10', }} /> -
    - )} + )} - {/* Location */} -
    + {/* Location */} {comparisonTypeOptions.find( (option) => option.value === formik.values.comparisonType )?.value === 'FARM' ? ( @@ -564,7 +565,7 @@ const DashboardProduction = () => { Boolean(formik.touched.location) } className={{ - select: 'rounded-[8px] text-sm border-[#18181B]/10', + select: 'rounded-lg text-sm border-base-content/10', }} /> ) : ( @@ -595,166 +596,164 @@ const DashboardProduction = () => { Boolean(formik.touched.location) } className={{ - label: 'mb-[8px] text-xs font-semibold', - select: 'rounded-[8px] text-sm border-[#18181B]/10', + select: 'rounded-lg text-sm border-base-content/10', }} /> )} + + {/* Flock */} + {!( + formik.values.analysisMode === 'COMPARISON' && + !( + formik.values.comparisonType === 'FLOCK' || + formik.values.comparisonType === 'KANDANG' + ) + ) && ( + <> + {comparisonTypeOptions.find( + (option) => option.value === formik.values.comparisonType + )?.value === 'FLOCK' ? ( + + formik.setFieldValue('flock', selected) + } + errorMessage={formik.errors.flock as string} + onInputChange={setInputValueFlock} + onMenuScrollToBottom={loadMoreFlock} + options={flockOptions} + isLoading={isLoadingFlockOptions} + isError={ + Boolean(formik.errors.flock) && + Boolean(formik.touched.flock) + } + className={{ + select: 'rounded-lg text-sm border-base-content/10', + }} + /> + ) : ( + + formik.setFieldValue('flock', selected) + } + errorMessage={formik.errors.flock as string} + onInputChange={setInputValueFlock} + onMenuScrollToBottom={loadMoreFlock} + options={flockOptions} + isLoading={isLoadingFlockOptions} + isError={ + Boolean(formik.errors.flock) && + Boolean(formik.touched.flock) + } + className={{ + select: 'rounded-lg text-sm border-base-content/10', + }} + /> + )} + + )} + + {/* Kandang */} + {!( + formik.values.analysisMode === 'COMPARISON' && + !(formik.values.comparisonType === 'KANDANG') + ) && ( + <> + {comparisonTypeOptions.find( + (option) => option.value === formik.values.comparisonType + )?.value === 'KANDANG' ? ( + + formik.setFieldValue('kandang', selected) + } + errorMessage={formik.errors.kandang as string} + onInputChange={setInputValueKandang} + onMenuScrollToBottom={loadMoreKandang} + options={kandangOptions} + isLoading={isLoadingKandangOptions} + isError={ + Boolean(formik.errors.kandang) && + Boolean(formik.touched.kandang) + } + className={{ + select: 'rounded-lg text-sm border-base-content/10', + }} + /> + ) : ( + + formik.setFieldValue('kandang', selected) + } + errorMessage={formik.errors.kandang as string} + onInputChange={setInputValueKandang} + onMenuScrollToBottom={loadMoreKandang} + options={kandangOptions} + isLoading={isLoadingKandangOptions} + isError={ + Boolean(formik.errors.kandang) && + Boolean(formik.touched.kandang) + } + className={{ + select: 'rounded-lg text-sm border-base-content/10', + }} + /> + )} + + )} + + {formErrorList.length > 0 && ( +
    + +
    + )}
    - {/* Flock */} - {!( - formik.values.analysisMode === 'COMPARISON' && - !( - formik.values.comparisonType === 'FLOCK' || - formik.values.comparisonType === 'KANDANG' - ) - ) && ( -
    - {comparisonTypeOptions.find( - (option) => option.value === formik.values.comparisonType - )?.value === 'FLOCK' ? ( - - formik.setFieldValue('flock', selected) - } - errorMessage={formik.errors.flock as string} - onInputChange={setInputValueFlock} - onMenuScrollToBottom={loadMoreFlock} - options={flockOptions} - isLoading={isLoadingFlockOptions} - isError={ - Boolean(formik.errors.flock) && - Boolean(formik.touched.flock) - } - className={{ - label: 'mb-[8px] text-xs font-semibold', - select: 'rounded-[8px] text-sm border-[#18181B]/10', - }} - /> - ) : ( - - formik.setFieldValue('flock', selected) - } - errorMessage={formik.errors.flock as string} - onInputChange={setInputValueFlock} - onMenuScrollToBottom={loadMoreFlock} - options={flockOptions} - isLoading={isLoadingFlockOptions} - isError={ - Boolean(formik.errors.flock) && - Boolean(formik.touched.flock) - } - className={{ - label: 'mb-[8px] text-xs font-semibold', - select: 'rounded-[8px] text-sm border-[#18181B]/10', - }} - /> - )} -
    - )} - - {/* Kandang */} - {!( - formik.values.analysisMode === 'COMPARISON' && - !(formik.values.comparisonType === 'KANDANG') - ) && ( -
    - {comparisonTypeOptions.find( - (option) => option.value === formik.values.comparisonType - )?.value === 'KANDANG' ? ( - - formik.setFieldValue('kandang', selected) - } - errorMessage={formik.errors.kandang as string} - onInputChange={setInputValueKandang} - onMenuScrollToBottom={loadMoreKandang} - options={kandangOptions} - isLoading={isLoadingKandangOptions} - isError={ - Boolean(formik.errors.kandang) && - Boolean(formik.touched.kandang) - } - className={{ - label: 'mb-[8px] text-xs font-semibold', - select: 'rounded-[8px] text-sm border-[#18181B]/10', - }} - /> - ) : ( - - formik.setFieldValue('kandang', selected) - } - errorMessage={formik.errors.kandang as string} - onInputChange={setInputValueKandang} - onMenuScrollToBottom={loadMoreKandang} - options={kandangOptions} - isLoading={isLoadingKandangOptions} - isError={ - Boolean(formik.errors.kandang) && - Boolean(formik.touched.kandang) - } - className={{ - label: 'mb-[8px] text-xs font-semibold', - select: 'rounded-[8px] text-sm border-[#18181B]/10', - }} - /> - )} -
    - )} - - {formErrorList.length > 0 && ( -
    - -
    - )} - {/* Action Buttons */} -
    +
    diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index 6a419cb4..ab2c347e 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -147,11 +147,12 @@ const DashboardLineChart = ({ return ( -
    +
    Performance{' '} setOpen(!open)} > {chartTypeLabels[chartData]}{' '} -
    +
    } - className={{ - content: '', - }} controlled={open} > - + { setChartData('body_weight'); setOpen(!open); @@ -194,7 +195,7 @@ const DashboardLineChart = ({ /> { setChartData('performance'); setOpen(!open); @@ -202,7 +203,7 @@ const DashboardLineChart = ({ /> { setChartData('fcr'); setOpen(!open); @@ -210,7 +211,7 @@ const DashboardLineChart = ({ /> { setChartData('quality_control'); setOpen(!open); @@ -218,7 +219,7 @@ const DashboardLineChart = ({ /> { setChartData('deplesi'); setOpen(!open); @@ -267,14 +268,14 @@ const DashboardLineChart = ({ }} variant='outline' color='none' - className={`flex items-center gap-[8px] px-[12px] py-[10px] rounded-[8px] border transition-colors ${ + className={`flex items-center gap-2 p-3 rounded-lg border transition-colors ${ isVisible - ? 'border-[#18181B]/10 hover:bg-[#18181B]/4' - : 'border-[#18181B]/10 bg-[#18181B]/4' + ? 'border-base-content/10 hover:bg-base-content/4' + : 'border-base-content/10 bg-base-content/4' }`} >
    {series.label} @@ -295,7 +296,7 @@ const DashboardLineChart = ({ icon='heroicons:eye' width={16} height={16} - className='text-[#18181B]/40' + className='text-base-content/40' /> ); @@ -371,7 +372,8 @@ const DashboardLineChart = ({ fontWeight: 600, }} label={ - chartData === 'body_weight' || chartData === 'performance' + (chartData === 'body_weight' || chartData === 'performance') && + analysisMode === 'OVERVIEW' ? { value: chartData === 'body_weight' @@ -379,7 +381,7 @@ const DashboardLineChart = ({ : 'Percentage', position: 'insideLeft', angle: -90, - offset: 25, + offset: 5, style: { fontSize: 12, fill: '#18181B', @@ -387,7 +389,20 @@ const DashboardLineChart = ({ fontWeight: 600, }, } - : undefined + : analysisMode === 'COMPARISON' + ? { + value: 'Percentage', + position: 'insideLeft', + angle: -90, + offset: 5, + style: { + fontSize: 12, + fill: '#18181B', + opacity: 0.2, + fontWeight: 600, + }, + } + : undefined } tickLine={false} axisLine={{ stroke: '#C1C1C180', opacity: 0.5 }} @@ -508,6 +523,7 @@ const DashboardLineChart = ({ return Array.from(tickSet).sort((a, b) => a - b); })()} + tickFormatter={(value) => formatNumber(Number(value))} /> `Week ${value}`} content={(props) => { return ( -
    -

    +

    +

    {analysisMode === 'OVERVIEW' ? selectedKandang ? selectedKandang.label || 'Overview Performance' @@ -563,11 +579,11 @@ const DashboardLineChart = ({ return (

  • - +
    -

    +

    Week {props.label}

    @@ -705,8 +721,8 @@ const DashboardLineChart = ({ return (
    {/* Chart icon */} -
    -
    +
    +
    {/* Empty state text */} -

    +

    Data Not Yet Available

    -

    +

    Please change your filters to get the data.

    diff --git a/src/components/pages/dashboard/chart/DashboardStats.tsx b/src/components/pages/dashboard/chart/DashboardStats.tsx index f17e18b0..331547b0 100644 --- a/src/components/pages/dashboard/chart/DashboardStats.tsx +++ b/src/components/pages/dashboard/chart/DashboardStats.tsx @@ -21,7 +21,7 @@ const CARD_CONFIG = [ key: 'Avg. Selling Price', icon: 'heroicons:document-currency-dollar', alertColor: 'success' as const, - suffix: ' /Kg', + suffix: ' /Kg Telur', prefix: '', }, { @@ -60,7 +60,7 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { {prefix} {formatNumber(value)} {suffix && ( - + {suffix} )} @@ -69,7 +69,7 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { }; return ( -
    +
    {CARD_CONFIG.map((config) => { // Find matching data from API const cardData = data.find((item) => item.label === config.key); @@ -80,42 +80,41 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { -
    +
    +
    From last month
    -
    +
    Filter Required
    } > -
    +
    -

    +

    {config.key}

    -

    +

    ********

    @@ -134,7 +133,7 @@ const DashboardStats = ({ data }: DashboardStatsProps) => { body: 'p-0', wrapperContent: 'h-full flex flex-col items-between justify-between', - footer: '!mt-0', + footer: 'mt-0!', }} variant='bordered' footer={ diff --git a/src/components/pages/dashboard/export/DashboardExportCharts.tsx b/src/components/pages/dashboard/export/DashboardExportCharts.tsx index c89014d8..ba0b2fe2 100644 --- a/src/components/pages/dashboard/export/DashboardExportCharts.tsx +++ b/src/components/pages/dashboard/export/DashboardExportCharts.tsx @@ -189,7 +189,8 @@ const DashboardExportCharts = forwardRef< > diff --git a/src/components/pages/dashboard/export/DashboardExportStats.tsx b/src/components/pages/dashboard/export/DashboardExportStats.tsx index 3f452d9c..aebdc751 100644 --- a/src/components/pages/dashboard/export/DashboardExportStats.tsx +++ b/src/components/pages/dashboard/export/DashboardExportStats.tsx @@ -72,7 +72,7 @@ const DashboardExportStats = forwardRef< {prefix} {formatNumber(value)} {suffix && ( - + {suffix} )} @@ -87,7 +87,7 @@ const DashboardExportStats = forwardRef< })); return ( -
    +
    {CARD_CONFIG.map((config) => { // Find matching data from API const cardData = data.find((item) => item.label === config.key); @@ -102,37 +102,37 @@ const DashboardExportStats = forwardRef< body: 'p-0', wrapperContent: 'h-full flex flex-col items-between justify-between', - footer: '!mt-0', + footer: 'mt-0!', }} variant='bordered' footer={ -
    -
    +
    +
    From last month
    -
    +
    Filter Required
    } > -
    +
    -

    +

    {config.key}

    -

    +

    ********

    @@ -147,21 +147,20 @@ const DashboardExportStats = forwardRef< -
    +
    +
    From last month
    {trend.value}% @@ -173,15 +172,15 @@ const DashboardExportStats = forwardRef<
    -

    +

    {cardData.label}

    -

    +

    {formatValue(cardData.value, config.prefix, config.suffix)}

    diff --git a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx index d2999544..66c76071 100644 --- a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx +++ b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx @@ -3,15 +3,15 @@ import { DashboardMeta } from '@/types/api/dashboard/dashboard'; const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { return ( -
    +
    {/* Header with title skeleton */} -
    +
    Performance{' '}
    @@ -24,9 +24,9 @@ const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { {!meta?.filters && ( <> {/* Filter icon */} -
    -
    -
    +
    +
    +
    {
    {/* Empty state text */} -

    +

    No Filters Selected

    -

    +

    Please choose filters to narrow down your results and make your search easier.

    @@ -50,8 +50,8 @@ const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { {meta?.filters && ( <> {/* Filter icon */} -
    -
    +
    +
    {
    {/* Empty state text */} -

    +

    Data Not Yet Available

    -

    +

    Please change your filters to get the data.

    )}
    -
    -
    -
    +
    +
    +
    -
    +
    {[1, 2, 3, 4].map((item) => ( -
    -
    -
    +
    +
    +
    ))}
    {/* X-axis skeleton (bottom) */} -
    +
    {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((item) => (
    ))}
    -
    -
    +
    +
    From b305d43ce6d759a4c5589ca6f2421deca19870ad Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 29 Jan 2026 14:56:52 +0700 Subject: [PATCH 5/7] fix(FE): fixing classname using dynamic value --- src/components/pages/dashboard/DashboardProduction.tsx | 4 ++-- src/components/pages/dashboard/chart/DashboardLineChart.tsx | 2 +- .../pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index b2149771..ad74413b 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -743,11 +743,11 @@ const DashboardProduction = () => {
    {/* Action Buttons */} -
    +
    diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index ab2c347e..76d18a1e 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -722,7 +722,7 @@ const DashboardLineChart = ({
    {/* Chart icon */}
    -
    +
    { <> {/* Filter icon */}
    -
    +
    Date: Thu, 29 Jan 2026 15:10:18 +0700 Subject: [PATCH 6/7] fix(FE): fixing rounded value --- src/components/pages/dashboard/DashboardProduction.tsx | 2 +- src/components/pages/dashboard/chart/DashboardLineChart.tsx | 2 +- .../pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index ad74413b..43c66129 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -410,7 +410,7 @@ const DashboardProduction = () => { ref={filterModal.ref} className={{ modal: 'p-0', - modalBox: 'p-0 rounded-[14px]', + modalBox: 'p-0 rounded-[3.5rem]', }} >
    diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index 76d18a1e..85b0f683 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -721,7 +721,7 @@ const DashboardLineChart = ({ return (
    {/* Chart icon */} -
    +
    { <> {/* Filter icon */}
    -
    +
    { {meta?.filters && ( <> {/* Filter icon */} -
    +
    Date: Thu, 29 Jan 2026 16:33:02 +0700 Subject: [PATCH 7/7] fix(FE): fixing rounded value --- src/components/pages/dashboard/DashboardProduction.tsx | 2 +- src/components/pages/dashboard/chart/DashboardLineChart.tsx | 2 +- .../pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 43c66129..2085d943 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -410,7 +410,7 @@ const DashboardProduction = () => { ref={filterModal.ref} className={{ modal: 'p-0', - modalBox: 'p-0 rounded-[3.5rem]', + modalBox: 'p-0 rounded-[0.875rem]', }} >
    diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index 85b0f683..092e4bca 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -721,7 +721,7 @@ const DashboardLineChart = ({ return (
    {/* Chart icon */} -
    +
    { <> {/* Filter icon */}
    -
    +
    { {meta?.filters && ( <> {/* Filter icon */} -
    +