From 1d79e8de1de43b38b81c25deeeed908a50d71427 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 3 Nov 2025 10:45:36 +0700 Subject: [PATCH] refactor(FE-Storyless): streamline RecordingForm component by native card and optimizing layout for better usability --- .../inventory/movement/form/MovementForm.tsx | 1566 ++++++++--------- 1 file changed, 776 insertions(+), 790 deletions(-) diff --git a/src/components/pages/inventory/movement/form/MovementForm.tsx b/src/components/pages/inventory/movement/form/MovementForm.tsx index 28148706..438c09c6 100644 --- a/src/components/pages/inventory/movement/form/MovementForm.tsx +++ b/src/components/pages/inventory/movement/form/MovementForm.tsx @@ -32,6 +32,7 @@ import { MovementApi } from '@/services/api/inventory'; import FileInput from '@/components/input/FileInput'; import CheckboxInput from '@/components/input/CheckboxInput'; import Badge from '@/components/Badge'; +import Card from '@/components/Card'; interface MovementFormProps { type?: 'add' | 'edit' | 'detail'; @@ -768,216 +769,270 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { className='w-full mt-8 flex flex-col gap-6' > {/* Top card - Movement details */} -
-
-
- - -
+ +
+ +
-
+ {/* Warehouse cards */}
-
-
-

Gudang Asal

- { - formik.setFieldTouched('source_warehouse', true); - formik.setFieldValue('source_warehouse', val); - formik.setFieldTouched('source_warehouse_id', true); - formik.setFieldValue( - 'source_warehouse_id', - (val as WarehouseOptionType)?.value - ); + + { + formik.setFieldTouched('source_warehouse', true); + formik.setFieldValue('source_warehouse', val); + formik.setFieldTouched('source_warehouse_id', true); + formik.setFieldValue( + 'source_warehouse_id', + (val as WarehouseOptionType)?.value + ); + }} + options={warehouseOptions} + onInputChange={setWarehouseSelectInputValue} + isLoading={isLoadingWarehouses} + isError={ + formik.touched.source_warehouse_id && + Boolean(formik.errors.source_warehouse_id) + } + errorMessage={formik.errors.source_warehouse_id as string} + isDisabled={type === 'detail'} + isClearable + startAdornment={ + formik.values.source_warehouse_id + ? getWarehouseStockAdornment( + formik.values.source_warehouse_id + ) + : undefined + } + /> + + {/* Area and Location Info */} +
+ - - {/* Area and Location Info */} -
- - -
-
-
- -
-
-

Gudang Tujuan

- { - formik.setFieldTouched('destination_warehouse', true); - formik.setFieldValue('destination_warehouse', val); - formik.setFieldTouched('destination_warehouse_id', true); - formik.setFieldValue( - 'destination_warehouse_id', - (val as WarehouseOptionType)?.value - ); + - - {/* Area and Location Info */} -
- - -
-
+ + + + { + formik.setFieldTouched('destination_warehouse', true); + formik.setFieldValue('destination_warehouse', val); + formik.setFieldTouched('destination_warehouse_id', true); + formik.setFieldValue( + 'destination_warehouse_id', + (val as WarehouseOptionType)?.value + ); + }} + options={warehouseOptions} + onInputChange={setWarehouseSelectInputValue} + isLoading={isLoadingWarehouses} + isError={ + formik.touched.destination_warehouse_id && + Boolean(formik.errors.destination_warehouse_id) + } + errorMessage={formik.errors.destination_warehouse_id as string} + isDisabled={type === 'detail'} + isClearable + startAdornment={ + formik.values.destination_warehouse_id + ? getWarehouseStockAdornment( + formik.values.destination_warehouse_id + ) + : undefined + } + /> + + {/* Area and Location Info */} +
+ + +
+
{/* Products table */} -
-
-

Produk

-
- - - - {type !== 'detail' && ( -
- 0 + +
+ + + + {type !== 'detail' && ( + + )} + + + {type !== 'detail' && } + + + + {formik.values.products?.map((product, idx) => ( + + {type !== 'detail' && ( + + )} + + + {type !== 'detail' && ( + )} - - - {type !== 'detail' && } - - - {formik.values.products?.map((product, idx) => ( - - {type !== 'detail' && ( - - )} - - - {type !== 'detail' && ( - - )} - - ))} - -
+ 0 + } + onChange={( + e: React.ChangeEvent + ) => { + if (e.target.checked) { + setSelectedProducts( + formik.values.products?.map((_, idx) => idx) ?? + [] + ); + } else { + setSelectedProducts([]); } + }} + classNames={{ + wrapper: 'flex justify-center', + checkbox: 'checkbox checkbox-sm', + }} + /> + + Produk + + * + + + Qty + + * + + Aksi
+ ) => { if (e.target.checked) { - setSelectedProducts( - formik.values.products?.map( - (_, idx) => idx - ) ?? [] - ); + setSelectedProducts([...selectedProducts, idx]); } else { - setSelectedProducts([]); + setSelectedProducts( + selectedProducts.filter((i) => i !== idx) + ); } }} classNames={{ @@ -985,221 +1040,262 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { checkbox: 'checkbox checkbox-sm', }} /> - + + { + formik.setFieldTouched( + `products.${idx}.product`, + true + ); + formik.setFieldValue( + `products.${idx}.product`, + val + ); + formik.setFieldTouched( + `products.${idx}.product_id`, + true + ); + formik.setFieldValue( + `products.${idx}.product_id`, + (val as ProductWarehouseOptionType)?.value + ); + }} + options={productWarehouseOptions} + onInputChange={setProductWarehouseSelectInputValue} + isLoading={isLoadingProductWarehouses} + isDisabled={ + type === 'detail' || + !formik.values.source_warehouse_id + } + placeholder={ + !formik.values.source_warehouse_id + ? 'Pilih gudang asal terlebih dahulu...' + : 'Pilih produk...' + } + isClearable + {...isRepeaterInputError( + 'products', + 'product_id', + idx + )} + className={{ + wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80', + }} + /> + + + +
+ +
+
- Produk - - * - - - Qty - - * - - Aksi
- - ) => { - if (e.target.checked) { - setSelectedProducts([ - ...selectedProducts, - idx, - ]); - } else { - setSelectedProducts( - selectedProducts.filter((i) => i !== idx) - ); - } - }} - classNames={{ - wrapper: 'flex justify-center', - checkbox: 'checkbox checkbox-sm', - }} - /> - - { - formik.setFieldTouched( - `products.${idx}.product`, - true - ); - formik.setFieldValue( - `products.${idx}.product`, - val - ); - formik.setFieldTouched( - `products.${idx}.product_id`, - true - ); - formik.setFieldValue( - `products.${idx}.product_id`, - (val as ProductWarehouseOptionType)?.value - ); - }} - options={productWarehouseOptions} - onInputChange={setProductWarehouseSelectInputValue} - isLoading={isLoadingProductWarehouses} - isDisabled={ - type === 'detail' || - !formik.values.source_warehouse_id - } - placeholder={ - !formik.values.source_warehouse_id - ? 'Pilih gudang asal terlebih dahulu...' - : 'Pilih produk...' - } - isClearable - {...isRepeaterInputError( - 'products', - 'product_id', - idx - )} - className={{ - wrapper: - 'w-full min-w-52 md:min-w-72 lg:min-w-80', - }} - /> - - - -
- -
-
-
- {type !== 'detail' && ( -
- {selectedProducts.length > 0 && ( - - )} + ))} + +
+
+ {type !== 'detail' && ( +
+ {selectedProducts.length > 0 && ( -
- )} -
-
+ )} + +
+ )} + {/* Deliveries table */} -
-
-

