From d8361be28fcb6bff6237311f2060e85bbef2da16 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Wed, 28 Jan 2026 14:45:48 +0700 Subject: [PATCH 01/65] refactor(FE): Replace UniformityTable with Uniformity page --- .../pages/production/uniformity/UniformityPageWrapper.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityPageWrapper.tsx b/src/components/pages/production/uniformity/UniformityPageWrapper.tsx index ac14ebb5..07f313b6 100644 --- a/src/components/pages/production/uniformity/UniformityPageWrapper.tsx +++ b/src/components/pages/production/uniformity/UniformityPageWrapper.tsx @@ -3,7 +3,7 @@ import { usePathname, useRouter } from 'next/navigation'; import Drawer from '@/components/Drawer'; import React, { ReactNode } from 'react'; -import UniformityTable from '@/components/pages/production/uniformity/UniformityTable'; +import Uniformity from '@/app/production/uniformity/page'; import { useUiStore } from '@/stores/ui/ui.store'; export default function UniformityPageWrapper({ @@ -40,8 +40,8 @@ export default function UniformityPageWrapper({ return ( <> -
- +
+
Date: Wed, 28 Jan 2026 15:10:36 +0700 Subject: [PATCH 02/65] refactor(FE): Refactor Uniformity header and add filter badge --- .../production/uniformity/UniformityChart.tsx | 2 +- .../production/uniformity/UniformityTable.tsx | 177 +++++++++++++----- 2 files changed, 135 insertions(+), 44 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityChart.tsx b/src/components/pages/production/uniformity/UniformityChart.tsx index 6ddf50d3..db37c8f1 100644 --- a/src/components/pages/production/uniformity/UniformityChart.tsx +++ b/src/components/pages/production/uniformity/UniformityChart.tsx @@ -101,7 +101,7 @@ const UniformityChart = ({ const shouldShowEmptyState = !isFiltered; return ( -
+
{ [] ); + // ===== CALCULATE FILTER COUNT ===== + const filterCount = useMemo(() => { + let count = 0; + + if (filterStartDate && filterEndDate) { + count += 1; + } + + if (filterLocation) { + count += 1; + } + + if (filterProjectFlock) { + count += 1; + } + + if (filterKandang) { + count += 1; + } + + return count; + }, [ + filterStartDate, + filterEndDate, + filterLocation, + filterProjectFlock, + filterKandang, + ]); + + const isFilterActive = filterCount > 0; + return ( <> -
-
- - - -
- -
- - - - - Export +
+
+
+ + - } - align='end' - > - - - - - + +
+ +
+ + + +
+ + + Export + +
+ + +
+ + } + > + + + +
-
-
- -
- -
+
+ +
+
From 3c96855b86ac6fc9903d0ff82af790f58aa30c97 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Wed, 28 Jan 2026 15:59:18 +0700 Subject: [PATCH 03/65] refactor(FE): Replace Card with section in UniformityTable --- .../pages/production/uniformity/UniformityTable.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index d1ad7343..8b549458 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -1039,12 +1039,7 @@ const UniformityTable = () => { - +
data={isResponseSuccess(uniformities) ? uniformities?.data : []} columns={uniformityColumns} @@ -1457,7 +1452,7 @@ const UniformityTable = () => { selectedRowIds={selectedRowIds} onClose={handleCloseFab} /> - +
); }; From 1a800a1157a100eec925a1cb8cbebfa7cd3b24ce Mon Sep 17 00:00:00 2001 From: rstubryan Date: Wed, 28 Jan 2026 16:14:26 +0700 Subject: [PATCH 04/65] refactor(FE): Refine drawer header and uniformity form styles --- src/components/helper/drawer/DrawerHeader.tsx | 12 +++++++++--- .../uniformity/form/UniformityForm.tsx | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/components/helper/drawer/DrawerHeader.tsx b/src/components/helper/drawer/DrawerHeader.tsx index f9d70a04..8bb635ae 100644 --- a/src/components/helper/drawer/DrawerHeader.tsx +++ b/src/components/helper/drawer/DrawerHeader.tsx @@ -58,6 +58,7 @@ const DrawerHeader = ({ if (leftIconOnClick) { return ( - {/* Error List Alert */} - {formErrorList.length > 0 && ( -
- -
- )} -
@@ -1387,6 +1380,18 @@ const UniformityTable = () => {
+
+ {/* Error List Alert */} + {formErrorList.length > 0 && ( +
+ +
+ )} +
+ {/* Action Buttons */}
- + No Filters Selected - + Please choose filters to narrow down your results and make your search easier. diff --git a/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx index 17ed7ee9..a72875f5 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx @@ -56,18 +56,19 @@ const UniformityGaugeChartSkeleton: React.FC<
-
-
- + No Filters Selected - + Please choose filters to narrow down your results and make your search easier. From 23402370b841649df23ead106e8d81b805c7e242 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 11:57:44 +0700 Subject: [PATCH 07/65] refactor(FE): Add rounded corners to uniformity components --- .../pages/production/uniformity/UniformityChart.tsx | 4 ++-- .../pages/production/uniformity/UniformityTable.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityChart.tsx b/src/components/pages/production/uniformity/UniformityChart.tsx index db37c8f1..a6d9833f 100644 --- a/src/components/pages/production/uniformity/UniformityChart.tsx +++ b/src/components/pages/production/uniformity/UniformityChart.tsx @@ -106,7 +106,7 @@ const UniformityChart = ({ title='Performance Overview ⓘ' variant='bordered' className={{ - wrapper: 'xl:col-span-1 2xl:col-span-3 w-full', + wrapper: 'xl:col-span-1 2xl:col-span-3 w-full rounded-xl', body: 'h-96', }} > @@ -125,7 +125,7 @@ const UniformityChart = ({ variant='bordered' title='Weekly Performance ⓘ' className={{ - wrapper: 'xl:col-span-1 2xl:col-span-1 w-full', + wrapper: 'xl:col-span-1 2xl:col-span-1 w-full rounded-xl', body: 'h-110', }} > diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index 86826b15..793a0fe2 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -1062,7 +1062,7 @@ const UniformityTable = () => { isResponseSuccess(uniformities) && uniformities?.data?.length === 0, }), - tableWrapperClassName: 'overflow-x-auto min-h-full ', + tableWrapperClassName: 'overflow-x-auto min-h-full rounded-xl', tableClassName: 'font-inter w-full table-auto min-h-full!', headerRowClassName: 'border-b border-b-gray-200', headerColumnClassName: From 2c8160f816fe49c3dcb6e98db3230c3c165be017 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 12:00:10 +0700 Subject: [PATCH 08/65] refactor(FE): Add padding to UniformityChart card bodies --- .../pages/production/uniformity/UniformityChart.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityChart.tsx b/src/components/pages/production/uniformity/UniformityChart.tsx index a6d9833f..84fa794b 100644 --- a/src/components/pages/production/uniformity/UniformityChart.tsx +++ b/src/components/pages/production/uniformity/UniformityChart.tsx @@ -107,7 +107,7 @@ const UniformityChart = ({ variant='bordered' className={{ wrapper: 'xl:col-span-1 2xl:col-span-3 w-full rounded-xl', - body: 'h-96', + body: 'h-96 p-4', }} >
@@ -126,7 +126,7 @@ const UniformityChart = ({ title='Weekly Performance ⓘ' className={{ wrapper: 'xl:col-span-1 2xl:col-span-1 w-full rounded-xl', - body: 'h-110', + body: 'h-110 p-4', }} > From 564d6d0da169b4f11607b21655bc5188bfb29927 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 13:58:42 +0700 Subject: [PATCH 09/65] refactor(FE): Add wrapperContent and refactor uniformity charts --- src/components/Card.tsx | 7 ++- .../production/uniformity/UniformityChart.tsx | 59 ++++++++++++------- .../skeleton/UniformityBarChartSkeleton.tsx | 2 +- 3 files changed, 44 insertions(+), 24 deletions(-) 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/pages/production/uniformity/UniformityChart.tsx b/src/components/pages/production/uniformity/UniformityChart.tsx index 84fa794b..0033e957 100644 --- a/src/components/pages/production/uniformity/UniformityChart.tsx +++ b/src/components/pages/production/uniformity/UniformityChart.tsx @@ -5,6 +5,7 @@ import UniformityGaugeChart from '@/components/pages/production/uniformity/chart import UniformityBarChartSkeleton from '@/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton'; import UniformityGaugeChartSkeleton from '@/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton'; import { Uniformity, type ChartData } from '@/types/api/production/uniformity'; +import { Icon } from '@iconify/react'; interface UniformityChartProps { uniformityData?: Uniformity | null; @@ -103,13 +104,23 @@ const UniformityChart = ({ return (
+
+
+ Performance Overview{' '} + +
+
{shouldShowEmptyState || !uniformityData || @@ -120,26 +131,30 @@ const UniformityChart = ({ )}
- {shouldShowEmptyState || !uniformityData || !gaugeChartData ? ( - + +
+
+ Weekly Performance{' '} + +
+
+ {shouldShowEmptyState || !uniformityData || !gaugeChartData ? ( -
- ) : ( - + ) : ( - - )} + )} +
); }; diff --git a/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx index 91c7c72d..b9d90dd9 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx @@ -90,7 +90,7 @@ const EmptyState = () => { const UniformityBarChartSkeleton = () => { return ( -
+
From 9817864c3ddfd6853cb0534263c7d9e86ef82746 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 14:04:35 +0700 Subject: [PATCH 10/65] refactor(FE): Reduce UniformityBarChartSkeleton min height --- .../uniformity/skeleton/UniformityBarChartSkeleton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx index b9d90dd9..fe7f9aff 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx @@ -90,7 +90,7 @@ const EmptyState = () => { const UniformityBarChartSkeleton = () => { return ( -
+
From 1ed83351e0ef1fd6e01ef472f1c139c382421a17 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 14:09:38 +0700 Subject: [PATCH 11/65] refacto(FE): Refine UniformityTableSkeleton styles and icon --- .../skeleton/UniformityTableSkeleton.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx index b90048a1..79f0117e 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx @@ -3,19 +3,20 @@ import { Icon } from '@iconify/react'; const UniformityTableSkeleton = () => { return ( -
-
-
- + No Data Available - + There is no uniformity data displayed. Enter uniformity check data to get started. From 4452b6fd03dcd9799ffca158ad52acd6ace3bd02 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 14:10:36 +0700 Subject: [PATCH 12/65] refactor(FE): Add spacing to UniformityTableSkeleton --- .../production/uniformity/skeleton/UniformityTableSkeleton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx index 79f0117e..08c1e0b5 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx @@ -3,7 +3,7 @@ import { Icon } from '@iconify/react'; const UniformityTableSkeleton = () => { return ( -
+
{/* Form Section */} -
-
+
{verifyUniformityResult ? (
diff --git a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx index df144c64..103fc791 100644 --- a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx @@ -241,23 +241,24 @@ const UniformityResultForm = () => { {/* Form Section */} -
-
+
{verifyUniformityResult ? (
-

Sampling and Range

+

+ Sampling and Range +

data={samplingTableData} columns={columnsSampling} @@ -270,7 +271,9 @@ const UniformityResultForm = () => {
-

Result

+

+ Result +

data={resultTableData} columns={resultColumns} From d9a1d340bb8ca04fa5cf3257ccd6f5286635c517 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 14:32:52 +0700 Subject: [PATCH 14/65] refactor(FE): Reduce vertical spacing in Uniformity components --- .../pages/production/uniformity/UniformityTable.tsx | 4 ++-- .../pages/production/uniformity/form/UniformityForm.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index 793a0fe2..be133c7c 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -1274,8 +1274,8 @@ const UniformityTable = () => {
-
-
+
+
- + Date: Thu, 29 Jan 2026 14:57:25 +0700 Subject: [PATCH 15/65] refactor(FE): Add badge color helpers for status and weight --- .../production/uniformity/uniformity-utils.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/components/pages/production/uniformity/uniformity-utils.ts b/src/components/pages/production/uniformity/uniformity-utils.ts index 340bb555..1b513de4 100644 --- a/src/components/pages/production/uniformity/uniformity-utils.ts +++ b/src/components/pages/production/uniformity/uniformity-utils.ts @@ -25,6 +25,20 @@ export const getWeightStatusText = (status: string): string => { return weightStatusTextMap[status] || status; }; +export const weightStatusBadgeColorMap: Record< + string, + 'success' | 'error' | 'neutral' | 'info' +> = { + ideal: 'success', + outside: 'error', +}; + +export const getWeightStatusBadgeColor = ( + status: string +): 'success' | 'error' | 'neutral' | 'info' => { + return weightStatusBadgeColorMap[status] || 'neutral'; +}; + export const statusColorMap: Record = { APPROVED: 'bg-[#00D39033]', Disetujui: 'bg-[#00D39033]', @@ -63,3 +77,29 @@ export const getStatusIndicatorColor = (status: string): string => { export const getStatusText = (status: string): string => { return statusTextMap[status] || status; }; + +export const statusBadgeColorMap: Record< + string, + 'success' | 'error' | 'neutral' | 'info' +> = { + APPROVED: 'success', + Disetujui: 'success', + approved: 'success', + disetujui: 'success', + REJECTED: 'error', + Ditolak: 'error', + rejected: 'error', + ditolak: 'error', + CREATED: 'neutral', + Pengajuan: 'neutral', + created: 'neutral', + pengajuan: 'neutral', + PENDING: 'neutral', + pending: 'neutral', +}; + +export const getStatusBadgeColor = ( + status: string +): 'success' | 'error' | 'neutral' | 'info' => { + return statusBadgeColorMap[status] || 'neutral'; +}; From 0e43957e6ea2bc9d735a35a792f3430a1808cdf7 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 14:58:09 +0700 Subject: [PATCH 16/65] refactor(FE): Replace Badge with StatusBadge in uniformity views --- .../production/uniformity/UniformityTable.tsx | 800 +++++++++--------- .../detail/UniformityDetailsPreview.tsx | 33 +- .../uniformity/form/UniformityResultForm.tsx | 33 +- 3 files changed, 406 insertions(+), 460 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index be133c7c..6cf28f02 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -19,6 +19,7 @@ import { isResponseSuccess } from '@/lib/api-helper'; import { type BaseApiResponse } from '@/types/api/api-general'; import Table from '@/components/Table'; import Badge from '@/components/Badge'; +import StatusBadge from '@/components/helper/StatusBadge'; import CheckboxInput from '@/components/input/CheckboxInput'; import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; @@ -45,6 +46,7 @@ import { getStatusColor, getStatusIndicatorColor, getStatusText, + getStatusBadgeColor, } from '@/components/pages/production/uniformity/uniformity-utils'; import { generateUniformityPDF } from '@/components/pages/production/uniformity/export/UniformityExportPDF'; import { generateUniformityExcel } from '@/components/pages/production/uniformity/export/UniformityExportExcel'; @@ -832,7 +834,7 @@ const UniformityTable = () => { }, cell: ({ row }) => { return ( -
+
{ { accessorKey: 'week', header: 'Tanggal (Week)', - cell: (props) => - `${formatDate(props.row.original.applied_at, 'DD MMM YYYY')} (${props.row.original.week})`, + cell: (props) => ( + + {`${formatDate(props.row.original.applied_at, 'DD MMM YYYY')} (${props.row.original.week})`} + + ), }, { accessorKey: 'status', @@ -872,20 +877,11 @@ const UniformityTable = () => { const uniformity = props.row.original; const status = uniformity.latest_approval?.action ?? uniformity.status; - return ( -
- - {getStatusText(status)} - -
- ); + + const badgeColor = getStatusBadgeColor(status); + const statusText = getStatusText(status); + + return ; }, }, { @@ -1039,425 +1035,413 @@ const UniformityTable = () => {
-
- - data={isResponseSuccess(uniformities) ? uniformities?.data : []} - columns={uniformityColumns} - pageSize={tableFilterState.pageSize} - page={isResponseSuccess(uniformities) ? uniformities?.meta?.page : 0} - totalItems={ - isResponseSuccess(uniformities) - ? uniformities?.meta?.total_results - : 0 - } - onPageChange={setPage} - isLoading={isLoading} - sorting={sorting} - setSorting={setSorting} - rowSelection={rowSelection} - setRowSelection={setRowSelection} - className={{ - containerClassName: cn({ - 'mb-20': - isResponseSuccess(uniformities) && - uniformities?.data?.length === 0, - }), - tableWrapperClassName: 'overflow-x-auto min-h-full rounded-xl', - tableClassName: 'font-inter w-full table-auto min-h-full!', - headerRowClassName: 'border-b border-b-gray-200', - headerColumnClassName: - 'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end', - bodyRowClassName: 'border-b border-b-gray-200', - bodyColumnClassName: - 'px-6 py-3 last:flex last:flex-row last:justify-end', - }} - emptyContent={} - /> + + data={isResponseSuccess(uniformities) ? uniformities?.data : []} + columns={uniformityColumns} + pageSize={tableFilterState.pageSize} + page={isResponseSuccess(uniformities) ? uniformities?.meta?.page : 0} + totalItems={ + isResponseSuccess(uniformities) + ? uniformities?.meta?.total_results + : 0 + } + onPageChange={setPage} + isLoading={isLoading} + sorting={sorting} + setSorting={setSorting} + rowSelection={rowSelection} + setRowSelection={setRowSelection} + className={{ + containerClassName: cn('p-3 pt-0', { + 'mb-20': + isResponseSuccess(uniformities) && + uniformities?.data?.length === 0, + }), + headerColumnClassName: 'text-nowrap', + }} + emptyContent={} + /> - -
- {createdUniformity ? ( - - ) : selectedRowIds.length === 1 ? ( - - ) : ( -
- {selectedRowIds.length} data dipilih -
- )} -
-
- - -
- -
-
- - -
- {selectedRowIds.length === 1 ? ( - - ) : ( -
- {selectedRowIds.length} data dipilih -
- )} -
-
- - -
- -
-
- - -
- {selectedRowIds.length === 1 ? ( - - ) : ( -
- {selectedRowIds.length} data dipilih -
- )} -
-
- - -
- {selectedRowIds.length === 1 ? ( - - ) : ( -
- {selectedRowIds.length} data dipilih -
- )} -
-
- - {/* Filter Modal */} - -
- {/* Modal Header */} -
-
- -

Filter Data

-
- + +
+ {createdUniformity ? ( + + ) : selectedRowIds.length === 1 ? ( + + ) : ( +
+ {selectedRowIds.length} data dipilih
+ )} +
+
-
-
-
- -
+ +
+ +
+
-
- -
-
+ +
+ {selectedRowIds.length === 1 ? ( + + ) : ( +
+ {selectedRowIds.length} data dipilih +
+ )} +
+
+ +
+ +
+
+ + +
+ {selectedRowIds.length === 1 ? ( + + ) : ( +
+ {selectedRowIds.length} data dipilih +
+ )} +
+
+ + +
+ {selectedRowIds.length === 1 ? ( + + ) : ( +
+ {selectedRowIds.length} data dipilih +
+ )} +
+
+ + {/* Filter Modal */} + +
+ {/* Modal Header */} +
+
+ +

Filter Data

+
+ +
+ +
+
- { - handleFilterLocationChange(value); - }} - options={filterLocationOptions} - onInputChange={setFilterLocationInputValue} - isLoading={isLoadingFilterLocations} - onMenuScrollToBottom={loadMoreFilterLocations} + label='Tanggal mulai' + name='start_date' + value={filterFormik.values.start_date} + onChange={handleFilterStartDateChange} + onBlur={filterFormik.handleBlur} isError={ - filterFormik.touched.location && - Boolean(filterFormik.errors.location) + filterFormik.touched.start_date && + Boolean(filterFormik.errors.start_date) } - errorMessage={filterFormik.errors.location} - isClearable + errorMessage={filterFormik.errors.start_date} className={{ wrapper: 'w-full' }} />
- { - handleFilterProjectFlockChange(value); - }} - options={filterProjectFlockOptions} - onInputChange={setFilterProjectFlockSearchValue} - isLoading={isLoadingFilterProjectFlocks} - onMenuScrollToBottom={loadMoreFilterProjectFlocks} - isDisabled={!filterFormik.values.location} + label='Tanggal akhir' + name='end_date' + value={filterFormik.values.end_date} + onChange={handleFilterEndDateChange} + onBlur={filterFormik.handleBlur} isError={ - filterFormik.touched.project_flock && - Boolean(filterFormik.errors.project_flock) + filterFormik.touched.end_date && + Boolean(filterFormik.errors.end_date) } - errorMessage={filterFormik.errors.project_flock} - isClearable - className={{ wrapper: 'w-full' }} - /> -
- -
- { - handleFilterKandangChange(value); - }} - options={filterKandangOptions} - isDisabled={!filterFormik.values.project_flock} - isError={ - filterFormik.touched.kandang && - Boolean(filterFormik.errors.kandang) - } - errorMessage={filterFormik.errors.kandang} - isClearable + errorMessage={filterFormik.errors.end_date} className={{ wrapper: 'w-full' }} />
-
- {/* Error List Alert */} - {formErrorList.length > 0 && ( -
- -
- )} +
+ { + handleFilterLocationChange(value); + }} + options={filterLocationOptions} + onInputChange={setFilterLocationInputValue} + isLoading={isLoadingFilterLocations} + onMenuScrollToBottom={loadMoreFilterLocations} + isError={ + filterFormik.touched.location && + Boolean(filterFormik.errors.location) + } + errorMessage={filterFormik.errors.location} + isClearable + className={{ wrapper: 'w-full' }} + />
- {/* Action Buttons */} -
- - +
+ { + handleFilterProjectFlockChange(value); + }} + options={filterProjectFlockOptions} + onInputChange={setFilterProjectFlockSearchValue} + isLoading={isLoadingFilterProjectFlocks} + onMenuScrollToBottom={loadMoreFilterProjectFlocks} + isDisabled={!filterFormik.values.location} + isError={ + filterFormik.touched.project_flock && + Boolean(filterFormik.errors.project_flock) + } + errorMessage={filterFormik.errors.project_flock} + isClearable + className={{ wrapper: 'w-full' }} + /> +
+ +
+ { + handleFilterKandangChange(value); + }} + options={filterKandangOptions} + isDisabled={!filterFormik.values.project_flock} + isError={ + filterFormik.touched.kandang && + Boolean(filterFormik.errors.kandang) + } + errorMessage={filterFormik.errors.kandang} + isClearable + className={{ wrapper: 'w-full' }} + />
- - {/* Floating Actions Button */} - + {/* Error List Alert */} + {formErrorList.length > 0 && ( +
+ +
+ )} +
+ + {/* Action Buttons */} +
+ + +
+
+ + + {/* Floating Actions Button */} + -
+ permissions: 'lti.production.uniformity.detail', + }, + { + action: 'DELETE', + icon: 'mdi:delete-outline', + label: 'Delete', + hidden: selectedRowIds.length !== 1, + onClick: handleDelete, + permissions: 'lti.production.uniformity.delete', + }, + ]} + approvals={[ + { + action: 'APPROVED', + icon: 'mdi:check-circle-outline', + label: 'Approve', + onClick: handleBulkApprove, + permissions: 'lti.production.uniformity.approve', + disabled: !canApproveReject, + }, + { + action: 'REJECTED', + icon: 'mdi:close-circle-outline', + label: 'Reject', + onClick: handleBulkReject, + permissions: 'lti.production.uniformity.approve', + disabled: !canApproveReject, + }, + ]} + selectedRowIds={selectedRowIds} + onClose={handleCloseFab} + /> ); }; diff --git a/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx b/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx index 9188ba59..8d38d669 100644 --- a/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx +++ b/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx @@ -10,11 +10,10 @@ import { UniformityInfoUmum, } from '@/types/api/production/uniformity'; import Table from '@/components/Table'; -import Badge from '@/components/Badge'; +import StatusBadge from '@/components/helper/StatusBadge'; import { - getWeightStatusColor, - getWeightStatusIndicatorColor, getWeightStatusText, + getWeightStatusBadgeColor, } from '@/components/pages/production/uniformity/uniformity-utils'; import { BodyWeightData } from '@/types/api/production/uniformity'; @@ -65,30 +64,12 @@ const UniformityDetailsPreview = ({ cell: (props) => { const status = props.row.original.status; return status ? ( -
- - {getWeightStatusText(status)} - -
+ ) : ( - - Unknown - + ); }, }, diff --git a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx index 103fc791..5963df8a 100644 --- a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx @@ -14,12 +14,11 @@ import { useRouter } from 'next/navigation'; import toast from 'react-hot-toast'; import { UniformityApi } from '@/services/api/uniformity'; import { isResponseError } from '@/lib/api-helper'; -import Badge from '@/components/Badge'; +import StatusBadge from '@/components/helper/StatusBadge'; import { formatNumber } from '@/lib/helper'; import { - getWeightStatusColor, - getWeightStatusIndicatorColor, getWeightStatusText, + getWeightStatusBadgeColor, } from '@/components/pages/production/uniformity/uniformity-utils'; import { DetailOptionType } from '@/types/api/production/uniformity'; import { @@ -204,30 +203,12 @@ const UniformityResultForm = () => { cell: (props) => { const status = props.row.original.status; return status ? ( -
- - {getWeightStatusText(status)} - -
+ ) : ( - - Unknown - + ); }, }, From b8031448ff33ae173d45ce6bcae728a8372b1eda Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 15:24:30 +0700 Subject: [PATCH 17/65] refactor(FE): Adjust checkbox alignment and column padding --- .../pages/production/uniformity/UniformityTable.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index 6cf28f02..bf482edc 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -821,7 +821,7 @@ const UniformityTable = () => { ); return ( -
+
{ }, cell: ({ row }) => { return ( -
+
{ isResponseSuccess(uniformities) && uniformities?.data?.length === 0, }), - headerColumnClassName: 'text-nowrap', + headerColumnClassName: + 'first:pl-3 first:pr-0 xl:first:pl-3 py-3 text-nowrap', + bodyColumnClassName: + 'first:pl-3 first:pr-0 xl:first:pl-3 py-3 text-nowrap', }} emptyContent={} /> From e93a9c801181ce6b6e5940dd403ebebbb457ee32 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 15:33:00 +0700 Subject: [PATCH 18/65] refactor(FE): Add divider above Next button in UniformityForm --- .../uniformity/form/UniformityForm.tsx | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/components/pages/production/uniformity/form/UniformityForm.tsx b/src/components/pages/production/uniformity/form/UniformityForm.tsx index 341c29a1..257de339 100644 --- a/src/components/pages/production/uniformity/form/UniformityForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityForm.tsx @@ -757,20 +757,23 @@ const UniformityForm = ({
{!isNextStep && ( - - - + <> +
+ + + + )}
From 6c6634fa1d001c3c5bd8050e7d63e00320932804 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 15:35:32 +0700 Subject: [PATCH 19/65] refactor(FE): Rename column header 'No' to 'Number' --- .../production/uniformity/detail/UniformityDetailsPreview.tsx | 2 +- .../pages/production/uniformity/form/UniformityPreviewForm.tsx | 2 +- .../pages/production/uniformity/form/UniformityResultForm.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx b/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx index 8d38d669..04c43a02 100644 --- a/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx +++ b/src/components/pages/production/uniformity/detail/UniformityDetailsPreview.tsx @@ -50,7 +50,7 @@ const UniformityDetailsPreview = ({ () => [ { accessorKey: 'number', - header: 'No', + header: 'Number', cell: (props) => props.row.original.number, }, { diff --git a/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx b/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx index 8cac641a..314eabfd 100644 --- a/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx @@ -50,7 +50,7 @@ const UniformityPreviewForm = () => { () => [ { accessorKey: 'number', - header: 'No', + header: 'Number', cell: (props) => props.row.original.number, }, { diff --git a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx index 5963df8a..98db02fc 100644 --- a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx @@ -189,7 +189,7 @@ const UniformityResultForm = () => { () => [ { accessorKey: 'number', - header: 'No', + header: 'Number', cell: (props) => props.row.original.number, }, { From aab8e0c5ce709f01d54664e6dbafb0e9bbeefcef Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 15:37:53 +0700 Subject: [PATCH 20/65] refactor(FE): Remove unused imports and accessorKey props --- .../pages/production/uniformity/UniformityTable.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index bf482edc..d45cb217 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -24,7 +24,6 @@ import CheckboxInput from '@/components/input/CheckboxInput'; import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import toast from 'react-hot-toast'; -import Card from '@/components/Card'; import UniformityTableSkeleton from '@/components/pages/production/uniformity/skeleton/UniformityTableSkeleton'; import RequirePermission from '@/components/helper/RequirePermission'; import { useUniformityStore } from '@/stores/uniformity/uniformity.store'; @@ -51,8 +50,6 @@ import { import { generateUniformityPDF } from '@/components/pages/production/uniformity/export/UniformityExportPDF'; import { generateUniformityExcel } from '@/components/pages/production/uniformity/export/UniformityExportExcel'; import Dropdown from '@/components/Dropdown'; -import Menu from '@/components/menu/Menu'; -import MenuItem from '@/components/menu/MenuItem'; import { useFormik } from 'formik'; import { UniformityTableFilterSchema, @@ -115,12 +112,10 @@ const UniformityConfirmationPreview = ({ const columns: ColumnDef[] = [ { - accessorKey: 'label', header: 'Label', cell: (props) => props.row.original.label, }, { - accessorKey: 'value', header: 'Value', cell: (props) => { const id = props.row.original.id; From db33247d6c3bb2b9e349bd8bda72121df2782238 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 15:41:05 +0700 Subject: [PATCH 21/65] refactor(FE): Use English copy for bulk reject modal --- src/components/pages/production/uniformity/UniformityTable.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index d45cb217..018e2537 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -1209,7 +1209,8 @@ const UniformityTable = () => { ref={bulkRejectModal.ref} type='error' iconPosition='left' - text={`Apakah anda yakin ingin menolak ${selectedRowIds.length} data Uniformity yang dipilih?`} + text={`Reject This Submission?`} + subtitleText={`Are you sure you want to reject this submission? (${selectedRowIds.length} data)`} secondaryButton={{ text: 'Cancel', }} From a51a020dfa7ae08802a4e83b966c8c7915d4bee8 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 29 Jan 2026 17:07:56 +0700 Subject: [PATCH 22/65] refactor(FE): Replace Button with static icon tiles in skeletons --- .../skeleton/UniformityBarChartSkeleton.tsx | 37 +++++++++++-------- .../skeleton/UniformityGaugeChartSkeleton.tsx | 33 ++++++++++------- .../skeleton/UniformityTableSkeleton.tsx | 33 ++++++++++------- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx index fe7f9aff..8d5994b2 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityBarChartSkeleton.tsx @@ -1,4 +1,3 @@ -import Button from '@/components/Button'; import { Icon } from '@iconify/react'; const LeftLegend = () => { @@ -65,26 +64,32 @@ const ChartArea = () => { const EmptyState = () => { return ( - <> -
-
- +
+
+ {/* Filter icon */} +
+
+
+ +
+
- + + {/* Empty state text */} +

No Filters Selected - - +

+

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

- +
); }; diff --git a/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx index a72875f5..f49ebc85 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityGaugeChartSkeleton.tsx @@ -1,4 +1,3 @@ -import Button from '@/components/Button'; import { Icon } from '@iconify/react'; import React from 'react'; import { Cell, Pie, PieChart, ResponsiveContainer } from 'recharts'; @@ -55,23 +54,29 @@ const UniformityGaugeChartSkeleton: React.FC< -
-
- +
+ {/* Filter icon */} +
+
+
+ +
+
- + + {/* Empty state text */} +

No Filters Selected - - +

+

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

diff --git a/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx b/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx index 08c1e0b5..f70b23e1 100644 --- a/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx +++ b/src/components/pages/production/uniformity/skeleton/UniformityTableSkeleton.tsx @@ -1,25 +1,30 @@ -import Button from '@/components/Button'; import { Icon } from '@iconify/react'; const UniformityTableSkeleton = () => { return ( -
-
- +
+ {/* Document icon */} +
+
+
+ +
+
- + + {/* Empty state text */} +

No Data Available - - +

+

There is no uniformity data displayed. Enter uniformity check data to get started. - +

); }; From c7818cefbb69f5cd1ec88950ecf32fb7f2f49d5e Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 29 Jan 2026 18:24:43 +0700 Subject: [PATCH 23/65] fix(FE): adjust ui debt supplier pixel perfect figma --- src/components/Card.tsx | 5 + src/components/Tabs.tsx | 35 ++-- src/components/helper/ButtonFilter.tsx | 8 +- .../pages/dashboard/DashboardProduction.tsx | 2 +- .../pages/report/finance/FinanceTabs.tsx | 25 ++- .../report/finance/tab/DebtSupplierTab.tsx | 172 +++++++++++------- src/stores/finance-tab/finance-tab.store.ts | 51 ++++++ 7 files changed, 214 insertions(+), 84 deletions(-) create mode 100644 src/stores/finance-tab/finance-tab.store.ts diff --git a/src/components/Card.tsx b/src/components/Card.tsx index c78766e1..ce7c1c57 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -123,6 +123,10 @@ const Card = ({ return cn(baseClasses, 'p-6', className?.body); }; + const getCollapsibleClasses = () => { + return cn('', className?.collapsible); + }; + const getTitleClasses = () => { const sizeClasses = { sm: 'text-lg', @@ -213,6 +217,7 @@ const Card = ({ titleClassName='w-full cursor-pointer' contentClassName='p-0' fullWidth={true} + className={getCollapsibleClasses()} > {cardContent} diff --git a/src/components/Tabs.tsx b/src/components/Tabs.tsx index 8f685452..8a06f9ed 100644 --- a/src/components/Tabs.tsx +++ b/src/components/Tabs.tsx @@ -25,8 +25,10 @@ export interface TabsProps wrapper?: string; tab?: string; content?: string; + tabHeaderWrapper?: string; }; onTabChange?: (tabId: string) => void; + sideContent?: ReactNode; } const Tabs = ({ @@ -38,6 +40,7 @@ const Tabs = ({ activeTabId: controlledActiveId, className, onTabChange, + sideContent, ...props }: TabsProps) => { // State internal hanya dipakai kalau `activeTabId` (controlled) tidak diset @@ -59,6 +62,7 @@ const Tabs = ({ wrapper: wrapperClassName, tab: tabClassName, content: contentClassName, + tabHeaderWrapper: tabHeaderWrapperClassName, } = typeof className === 'object' ? className : { wrapper: className, tab: undefined }; @@ -102,6 +106,10 @@ const Tabs = ({ tabClassName ); + const getSideContentClasses = () => { + return cn('flex flex-row', tabHeaderWrapperClassName); + }; + const activeContent = tabs.find((tab) => tab.id === activeTabId)?.content; return ( @@ -112,18 +120,21 @@ const Tabs = ({ typeof className === 'string' ? className : containerClassName )} > -
- {tabs.map(({ id, label, disabled }) => ( - - ))} +
+
+ {tabs.map(({ id, label, disabled }) => ( + + ))} +
+ {sideContent && sideContent}
{activeContent && ( diff --git a/src/components/helper/ButtonFilter.tsx b/src/components/helper/ButtonFilter.tsx index aca86a88..cff1d167 100644 --- a/src/components/helper/ButtonFilter.tsx +++ b/src/components/helper/ButtonFilter.tsx @@ -19,11 +19,11 @@ const ButtonFilter = ({ values, onClick, ...props }: ButtonFilterProps) => { variant='outline' color='none' className={cn( - 'padding-[12px] rounded-[8px] max-h-[40px] font-semibold text-[14px] gap-[6px]', + 'rounded-lg max-h-10 font-semibold text-sm gap-1.5', 'text-sm text-base-content/50 border border-base-content/10 shadow-button-soft', getFilledFormikValuesCount(values) > 0 - ? 'border-primary-gradient !rounded-[8px]' - : '!rounded-[8px]', + ? 'border-primary-gradient text-primary rounded-lg!' + : 'rounded-lg', props.className )} > @@ -37,7 +37,7 @@ const ButtonFilter = ({ values, onClick, ...props }: ButtonFilterProps) => { /> Filter {getFilledFormikValuesCount(values) > 0 && ( - + {getFilledFormikValuesCount(values)} )} diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 2085d943..674f3719 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -226,7 +226,7 @@ const DashboardProduction = () => { variant='outline' color='none' className={cn( - 'p-2 rounded-lg font-semibold text-sm gap-1.5', + 'rounded-lg font-semibold text-sm gap-1.5', 'text-sm text-base-content/50 border border-base-content/10 shadow-button-soft' )} > diff --git a/src/components/pages/report/finance/FinanceTabs.tsx b/src/components/pages/report/finance/FinanceTabs.tsx index 58d1e78b..e7800f96 100644 --- a/src/components/pages/report/finance/FinanceTabs.tsx +++ b/src/components/pages/report/finance/FinanceTabs.tsx @@ -1,28 +1,43 @@ 'use client'; +import { useState } from 'react'; import Tabs from '@/components/Tabs'; import CustomerPaymentTab from '@/components/pages/report/finance/tab/CustomerPaymentTab'; import DebtSupplierTab from '@/components/pages/report/finance/tab/DebtSupplierTab'; +import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; const FinanceTabs = () => { + const [activeTabId, setActiveTabId] = useState('1'); + const tabActions = useFinanceTabStore((state) => state.tabActions); + const tabs = [ { id: '1', label: 'Rekapitulasi Hutang Ke Supplier', - - content: , + content: , }, { id: '2', label: 'Kontrol Pembayaran Customer', - content: , }, ]; return ( -
- +
+
); }; diff --git a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx index c5065d29..aa66cf66 100644 --- a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx +++ b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx @@ -22,7 +22,7 @@ import { generateDebtSupplierExcel } from '@/components/pages/report/finance/exp import { generateDebtSupplierPDF } from '@/components/pages/report/finance/export/DebtSupllierExportPDF'; import { Icon } from '@iconify/react'; import { ColumnDef } from '@tanstack/react-table'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import toast from 'react-hot-toast'; import useSWR from 'swr'; import { DebtSupplierApi } from '@/services/api/report/debt-supplier'; @@ -37,6 +37,7 @@ import { Color } from '@/types/theme'; import { Supplier } from '@/types/api/master-data/supplier'; import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; import SelectInputRadio from '@/components/input/SelectInputRadio'; +import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; const dueStatus: Record = { 'Sudah Jatuh Tempo': 'error', @@ -75,7 +76,11 @@ const getPillBadge = ( ); }; -const DebtSupplierTab = () => { +interface DebtSupplierTabProps { + tabId: string; +} + +const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { // ===== STATE MANAGEMENT ===== const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); const [isExcelExportLoading, setIsExcelExportLoading] = useState(false); @@ -271,6 +276,77 @@ const DebtSupplierTab = () => { } }, [debtSupplierExport]); + // ===== REGISTER TAB ACTIONS TO STORE ===== + const setTabActions = useFinanceTabStore((state) => state.setTabActions); + const clearTabActions = useFinanceTabStore((state) => state.clearTabActions); + + useEffect(() => { + setTabActions( + tabId, +
+ + + + + Export +
+ +
+ + } + align='end' + className={{ + content: + 'mt-1 p-0 w-full shadow-button-soft border border-base-content/10 rounded-lg', + }} + > + + + + +
+
+ ); + }, [ + tabId, + formik.values, + isAnyExportLoading, + handleExportExcel, + handleExportPdf, + setTabActions, + ]); + + // Cleanup on unmount + useEffect(() => { + return () => { + clearTabActions(tabId); + }; + }, [tabId, clearTabActions]); + const getTableColumns = (supplier: DebtSupplier): ColumnDef[] => [ { id: 'no', @@ -478,41 +554,9 @@ const DebtSupplierTab = () => { ]; return ( <> -
- -
- - - - - Export - - } - align='end' - > - - - - - -
-
- +
{!isSubmitted ? ( -
+
Silakan klik tombol Filter untuk mengatur filter dan menampilkan data.
@@ -521,7 +565,7 @@ const DebtSupplierTab = () => {
) : data.length === 0 ? ( -
+
Tidak ada data yang dapat ditampilkan...
) : ( @@ -531,10 +575,11 @@ const DebtSupplierTab = () => { key={supplierReport.supplier.id} title={supplierReport.supplier.name} className={{ - wrapper: 'w-full !rounded-lg', - body: 'p-0 rounded-lg', + wrapper: 'w-full rounded-lg border-none', + body: 'p-0', title: - 'ps-2 pt-1 pb-1 font-normal text-md bg-primary text-white', + 'px-2 py-1.5 font-normal text-sm bg-primary text-white', + collapsible: 'rounded-lg', }} variant='bordered' collapsible={true} @@ -551,8 +596,9 @@ const DebtSupplierTab = () => { pageSize={supplierReport.rows.length + 1} renderFooter={supplierReport.rows.length > 0} className={{ - containerClassName: 'w-full', - tableWrapperClassName: 'overflow-x-auto', + containerClassName: 'w-full mb-0', + tableWrapperClassName: + 'overflow-x-auto rounded-tr-none rounded-tl-none', headerColumnClassName: cn( TABLE_DEFAULT_STYLING.headerColumnClassName, 'whitespace-nowrap' @@ -617,33 +663,34 @@ const DebtSupplierTab = () => { ref={filterModal.ref} className={{ modal: 'p-0', - modalBox: 'p-0 rounded-2xl xl:max-w-4/12 max-w-sm', + modalBox: 'p-0 rounded-[0.875rem] xl:max-w-4/12 max-w-sm', }} > -
+ {/* Modal Header */} -
+
-

Filter Data

+

Filter Data

-
-
-
+ + {/* Modal Body */} +
+
+ +
{ @@ -655,11 +702,8 @@ const DebtSupplierTab = () => { } errorMessage={formik.errors.startDate} /> -
- -
+
{ @@ -730,15 +774,19 @@ const DebtSupplierTab = () => {
{/* Action Buttons */} -
+
-
diff --git a/src/stores/finance-tab/finance-tab.store.ts b/src/stores/finance-tab/finance-tab.store.ts new file mode 100644 index 00000000..9b5cf096 --- /dev/null +++ b/src/stores/finance-tab/finance-tab.store.ts @@ -0,0 +1,51 @@ +'use client'; + +import { ReactNode } from 'react'; +import { create } from 'zustand'; +import { devtools } from 'zustand/middleware'; + +export type FinanceTabActionsSlice = { + // State - actions per tab ID + tabActions: Record; + + // Actions + setTabActions: (tabId: string, actions: ReactNode) => void; + clearTabActions: (tabId: string) => void; + clearAllTabActions: () => void; +}; + +export const useFinanceTabStore = create()( + devtools( + (set) => ({ + tabActions: {}, + + setTabActions: (tabId, actions) => + set( + (state) => ({ + tabActions: { + ...state.tabActions, + [tabId]: actions, + }, + }), + false, + 'setTabActions' + ), + + clearTabActions: (tabId) => + set( + (state) => { + const { [tabId]: _, ...rest } = state.tabActions; + return { tabActions: rest }; + }, + false, + 'clearTabActions' + ), + + clearAllTabActions: () => + set({ tabActions: {} }, false, 'clearAllTabActions'), + }), + { + name: 'FinanceTabStore', + } + ) +); From 0ed6c246b1289b4c496d0c19c66b8d25e479eef2 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 29 Jan 2026 20:18:42 +0700 Subject: [PATCH 24/65] fix(FE): fix badge and table pdf --- src/components/helper/StatusBadge.tsx | 2 + .../finance/export/DebtSupllierExportPDF.tsx | 59 ++++++++++++------- .../report/finance/tab/DebtSupplierTab.tsx | 21 +------ 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/components/helper/StatusBadge.tsx b/src/components/helper/StatusBadge.tsx index c4f99593..f9725fff 100644 --- a/src/components/helper/StatusBadge.tsx +++ b/src/components/helper/StatusBadge.tsx @@ -27,6 +27,7 @@ const StatusBadge = ({ 'bg-success/30': color === 'success', 'bg-error/20': color === 'error', 'bg-primary/20': color === 'info', + 'bg-[#FF9A20]/12': color === 'warning', }, className?.badge ), @@ -43,6 +44,7 @@ const StatusBadge = ({ 'text-[#008000]': color === 'success', 'text-error': color === 'error', 'text-primary': color === 'info', + 'text-[#FF9A20]': color === 'warning', })} > diff --git a/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx b/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx index 869430b0..edcd360f 100644 --- a/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx +++ b/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx @@ -281,16 +281,16 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { No - + No. PR - + No. PO - + Tgl Terima/Bayar - + Tgl PO @@ -320,7 +320,12 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { Status - + No. Perjalanan @@ -330,16 +335,16 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { {/* NO */} - + {/* No. PR */} - + {/* No. PO */} - + {/* Tgl Terima/Bayar */} - + {/* Tgl PO */} @@ -381,8 +386,13 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { {/* Status */} - - {/* No. Perjalanan */} + + @@ -400,13 +410,13 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { {index + 1} - + {item.pr_number || '-'} - + {item.po_number || '-'} - + {item.received_date ? item.received_date != '-' @@ -415,7 +425,7 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { : '-'} - + {item.po_date ? item.po_date != '-' @@ -526,7 +536,12 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { - )} - + {item.travel_number || '-'} @@ -538,18 +553,18 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => { Total - - - - - - + + + + + + {formatNumber(supplierReport.total.aging)} Hari diff --git a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx index aa66cf66..811c739b 100644 --- a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx +++ b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx @@ -2,10 +2,7 @@ import Button from '@/components/Button'; import Card from '@/components/Card'; import Dropdown from '@/components/Dropdown'; import DateInput from '@/components/input/DateInput'; -import SelectInput, { - OptionType, - useSelect, -} from '@/components/input/SelectInput'; +import { OptionType, useSelect } from '@/components/input/SelectInput'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; import Modal, { useModal } from '@/components/Modal'; @@ -32,12 +29,12 @@ import { DebtSupplierFilterType, } from '@/components/pages/report/finance/filter/DebtSupplierFilter'; import ButtonFilter from '@/components/helper/ButtonFilter'; -import Badge from '@/components/Badge'; import { Color } from '@/types/theme'; import { Supplier } from '@/types/api/master-data/supplier'; import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; import SelectInputRadio from '@/components/input/SelectInputRadio'; import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; +import StatusBadge from '@/components/helper/StatusBadge'; const dueStatus: Record = { 'Sudah Jatuh Tempo': 'error', @@ -61,19 +58,7 @@ const getPillBadge = ( ? dueStatus[statusText] || 'neutral' : paymentStatus[statusText] || 'neutral'; - return ( - - {statusText} - - ); + return ; }; interface DebtSupplierTabProps { From e980320d002c8a1220201f90f8edb33ce6c4cdf7 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 29 Jan 2026 20:59:16 +0700 Subject: [PATCH 25/65] fix(FE): fixing report finance filter ui --- src/components/input/DateInput.tsx | 27 +- .../pages/dashboard/DashboardProduction.tsx | 1 + .../pages/report/finance/FinanceTabs.tsx | 2 +- .../report/finance/tab/CustomerPaymentTab.tsx | 412 ++++++++++-------- .../report/finance/tab/DebtSupplierTab.tsx | 6 +- 5 files changed, 253 insertions(+), 195 deletions(-) diff --git a/src/components/input/DateInput.tsx b/src/components/input/DateInput.tsx index da1a4d81..7c0863c5 100644 --- a/src/components/input/DateInput.tsx +++ b/src/components/input/DateInput.tsx @@ -280,7 +280,7 @@ const DateInput = ({ ref={calendarModal.ref} className={{ modal: 'rounded', - modalBox: `!max-w-max min-h-${isRange ? '124' : '110'} flex flex-col`, + modalBox: `max-w-max flex flex-col`, }} closeOnBackdrop > @@ -296,7 +296,11 @@ const DateInput = ({ endMonth={maxDate ?? new Date(new Date().getFullYear() + 5, 11)} selected={selectedRange as DateRange} onSelect={handleSelectRange} - footer={
{displayValue}
} + footer={ +
+ {displayValue} +
+ } disabled={ [ minDate ? { before: minDate } : undefined, @@ -326,17 +330,26 @@ const DateInput = ({ )}
{isRange && ( - - Tekan dua kali untuk memilih tanggal awal + + Tekan dua kali untuk reset tanggal awal )} -
- {isRange && ( - )} diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 674f3719..27cc208b 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -463,6 +463,7 @@ const DashboardProduction = () => { Boolean(formik.errors.endDate) && Boolean(formik.touched.endDate) } + isRange />
diff --git a/src/components/pages/report/finance/FinanceTabs.tsx b/src/components/pages/report/finance/FinanceTabs.tsx index e7800f96..ffb0d3f1 100644 --- a/src/components/pages/report/finance/FinanceTabs.tsx +++ b/src/components/pages/report/finance/FinanceTabs.tsx @@ -19,7 +19,7 @@ const FinanceTabs = () => { { id: '2', label: 'Kontrol Pembayaran Customer', - content: , + content: , }, ]; diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index dc1705ed..0ce0b904 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useCallback } from 'react'; +import { useState, useMemo, useCallback, useEffect } from 'react'; import useSWR from 'swr'; import { Icon } from '@iconify/react'; import Card from '@/components/Card'; @@ -11,7 +11,7 @@ import { FinanceApi } from '@/services/api/report/finance-report'; import { UserApi } from '@/services/api/user'; import Table from '@/components/Table'; import { ColumnDef } from '@tanstack/react-table'; -import { formatCurrency, formatDate, formatNumber } from '@/lib/helper'; +import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper'; import { CustomerPaymentReport, CustomerPaymentSummary, @@ -26,8 +26,13 @@ import { useModal } from '@/components/Modal'; import toast from 'react-hot-toast'; import { generateCustomerPaymentExcel } from '@/components/pages/report/finance/export/CustomerPaymentExportXLSX'; import { generateCustomerPaymentPDF } from '@/components/pages/report/finance/export/CustomerPaymentExportPDF'; +import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; -const CustomerPaymentTab = () => { +interface CustomerPaymentTabProps { + tabId: string; +} + +const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { // ===== STATE MANAGEMENT ===== const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); const [isExcelExportLoading, setIsExcelExportLoading] = useState(false); @@ -111,6 +116,10 @@ const CustomerPaymentTab = () => { }; // ===== FILTER HANDLERS ===== + const handleFilterModalOpen = useCallback(() => { + filterModal.openModal(); + }, [filterModal]); + const handleResetFilters = useCallback(() => { setIsSubmitted(false); setFilterCustomer([]); @@ -298,6 +307,92 @@ const CustomerPaymentTab = () => { } }, [customerPaymentExport]); + // ===== REGISTER TAB ACTIONS TO STORE ===== + const setTabActions = useFinanceTabStore((state) => state.setTabActions); + const clearTabActions = useFinanceTabStore((state) => state.clearTabActions); + + useEffect(() => { + setTabActions( + tabId, +
+ + + + + Export +
+ +
+ + } + align='end' + className={{ + content: + 'mt-1 p-0 w-full shadow-button-soft border border-base-content/10 rounded-lg', + }} + > + + + + +
+
+ ); + }, [ + tabId, + hasFilters, + activeFiltersCount, + isAnyExportLoading, + handleExportExcel, + handleExportPdf, + filterModal.open, + setTabActions, + ]); + + // Cleanup on unmount + useEffect(() => { + return () => { + clearTabActions(tabId); + }; + }, [tabId, clearTabActions]); + const getTableColumns = ( summary: CustomerPaymentSummary ): ColumnDef[] => { @@ -552,181 +647,10 @@ const CustomerPaymentTab = () => { }; return ( -
- -
- - - - - Export - - } - align='end' - > - - - - - -
- - {/* Filter Modal */} - -
- {/* Modal Header */} -
-
- -

Filter Data

-
- -
-
-
-
- { - setFilterStartDate(e.target.value); - }} - className={{ wrapper: 'w-full' }} - /> -
- -
- { - setFilterEndDate(e.target.value); - }} - className={{ wrapper: 'w-full' }} - /> -
-
- -
- { - setFilterCustomer( - Array.isArray(val) ? val : val ? [val] : [] - ); - }} - onInputChange={setCustomerInputValue} - isLoading={isLoadingCustomers} - isClearable - onMenuScrollToBottom={loadMoreCustomers} - className={{ wrapper: 'w-full' }} - /> -
- - {/* TODO: Uncomment when BE is ready */} - {/*
- { - setFilterSales(Array.isArray(val) ? val : val ? [val] : []); - }} - onInputChange={setSalesInputValue} - isLoading={isLoadingSales} - isClearable - onMenuScrollToBottom={loadMoreSales} - className={{ wrapper: 'w-full' }} - /> -
*/} - - {/* TODO: Uncomment when BE is ready */} - {/*
- -
*/} -
- - {/* Action Buttons */} -
- - -
-
-
- + <> +
{!isSubmitted ? ( -
+
Silakan klik tombol Filter untuk mengatur filter dan menampilkan data.
@@ -735,7 +659,7 @@ const CustomerPaymentTab = () => {
) : data.length === 0 ? ( -
+
Tidak ada data yang dapat ditampilkan...
) : ( @@ -757,15 +681,17 @@ const CustomerPaymentTab = () => { title={customerReport.customer.name} subtitle={`(${customerReport.customer.address})`} className={{ - wrapper: 'w-full rounded-2xl', + wrapper: 'w-full rounded-lg border-none', body: 'p-0', title: - 'py-1.5 px-3 bg-primary text-white text-lg font-normal', + 'px-2 py-1.5 font-normal text-sm bg-primary text-white', subtitle: - 'px-3 pb-1 bg-primary text-white text-sm font-normal', + 'px-2 pb-1.5 bg-primary text-white text-xs font-normal', + collapsible: 'rounded-lg', }} variant='bordered' collapsible={true} + defaultCollapsed={true} > { renderFooter={customerReport.rows.length > 0} className={{ containerClassName: 'w-full mb-0!', - tableWrapperClassName: 'overflow-x-auto', + tableWrapperClassName: + 'overflow-x-auto rounded-tr-none rounded-tl-none', tableClassName: 'w-full table-auto text-sm', headerRowClassName: 'border-b border-b-gray-200 bg-gray-50', headerColumnClassName: @@ -799,8 +726,8 @@ const CustomerPaymentTab = () => { if (row.index === 0) { return ( ))} diff --git a/src/components/helper/skeleton/DataStateSkeleton.tsx b/src/components/helper/skeleton/DataStateSkeleton.tsx new file mode 100644 index 00000000..cea68b82 --- /dev/null +++ b/src/components/helper/skeleton/DataStateSkeleton.tsx @@ -0,0 +1,26 @@ +import IconSkeleton from '@/components/helper/skeleton/IconSkeleton'; +import { Icon } from '@iconify/react'; + +const DataStateSkeleton = ({ + icon, + title, + description, +}: { + icon: React.ReactNode; + title: string; + description: string; +}) => { + return ( +
+ {icon} +

+ {title} +

+

+ {description} +

+
+ ); +}; + +export default DataStateSkeleton; diff --git a/src/components/helper/skeleton/IconSkeleton.tsx b/src/components/helper/skeleton/IconSkeleton.tsx new file mode 100644 index 00000000..0100f14b --- /dev/null +++ b/src/components/helper/skeleton/IconSkeleton.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from 'react'; + +const IconSkeleton = ({ children }: { children: ReactNode }) => { + return ( +
+
+ {children} +
+
+ ); +}; + +export default IconSkeleton; diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 27cc208b..674f3719 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -463,7 +463,6 @@ const DashboardProduction = () => { Boolean(formik.errors.endDate) && Boolean(formik.touched.endDate) } - isRange /> diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index 092e4bca..58749cf2 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -1,6 +1,7 @@ import Button from '@/components/Button'; import Card from '@/components/Card'; import Dropdown from '@/components/Dropdown'; +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; import { OptionType } from '@/components/input/SelectInput'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; @@ -721,24 +722,18 @@ const DashboardLineChart = ({ return (
{/* Chart icon */} -
-
+ -
-
- - {/* Empty state text */} -

- Data Not Yet Available -

-

- Please change your filters to get the data. -

+ } + title='Data Not Yet Available' + description='Please change your filters to get the data.' + />
); } diff --git a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx index 6e4e4b97..7f19a6d0 100644 --- a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx +++ b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx @@ -1,5 +1,6 @@ import { Icon } from '@iconify/react'; import { DashboardMeta } from '@/types/api/dashboard/dashboard'; +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { return ( @@ -24,50 +25,35 @@ 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. -

+ + } + title='No Filters Selected' + description='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. -

+ } + title='Data Not Yet Available' + description='Please change your filters to get the data.' + /> )} diff --git a/src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx b/src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx new file mode 100644 index 00000000..8ab0ffd3 --- /dev/null +++ b/src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx @@ -0,0 +1,37 @@ +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; +import Table from '@/components/Table'; +import { CustomerPaymentRow } from '@/types/api/report/customer-payment'; +import { ColumnDef } from '@tanstack/react-table'; + +const CustomerSupplierSkeleton = ({ + columns, + icon, + title, + subtitle, +}: { + columns: ColumnDef[]; + icon: React.ReactNode; + title: string; + subtitle: string; +}) => { + return ( +
+
{ ); }) )} - - + + + {/* Filter Modal */} + + {/* Modal Header */} +
+
+ +

Filter Data

+
+ +
+
+
+ +
+ { + setFilterStartDate(e.target.value); + }} + className={{ wrapper: 'w-full' }} + isNestedModal + /> +
+ + { + setFilterEndDate(e.target.value); + }} + className={{ wrapper: 'w-full' }} + isNestedModal + /> +
+
+ + { + setFilterCustomer(Array.isArray(val) ? val : val ? [val] : []); + }} + onInputChange={setCustomerInputValue} + isLoading={isLoadingCustomers} + isClearable + onMenuScrollToBottom={loadMoreCustomers} + className={{ wrapper: 'w-full' }} + /> + + {/* TODO: Uncomment when BE is ready */} + {/*
+ { + setFilterSales(Array.isArray(val) ? val : val ? [val] : []); + }} + onInputChange={setSalesInputValue} + isLoading={isLoadingSales} + isClearable + onMenuScrollToBottom={loadMoreSales} + className={{ wrapper: 'w-full' }} + /> +
*/} + + {/* TODO: Uncomment when BE is ready */} + {/*
+ +
*/} + + {/* Action Buttons */} +
+
+ + +
+
+ ); }; diff --git a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx index 811c739b..ac53a7a3 100644 --- a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx +++ b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx @@ -686,6 +686,7 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { formik.touched.startDate && !!formik.errors.startDate } errorMessage={formik.errors.startDate} + isNestedModal />
{ className={{ wrapper: 'w-full' }} isError={formik.touched.endDate && !!formik.errors.endDate} errorMessage={formik.errors.endDate} + isNestedModal /> @@ -759,7 +761,7 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { {/* Action Buttons */} -
+
-
-
+ +
+ {/* Rentang Waktu */}
- + Tanggal + +
+ +
+ +
+
+ +
+ { + handleFilterLocationChange(value); + }} + options={filterLocationOptions} + onInputChange={setFilterLocationInputValue} + isLoading={isLoadingFilterLocations} + onMenuScrollToBottom={loadMoreFilterLocations} isError={ - filterFormik.touched.start_date && - Boolean(filterFormik.errors.start_date) + filterFormik.touched.location && + Boolean(filterFormik.errors.location) } - errorMessage={filterFormik.errors.start_date} + errorMessage={filterFormik.errors.location} + isClearable className={{ wrapper: 'w-full' }} />
- { + handleFilterProjectFlockChange(value); + }} + options={filterProjectFlockOptions} + onInputChange={setFilterProjectFlockSearchValue} + isLoading={isLoadingFilterProjectFlocks} + onMenuScrollToBottom={loadMoreFilterProjectFlocks} + isDisabled={!filterFormik.values.location} isError={ - filterFormik.touched.end_date && - Boolean(filterFormik.errors.end_date) + filterFormik.touched.project_flock && + Boolean(filterFormik.errors.project_flock) } - errorMessage={filterFormik.errors.end_date} + errorMessage={filterFormik.errors.project_flock} + isClearable className={{ wrapper: 'w-full' }} />
-
-
- { - handleFilterLocationChange(value); - }} - options={filterLocationOptions} - onInputChange={setFilterLocationInputValue} - isLoading={isLoadingFilterLocations} - onMenuScrollToBottom={loadMoreFilterLocations} - isError={ - filterFormik.touched.location && - Boolean(filterFormik.errors.location) - } - errorMessage={filterFormik.errors.location} - isClearable - className={{ wrapper: 'w-full' }} - /> -
- -
- { - handleFilterProjectFlockChange(value); - }} - options={filterProjectFlockOptions} - onInputChange={setFilterProjectFlockSearchValue} - isLoading={isLoadingFilterProjectFlocks} - onMenuScrollToBottom={loadMoreFilterProjectFlocks} - isDisabled={!filterFormik.values.location} - isError={ - filterFormik.touched.project_flock && - Boolean(filterFormik.errors.project_flock) - } - errorMessage={filterFormik.errors.project_flock} - isClearable - className={{ wrapper: 'w-full' }} - /> -
- -
- { - handleFilterKandangChange(value); - }} - options={filterKandangOptions} - isDisabled={!filterFormik.values.project_flock} - isError={ - filterFormik.touched.kandang && - Boolean(filterFormik.errors.kandang) - } - errorMessage={filterFormik.errors.kandang} - isClearable - className={{ wrapper: 'w-full' }} - /> -
-
- -
- {/* Error List Alert */} - {formErrorList.length > 0 && ( -
- +
+ { + handleFilterKandangChange(value); + }} + options={filterKandangOptions} + isDisabled={!filterFormik.values.project_flock} + isError={ + filterFormik.touched.kandang && + Boolean(filterFormik.errors.kandang) + } + errorMessage={filterFormik.errors.kandang} + isClearable + className={{ wrapper: 'w-full' }} + />
- )} -
- {/* Action Buttons */} -
- - -
+ {formErrorList.length > 0 && ( +
+ +
+ )} +
+ + {/* Action Buttons */} +
+ + +
+
From 89f711241da265adcf2d26a59389cd40c0905013 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 10:49:17 +0700 Subject: [PATCH 33/65] refactor(FE): Remove left chart margin and lower min-height --- .../pages/production/uniformity/chart/UniformityBarChart.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/production/uniformity/chart/UniformityBarChart.tsx b/src/components/pages/production/uniformity/chart/UniformityBarChart.tsx index 82f0085c..e03f6927 100644 --- a/src/components/pages/production/uniformity/chart/UniformityBarChart.tsx +++ b/src/components/pages/production/uniformity/chart/UniformityBarChart.tsx @@ -164,7 +164,7 @@ const UniformityBarChart: React.FC = ({ data }) => { const margin = { top: 20, right: 30, - left: 20, + left: 0, bottom: 5, }; @@ -172,7 +172,7 @@ const UniformityBarChart: React.FC = ({ data }) => { From ba1d462a0a994a7cc7f9260d7a9d89a0dc35c969 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Fri, 30 Jan 2026 11:02:18 +0700 Subject: [PATCH 34/65] fix(FE): adding skeleton state data on null or unfiltered --- src/components/Table.tsx | 14 ++++- .../helper/skeleton/DataStateSkeleton.tsx | 26 ++++++++ .../helper/skeleton/IconSkeleton.tsx | 13 ++++ .../pages/dashboard/DashboardProduction.tsx | 1 - .../dashboard/chart/DashboardLineChart.tsx | 19 +++--- .../skeleton/DashboardLineChartSkeleton.tsx | 52 ++++++---------- .../skeleton/CustomerSupplierSkeleton.tsx | 37 +++++++++++ .../finance/skeleton/DebtSupplierSkeleton.tsx | 38 ++++++++++++ .../report/finance/tab/CustomerPaymentTab.tsx | 35 ++++++++--- .../report/finance/tab/DebtSupplierTab.tsx | 61 +++++++++++++------ 10 files changed, 222 insertions(+), 74 deletions(-) create mode 100644 src/components/helper/skeleton/DataStateSkeleton.tsx create mode 100644 src/components/helper/skeleton/IconSkeleton.tsx create mode 100644 src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx create mode 100644 src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 0be39fb5..b40d9db5 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -42,6 +42,7 @@ interface TableClassNames { footerRowClassName?: string; footerColumnClassName?: string; paginationClassName?: string; + skeletonCellClassName?: string; } export interface TableProps { @@ -79,7 +80,9 @@ export interface TableProps { getSubRows?: (originalRow: TData, index: number) => TData[] | undefined; } -const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}]; +const DUMMY_SKELETON_DATA = Array.from({ length: 10 }, (_, index) => ({ + id: index, +})); const emptyContentDefaultValue = (
@@ -414,7 +417,14 @@ const Table = ({ cell.getContext() )} - {isLoading &&
} + {isLoading && ( +
+ )}
+
+ +
+ + ); +}; + +export default CustomerSupplierSkeleton; diff --git a/src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx b/src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx new file mode 100644 index 00000000..b9397f8f --- /dev/null +++ b/src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx @@ -0,0 +1,38 @@ +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; +import Table from '@/components/Table'; +import { DebtRow } from '@/types/api/report/debt-supplier'; +import { Icon } from '@iconify/react'; +import { ColumnDef } from '@tanstack/react-table'; + +const DebtSupplierSkeleton = ({ + columns, + icon, + title, + subtitle, +}: { + columns: ColumnDef[]; + icon: React.ReactNode; + title: string; + subtitle: string; +}) => { + return ( +
+
+
+ +
+ + ); +}; + +export default DebtSupplierSkeleton; diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 0ce0b904..2987455a 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -14,6 +14,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper'; import { CustomerPaymentReport, + CustomerPaymentRow, CustomerPaymentSummary, } from '@/types/api/report/customer-payment'; import { isResponseSuccess } from '@/lib/api-helper'; @@ -27,6 +28,7 @@ import toast from 'react-hot-toast'; import { generateCustomerPaymentExcel } from '@/components/pages/report/finance/export/CustomerPaymentExportXLSX'; import { generateCustomerPaymentPDF } from '@/components/pages/report/finance/export/CustomerPaymentExportPDF'; import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; +import CustomerSupplierSkeleton from '@/components/pages/report/finance/skeleton/CustomerSupplierSkeleton'; interface CustomerPaymentTabProps { tabId: string; @@ -650,18 +652,37 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { <>
{!isSubmitted ? ( -
- Silakan klik tombol Filter untuk mengatur filter dan menampilkan - data. -
+ + } + title='No Filters Selected' + subtitle='Please choose filters to narrow down your results and make your search easier.' + /> ) : isLoading ? (
) : data.length === 0 ? ( -
- Tidak ada data yang dapat ditampilkan... -
+ + } + title='Data Not Yet Available' + subtitle='Please change your filters to get the data.' + /> ) : ( data.map((customerReport) => { const summary = customerReport.summary || { diff --git a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx index ac53a7a3..646cfb15 100644 --- a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx +++ b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx @@ -35,6 +35,8 @@ import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; import SelectInputRadio from '@/components/input/SelectInputRadio'; import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; import StatusBadge from '@/components/helper/StatusBadge'; +import DebtSupplierSkeleton from '@/components/pages/report/finance/skeleton/DebtSupplierSkeleton'; +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; const dueStatus: Record = { 'Sudah Jatuh Tempo': 'error', @@ -332,7 +334,7 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { }; }, [tabId, clearTabActions]); - const getTableColumns = (supplier: DebtSupplier): ColumnDef[] => [ + const getTableColumns = (supplier?: DebtSupplier): ColumnDef[] => [ { id: 'no', header: 'No', @@ -398,8 +400,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { return
{formatNumber(value)} Hari
; }, footer: () => { - const value = supplier.total.aging; - return
{formatNumber(value)} Hari
; + const value = supplier?.total.aging; + return ( +
{formatNumber(value || 0)} Hari
+ ); }, }, { @@ -460,10 +464,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { ); }, footer: () => { - const value = supplier.total.total_price; + const value = supplier?.total.total_price; return ( -
- {formatCurrency(value)} +
+ {formatCurrency(value || 0)}
); }, @@ -482,10 +486,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { ); }, footer: () => { - const value = supplier.total.payment_price; + const value = supplier?.total.payment_price; return ( -
- {formatCurrency(value)} +
+ {formatCurrency(value || 0)}
); }, @@ -504,10 +508,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { ); }, footer: () => { - const value = supplier.total.debt_price; + const value = supplier?.total.debt_price; return ( -
- {formatCurrency(value)} +
+ {formatCurrency(value || 0)}
); }, @@ -541,18 +545,37 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { <>
{!isSubmitted ? ( -
- Silakan klik tombol Filter untuk mengatur filter dan menampilkan - data. -
+ + } + title='No Filters Selected' + subtitle='Please choose filters to narrow down your results and make your search easier.' + /> ) : isLoading ? (
) : data.length === 0 ? ( -
- Tidak ada data yang dapat ditampilkan... -
+ + } + title='Data Not Yet Available' + subtitle='Please change your filters to get the data.' + /> ) : ( data.map((supplierReport) => { return ( From de8fda93605c633c0bce0b29b4b46a6369b853b2 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 11:03:17 +0700 Subject: [PATCH 35/65] fix: reset input error when dialog is closed --- .../MasterConfigurationContent.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx b/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx index 9fa75c33..33ad2608 100644 --- a/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx +++ b/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { Plus, MoreVertical, Pencil, Trash2 } from 'lucide-react'; import { Card, CardContent } from '@/figma-make/components/base/card'; import { Button } from '@/figma-make/components/base/button'; @@ -404,7 +404,22 @@ export function MasterConfigurationContent() {
{/* Add/Edit Modal */} - + { + if (!open) { + setIsFormInvalid(false); + setConfigurationForm({ + id: 0, + date: '', + percentage_threshold_bad: '', + percentage_threshold_enough: '', + }); + } + + setShowModal(open); + }} + > From 8babb4e3d7d3b9a26c849ffefb901ea1c0f02b82 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 11:05:38 +0700 Subject: [PATCH 36/65] refactor(FE): Use className props for drawer widths --- src/components/Drawer.tsx | 8 +++++--- .../pages/production/uniformity/UniformityPageWrapper.tsx | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/Drawer.tsx b/src/components/Drawer.tsx index bbc36782..fc0af9fb 100644 --- a/src/components/Drawer.tsx +++ b/src/components/Drawer.tsx @@ -16,7 +16,6 @@ interface DrawerProps { onBackdropClick?: () => void; closeOnBackdropClick?: boolean; expandedContent?: ReactNode; - expandedWidth?: string; } type DrawerClassName = { @@ -25,6 +24,7 @@ type DrawerClassName = { drawerSide?: string; drawerOverlay?: string; drawerSidebarContent?: string; + drawerExpandedContent?: string; }; const Drawer = ({ @@ -39,7 +39,6 @@ const Drawer = ({ onBackdropClick, closeOnBackdropClick = true, expandedContent, - expandedWidth = 'w-[400px]', }: DrawerProps) => { const getDrawerClassNames = (): DrawerClassName => { const baseClassNames = { @@ -56,6 +55,9 @@ const Drawer = ({ ? 'w-full lg:min-w-[600px] lg:max-w-[600px]' : 'w-full max-w-[300px] lg:w-[300px]'; } + if (className?.drawerSidebarContent) { + return ''; + } return 'w-full sm:min-w-120 sm:w-fit'; }; @@ -174,7 +176,7 @@ const Drawer = ({
diff --git a/src/components/pages/production/uniformity/UniformityPageWrapper.tsx b/src/components/pages/production/uniformity/UniformityPageWrapper.tsx index 07f313b6..5c8f1313 100644 --- a/src/components/pages/production/uniformity/UniformityPageWrapper.tsx +++ b/src/components/pages/production/uniformity/UniformityPageWrapper.tsx @@ -58,7 +58,10 @@ export default function UniformityPageWrapper({ zIndex='99999' sidebarContent={isOpen ?
{children}
: null} expandedContent={expandedDrawerOpen ? expandedDrawerContent : null} - expandedWidth='w-[500px]' + className={{ + drawerSidebarContent: 'w-[446px]', + drawerExpandedContent: 'w-[446px]', + }} /> ); From 7956ce5b6f61da9cd07ec3ebd61475d9bc2c8600 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 11:18:39 +0700 Subject: [PATCH 37/65] fix: issue when selecting all phase and employee --- .../daily-checklist/DailyChecklistContent.tsx | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx index 37430354..b99842bd 100644 --- a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx +++ b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx @@ -535,14 +535,6 @@ export function DailyChecklistContent() { } }; - const toggleSelectAllAbk = () => { - if (tempSelectedEmployees.length === employees.length) { - setTempSelectedEmployees([]); - } else { - setTempSelectedEmployees([...employees]); - } - }; - const applyAbkSelection = async () => { if (!dailyChecklistId) { toast.error('Checklist belum tersedia'); @@ -853,10 +845,34 @@ export function DailyChecklistContent() { ); const isAllAbkSelected = - tempSelectedEmployees.length === employees.length && employees.length > 0; + tempSelectedEmployees.length === filteredEmployees.length && + filteredEmployees.length > 0 && + tempSelectedEmployees.every((tempSelectedEmployee) => { + return ( + filteredEmployees.findIndex( + (filteredEmployee) => filteredEmployee.id === tempSelectedEmployee.id + ) >= 0 + ); + }); const isAllPhasesSelected = - tempSelectedPhaseIds.length === availablePhases.length && - availablePhases.length > 0; + tempSelectedPhaseIds.length === filteredPhases.length && + filteredPhases.length > 0 && + tempSelectedPhaseIds.every((tempSelectedPhaseId) => { + return ( + filteredPhases.findIndex( + (filteredPhase) => + String(filteredPhase.id) === String(tempSelectedPhaseId) + ) >= 0 + ); + }); + + const toggleSelectAllAbk = () => { + if (isAllAbkSelected) { + setTempSelectedEmployees([]); + } else { + setTempSelectedEmployees([...filteredEmployees]); + } + }; // Group activities by PHASE → TIME_TYPE → ACTIVITIES const groupActivitiesByPhase = () => { @@ -1519,14 +1535,14 @@ export function DailyChecklistContent() { setTempSelectedPhaseIds([]); } else { setTempSelectedPhaseIds( - availablePhases.map((p) => String(p.id)) + filteredPhases.map((p) => String(p.id)) ); } }} className='checkbox-clean' /> - Pilih Semua ({availablePhases.length} Fase) + Pilih Semua ({filteredPhases.length} Fase)
@@ -1621,7 +1637,7 @@ export function DailyChecklistContent() { />
- {employees.length > 0 && ( + {filteredEmployees.length > 0 && (
From 8a647801354b5f27bb1c7b3443332818ef467fe2 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Fri, 30 Jan 2026 11:20:47 +0700 Subject: [PATCH 38/65] fix(FE): adding margin on data state skeleton --- .../helper/skeleton/DataStateSkeleton.tsx | 8 +++++- .../helper/skeleton/IconSkeleton.tsx | 26 ++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/components/helper/skeleton/DataStateSkeleton.tsx b/src/components/helper/skeleton/DataStateSkeleton.tsx index cea68b82..cd5474e0 100644 --- a/src/components/helper/skeleton/DataStateSkeleton.tsx +++ b/src/components/helper/skeleton/DataStateSkeleton.tsx @@ -12,7 +12,13 @@ const DataStateSkeleton = ({ }) => { return (
- {icon} + + {icon} +

{title}

diff --git a/src/components/helper/skeleton/IconSkeleton.tsx b/src/components/helper/skeleton/IconSkeleton.tsx index 0100f14b..7fde0cd8 100644 --- a/src/components/helper/skeleton/IconSkeleton.tsx +++ b/src/components/helper/skeleton/IconSkeleton.tsx @@ -1,9 +1,29 @@ +import { cn } from '@/lib/helper'; import { ReactNode } from 'react'; -const IconSkeleton = ({ children }: { children: ReactNode }) => { +const IconSkeleton = ({ + children, + className, +}: { + children: ReactNode; + className?: { + outer?: string; + inner?: string; + }; +}) => { return ( -
-
+
+
{children}
From 359cdb253462a14c4642230082f874940a48bcdb Mon Sep 17 00:00:00 2001 From: randy-ar Date: Fri, 30 Jan 2026 11:24:42 +0700 Subject: [PATCH 39/65] fix(FE): adding margin on data state skeleton --- src/components/helper/skeleton/IconSkeleton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/helper/skeleton/IconSkeleton.tsx b/src/components/helper/skeleton/IconSkeleton.tsx index 7fde0cd8..4c865719 100644 --- a/src/components/helper/skeleton/IconSkeleton.tsx +++ b/src/components/helper/skeleton/IconSkeleton.tsx @@ -14,7 +14,7 @@ const IconSkeleton = ({ return (
From 99f8e5dcf3671956adb57de2364d6b04fd2bd8d9 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 11:45:50 +0700 Subject: [PATCH 40/65] chore: add validation in phase selection and sort activity and employee name --- .../daily-checklist/DailyChecklistContent.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx index b99842bd..79049480 100644 --- a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx +++ b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx @@ -127,6 +127,10 @@ export function DailyChecklistContent() { { id: number; name: string }[] >([]); + const sortedSelectedEmployees = selectedEmployees.toSorted((a, b) => + a.name.localeCompare(b.name) + ); + const [dailyChecklistId, setDailyChecklistId] = useState(null); const [checklistStatus, setChecklistStatus] = useState('DRAFT'); // const [isEditMode, setIsEditMode] = useState(false); @@ -486,6 +490,11 @@ export function DailyChecklistContent() { return; } + if (!tempSelectedPhaseIds.length) { + toast.error('Pilih minimal satu fase'); + return; + } + try { // Insert new phase links const setDailyChecklistPhaseRes = @@ -1146,7 +1155,7 @@ export function DailyChecklistContent() {
- {selectedEmployees.map((emp) => ( + {sortedSelectedEmployees.map((emp) => ( {activity.employees.length > 0 && - activity.employees[0].note ? ( + activity.employees[ + activity.employees.length - 1 + ].note ? (

- {activity.employees[0].note} + { + activity.employees[ + activity.employees.length - 1 + ].note + }

) : (

From 8947d48a4396e1ffb8c5dd7b552f044d568cb810 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 13:20:04 +0700 Subject: [PATCH 42/65] refactor(FE): Adjust spacing and border in UniformityForm --- .../pages/production/uniformity/form/UniformityForm.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/pages/production/uniformity/form/UniformityForm.tsx b/src/components/pages/production/uniformity/form/UniformityForm.tsx index 257de339..f5e687c7 100644 --- a/src/components/pages/production/uniformity/form/UniformityForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityForm.tsx @@ -511,7 +511,7 @@ const UniformityForm = ({ Informasi Umum -
+ -

+
diff --git a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx index 98db02fc..20b267f7 100644 --- a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx @@ -280,7 +280,7 @@ const UniformityResultForm = () => { onClick={handleSubmit} isLoading={isSubmitting} disabled={!uniformityFormData} - className='mb-10' + className='mb-10 px-3 py-2.5 text-sm text-base-100 rounded-lg shadow-sm' > Submit From fbf7cb2d2120350bd93f4b48f853c5aa395711b0 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 13:37:13 +0700 Subject: [PATCH 47/65] refactor(FE): Wrap table headers in styled span --- .../uniformity/form/UniformityPreviewForm.tsx | 8 ++++-- .../uniformity/form/UniformityResultForm.tsx | 28 ++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx b/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx index a1f98526..3cc120fd 100644 --- a/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityPreviewForm.tsx @@ -50,12 +50,16 @@ const UniformityPreviewForm = () => { () => [ { accessorKey: 'number', - header: 'Number', + header: () => ( + Number + ), cell: (props) => props.row.original.number, }, { accessorKey: 'weight', - header: 'Weight (g)', + header: () => ( + Weight (g) + ), cell: (props) => {props.row.original.weight}, }, ], diff --git a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx index 20b267f7..3cc12017 100644 --- a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx @@ -120,12 +120,16 @@ const UniformityResultForm = () => { () => [ { accessorKey: 'label', - header: 'Label', + header: () => ( + Label + ), cell: (props) => props.row.original.label, }, { accessorKey: 'value', - header: 'Value', + header: () => ( + Value + ), cell: (props) => {props.row.original.value}, }, ], @@ -160,12 +164,16 @@ const UniformityResultForm = () => { () => [ { accessorKey: 'label', - header: 'Label', + header: () => ( + Label + ), cell: (props) => props.row.original.label, }, { accessorKey: 'value', - header: 'Value', + header: () => ( + Value + ), cell: (props) => {props.row.original.value}, }, ], @@ -189,17 +197,23 @@ const UniformityResultForm = () => { () => [ { accessorKey: 'number', - header: 'Number', + header: () => ( + Number + ), cell: (props) => props.row.original.number, }, { accessorKey: 'weight', - header: 'Weight (g)', + header: () => ( + Weight (g) + ), cell: (props) => {props.row.original.weight}, }, { accessorKey: 'status', - header: 'Status', + header: () => ( + Status + ), cell: (props) => { const status = props.row.original.status; return status ? ( From ace301853926e280e61c6661b630de99dba630d5 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 13:40:19 +0700 Subject: [PATCH 48/65] refactor(FE): Add bottom margin to Informasi Umum heading --- .../pages/production/uniformity/form/UniformityForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pages/production/uniformity/form/UniformityForm.tsx b/src/components/pages/production/uniformity/form/UniformityForm.tsx index eeb161f0..c3ec0615 100644 --- a/src/components/pages/production/uniformity/form/UniformityForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityForm.tsx @@ -507,7 +507,7 @@ const UniformityForm = ({ />
-

+

Informasi Umum

From 2a12bc4ba482c492c13ac317b7259cce6811f5c5 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 13:46:46 +0700 Subject: [PATCH 49/65] refactor(FE): Tweak spacing and icon size in uniformity form --- .../uniformity/form/UniformityResultForm.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx index 3cc12017..9660d2c6 100644 --- a/src/components/pages/production/uniformity/form/UniformityResultForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityResultForm.tsx @@ -241,7 +241,7 @@ const UniformityResultForm = () => { > @@ -249,9 +249,9 @@ const UniformityResultForm = () => { {/* Form Section */}
{verifyUniformityResult ? ( -
+
-

+

Sampling and Range

@@ -266,7 +266,7 @@ const UniformityResultForm = () => {
-

+

Result

@@ -279,7 +279,7 @@ const UniformityResultForm = () => { }} />
-
+
data={tableData} columns={columnsUniformity} @@ -294,7 +294,7 @@ const UniformityResultForm = () => { onClick={handleSubmit} isLoading={isSubmitting} disabled={!uniformityFormData} - className='mb-10 px-3 py-2.5 text-sm text-base-100 rounded-lg shadow-sm' + className='mb-5 px-3 py-2.5 text-sm text-base-100 rounded-lg shadow-sm' > Submit From ae0d03ddc03b046ec0560570c6452b96fe207135 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 13:49:47 +0700 Subject: [PATCH 50/65] refactor(FE): Reduce info icon size to 15 --- .../pages/production/uniformity/form/UniformityForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/production/uniformity/form/UniformityForm.tsx b/src/components/pages/production/uniformity/form/UniformityForm.tsx index c3ec0615..0c71eb26 100644 --- a/src/components/pages/production/uniformity/form/UniformityForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityForm.tsx @@ -611,8 +611,8 @@ const UniformityForm = ({ > From 64bd57cad47f187553678d0354ec7884d3f15870 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 13:50:21 +0700 Subject: [PATCH 51/65] refactor(FE): Reduce info icon size to 15 --- .../pages/production/uniformity/form/UniformityForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/production/uniformity/form/UniformityForm.tsx b/src/components/pages/production/uniformity/form/UniformityForm.tsx index 0c71eb26..8ab62d85 100644 --- a/src/components/pages/production/uniformity/form/UniformityForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityForm.tsx @@ -598,8 +598,8 @@ const UniformityForm = ({ > From aecf4701736a2620fa697766e73a00dc4e3f239f Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 13:57:17 +0700 Subject: [PATCH 52/65] chore: add max size and bottom label for file input in daily checklist form --- .../components/pages/daily-checklist/DailyChecklistContent.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx index 79049480..266b8740 100644 --- a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx +++ b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx @@ -1478,6 +1478,8 @@ export function DailyChecklistContent() { inputWrapper: 'flex items-center', label: 'font-semibold text-gray-900', }} + maxSize={5242880} // 5 MB + bottomLabel='Ukuran file maksimal 5MB' /> )} From a5613980c0d29fe33376e97fbcb9370774bea0dd Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 30 Jan 2026 14:13:38 +0700 Subject: [PATCH 53/65] refactor(FE): Update UniformityGaugeChart styles --- .../uniformity/chart/UniformityGaugeChart.tsx | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/components/pages/production/uniformity/chart/UniformityGaugeChart.tsx b/src/components/pages/production/uniformity/chart/UniformityGaugeChart.tsx index 54f8e4ec..8249e1d5 100644 --- a/src/components/pages/production/uniformity/chart/UniformityGaugeChart.tsx +++ b/src/components/pages/production/uniformity/chart/UniformityGaugeChart.tsx @@ -65,12 +65,12 @@ const UniformityGaugeChart: React.FC = ({ -
- +
+ {value}% -
- +
+ {label}
@@ -81,7 +81,7 @@ const UniformityGaugeChart: React.FC = ({
); }; From 8ce72b21e1df2ae8be983fdfabce20387d3f7cd5 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 15:39:16 +0700 Subject: [PATCH 63/65] chore: update permissions for /report/marketing --- src/config/route-permission.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config/route-permission.ts b/src/config/route-permission.ts index 44f3728e..20ee5292 100644 --- a/src/config/route-permission.ts +++ b/src/config/route-permission.ts @@ -116,7 +116,10 @@ export const ROUTE_PERMISSIONS: Record = { // Report '/report/logistic-stock/': ['lti.repport.purchasesupplier.list'], '/report/expense/': ['lti.repport.expense.list'], - '/report/marketing/': ['lti.repport.delivery.list'], + '/report/marketing/': [ + 'lti.repport.delivery.list', + 'lti.repport.gethppperkandang.list', + ], '/report/production-result/': ['lti.repport.production_result.list'], '/report/finance/': [ 'lti.repport.finance.list', From c6b9ed4f129d78dad118932c5a7ca873d2cfe159 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 16:54:19 +0700 Subject: [PATCH 64/65] hotfix: add permission guard in transfer to laying page --- src/app/production/transfer-to-laying/page.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/production/transfer-to-laying/page.tsx b/src/app/production/transfer-to-laying/page.tsx index 5d790345..be8ff454 100644 --- a/src/app/production/transfer-to-laying/page.tsx +++ b/src/app/production/transfer-to-laying/page.tsx @@ -1,15 +1,25 @@ import TransferToLayingsTable from '@/components/pages/production/transfer-to-laying/TransferToLayingsTable'; import TransferToLayingFormModal from '@/components/pages/production/transfer-to-laying/TransferToLayingFormModal'; import TransferToLayingDetailModal from '@/components/pages/production/transfer-to-laying/TransferToLayingDetailModal'; +import RequirePermission from '@/components/helper/RequirePermission'; const TransferToLaying = () => { return (
- + + + - + + +
); }; From 5b167db6c3d9e55e6f80aa39725e396091040d85 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 30 Jan 2026 16:55:32 +0700 Subject: [PATCH 65/65] chore: add permission for transfer to laying --- src/config/constant.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config/constant.ts b/src/config/constant.ts index 120b6b6a..9c6946f7 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -82,6 +82,8 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ permission: [ 'lti.production.project_flocks.list', 'lti.production.recording.list', + 'lti.production.transfer_to_laying.list', + 'lti.production.uniformity.list', ], submenu: [ { @@ -97,6 +99,7 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ { text: 'Transfer ke Laying', link: '/production/transfer-to-laying', + permission: ['lti.production.transfer_to_laying.list'], }, { text: 'Uniformity',
Aktivitas + a.name.localeCompare(b.name, undefined, { + sensitivity: 'base', + }) + ); + + console.log(activities); + activities.forEach((activity, index) => { const taskId = taskIdsByPhaseActivityId[activity.id]; @@ -1260,7 +1277,7 @@ export function DailyChecklistContent() {

)} - {selectedEmployees.map((emp) => ( + {sortedSelectedEmployees.map((emp) => (
Date: Fri, 30 Jan 2026 11:46:29 +0700 Subject: [PATCH 41/65] chore: sort activity and employee name --- .../detail/DetailDailyChecklistContent.tsx | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx b/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx index 0b3ece27..d8723df0 100644 --- a/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx +++ b/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx @@ -275,6 +275,13 @@ export function DetailDailyChecklistContent() { ]) ).values() ); + + uniqueEmployees.sort((a, b) => + a.name.localeCompare(b.name, undefined, { + sensitivity: 'base', + }) + ); + setEmployees(uniqueEmployees); // Group data by Phase → Time Type → Activity @@ -779,11 +786,23 @@ export function DetailDailyChecklistContent() { } // ACTIVITY rows - timeGroup.activities.forEach((activity, index) => { + const activities = timeGroup.activities; + + activities.sort((a, b) => + a.name.localeCompare(b.name, undefined, { + sensitivity: 'base', + }) + ); + + activities.forEach((activity, index) => { const indentClass = hasMultipleTimeTypes ? 'pl-12' : 'pl-8'; + console.log({ + activity, + }); + rows.push(