From 322b519def4db1b92a3aee81863db64092f24ba8 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 12 Feb 2026 10:55:40 +0700 Subject: [PATCH] refactor(FE): Refactor filter schema and form handling for PurchasesPerSupplier --- .../filter/PurchasesPerSupplierFilter.ts | 110 ++++---------- .../tab/PurchasesPerSupplierTab.tsx | 137 ++++++++++-------- 2 files changed, 106 insertions(+), 141 deletions(-) diff --git a/src/components/pages/report/logistic-stock/filter/PurchasesPerSupplierFilter.ts b/src/components/pages/report/logistic-stock/filter/PurchasesPerSupplierFilter.ts index 70a01615..b3d9943b 100644 --- a/src/components/pages/report/logistic-stock/filter/PurchasesPerSupplierFilter.ts +++ b/src/components/pages/report/logistic-stock/filter/PurchasesPerSupplierFilter.ts @@ -1,88 +1,38 @@ -import { OptionType } from '@/components/input/SelectInput'; import * as yup from 'yup'; export type PurchasesPerSupplierFilterType = { - start_date: string | null | undefined; - end_date: string | null | undefined; - area_ids: OptionType[] | null | undefined; - supplier_ids: OptionType[] | null | undefined; - product_ids: OptionType[] | null | undefined; - product_category_ids: OptionType[] | null | undefined; - filter_by: OptionType | null | undefined; - sort_by: OptionType | null | undefined; + start_date: string | null; + end_date: string | null; + area_ids: string | null; + supplier_ids: string | null; + product_ids: string | null; + product_category_ids: string | null; + filter_by: string | null; + sort_by: string | null; }; -export const PurchasesPerSupplierFilterSchema: yup.ObjectSchema = - yup.object({ - start_date: yup.string().optional().nullable(), - end_date: yup - .string() - .optional() - .nullable() - .test( - 'is-greater-than-start', - 'Tanggal akhir tidak boleh masa lampau', - function (value) { - const { start_date } = this.parent; - if (!start_date || !value) return true; - return new Date(value) >= new Date(start_date); - } - ), - area_ids: yup - .array() - .of( - yup.object({ - value: yup.mixed().required(), - label: yup.string().required(), - }) - ) - .optional() - .nullable(), - supplier_ids: yup - .array() - .of( - yup.object({ - value: yup.mixed().required(), - label: yup.string().required(), - }) - ) - .optional() - .nullable(), - product_ids: yup - .array() - .of( - yup.object({ - value: yup.mixed().required(), - label: yup.string().required(), - }) - ) - .optional() - .nullable(), - product_category_ids: yup - .array() - .of( - yup.object({ - value: yup.mixed().required(), - label: yup.string().required(), - }) - ) - .optional() - .nullable(), - filter_by: yup - .object({ - value: yup.mixed().required(), - label: yup.string().required(), - }) - .optional() - .nullable(), - sort_by: yup - .object({ - value: yup.mixed().required(), - label: yup.string().required(), - }) - .optional() - .nullable(), - }); +export const PurchasesPerSupplierFilterSchema = yup.object({ + start_date: yup.string().optional().nullable(), + end_date: yup + .string() + .optional() + .nullable() + .test( + 'is-greater-than-start', + 'Tanggal akhir tidak boleh masa lampau', + function (value) { + const { start_date } = this.parent; + if (!start_date || !value) return true; + return new Date(value) >= new Date(start_date); + } + ), + area_ids: yup.string().nullable(), + supplier_ids: yup.string().nullable(), + product_ids: yup.string().nullable(), + product_category_ids: yup.string().nullable(), + filter_by: yup.string().nullable(), + sort_by: yup.string().nullable(), +}); export type PurchasesPerSupplierFilterValues = yup.InferType< typeof PurchasesPerSupplierFilterSchema diff --git a/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx b/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx index 794c45d6..23fb067e 100644 --- a/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx +++ b/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx @@ -125,21 +125,14 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { validationSchema: PurchasesPerSupplierFilterSchema, onSubmit: (values, { setSubmitting }) => { setFilterParams({ - start_date: values.start_date?.toString() || undefined, - end_date: values.end_date?.toString() || undefined, - area_id: - values.area_ids?.map((v) => String(v.value)).join(',') || undefined, - supplier_id: - values.supplier_ids?.map((v) => String(v.value)).join(',') || - undefined, - product_id: - values.product_ids?.map((v) => String(v.value)).join(',') || - undefined, - product_category_id: - values.product_category_ids?.map((v) => String(v.value)).join(',') || - undefined, - filter_by: values.filter_by?.value?.toString() || undefined, - sort_by: values.sort_by?.value?.toString() || undefined, + start_date: values.start_date || undefined, + end_date: values.end_date || undefined, + area_id: values.area_ids || undefined, + supplier_id: values.supplier_ids || undefined, + product_id: values.product_ids || undefined, + product_category_id: values.product_category_ids || undefined, + filter_by: values.filter_by || undefined, + sort_by: values.sort_by || undefined, }); filterModal.closeModal(); setIsSubmitted(true); @@ -220,6 +213,48 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { [formik, dateErrorShown] ); + // ===== DERIVED VALUES ===== + const areaIdsValue = useMemo(() => { + if (!formik.values.area_ids) return []; + const ids = formik.values.area_ids.split(','); + return areaOptions.filter((opt) => ids.includes(String(opt.value))); + }, [formik.values.area_ids, areaOptions]); + + const supplierIdsValue = useMemo(() => { + if (!formik.values.supplier_ids) return []; + const ids = formik.values.supplier_ids.split(','); + return supplierOptions.filter((opt) => ids.includes(String(opt.value))); + }, [formik.values.supplier_ids, supplierOptions]); + + const productIdsValue = useMemo(() => { + if (!formik.values.product_ids) return []; + const ids = formik.values.product_ids.split(','); + return productOptions.filter((opt) => ids.includes(String(opt.value))); + }, [formik.values.product_ids, productOptions]); + + const productCategoryIdsValue = useMemo(() => { + if (!formik.values.product_category_ids) return []; + const ids = formik.values.product_category_ids.split(','); + return productCategoryOptions.filter((opt) => + ids.includes(String(opt.value)) + ); + }, [formik.values.product_category_ids, productCategoryOptions]); + + const filterByValue = useMemo(() => { + if (!formik.values.filter_by) return null; + return ( + dataTypeOptions.find((opt) => opt.value === formik.values.filter_by) || + null + ); + }, [formik.values.filter_by, dataTypeOptions]); + + const sortByValue = useMemo(() => { + if (!formik.values.sort_by) return null; + return ( + sortByOptions.find((opt) => opt.value === formik.values.sort_by) || null + ); + }, [formik.values.sort_by, sortByOptions]); + // ===== ACTIVE FILTERS COUNT ===== const activeFiltersCount = useMemo(() => { let count = 0; @@ -875,17 +910,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { label='Area' placeholder='Pilih Area' options={areaOptions} - value={ - (formik.values.area_ids as - | { value: number; label: string } - | { value: number; label: string }[] - | null - | undefined) || [] - } + value={areaIdsValue} onChange={(val) => { formik.setFieldValue( 'area_ids', - Array.isArray(val) ? val : val ? [val] : null + Array.isArray(val) && val.length > 0 + ? val.map((v) => String(v.value)).join(',') + : null ); }} isLoading={isLoadingAreas} @@ -898,17 +929,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { label='Supplier' placeholder='Pilih Supplier' options={supplierOptions} - value={ - (formik.values.supplier_ids as - | { value: number; label: string } - | { value: number; label: string }[] - | null - | undefined) || [] - } + value={supplierIdsValue} onChange={(val) => { formik.setFieldValue( 'supplier_ids', - Array.isArray(val) ? val : val ? [val] : null + Array.isArray(val) && val.length > 0 + ? val.map((v) => String(v.value)).join(',') + : null ); }} isLoading={isLoadingSuppliers} @@ -921,17 +948,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { label='Produk' placeholder='Pilih Produk' options={productOptions} - value={ - (formik.values.product_ids as - | { value: number; label: string } - | { value: number; label: string }[] - | null - | undefined) || [] - } + value={productIdsValue} onChange={(val) => { formik.setFieldValue( 'product_ids', - Array.isArray(val) ? val : val ? [val] : null + Array.isArray(val) && val.length > 0 + ? val.map((v) => String(v.value)).join(',') + : null ); }} isLoading={isLoadingProducts} @@ -944,17 +967,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { label='Kategori Produk' placeholder='Pilih Kategori Produk' options={productCategoryOptions} - value={ - (formik.values.product_category_ids as - | { value: number; label: string } - | { value: number; label: string }[] - | null - | undefined) || [] - } + value={productCategoryIdsValue} onChange={(val) => { formik.setFieldValue( 'product_category_ids', - Array.isArray(val) ? val : val ? [val] : null + Array.isArray(val) && val.length > 0 + ? val.map((v) => String(v.value)).join(',') + : null ); }} isLoading={isLoadingProductCategories} @@ -967,15 +986,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { label='Filter Berdasarkan' placeholder='Pilih Filter Berdasarkan' options={dataTypeOptions} - value={ - (formik.values.filter_by as - | { value: string; label: string } - | null - | undefined) || null - } + value={filterByValue} onChange={(val) => { if (!Array.isArray(val)) { - formik.setFieldValue('filter_by', val); + formik.setFieldValue( + 'filter_by', + val?.value?.toString() || null + ); } }} className={{ wrapper: 'w-full' }} @@ -987,15 +1004,13 @@ const PurchasesPerSupplierTab = ({ tabId }: PurchasesPerSupplierTabProps) => { label='Urutkan Berdasarkan' placeholder='Pilih Urutkan Berdasarkan' options={sortByOptions} - value={ - (formik.values.sort_by as - | { value: string; label: string } - | null - | undefined) || null - } + value={sortByValue} onChange={(val) => { if (!Array.isArray(val)) { - formik.setFieldValue('sort_by', val); + formik.setFieldValue( + 'sort_by', + val?.value?.toString() || null + ); } }} className={{ wrapper: 'w-full' }}