refactor(FE-170): streamline RecordingForm component by native card and optimizing layout for better usability

This commit is contained in:
rstubryan
2025-11-03 10:44:37 +07:00
parent d8599a850a
commit e4ab86c3eb
@@ -32,6 +32,7 @@ import { MovementApi } from '@/services/api/inventory';
import FileInput from '@/components/input/FileInput'; import FileInput from '@/components/input/FileInput';
import CheckboxInput from '@/components/input/CheckboxInput'; import CheckboxInput from '@/components/input/CheckboxInput';
import Badge from '@/components/Badge'; import Badge from '@/components/Badge';
import Card from '@/components/Card';
interface MovementFormProps { interface MovementFormProps {
type?: 'add' | 'edit' | 'detail'; type?: 'add' | 'edit' | 'detail';
@@ -768,8 +769,13 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
className='w-full mt-8 flex flex-col gap-6' className='w-full mt-8 flex flex-col gap-6'
> >
{/* Top card - Movement details */} {/* Top card - Movement details */}
<div className='card bg-base-100 shadow mb-4'> <Card
<div className='card-body'> title='Detail Movement'
className={{
wrapper: 'w-full mb-4 shadow',
body: 'flex flex-col gap-6',
}}
>
<div className='grid grid-cols-1 md:grid-cols-2 gap-4'> <div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
<TextInput <TextInput
required required
@@ -802,14 +808,17 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
readOnly={type === 'detail'} readOnly={type === 'detail'}
/> />
</div> </div>
</div> </Card>
</div>
{/* Warehouse cards */} {/* Warehouse cards */}
<div className='grid grid-cols-1 md:grid-cols-2 gap-4 mb-4'> <div className='grid grid-cols-1 md:grid-cols-2 gap-4 mb-4'>
<div className='card bg-base-100 shadow'> <Card
<div className='card-body space-y-4'> title='Gudang Asal'
<h3 className='card-title text-lg'>Gudang Asal</h3> className={{
wrapper: 'w-full shadow',
body: 'space-y-4',
}}
>
<SelectInput <SelectInput
required required
label='Gudang' label='Gudang'
@@ -872,12 +881,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
}} }}
/> />
</div> </div>
</div> </Card>
</div>
<div className='card bg-base-100 shadow'> <Card
<div className='card-body space-y-4'> title='Gudang Tujuan'
<h3 className='card-title text-lg'>Gudang Tujuan</h3> className={{
wrapper: 'w-full shadow',
body: 'space-y-4',
}}
>
<SelectInput <SelectInput
required required
label='Gudang' label='Gudang'
@@ -899,9 +911,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
formik.touched.destination_warehouse_id && formik.touched.destination_warehouse_id &&
Boolean(formik.errors.destination_warehouse_id) Boolean(formik.errors.destination_warehouse_id)
} }
errorMessage={ errorMessage={formik.errors.destination_warehouse_id as string}
formik.errors.destination_warehouse_id as string
}
isDisabled={type === 'detail'} isDisabled={type === 'detail'}
isClearable isClearable
startAdornment={ startAdornment={
@@ -919,10 +929,8 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
label='Area' label='Area'
name='destination_warehouse_area' name='destination_warehouse_area'
value={ value={
( (formik.values.destination_warehouse as WarehouseOptionType)
formik.values ?.area || '-'
.destination_warehouse as WarehouseOptionType
)?.area || '-'
} }
readOnly readOnly
disabled disabled
@@ -934,10 +942,8 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
label='Lokasi' label='Lokasi'
name='destination_warehouse_location' name='destination_warehouse_location'
value={ value={
( (formik.values.destination_warehouse as WarehouseOptionType)
formik.values ?.location || '-'
.destination_warehouse as WarehouseOptionType
)?.location || '-'
} }
readOnly readOnly
disabled disabled
@@ -946,14 +952,17 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
}} }}
/> />
</div> </div>
</div> </Card>
</div>
</div> </div>
{/* Products table */} {/* Products table */}
<div className='card bg-base-100 shadow mb-4'> <Card
<div className='card-body'> title='Produk'
<h2 className='card-title mb-4'>Produk</h2> className={{
wrapper: 'w-full mb-4 shadow',
title: 'mb-4',
}}
>
<div className='overflow-x-auto'> <div className='overflow-x-auto'>
<table className='table'> <table className='table'>
<thead> <thead>
@@ -972,9 +981,8 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
) => { ) => {
if (e.target.checked) { if (e.target.checked) {
setSelectedProducts( setSelectedProducts(
formik.values.products?.map( formik.values.products?.map((_, idx) => idx) ??
(_, idx) => idx []
) ?? []
); );
} else { } else {
setSelectedProducts([]); setSelectedProducts([]);
@@ -1020,10 +1028,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
e: React.ChangeEvent<HTMLInputElement> e: React.ChangeEvent<HTMLInputElement>
) => { ) => {
if (e.target.checked) { if (e.target.checked) {
setSelectedProducts([ setSelectedProducts([...selectedProducts, idx]);
...selectedProducts,
idx,
]);
} else { } else {
setSelectedProducts( setSelectedProducts(
selectedProducts.filter((i) => i !== idx) selectedProducts.filter((i) => i !== idx)
@@ -1078,8 +1083,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
idx idx
)} )}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1097,25 +1101,18 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
decimalSeparator='.' decimalSeparator='.'
bottomLabel={getProductQtyBottomLabel(idx)} bottomLabel={getProductQtyBottomLabel(idx)}
isError={ isError={
isRepeaterInputError( isRepeaterInputError('products', 'product_qty', idx)
'products', .isError || Boolean(getProductQtyError(idx))
'product_qty',
idx
).isError || Boolean(getProductQtyError(idx))
} }
errorMessage={ errorMessage={
isRepeaterInputError( isRepeaterInputError('products', 'product_qty', idx)
'products', .errorMessage ||
'product_qty',
idx
).errorMessage ||
getProductQtyError(idx) || getProductQtyError(idx) ||
undefined undefined
} }
readOnly={type === 'detail'} readOnly={type === 'detail'}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1169,13 +1166,16 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</Button> </Button>
</div> </div>
)} )}
</div> </Card>
</div>
{/* Deliveries table */} {/* Deliveries table */}
<div className='card bg-base-100 shadow mb-4'> <Card
<div className='card-body'> title='Pengiriman'
<h2 className='card-title mb-8'>Pengiriman</h2> className={{
wrapper: 'w-full mb-4 shadow',
title: 'mb-8',
}}
>
<div className='overflow-x-auto'> <div className='overflow-x-auto'>
<table className='table'> <table className='table'>
<thead> <thead>
@@ -1340,8 +1340,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
.errorMessage .errorMessage
} }
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1367,10 +1366,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
getDeliveryQtyError(idx, 0) || getDeliveryQtyError(idx, 0) ||
undefined undefined
} }
bottomLabel={getDeliveryProductQtyBottomLabel( bottomLabel={getDeliveryProductQtyBottomLabel(idx, 0)}
idx,
0
)}
readOnly={type === 'detail'} readOnly={type === 'detail'}
className={{ className={{
wrapper: 'w-full min-w-48', wrapper: 'w-full min-w-48',
@@ -1411,8 +1407,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
idx idx
)} )}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1431,8 +1426,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
)} )}
readOnly={type === 'detail'} readOnly={type === 'detail'}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1470,9 +1464,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
const file = e.target.files?.[0]; const file = e.target.files?.[0];
if (file) { if (file) {
if (file.size > 2 * 1024 * 1024) { if (file.size > 2 * 1024 * 1024) {
toast.error( toast.error('Ukuran dokumen maksimal 2 MB!');
'Ukuran dokumen maksimal 2 MB!'
);
e.target.value = ''; e.target.value = '';
return; return;
} }
@@ -1514,8 +1506,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
)} )}
readOnly={type === 'detail'} readOnly={type === 'detail'}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1525,9 +1516,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
name={`deliveries.${idx}.delivery_cost_per_item`} name={`deliveries.${idx}.delivery_cost_per_item`}
placeholder='Masukkan biaya per item...' placeholder='Masukkan biaya per item...'
value={delivery.delivery_cost_per_item || ''} value={delivery.delivery_cost_per_item || ''}
onChange={handleDeliveryCostPerItemChangeWrapper( onChange={handleDeliveryCostPerItemChangeWrapper(idx)}
idx
)}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
decimalScale={0} decimalScale={0}
allowNegative={false} allowNegative={false}
@@ -1541,8 +1530,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
)} )}
readOnly={type === 'detail'} readOnly={type === 'detail'}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1561,8 +1549,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
)} )}
readOnly={type === 'detail'} readOnly={type === 'detail'}
className={{ className={{
wrapper: wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80',
'w-full min-w-52 md:min-w-72 lg:min-w-80',
}} }}
/> />
</td> </td>
@@ -1616,8 +1603,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</Button> </Button>
</div> </div>
)} )}
</div> </Card>
</div>
{/* Action buttons */} {/* Action buttons */}
<div className='flex flex-row justify-between gap-2 flex-wrap'> <div className='flex flex-row justify-between gap-2 flex-wrap'>