mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 15:25:46 +00:00
feat: implement lazy loading in SelectInput
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
import { InventoryAdjustmentApi } from '@/services/api/inventory';
|
||||
import {
|
||||
CreateInventoryAdjustmentPayload,
|
||||
@@ -22,12 +22,18 @@ import {
|
||||
} from '@/services/api/master-data';
|
||||
import Button from '@/components/Button';
|
||||
import { Icon } from '@iconify/react';
|
||||
import SelectInput, { OptionType } from '@/components/input/SelectInput';
|
||||
import SelectInput, {
|
||||
OptionType,
|
||||
useSelect,
|
||||
} from '@/components/input/SelectInput';
|
||||
import TextInput from '@/components/input/TextInput';
|
||||
import { RadioGroup } from '@/components/input/RadioInput';
|
||||
import TextArea from '@/components/input/TextArea';
|
||||
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
|
||||
import AlertErrorList from '@/components/helper/form/FormErrors';
|
||||
import { ProductCategory } from '@/types/api/master-data/product-category';
|
||||
import { Product } from '@/types/api/master-data/product';
|
||||
import { Warehouse } from '@/types/api/master-data/warehouse';
|
||||
|
||||
interface InventoryAdjustmentFormProps {
|
||||
type?: 'add' | 'edit' | 'detail';
|
||||
@@ -44,10 +50,7 @@ const InventoryAdjustmentForm = ({
|
||||
InventoryAdjustmentFormErrorMessage,
|
||||
setInventoryAdjustmentFormErrorMessage,
|
||||
] = useState('');
|
||||
const [selectedProductCategories, setSelectedProductCategories] =
|
||||
useState('');
|
||||
const [disabledProduct, setDisabledProduct] = useState(true);
|
||||
const [optionsProduct, setOptionsProduct] = useState<OptionType[]>([]);
|
||||
const [quantityLabel, setQuantityLabel] = useState('Tambah Stok');
|
||||
|
||||
// Submit Handler
|
||||
@@ -108,45 +111,30 @@ const InventoryAdjustmentForm = ({
|
||||
});
|
||||
|
||||
// Fetch Data
|
||||
const productCategoriesUrl = `${
|
||||
ProductCategoryApi.basePath
|
||||
}?${new URLSearchParams({
|
||||
search: '',
|
||||
}).toString()}`;
|
||||
const { data: productCategories, isLoading: isLoadingProductCategories } =
|
||||
useSWR(productCategoriesUrl, ProductCategoryApi.getAllFetcher);
|
||||
const {
|
||||
setInputValue: setProductCategoryInputValue,
|
||||
options: productCategoryOptions,
|
||||
isLoadingOptions: isLoadingProductCategoryOptions,
|
||||
loadMore: loadMoreProductCategories,
|
||||
} = useSelect<ProductCategory>(ProductCategoryApi.basePath, 'id', 'name');
|
||||
|
||||
const productUrl = `${ProductApi.basePath}?${new URLSearchParams({
|
||||
search: '',
|
||||
product_category_id: selectedProductCategories,
|
||||
}).toString()}`;
|
||||
const { data: products, isLoading: isLoadingProducts } = useSWR(
|
||||
productUrl,
|
||||
ProductApi.getAllFetcher
|
||||
);
|
||||
const {
|
||||
setInputValue: setProductInputValue,
|
||||
options: productOptions,
|
||||
isLoadingOptions: isLoadingProductOptions,
|
||||
loadMore: loadMoreProducts,
|
||||
} = useSelect<Product>(ProductApi.basePath, 'id', 'name', 'search', {
|
||||
product_category_id: formik.values.product_category_id
|
||||
? String(formik.values.product_category_id)
|
||||
: '',
|
||||
});
|
||||
|
||||
const warehouseUrl = `${WarehouseApi.basePath}?${new URLSearchParams({
|
||||
search: '',
|
||||
limit: '100',
|
||||
}).toString()}`;
|
||||
const { data: warehouses, isLoading: isLoadingWarehouses } = useSWR(
|
||||
warehouseUrl,
|
||||
WarehouseApi.getAllFetcher
|
||||
);
|
||||
|
||||
// Map Data to Options
|
||||
const optionsProductCategory = isResponseSuccess(productCategories)
|
||||
? productCategories?.data.map((productCategory) => ({
|
||||
value: productCategory.id,
|
||||
label: productCategory.name,
|
||||
}))
|
||||
: [];
|
||||
const optionsWarehouse = isResponseSuccess(warehouses)
|
||||
? warehouses?.data.map((warehouse) => ({
|
||||
value: warehouse.id,
|
||||
label: warehouse.name,
|
||||
}))
|
||||
: [];
|
||||
const {
|
||||
setInputValue: setWarehouseInputValue,
|
||||
options: warehouseOptions,
|
||||
isLoadingOptions: isLoadingWarehouseOptions,
|
||||
loadMore: loadMoreWarehouses,
|
||||
} = useSelect<Warehouse>(WarehouseApi.basePath, 'id', 'name');
|
||||
|
||||
// Options Handler
|
||||
const productCategoryChangeHandler = (
|
||||
@@ -157,7 +145,6 @@ const InventoryAdjustmentForm = ({
|
||||
|
||||
formik.setFieldValue('product_category', val);
|
||||
|
||||
setSelectedProductCategories((val as OptionType)?.value as string);
|
||||
const disabled = (val as OptionType)?.value == null;
|
||||
setDisabledProduct(disabled);
|
||||
formik.setFieldValue('product_id', 0);
|
||||
@@ -193,9 +180,6 @@ const InventoryAdjustmentForm = ({
|
||||
// Effect
|
||||
useEffect(() => {
|
||||
if (initialValues?.product_warehouse?.product?.id) {
|
||||
setSelectedProductCategories(
|
||||
String(initialValues.product_warehouse.product.id)
|
||||
);
|
||||
setDisabledProduct(false);
|
||||
formik.setFieldValue(
|
||||
'product_id',
|
||||
@@ -219,25 +203,10 @@ const InventoryAdjustmentForm = ({
|
||||
);
|
||||
formik.setFieldValue('note', initialValues.note);
|
||||
}
|
||||
}, [
|
||||
formik,
|
||||
initialValues,
|
||||
setQuantityLabel,
|
||||
setDisabledProduct,
|
||||
setSelectedProductCategories,
|
||||
]);
|
||||
}, [formik, initialValues, setQuantityLabel, setDisabledProduct]);
|
||||
useEffect(() => {
|
||||
formikSetValues(formikInitialValues as InventoryAdjustmentFormValues);
|
||||
}, [formikSetValues, formikInitialValues]);
|
||||
useEffect(() => {
|
||||
if (isResponseSuccess(products)) {
|
||||
const options = products.data.map((p) => ({
|
||||
value: p.id,
|
||||
label: p.name,
|
||||
}));
|
||||
setOptionsProduct(options);
|
||||
}
|
||||
}, [products]);
|
||||
|
||||
// Utils Function
|
||||
const formatNumber = (value: string) => {
|
||||
@@ -282,9 +251,10 @@ const InventoryAdjustmentForm = ({
|
||||
label='Kategori Produk'
|
||||
value={formik.values.product_category as OptionType}
|
||||
onChange={productCategoryChangeHandler}
|
||||
onInputChange={setSelectedProductCategories}
|
||||
options={optionsProductCategory}
|
||||
isLoading={isLoadingProductCategories}
|
||||
onInputChange={setProductCategoryInputValue}
|
||||
options={productCategoryOptions}
|
||||
onMenuScrollToBottom={loadMoreProductCategories}
|
||||
isLoading={isLoadingProductCategoryOptions}
|
||||
isError={
|
||||
formik.touched.product_category &&
|
||||
Boolean(formik.errors.product_category)
|
||||
@@ -300,8 +270,10 @@ const InventoryAdjustmentForm = ({
|
||||
label='Produk'
|
||||
value={formik.values.product as OptionType}
|
||||
onChange={productChangeHandler}
|
||||
options={optionsProduct}
|
||||
isLoading={isLoadingProducts}
|
||||
onInputChange={setProductInputValue}
|
||||
options={productOptions}
|
||||
onMenuScrollToBottom={loadMoreProducts}
|
||||
isLoading={isLoadingProductOptions}
|
||||
isError={formik.touched.product && Boolean(formik.errors.product)}
|
||||
errorMessage={formik.errors.product as string}
|
||||
isDisabled={type === 'detail' || disabledProduct}
|
||||
@@ -314,8 +286,10 @@ const InventoryAdjustmentForm = ({
|
||||
label='Warehouse'
|
||||
value={formik.values.warehouse as OptionType}
|
||||
onChange={warehouseChangeHandler}
|
||||
options={optionsWarehouse}
|
||||
isLoading={isLoadingWarehouses}
|
||||
onInputChange={setWarehouseInputValue}
|
||||
options={warehouseOptions}
|
||||
onMenuScrollToBottom={loadMoreWarehouses}
|
||||
isLoading={isLoadingWarehouseOptions}
|
||||
isError={
|
||||
formik.touched.warehouse && Boolean(formik.errors.warehouse)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ import Card from '@/components/Card';
|
||||
import { S3_PUBLIC_BASE_URL } from '@/config/constant';
|
||||
import { getUniqueFormikErrors } from '@/lib/formik-helper';
|
||||
import AlertErrorList from '@/components/helper/form/FormErrors';
|
||||
import { Warehouse } from '@/types/api/master-data/warehouse';
|
||||
import { ProductWarehouse } from '@/types/api/inventory/product-warehouse';
|
||||
|
||||
interface MovementFormProps {
|
||||
type?: 'add' | 'edit' | 'detail';
|
||||
@@ -49,10 +51,6 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
|
||||
// ===== STATE MANAGEMENT =====
|
||||
const [movementFormErrorMessage, setMovementFormErrorMessage] = useState('');
|
||||
const [
|
||||
productWarehouseSelectInputValue,
|
||||
setProductWarehouseSelectInputValue,
|
||||
] = useState('');
|
||||
const [selectedProducts, setSelectedProducts] = useState<number[]>([]);
|
||||
const [selectedDeliveries, setSelectedDeliveries] = useState<number[]>([]);
|
||||
const [formErrorList, setFormErrorList] = useState<string[]>([]);
|
||||
@@ -93,10 +91,11 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
|
||||
// ===== USE SELECT HOOKS =====
|
||||
const {
|
||||
inputValue: warehouseSelectInputValue,
|
||||
setInputValue: setWarehouseSelectInputValue,
|
||||
isLoadingOptions: isLoadingWarehouses,
|
||||
} = useSelect(WarehouseApi.basePath, 'id', 'name', 'search');
|
||||
loadMore: loadMoreWarehouses,
|
||||
rawData: warehouses,
|
||||
} = useSelect<Warehouse>(WarehouseApi.basePath, 'id', 'name', 'search');
|
||||
|
||||
// ===== SELECT INPUT DATA =====
|
||||
const {
|
||||
@@ -107,12 +106,6 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
category: 'BOP',
|
||||
});
|
||||
|
||||
const warehousesUrl = `${WarehouseApi.basePath}?${new URLSearchParams({ search: warehouseSelectInputValue }).toString()}`;
|
||||
const { data: warehouses } = useSWR(
|
||||
warehousesUrl,
|
||||
WarehouseApi.getAllFetcher
|
||||
);
|
||||
|
||||
// ===== DATA PROCESSING =====
|
||||
const warehouseStockMap = useMemo(() => {
|
||||
if (!isResponseSuccess(allProductWarehouses)) return new Map();
|
||||
@@ -269,25 +262,22 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
});
|
||||
|
||||
// ===== PRODUCT WAREHOUSE FETCHING (after form initialization) =====
|
||||
const getProductWarehousesUrl = useCallback(() => {
|
||||
const productWarehouseParams = new URLSearchParams({
|
||||
search: productWarehouseSelectInputValue,
|
||||
});
|
||||
if (formik.values.source_warehouse_id) {
|
||||
productWarehouseParams.append(
|
||||
'warehouse_id',
|
||||
formik.values.source_warehouse_id.toString()
|
||||
);
|
||||
const {
|
||||
setInputValue: setProductWarehouseSelectInputValue,
|
||||
isLoadingOptions: isLoadingProductWarehouses,
|
||||
loadMore: loadMoreProductWarehouses,
|
||||
rawData: productWarehouses,
|
||||
} = useSelect<ProductWarehouse>(
|
||||
formik.values.source_warehouse_id ? ProductWarehouseApi.basePath : null,
|
||||
'id',
|
||||
'name',
|
||||
'search',
|
||||
{
|
||||
warehouse_id: formik.values.source_warehouse_id
|
||||
? formik.values.source_warehouse_id.toString()
|
||||
: '',
|
||||
}
|
||||
return `${ProductWarehouseApi.basePath}?${productWarehouseParams.toString()}`;
|
||||
}, [formik.values.source_warehouse_id, productWarehouseSelectInputValue]);
|
||||
|
||||
const productWarehousesUrl = getProductWarehousesUrl();
|
||||
const { data: productWarehouses, isLoading: isLoadingProductWarehouses } =
|
||||
useSWR(
|
||||
formik.values.source_warehouse_id ? productWarehousesUrl : null,
|
||||
ProductWarehouseApi.getAllFetcher
|
||||
);
|
||||
);
|
||||
|
||||
const productWarehouseOptions = isResponseSuccess(productWarehouses)
|
||||
? productWarehouses?.data.map((pw) => ({
|
||||
@@ -1006,6 +996,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
}}
|
||||
options={warehouseOptions}
|
||||
onInputChange={setWarehouseSelectInputValue}
|
||||
onMenuScrollToBottom={loadMoreWarehouses}
|
||||
isLoading={isLoadingWarehouses}
|
||||
isError={
|
||||
formik.touched.source_warehouse_id &&
|
||||
@@ -1104,6 +1095,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
options={warehouseOptions}
|
||||
onInputChange={setWarehouseSelectInputValue}
|
||||
isLoading={isLoadingWarehouses}
|
||||
onMenuScrollToBottom={loadMoreWarehouses}
|
||||
isError={
|
||||
formik.touched.destination_warehouse_id &&
|
||||
Boolean(formik.errors.destination_warehouse_id)
|
||||
@@ -1263,6 +1255,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
}}
|
||||
options={productWarehouseOptions}
|
||||
onInputChange={setProductWarehouseSelectInputValue}
|
||||
onMenuScrollToBottom={loadMoreProductWarehouses}
|
||||
isLoading={isLoadingProductWarehouses}
|
||||
isDisabled={
|
||||
type === 'detail' ||
|
||||
|
||||
Reference in New Issue
Block a user