refactor(FE-208): rename PurchaseRequestForm to PurchaseRequisitionsForm and update related components

This commit is contained in:
rstubryan
2025-11-08 09:53:21 +07:00
parent 53751d566c
commit 10dca5c692
5 changed files with 300 additions and 506 deletions
+4 -4
View File
@@ -1,11 +1,11 @@
import PurchaseRequestForm from '@/components/pages/purchase/form/request/PurchaseRequestForm'; import PurchaseRequisitionsForm from '@/components/pages/purchase/form/request/PurchaseRequisitionsForm';
const AddPurchaseRequest = () => { const AddPurchaseRequisitions = () => {
return ( return (
<div className='w-full p-4 flex flex-row justify-center'> <div className='w-full p-4 flex flex-row justify-center'>
<PurchaseRequestForm /> <PurchaseRequisitionsForm />
</div> </div>
); );
}; };
export default AddPurchaseRequest; export default AddPurchaseRequisitions;
+6 -244
View File
@@ -2,243 +2,9 @@
import { useRouter, useSearchParams } from 'next/navigation'; import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr'; import useSWR from 'swr';
import PurchaseRequisitionsForm from '@/components/pages/purchase/form/request/PurchaseRequisitionsForm';
import PurchaseRequestForm from '@/components/pages/purchase/form/request/PurchaseRequestForm';
import { PurchaseApi } from '@/services/api/purchase'; import { PurchaseApi } from '@/services/api/purchase';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
import { Purchase } from '@/types/api/purchase/purchase';
// TODO: delete dummy data
const DUMMY_PURCHASE_EDIT: Purchase = {
id: 1,
pr_number: 'PR-001',
po_number: 'PO-001',
po_date: '2024-01-15',
supplier: {
id: 1,
name: 'Supplier A',
address: '123 Main St, Cityville',
account_number: 'ACC-12345',
alias: 'SupA',
category: 'Electronics',
type: 'Local',
phone: '555-1234',
email: 'email@.com',
npwp: '12.345.678.9-012.345',
pic: 'John Doe',
balance: 1000000,
hatchery: 'N/A',
due_date: 30,
created_at: '2024-01-10T10:00:00Z',
updated_at: '2024-01-12T12:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
credit_term: 30,
due_date: '2024-02-14',
grand_total: 1500000,
notes: 'Urgent delivery required',
deleted_at: null,
created_at: '2024-01-10T10:00:00Z',
updated_at: '2024-01-12T12:00:00Z',
created_by: 2,
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
purchase_items: [
{
id: 1,
product_warehouse: {
id: 1,
product_id: 1,
warehouse_id: 1,
quantity: 100,
product: {
id: 1,
name: 'Product A',
brand: 'Brand A',
sku: 'PROD-A-001',
product_price: 500000,
expiry_period: 0,
uom: {
id: 1,
name: 'pcs',
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
product_category: {
id: 1,
code: 'CAT-1',
name: 'Electronics',
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
suppliers: [
{
id: 1,
name: 'Supplier A',
alias: 'SupA',
pic: 'John Doe',
type: 'Local',
category: 'Electronics',
hatchery: 'N/A',
phone: '555-1234',
email: 'email@.com',
address: '123 Main St, Cityville',
npwp: '12.345.678.9-012.345',
account_number: 'ACC-12345',
due_date: 30,
balance: 1000000,
created_at: '2024-01-10T10:00:00Z',
updated_at: '2024-01-12T12:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
],
flags: [],
created_at: '2024-01-05T09:00:00Z',
updated_at: '2024-01-07T11:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
warehouse: {
id: 1,
name: 'Main Warehouse',
type: 'AREA',
area: { id: 1, name: 'Area 1' },
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
created_at: '2024-01-05T09:00:00Z',
updated_at: '2024-01-07T11:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
product: {
id: 1,
name: 'Product A',
brand: 'Brand A',
sku: 'PROD-A-001',
product_price: 500000,
expiry_period: 0,
uom: {
id: 1,
name: 'pcs',
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
product_category: {
id: 1,
code: 'CAT-1',
name: 'Electronics',
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
suppliers: [
{
id: 1,
name: 'Supplier A',
alias: 'SupA',
pic: 'John Doe',
type: 'Local',
category: 'Electronics',
hatchery: 'N/A',
phone: '555-1234',
email: 'email@.com',
address: '123 Main St, Cityville',
npwp: '12.345.678.9-012.345',
account_number: 'ACC-12345',
due_date: 30,
balance: 1000000,
created_at: '2024-01-10T10:00:00Z',
updated_at: '2024-01-12T12:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
],
flags: [],
created_at: '2024-01-05T09:00:00Z',
updated_at: '2024-01-07T11:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
warehouse: {
id: 1,
name: 'Main Warehouse',
type: 'AREA',
area: { id: 1, name: 'Area 1' },
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
sub_qty: 3,
},
],
};
const PurchaseEdit = () => { const PurchaseEdit = () => {
const router = useRouter(); const router = useRouter();
@@ -261,11 +27,7 @@ const PurchaseEdit = () => {
); );
} }
// TODO: remove dummy data and integrate with real API if (!isLoadingPurchase && (!purchase || isResponseError(purchase))) {
if (
!isLoadingPurchase &&
(!purchase || (isResponseError(purchase) && !DUMMY_PURCHASE_EDIT))
) {
router.replace('/404'); router.replace('/404');
return; return;
} }
@@ -275,9 +37,9 @@ const PurchaseEdit = () => {
{isLoadingPurchase && ( {isLoadingPurchase && (
<span className='loading loading-spinner loading-xl' /> <span className='loading loading-spinner loading-xl' />
)} )}
{!isLoadingPurchase && isResponseSuccess(purchase) && (
{/* DEBUG TEMP: force dummy to verify form mapping/rendering */} <PurchaseRequisitionsForm type='edit' initialValues={purchase.data} />
<PurchaseRequestForm type='edit' initialValues={DUMMY_PURCHASE_EDIT} /> )}
</div> </div>
); );
}; };
+6 -66
View File
@@ -2,59 +2,9 @@
import { useRouter, useSearchParams } from 'next/navigation'; import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr'; import useSWR from 'swr';
import PurchaseRequisitionsForm from '@/components/pages/purchase/form/request/PurchaseRequisitionsForm';
import PurchaseRequestForm from '@/components/pages/purchase/form/request/PurchaseRequestForm';
import { PurchaseApi } from '@/services/api/purchase'; import { PurchaseApi } from '@/services/api/purchase';
import { isResponseError } from '@/lib/api-helper'; import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
import { Purchase } from '@/types/api/purchase/purchase';
// TODO: delete dummy data
const DUMMY_PURCHASE_DETAIL: Purchase = {
id: 1,
pr_number: 'PR-001',
po_number: 'PO-001',
po_date: '2024-01-15',
supplier: {
id: 1,
name: 'Supplier A',
address: '123 Main St, Cityville',
account_number: 'ACC-12345',
alias: 'SupA',
category: 'Electronics',
type: 'Local',
phone: '555-1234',
email: 'email@.com',
npwp: '12.345.678.9-012.345',
pic: 'John Doe',
balance: 1000000,
hatchery: 'N/A',
due_date: 30,
created_at: '2024-01-10T10:00:00Z',
updated_at: '2024-01-12T12:00:00Z',
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
},
credit_term: 30,
due_date: '2024-02-14',
grand_total: 1500000,
notes: 'Urgent delivery required',
deleted_at: null,
created_at: '2024-01-10T10:00:00Z',
updated_at: '2024-01-12T12:00:00Z',
created_by: 2,
created_user: {
id: 2,
id_user: 2,
email: 'a@email.com',
name: 'Admin User',
},
};
const PurchaseDetail = () => { const PurchaseDetail = () => {
const router = useRouter(); const router = useRouter();
@@ -77,11 +27,7 @@ const PurchaseDetail = () => {
); );
} }
// TODO: remove dummy data and integrate with real API if (!isLoadingPurchase && (!purchase || isResponseError(purchase))) {
if (
!isLoadingPurchase &&
(!purchase || (isResponseError(purchase) && !DUMMY_PURCHASE_DETAIL))
) {
router.replace('/404'); router.replace('/404');
return; return;
} }
@@ -91,15 +37,9 @@ const PurchaseDetail = () => {
{isLoadingPurchase && ( {isLoadingPurchase && (
<span className='loading loading-spinner loading-xl' /> <span className='loading loading-spinner loading-xl' />
)} )}
{/* {!isLoadingPurchase && isResponseSuccess(purchase) && ( {!isLoadingPurchase && isResponseSuccess(purchase) && (
<PurchaseRequestForm type='detail' initialValues={purchase.data} /> <PurchaseRequisitionsForm type='detail' initialValues={purchase.data} />
)} */} )}
{/* TODO: remove this dummy data and integrate to real API */}
<PurchaseRequestForm
type='detail'
initialValues={DUMMY_PURCHASE_DETAIL}
/>
</div> </div>
); );
}; };
@@ -149,9 +149,12 @@ const PurchaseTable = () => {
cell: (props) => props.row.original.supplier.name, cell: (props) => props.row.original.supplier.name,
}, },
{ {
accessorKey: 'created_user', accessorKey: 'created_by',
header: 'Nama Pengaju', header: 'Nama Pengaju',
cell: (props) => props.row.original.created_user.name, cell: (props) => {
const purchase = props.row.original;
return purchase.created_user?.name || `User ID: ${purchase.created_by}`;
},
}, },
{ {
accessorKey: 'po_date', accessorKey: 'po_date',
@@ -172,8 +175,9 @@ const PurchaseTable = () => {
{ {
header: 'Aging', header: 'Aging',
cell: (props) => { cell: (props) => {
if (!props.row.original.po_date) return '-'; const purchase = props.row.original;
const poDate = new Date(props.row.original.po_date); if (!purchase.po_date) return '-';
const poDate = new Date(purchase.po_date);
const today = new Date(); const today = new Date();
const diffTime = Math.abs(today.getTime() - poDate.getTime()); const diffTime = Math.abs(today.getTime() - poDate.getTime());
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
@@ -17,11 +17,11 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import { useModal } from '@/components/Modal'; import { useModal } from '@/components/Modal';
import { import {
PurchaseRequestFormSchema, PurchaseRequisitionsFormSchema,
PurchaseRequestFormValues, PurchaseRequisitionsFormValues,
getPurchaseRequestFormInitialValues, getPurchaseRequisitionsFormInitialValues,
UpdatePurchaseRequestFormSchema, UpdatePurchaseRequisitionsFormSchema,
} from './PurchaseRequestForm.schema'; } from './PurchaseRequisitionsForm.schema';
import { import {
SupplierApi, SupplierApi,
AreaApi, AreaApi,
@@ -37,7 +37,7 @@ import { PurchaseApi } from '@/services/api/purchase';
import Card from '@/components/Card'; import Card from '@/components/Card';
import { import {
CreatePurchaseRequestPayload, CreatePurchaseRequisitionsPayload,
Purchase, Purchase,
} from '@/types/api/purchase/purchase'; } from '@/types/api/purchase/purchase';
@@ -46,7 +46,7 @@ interface PurchaseRequestFormProps {
initialValues?: Purchase; initialValues?: Purchase;
} }
const PurchaseRequestForm = ({ const PurchaseRequisitionsForm = ({
type = 'add', type = 'add',
initialValues, initialValues,
}: PurchaseRequestFormProps) => { }: PurchaseRequestFormProps) => {
@@ -72,10 +72,10 @@ const PurchaseRequestForm = ({
// ===== UTILITY FUNCTIONS ===== // ===== UTILITY FUNCTIONS =====
const getPurchaseItemError = ( const getPurchaseItemError = (
idx: number, idx: number,
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'sub_qty' field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'quantity'
): { isError: boolean; errorMessage: string } => { ): { isError: boolean; errorMessage: string } => {
const touchedItem = formik.touched.purchase_items?.[idx]; const touchedItem = formik.touched.items?.[idx];
const errorItem = formik.errors.purchase_items?.[idx] as const errorItem = formik.errors.items?.[idx] as
| Record<string, string> | Record<string, string>
| undefined; | undefined;
@@ -103,7 +103,7 @@ const PurchaseRequestForm = ({
// ===== SUBMISSION HANDLERS ===== // ===== SUBMISSION HANDLERS =====
const createPurchaseRequestHandler = useCallback( const createPurchaseRequestHandler = useCallback(
async (payload: CreatePurchaseRequestPayload) => { async (payload: CreatePurchaseRequisitionsPayload) => {
const res = await PurchaseApi.create(payload); const res = await PurchaseApi.create(payload);
if (isResponseError(res)) { if (isResponseError(res)) {
setPurchaseRequestFormErrorMessage(res.message); setPurchaseRequestFormErrorMessage(res.message);
@@ -118,7 +118,7 @@ const PurchaseRequestForm = ({
const updatePurchaseRequestHandler = useCallback( const updatePurchaseRequestHandler = useCallback(
async ( async (
purchaseRequestId: number, purchaseRequestId: number,
payload: CreatePurchaseRequestPayload payload: CreatePurchaseRequisitionsPayload
) => { ) => {
const res = await PurchaseApi.update(purchaseRequestId, payload); const res = await PurchaseApi.update(purchaseRequestId, payload);
if (isResponseError(res)) { if (isResponseError(res)) {
@@ -170,47 +170,51 @@ const PurchaseRequestForm = ({
} = useSelect(WarehouseApi.basePath, 'id', 'name', 'search'); } = useSelect(WarehouseApi.basePath, 'id', 'name', 'search');
// ===== FORM CONFIGURATION ===== // ===== FORM CONFIGURATION =====
const formikInitialValues = useMemo<PurchaseRequestFormValues>( const formikInitialValues = useMemo<PurchaseRequisitionsFormValues>(
() => getPurchaseRequestFormInitialValues(initialValues), () => getPurchaseRequisitionsFormInitialValues(initialValues),
[initialValues] [initialValues]
); );
const formik = useFormik<PurchaseRequestFormValues>({ const formik = useFormik<PurchaseRequisitionsFormValues>({
initialValues: formikInitialValues, initialValues: formikInitialValues,
validationSchema: validationSchema:
type === 'edit' type === 'edit'
? UpdatePurchaseRequestFormSchema ? UpdatePurchaseRequisitionsFormSchema
: PurchaseRequestFormSchema, : PurchaseRequisitionsFormSchema,
validateOnChange: true, validateOnChange: true,
validateOnBlur: true, validateOnBlur: true,
onSubmit: async (values) => { onSubmit: async (values) => {
const payload: CreatePurchaseRequestPayload = { const payload: CreatePurchaseRequisitionsPayload = {
supplier_id: supplier_id:
typeof values.supplier_id === 'string' typeof values.supplier_id === 'string'
? parseInt(values.supplier_id) || 0 ? parseInt(values.supplier_id) || 0
: values.supplier_id || 0, : values.supplier_id || 0,
credit_term:
typeof values.credit_term === 'string'
? parseInt(values.credit_term) || 0
: values.credit_term || 0,
notes: values.notes || '', notes: values.notes || '',
purchase_items: (values.purchase_items || []).map((item) => ({ area_id:
typeof values.area_id === 'string'
? parseInt(values.area_id) || 0
: values.area_id || 0,
location_id:
typeof values.location_id === 'string'
? parseInt(values.location_id) || 0
: values.location_id || 0,
warehouse_id: warehouse_id:
typeof item.warehouse_id === 'string' typeof values.warehouse_id === 'string'
? parseInt(item.warehouse_id) || 0 ? parseInt(values.warehouse_id) || 0
: item.warehouse_id || 0, : values.warehouse_id || 0,
product_id: items: (values.items || []).map((item) => ({
typeof item.product_id === 'string'
? parseInt(item.product_id) || 0
: item.product_id || 0,
product_warehouse_id: product_warehouse_id:
typeof item.product_warehouse_id === 'string' typeof item.product_warehouse_id === 'string'
? parseInt(item.product_warehouse_id) || 0 ? parseInt(item.product_warehouse_id) || 0
: item.product_warehouse_id || 0, : item.product_warehouse_id || 0,
sub_qty: product_id:
typeof item.sub_qty === 'string' typeof item.product_id === 'string'
? parseFloat(item.sub_qty) || 0 ? parseInt(item.product_id) || 0
: item.sub_qty || 0, : item.product_id || 0,
quantity:
typeof item.quantity === 'string'
? parseFloat(item.quantity) || 0
: item.quantity || 0,
})), })),
}; };
@@ -261,7 +265,7 @@ const PurchaseRequestForm = ({
const productUrl = useMemo(() => { const productUrl = useMemo(() => {
const productIds = const productIds =
formik.values.purchase_items formik.values.items
?.filter( ?.filter(
(item) => item.product_id && typeof item.product_id === 'number' (item) => item.product_id && typeof item.product_id === 'number'
) )
@@ -272,7 +276,7 @@ const PurchaseRequestForm = ({
id: productIds.join(','), id: productIds.join(','),
}).toString()}` }).toString()}`
: null; : null;
}, [formik.values.purchase_items]); }, [formik.values.items]);
const { data: productsResponse } = useSWR( const { data: productsResponse } = useSWR(
productUrl, productUrl,
@@ -392,16 +396,12 @@ const PurchaseRequestForm = ({
setLocationSelectInputValue(''); setLocationSelectInputValue('');
// Reset area dependent fields in all purchase items // Reset area dependent fields in all purchase items
if (formik.values.purchase_items) { if (formik.values.items) {
formik.values.purchase_items.forEach((_, idx) => { formik.values.items.forEach((_, idx) => {
formik.setFieldValue(`purchase_items.${idx}.warehouse`, null); formik.setFieldValue(`items.${idx}.product_warehouse`, null);
formik.setFieldValue(`purchase_items.${idx}.warehouse_id`, ''); formik.setFieldValue(`items.${idx}.product_warehouse_id`, null);
formik.setFieldValue(`purchase_items.${idx}.product_warehouse`, null); formik.setFieldValue(`items.${idx}.product`, null);
formik.setFieldValue( formik.setFieldValue(`items.${idx}.product_id`, '');
`purchase_items.${idx}.product_warehouse_id`,
null
);
formik.setFieldValue(`purchase_items.${idx}.product_id`, '');
}); });
} }
}; };
@@ -414,16 +414,12 @@ const PurchaseRequestForm = ({
formik.setFieldValue('location_id', (location as OptionType)?.value || 0); formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
// Reset location dependent fields in all purchase items // Reset location dependent fields in all purchase items
if (formik.values.purchase_items) { if (formik.values.items) {
formik.values.purchase_items.forEach((_, idx) => { formik.values.items.forEach((_, idx) => {
formik.setFieldValue(`purchase_items.${idx}.warehouse`, null); formik.setFieldValue(`items.${idx}.product_warehouse`, null);
formik.setFieldValue(`purchase_items.${idx}.warehouse_id`, ''); formik.setFieldValue(`items.${idx}.product_warehouse_id`, null);
formik.setFieldValue(`purchase_items.${idx}.product_warehouse`, null); formik.setFieldValue(`items.${idx}.product`, null);
formik.setFieldValue( formik.setFieldValue(`items.${idx}.product_id`, '');
`purchase_items.${idx}.product_warehouse_id`,
null
);
formik.setFieldValue(`purchase_items.${idx}.product_id`, '');
}); });
} }
}; };
@@ -431,48 +427,43 @@ const PurchaseRequestForm = ({
// Purchase Items Handlers // Purchase Items Handlers
const addPurchaseItem = () => { const addPurchaseItem = () => {
const newPurchaseItems = [ const newPurchaseItems = [
...(formik.values.purchase_items || []), ...(formik.values.items || []),
{ {
warehouse: null,
warehouse_id: '',
product: null,
product_id: '',
product_warehouse: null, product_warehouse: null,
product_warehouse_id: null, product_warehouse_id: null,
sub_qty: '', product: null,
product_id: '',
quantity: '',
}, },
]; ];
formik.setFieldValue('purchase_items', newPurchaseItems); formik.setFieldValue('items', newPurchaseItems);
}; };
const removePurchaseItem = (idx: number) => { const removePurchaseItem = (idx: number) => {
const updatedPurchaseItems = formik.values.purchase_items?.filter( const updatedPurchaseItems = formik.values.items?.filter(
(_, i) => i !== idx (_, i) => i !== idx
); );
formik.setFieldValue('purchase_items', updatedPurchaseItems); formik.setFieldValue('items', updatedPurchaseItems);
}; };
const removeSelectedPurchaseItems = () => { const removeSelectedPurchaseItems = () => {
const updatedPurchaseItems = formik.values.purchase_items?.filter( const updatedPurchaseItems = formik.values.items?.filter(
(_, idx) => !selectedPurchaseItems.includes(idx) (_, idx) => !selectedPurchaseItems.includes(idx)
); );
formik.setFieldValue('purchase_items', updatedPurchaseItems); formik.setFieldValue('items', updatedPurchaseItems);
setSelectedPurchaseItems([]); setSelectedPurchaseItems([]);
}; };
// ===== PURCHASE ITEM OPERATIONS ===== // ===== PURCHASE ITEM OPERATIONS =====
const handlePurchaseItemChange = ( const handlePurchaseItemChange = (
idx: number, idx: number,
field: 'sub_qty' | 'price', field: 'quantity',
value: string | number value: string | number
) => { ) => {
if (field === 'sub_qty') { if (field === 'quantity') {
const numValue = typeof value === 'string' ? parseInt(value) || 0 : value;
formik.setFieldValue(`purchase_items.${idx}.sub_qty`, numValue);
} else if (field === 'price') {
const numValue = const numValue =
typeof value === 'string' ? parseFloat(value) || 0 : value; typeof value === 'string' ? parseFloat(value) || 0 : value;
formik.setFieldValue(`purchase_items.${idx}.price`, numValue); formik.setFieldValue(`items.${idx}.quantity`, numValue);
} }
}; };
@@ -525,28 +516,28 @@ const PurchaseRequestForm = ({
isClearable isClearable
/> />
<NumberInput {/*<NumberInput*/}
required={!!formik.values.supplier_id} {/* required={!!formik.values.supplier_id}*/}
label='Jatuh tempo (hari)' {/* label='Jatuh tempo (hari)'*/}
name='credit_term' {/* name='credit_term'*/}
value={formik.values.credit_term || ''} {/* value={formik.values.credit_term || ''}*/}
onChange={formik.handleChange} {/* onChange={formik.handleChange}*/}
onBlur={formik.handleBlur} {/* onBlur={formik.handleBlur}*/}
isError={ {/* isError={*/}
formik.touched.credit_term && {/* formik.touched.credit_term &&*/}
Boolean(formik.errors.credit_term) {/* Boolean(formik.errors.credit_term)*/}
} {/* }*/}
errorMessage={formik.errors.credit_term as string} {/* errorMessage={formik.errors.credit_term as string}*/}
readOnly={type === 'detail' || !formik.values.supplier_id} {/* readOnly={type === 'detail' || !formik.values.supplier_id}*/}
disabled={type === 'detail' || !formik.values.supplier_id} {/* disabled={type === 'detail' || !formik.values.supplier_id}*/}
allowNegative={false} {/* allowNegative={false}*/}
decimalScale={0} {/* decimalScale={0}*/}
placeholder={ {/* placeholder={*/}
!formik.values.supplier_id {/* !formik.values.supplier_id*/}
? 'Pilih Vendor terlebih dahulu' {/* ? 'Pilih Vendor terlebih dahulu'*/}
: 'Masukkan jumlah hari jatuh tempo' {/* : 'Masukkan jumlah hari jatuh tempo'*/}
} {/* }*/}
/> {/*/>*/}
<SelectInput <SelectInput
label='Area' label='Area'
@@ -583,6 +574,59 @@ const PurchaseRequestForm = ({
key={`location-${formik.values.area_id}`} key={`location-${formik.values.area_id}`}
/> />
<SelectInput
label='Gudang'
placeholder={
!formik.values.area_id || !formik.values.location_id
? 'Pilih Area dan Lokasi terlebih dahulu'
: 'Pilih Gudang...'
}
value={formik.values.warehouse}
onChange={(val) => {
const warehouse = val as OptionType | null;
formik.setFieldTouched('warehouse', true);
formik.setFieldValue('warehouse', warehouse);
formik.setFieldTouched('warehouse_id', true);
formik.setFieldValue(
'warehouse_id',
(warehouse as OptionType)?.value || 0
);
if (formik.values.items) {
formik.values.items.forEach((_, idx) => {
formik.setFieldValue(
`items.${idx}.product_warehouse`,
null
);
formik.setFieldValue(
`items.${idx}.product_warehouse_id`,
null
);
formik.setFieldValue(`items.${idx}.product`, null);
formik.setFieldValue(`items.${idx}.product_id`, '');
});
}
}}
options={warehouseOptions}
onInputChange={setWarehouseSelectInputValue}
isLoading={isLoadingWarehouses}
isError={
formik.touched.warehouse &&
Boolean(formik.errors.warehouse_id)
}
errorMessage={formik.errors.warehouse_id as string}
isDisabled={
type === 'detail' ||
!formik.values.area_id ||
!formik.values.location_id
}
isClearable={
type !== 'detail' &&
!!formik.values.area_id &&
!!formik.values.location_id
}
key={`warehouse-${formik.values.area_id}-${formik.values.location_id}`}
/>
<div className={'col-span-2'}> <div className={'col-span-2'}>
<TextInput <TextInput
label='Notes' label='Notes'
@@ -618,16 +662,14 @@ const PurchaseRequestForm = ({
type='checkbox' type='checkbox'
className='checkbox checkbox-sm' className='checkbox checkbox-sm'
checked={ checked={
formik.values.purchase_items?.length === formik.values.items?.length ===
selectedPurchaseItems.length && selectedPurchaseItems.length &&
formik.values.purchase_items?.length > 0 formik.values.items?.length > 0
} }
onChange={(e) => { onChange={(e) => {
if (e.target.checked) { if (e.target.checked) {
setSelectedPurchaseItems( setSelectedPurchaseItems(
formik.values.purchase_items?.map( formik.values.items?.map((_, idx) => idx) ?? []
(_, idx) => idx
) ?? []
); );
} else { } else {
setSelectedPurchaseItems([]); setSelectedPurchaseItems([]);
@@ -636,10 +678,6 @@ const PurchaseRequestForm = ({
/> />
</th> </th>
)} )}
<th>
Gudang
<span className='text-error'>*</span>
</th>
<th> <th>
Item Item
<span className='text-error'>*</span> <span className='text-error'>*</span>
@@ -654,7 +692,7 @@ const PurchaseRequestForm = ({
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{formik.values.purchase_items?.map((item, idx) => ( {formik.values.items?.map((item, idx) => (
<tr key={`purchase-item-${idx}`}> <tr key={`purchase-item-${idx}`}>
{type !== 'detail' && ( {type !== 'detail' && (
<td className='!align-middle'> <td className='!align-middle'>
@@ -677,91 +715,141 @@ const PurchaseRequestForm = ({
/> />
</td> </td>
)} )}
<td> {/*<td>*/}
<SelectInput {/* <SelectInput*/}
required {/* required*/}
value={item.warehouse} {/* value={item.warehouse}*/}
key={`warehouse-${idx}`} {/* key={`warehouse-${idx}`}*/}
onChange={(val) => { {/* onChange={(val) => {*/}
const warehouse = val as OptionType | null; {/* const warehouse = val as OptionType | null;*/}
formik.setFieldValue( {/* formik.setFieldValue(*/}
`purchase_items.${idx}.warehouse`, {/* `purchase_items.${idx}.warehouse`,*/}
warehouse {/* warehouse*/}
); {/* );*/}
formik.setFieldValue( {/* formik.setFieldValue(*/}
`purchase_items.${idx}.warehouse_id`, {/* `purchase_items.${idx}.warehouse_id`,*/}
(warehouse as OptionType)?.value || 0 {/* (warehouse as OptionType)?.value || 0*/}
); {/* );*/}
formik.setFieldTouched( {/* formik.setFieldTouched(*/}
`purchase_items.${idx}.product_warehouse`, {/* `purchase_items.${idx}.product_warehouse`,*/}
false {/* false*/}
); {/* );*/}
formik.setFieldValue( {/* formik.setFieldValue(*/}
`purchase_items.${idx}.product_warehouse`, {/* `purchase_items.${idx}.product_warehouse`,*/}
null {/* null*/}
); {/* );*/}
formik.setFieldTouched( {/* formik.setFieldTouched(*/}
`purchase_items.${idx}.product_warehouse_id`, {/* `purchase_items.${idx}.product_warehouse_id`,*/}
false {/* false*/}
); {/* );*/}
formik.setFieldValue( {/* formik.setFieldValue(*/}
`purchase_items.${idx}.product_warehouse_id`, {/* `purchase_items.${idx}.product_warehouse_id`,*/}
0 {/* 0*/}
); {/* );*/}
formik.setFieldTouched( {/* formik.setFieldTouched(*/}
`purchase_items.${idx}.product_id`, {/* `purchase_items.${idx}.product_id`,*/}
false {/* false*/}
); {/* );*/}
formik.setFieldValue( {/* formik.setFieldValue(*/}
`purchase_items.${idx}.product_id`, {/* `purchase_items.${idx}.product_id`,*/}
0 {/* 0*/}
); {/* );*/}
}} {/* }}*/}
options={warehouseOptions} {/* options={warehouseOptions}*/}
onInputChange={setWarehouseSelectInputValue} {/* onInputChange={setWarehouseSelectInputValue}*/}
isLoading={isLoadingWarehouses} {/* isLoading={isLoadingWarehouses}*/}
isError={ {/* isError={*/}
getPurchaseItemError(idx, 'warehouse_id').isError {/* getPurchaseItemError(idx, 'warehouse_id').isError*/}
} {/* }*/}
errorMessage={ {/* errorMessage={*/}
getPurchaseItemError(idx, 'warehouse_id') {/* getPurchaseItemError(idx, 'warehouse_id')*/}
.errorMessage {/* .errorMessage*/}
} {/* }*/}
isDisabled={type === 'detail'} {/* isDisabled={type === 'detail'}*/}
isClearable {/* isClearable*/}
placeholder='Pilih Gudang' {/* placeholder='Pilih Gudang'*/}
className={{ {/* className={{*/}
wrapper: 'min-w-32', {/* wrapper: 'min-w-32',*/}
}} {/* }}*/}
/> {/* />*/}
</td> {/*</td>*/}
{/*<td>*/}
{/* <SelectInput*/}
{/* required*/}
{/* value={item.product_warehouse}*/}
{/* key={`product-warehouse-${idx}-${item.warehouse_id}`}*/}
{/* onChange={(val) => {*/}
{/* const productWarehouse =*/}
{/* val as ProductWarehouseOptionType | null;*/}
{/* formik.setFieldValue(*/}
{/* `purchase_items.${idx}.product_warehouse`,*/}
{/* productWarehouse*/}
{/* );*/}
{/* formik.setFieldValue(*/}
{/* `purchase_items.${idx}.product_warehouse_id`,*/}
{/* (productWarehouse as ProductWarehouseOptionType)*/}
{/* ?.value || 0*/}
{/* );*/}
{/* const productId =*/}
{/* (productWarehouse as ProductWarehouseOptionType)*/}
{/* ?.product_id || 0;*/}
{/* formik.setFieldValue(*/}
{/* `purchase_items.${idx}.product_id`,*/}
{/* productId*/}
{/* );*/}
{/* }}*/}
{/* options={getProductWarehouseOptionsForItem(*/}
{/* item.warehouse_id*/}
{/* )}*/}
{/* isLoading={isLoadingProductWarehouses}*/}
{/* isError={*/}
{/* getPurchaseItemError(idx, 'product_warehouse_id')*/}
{/* .isError*/}
{/* }*/}
{/* errorMessage={*/}
{/* getPurchaseItemError(idx, 'product_warehouse_id')*/}
{/* .errorMessage*/}
{/* }*/}
{/* isDisabled={type === 'detail' || !item.warehouse_id}*/}
{/* isClearable={type !== 'detail' && !!item.warehouse_id}*/}
{/* placeholder={*/}
{/* !item.warehouse_id*/}
{/* ? 'Pilih Gudang terlebih dahulu'*/}
{/* : 'Pilih Produk'*/}
{/* }*/}
{/* className={{*/}
{/* wrapper: 'min-w-32',*/}
{/* }}*/}
{/* />*/}
{/*</td>*/}
<td> <td>
<SelectInput <SelectInput
required required
value={item.product_warehouse} value={item.product_warehouse}
key={`product-warehouse-${idx}-${item.warehouse_id}`} key={`product-warehouse-${idx}-${formik.values.warehouse_id}`}
onChange={(val) => { onChange={(val) => {
const productWarehouse = const productWarehouse =
val as ProductWarehouseOptionType | null; val as ProductWarehouseOptionType | null;
formik.setFieldValue( formik.setFieldValue(
`purchase_items.${idx}.product_warehouse`, `items.${idx}.product_warehouse`,
productWarehouse productWarehouse
); );
formik.setFieldValue( formik.setFieldValue(
`purchase_items.${idx}.product_warehouse_id`, `items.${idx}.product_warehouse_id`,
(productWarehouse as ProductWarehouseOptionType) (productWarehouse as ProductWarehouseOptionType)
?.value || 0 ?.value || 0
); );
const productId = const productId =
(productWarehouse as ProductWarehouseOptionType) (productWarehouse as ProductWarehouseOptionType)
?.product_id || 0; ?.product_id || 0;
formik.setFieldValue( formik.setFieldValue(
`purchase_items.${idx}.product_id`, `items.${idx}.product_id`,
productId productId
); );
}} }}
options={getProductWarehouseOptionsForItem( options={getProductWarehouseOptionsForItem(
item.warehouse_id formik.values.warehouse_id
)} )}
isLoading={isLoadingProductWarehouses} isLoading={isLoadingProductWarehouses}
isError={ isError={
@@ -772,10 +860,14 @@ const PurchaseRequestForm = ({
getPurchaseItemError(idx, 'product_warehouse_id') getPurchaseItemError(idx, 'product_warehouse_id')
.errorMessage .errorMessage
} }
isDisabled={type === 'detail' || !item.warehouse_id} isDisabled={
isClearable={type !== 'detail' && !!item.warehouse_id} type === 'detail' || !formik.values.warehouse_id
}
isClearable={
type !== 'detail' && !!formik.values.warehouse_id
}
placeholder={ placeholder={
!item.warehouse_id !formik.values.warehouse_id
? 'Pilih Gudang terlebih dahulu' ? 'Pilih Gudang terlebih dahulu'
: 'Pilih Produk' : 'Pilih Produk'
} }
@@ -787,12 +879,12 @@ const PurchaseRequestForm = ({
<td> <td>
<NumberInput <NumberInput
required required
name={`purchase_items.${idx}.sub_qty`} name={`items.${idx}.quantity`}
value={item.sub_qty || ''} value={item.quantity || ''}
onChange={(e) => onChange={(e) =>
handlePurchaseItemChange( handlePurchaseItemChange(
idx, idx,
'sub_qty', 'quantity',
e.target.value e.target.value
) )
} }
@@ -801,9 +893,11 @@ const PurchaseRequestForm = ({
readOnly={type === 'detail'} readOnly={type === 'detail'}
allowNegative={false} allowNegative={false}
decimalScale={0} decimalScale={0}
isError={getPurchaseItemError(idx, 'sub_qty').isError} isError={
getPurchaseItemError(idx, 'quantity').isError
}
errorMessage={ errorMessage={
getPurchaseItemError(idx, 'sub_qty').errorMessage getPurchaseItemError(idx, 'quantity').errorMessage
} }
className={{ className={{
wrapper: 'min-w-24', wrapper: 'min-w-24',
@@ -813,24 +907,18 @@ const PurchaseRequestForm = ({
<td> <td>
<TextInput <TextInput
required required
name={`purchase_items.${idx}.price`} name={`items.${idx}.price`}
value={ value={
item.product_id && productData[item.product_id] item.product_id && productData[item.product_id]
? ( ? (
productData[item.product_id].product_price * productData[item.product_id].product_price *
(parseFloat( (parseFloat(
item.sub_qty?.toString() || '0' item.quantity?.toString() || '0'
) || 0) ) || 0)
).toLocaleString('en-US') ).toLocaleString('en-US')
: '' : ''
} }
onChange={(e) => onChange={(e) => {}}
handlePurchaseItemChange(
idx,
'price',
e.target.value
)
}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
type='text' type='text'
className={{ className={{
@@ -856,7 +944,7 @@ const PurchaseRequestForm = ({
<td> <td>
<TextInput <TextInput
required required
name={`purchase_items.${idx}.uom`} name={`items.${idx}.uom`}
value={ value={
item.product_id && productData[item.product_id] item.product_id && productData[item.product_id]
? productData[item.product_id].uom.name ? productData[item.product_id].uom.name
@@ -1011,4 +1099,4 @@ const PurchaseRequestForm = ({
); );
}; };
export default PurchaseRequestForm; export default PurchaseRequisitionsForm;