Pengiriman

-
- - - - {type !== 'detail' && ( - + + + {type !== 'detail' && ( + + )} + + ))} + +
- 0 + +
+ + + + {type !== 'detail' && ( + + )} + + + + + + + + + {type !== 'detail' && } + + + + {formik.values.deliveries?.map((delivery, idx) => ( + + {type !== 'detail' && ( + )} - - - - - - - - - {type !== 'detail' && } - - - - {formik.values.deliveries?.map((delivery, idx) => ( - - {type !== 'detail' && ( - - )} - - - - - + + - - - - {type !== 'detail' && ( - + + + + ) : ( + { + const file = e.target.files?.[0]; + if (file) { + if (file.size > 2 * 1024 * 1024) { + toast.error('Ukuran dokumen maksimal 2 MB!'); + e.target.value = ''; + return; + } + formik.setFieldValue( + `deliveries.${idx}.document`, + file + ); + } + }} + {...isRepeaterInputError( + 'deliveries', + 'document', + idx + )} + className={{ + wrapper: + 'w-full min-w-72 md:w-min-80 lg:w-min-96', + }} + /> )} - - ))} - -
+ 0 + } + onChange={( + e: React.ChangeEvent + ) => { + if (e.target.checked) { + setSelectedDeliveries( + formik.values.deliveries?.map( + (_, idx) => idx + ) ?? [] + ); + } else { + setSelectedDeliveries([]); } + }} + classNames={{ + wrapper: 'flex justify-center', + checkbox: 'checkbox checkbox-sm', + }} + /> + + Produk + + * + + + Qty + + * + + + Supplier + + * + + + Plat Nomor + + * + + Dokumen + Biaya Pengiriman (Rp.) + + * + + + Biaya Per Item (Rp.) + + * + + + Nama Sopir + + * + + Aksi
+ ) => { if (e.target.checked) { - setSelectedDeliveries( - formik.values.deliveries?.map( - (_, idx) => idx - ) ?? [] - ); + setSelectedDeliveries([ + ...selectedDeliveries, + idx, + ]); } else { - setSelectedDeliveries([]); + setSelectedDeliveries( + selectedDeliveries.filter((i) => i !== idx) + ); } }} classNames={{ @@ -1207,417 +1303,307 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { checkbox: 'checkbox checkbox-sm', }} /> - + - Produk - - * - - - Qty - - * - - - Supplier - - * - - - Plat Nomor - - * - - Dokumen - Biaya Pengiriman (Rp.) - - * - - - Biaya Per Item (Rp.) - - * - - - Nama Sopir - - * - - Aksi
- - ) => { - if (e.target.checked) { - setSelectedDeliveries([ - ...selectedDeliveries, - idx, - ]); - } else { - setSelectedDeliveries( - selectedDeliveries.filter((i) => i !== idx) - ); - } - }} - classNames={{ - wrapper: 'flex justify-center', - checkbox: 'checkbox checkbox-sm', - }} - /> - - { - formik.setFieldTouched( - `deliveries.${idx}.products.0.product`, - true - ); - formik.setFieldValue( - `deliveries.${idx}.products.0.product`, - val - ); - formik.setFieldTouched( - `deliveries.${idx}.products.0.product_id`, - true - ); - formik.setFieldValue( - `deliveries.${idx}.products.0.product_id`, - (val as OptionType)?.value - ); - }} - options={getFilteredProductWarehouseOptions()} - isDisabled={type === 'detail'} - isClearable - isError={ - isDeliveryProductInputError(idx, 0, 'product_id') - .isError - } - errorMessage={ - isDeliveryProductInputError(idx, 0, 'product_id') - .errorMessage - } - className={{ - wrapper: - 'w-full min-w-52 md:min-w-72 lg:min-w-80', - }} - /> - - - - { - formik.setFieldTouched( - `deliveries.${idx}.supplier`, - true - ); - formik.setFieldValue( - `deliveries.${idx}.supplier`, - val - ); - formik.setFieldTouched( - `deliveries.${idx}.supplier_id`, - true - ); - formik.setFieldValue( - `deliveries.${idx}.supplier_id`, - (val as OptionType)?.value - ); - }} - options={supplierOptions} - onInputChange={setSupplierSelectInputValue} - isLoading={isLoadingSuppliers} - isDisabled={type === 'detail'} - isClearable - {...isRepeaterInputError( - 'deliveries', - 'supplier_id', - idx - )} - className={{ - wrapper: - 'w-full min-w-52 md:min-w-72 lg:min-w-80', - }} - /> - - - - {type === 'detail' ? ( - <> -
- -
- - ) : ( - { - const file = e.target.files?.[0]; - if (file) { - if (file.size > 2 * 1024 * 1024) { - toast.error( - 'Ukuran dokumen maksimal 2 MB!' - ); - e.target.value = ''; - return; - } - formik.setFieldValue( - `deliveries.${idx}.document`, - file - ); - } - }} - {...isRepeaterInputError( - 'deliveries', - 'document', - idx - )} - className={{ - wrapper: - 'w-full min-w-72 md:w-min-80 lg:w-min-96', - }} - /> +
+ { + formik.setFieldTouched( + `deliveries.${idx}.products.0.product`, + true + ); + formik.setFieldValue( + `deliveries.${idx}.products.0.product`, + val + ); + formik.setFieldTouched( + `deliveries.${idx}.products.0.product_id`, + true + ); + formik.setFieldValue( + `deliveries.${idx}.products.0.product_id`, + (val as OptionType)?.value + ); + }} + options={getFilteredProductWarehouseOptions()} + isDisabled={type === 'detail'} + isClearable + isError={ + isDeliveryProductInputError(idx, 0, 'product_id') + .isError + } + errorMessage={ + isDeliveryProductInputError(idx, 0, 'product_id') + .errorMessage + } + className={{ + wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80', + }} + /> + + + + { + formik.setFieldTouched( + `deliveries.${idx}.supplier`, + true + ); + formik.setFieldValue( + `deliveries.${idx}.supplier`, + val + ); + formik.setFieldTouched( + `deliveries.${idx}.supplier_id`, + true + ); + formik.setFieldValue( + `deliveries.${idx}.supplier_id`, + (val as OptionType)?.value + ); + }} + options={supplierOptions} + onInputChange={setSupplierSelectInputValue} + isLoading={isLoadingSuppliers} + isDisabled={type === 'detail'} + isClearable + {...isRepeaterInputError( + 'deliveries', + 'supplier_id', + idx )} - - - - - - - + className={{ + wrapper: 'w-full min-w-52 md:min-w-72 lg:min-w-80', + }} + /> + + + + {type === 'detail' ? ( + <>
-
-
- {type !== 'detail' && ( -
- {selectedDeliveries.length > 0 && ( - - )} + +
+ + + + + + +
+ +
+
+
+ {type !== 'detail' && ( +
+ {selectedDeliveries.length > 0 && ( -
- )} -
-
+ )} + +
+ )} + {/* Action buttons */}