mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 15:25:46 +00:00
refactor(FE-170): streamline RecordingForm component by native card and optimizing layout for better usability
This commit is contained in:
@@ -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'>
|
||||||
|
|||||||
Reference in New Issue
Block a user