diff --git a/src/components/input/NumberInput.tsx b/src/components/input/NumberInput.tsx index e6e0e773..9eab9db6 100644 --- a/src/components/input/NumberInput.tsx +++ b/src/components/input/NumberInput.tsx @@ -35,7 +35,9 @@ const NumberInput = ({ | undefined; if (newChangeEvent) { - newChangeEvent.target.value = numberFormatValues.value; + newChangeEvent.target.value = parseFloat( + numberFormatValues.value + ) as unknown as string; onChange?.(newChangeEvent); } diff --git a/src/components/pages/expense/pdf/ExpensePDF.tsx b/src/components/pages/expense/pdf/ExpensePDF.tsx index f76b6f11..d6e694a9 100644 --- a/src/components/pages/expense/pdf/ExpensePDF.tsx +++ b/src/components/pages/expense/pdf/ExpensePDF.tsx @@ -287,8 +287,8 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => { PT LUMBUNG TELUR INDONESIA - SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel. - Cipedes, Kec. Sukajadi, Kota Bandung 40162 + Setra Duta Raya No.L3 No.7, Ciwaruga, Kec. Parongpong, Kabupaten + Bandung Barat, Jawa Barat 40514 diff --git a/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx b/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx index cdf18652..55420468 100644 --- a/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx +++ b/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx @@ -101,8 +101,8 @@ const PDFDocument = ({ PT LUMBUNG TELUR INDONESIA - SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel. - Cipedes, Kec. Sukajadi, Kota Bandung 40162 + Setra Duta Raya No.L3 No.7, Ciwaruga, Kec. Parongpong, Kabupaten + Bandung Barat, Jawa Barat 40514 diff --git a/src/components/pages/marketing/pdf/SalesOrderExport.tsx b/src/components/pages/marketing/pdf/SalesOrderExport.tsx index 55eb3b5b..87021ba5 100644 --- a/src/components/pages/marketing/pdf/SalesOrderExport.tsx +++ b/src/components/pages/marketing/pdf/SalesOrderExport.tsx @@ -87,8 +87,8 @@ const PDFDocument = ({ data }: { data: Marketing }) => { PT LUMBUNG TELUR INDONESIA - SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel. - Cipedes, Kec. Sukajadi, Kota Bandung 40162 + Setra Duta Raya No.L3 No.7, Ciwaruga, Kec. Parongpong, Kabupaten + Bandung Barat, Jawa Barat 40514 diff --git a/src/components/pages/master-data/product/form/ProductForm.tsx b/src/components/pages/master-data/product/form/ProductForm.tsx index 01fa192c..72355c22 100644 --- a/src/components/pages/master-data/product/form/ProductForm.tsx +++ b/src/components/pages/master-data/product/form/ProductForm.tsx @@ -154,17 +154,17 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { sku: values.sku, uom_id: values.uom_id, product_category_id: values.product_category_id, - product_price: parseInt(values.product_price.toString()) || 0, + product_price: parseFloat(values.product_price.toString()) || 0, selling_price: values.selling_price - ? parseInt(values.selling_price.toString()) || 0 + ? parseFloat(values.selling_price.toString()) || 0 : undefined, - tax: values.tax ? parseInt(values.tax.toString()) || 0 : undefined, + tax: values.tax ? parseFloat(values.tax.toString()) || 0 : undefined, expiry_period: values.expiry_period - ? parseInt(values.expiry_period.toString()) || 0 + ? parseFloat(values.expiry_period.toString()) || 0 : undefined, suppliers: values.suppliers.map((s) => ({ supplier_id: s.supplier?.value as number, - price: parseInt(s.price.toString()) || 0, + price: parseFloat(s.price.toString()) || 0, })), flag: values.flag, sub_flags: values.sub_flags, diff --git a/src/components/pages/purchase/PurchaseFilterModal.tsx b/src/components/pages/purchase/PurchaseFilterModal.tsx new file mode 100644 index 00000000..a9cd00cd --- /dev/null +++ b/src/components/pages/purchase/PurchaseFilterModal.tsx @@ -0,0 +1,201 @@ +'use client'; + +import { RefObject, useState, useEffect } from 'react'; +import { useFormik } from 'formik'; +import toast from 'react-hot-toast'; + +import { Icon } from '@iconify/react'; +import Modal from '@/components/Modal'; +import Button from '@/components/Button'; +import DateInput from '@/components/input/DateInput'; +import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; + +import { OptionType, useSelect } from '@/components/input/SelectInput'; +import { PurchaseFilter } from '@/types/api/purchase/purchase'; +import { ProductCategory } from '@/types/api/master-data/product-category'; +import { ProductCategoryApi } from '@/services/api/master-data'; +import { PURCHASE_ORDER_APPROVAL_LINE } from '@/config/approval-line'; + +interface PurchaseFilterModalProps { + ref: RefObject; + onSubmit?: (values: PurchaseFilter) => void; + onReset?: () => void; +} + +const PurchaseFilterModal = ({ + ref, + onSubmit, + onReset, +}: PurchaseFilterModalProps) => { + const closeModalHandler = () => { + ref.current?.close(); + }; + + // ===== DATE ERROR STATE ===== + const [dateErrorShown, setDateErrorShown] = useState(false); + const [hasDateError, setHasDateError] = useState(false); + + // ===== CLEANUP TOAST ON UNMOUNT ===== + useEffect(() => { + return () => { + if (dateErrorShown) { + toast.dismiss(); + } + }; + }, [dateErrorShown]); + + // ===== CLEANUP TOAST WHEN MODAL CLOSES ===== + useEffect(() => { + const dialogElement = ref.current; + const handleModalClose = () => { + if (dateErrorShown) { + toast.dismiss(); + setDateErrorShown(false); + } + }; + + dialogElement?.addEventListener('close', handleModalClose); + + return () => { + dialogElement?.removeEventListener('close', handleModalClose); + }; + }, [ref, dateErrorShown]); + + const { + setInputValue: setProductCategoryInputValue, + options: productCategoryOptions, + isLoadingOptions: isLoadingProductCategoryOptions, + loadMore: loadMoreProductCategory, + } = useSelect( + ProductCategoryApi.basePath, + 'id', + 'name', + 'search' + ); + + const formik = useFormik<{ + poDate: string; + category: { label: string; value: number }[]; + status: { label: string; value: string }[]; + }>({ + initialValues: { + poDate: '', + category: [], + status: [], + }, + onSubmit: async (values) => { + const formattedValues = { + ...values, + category: values.category.map((item) => String(item.value)), + status: values.status.map((item) => String(item.value)), + }; + + onSubmit?.(formattedValues); + closeModalHandler(); + }, + onReset: () => { + onReset?.(); + closeModalHandler(); + }, + }); + + const productCategoryChangeHandler = ( + val: OptionType | OptionType[] | null + ) => { + formik.setFieldValue('category', val); + }; + + const statusChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldValue('status', val); + }; + + return ( + +
+ {/* Modal Header */} +
+
+ +

Filter Data

+
+ + +
+ + {/* Modal Body */} +
+
+ + + + + ({ + label: item.step_name, + value: item.step_name, + }))} + /> +
+
+ + {/* Modal Footer */} +
+ + + +
+
+
+ ); +}; + +export default PurchaseFilterModal; diff --git a/src/components/pages/purchase/PurchaseTable.tsx b/src/components/pages/purchase/PurchaseTable.tsx index 43ddab1d..d1ae638c 100644 --- a/src/components/pages/purchase/PurchaseTable.tsx +++ b/src/components/pages/purchase/PurchaseTable.tsx @@ -14,6 +14,7 @@ import useSWRInfinite from 'swr/infinite'; import { CellContext, ColumnDef, SortingState } from '@tanstack/react-table'; import toast from 'react-hot-toast'; +import Link from 'next/link'; import { Icon } from '@iconify/react'; import Table from '@/components/Table'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; @@ -25,18 +26,19 @@ import PopoverContent from '@/components/popover/PopoverContent'; import RequirePermission from '@/components/helper/RequirePermission'; import StatusBadge from '@/components/helper/StatusBadge'; import PurchaseTableSkeleton from '@/components/pages/purchase/skeleton/PurchaseTableSkeleton'; +import ButtonFilter from '@/components/helper/ButtonFilter'; +import PurchaseFilterModal from '@/components/pages/purchase/PurchaseFilterModal'; import { cn, formatDate } from '@/lib/helper'; import { isResponseSuccess } from '@/lib/api-helper'; import { BaseApiResponse } from '@/types/api/api-general'; import { useTableFilter } from '@/services/hooks/useTableFilter'; -import { Purchase } from '@/types/api/purchase/purchase'; +import { Purchase, PurchaseFilter } from '@/types/api/purchase/purchase'; import { PurchaseApi } from '@/services/api/purchase'; import { ExpenseApi } from '@/services/api/expense'; import { Expense } from '@/types/api/expense'; import { Color } from '@/types/theme'; -import Link from 'next/link'; // ===== STATUS BADGE UTILITIES ===== const statusTextMap: Record = { @@ -165,14 +167,21 @@ const PurchaseTable = () => { } = useTableFilter({ initial: { search: '', + po_date: '', + approval_status: '', + product_category_id: '', }, paramMap: { page: 'page', pageSize: 'limit', + po_date: 'po_date', + approval_status: 'approval_status', + product_category_id: 'product_category_id', }, }); // ===== MODAL HOOKS ===== + const filterModal = useModal(); const deleteModal = useModal(); // ===== API DATA FETCHING ===== @@ -410,13 +419,17 @@ const PurchaseTable = () => { [updateFilter, setSearchValue] ); - // const pageSizeChangeHandler = useCallback( - // (val: OptionType | OptionType[] | null) => { - // const newVal = val as OptionType; - // setPageSize(newVal.value as number); - // }, - // [setPageSize] - // ); + const filterSubmitHandler = (values: PurchaseFilter) => { + updateFilter('po_date', values.poDate); + updateFilter('product_category_id', values.category.join(',')); + updateFilter('approval_status', values.status.join(',')); + }; + + const filterResetHandler = () => { + updateFilter('po_date', ''); + updateFilter('product_category_id', ''); + updateFilter('approval_status', ''); + }; return ( <> @@ -455,6 +468,19 @@ const PurchaseTable = () => { 'placeholder:font-semibold placeholder:text-base-content/50', }} /> + + @@ -513,6 +539,12 @@ const PurchaseTable = () => { {/* ===== MODAL COMPONENTS ===== */} + + { {/* eslint-disable-next-line jsx-a11y/alt-text */} @@ -273,8 +273,8 @@ const PurchaseOrderInvoice = ({ data }: PurchaseOrderInvoiceProps) => { PT LUMBUNG TELUR INDONESIA - SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel. - Cipedes, Kec. Sukajadi, Kota Bandung 40162 + Setra Duta Raya No.L3 No.7, Ciwaruga, Kec. Parongpong, Kabupaten + Bandung Barat, Jawa Barat 40514 diff --git a/src/components/pages/report/expense/export/ReportExpenseExportPDF.tsx b/src/components/pages/report/expense/export/ReportExpenseExportPDF.tsx index 352b0fa8..64d3178c 100644 --- a/src/components/pages/report/expense/export/ReportExpenseExportPDF.tsx +++ b/src/components/pages/report/expense/export/ReportExpenseExportPDF.tsx @@ -47,7 +47,7 @@ export const generateReportExpensePDF = async ( doc.setFontSize(7); doc.setTextColor(102, 102, 102); doc.text( - 'SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel. Cipedes, Kec. Sukajadi, Kota Bandung 40162', + 'Setra Duta Raya No.L3 No.7, Ciwaruga, Kec. Parongpong, Kabupaten Bandung Barat, Jawa Barat 40514', marginX, 25 ); diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index d39719a3..b0abe694 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -144,3 +144,9 @@ export type DeletePurchaseRequestItemPayload = { }; export type UpdatePurchaseRequestPayload = CreatePurchaseRequestPayload; + +export type PurchaseFilter = { + poDate: string; + category: string[]; + status: string[]; +};