fixing response in transfertype

This commit is contained in:
bagusajisaputroo
2025-05-07 16:22:25 +07:00
parent 4c0a0468af
commit 873d516988
4 changed files with 255 additions and 184 deletions

View File

@ -2,7 +2,6 @@ import { apiConfig } from '@/config/api.config';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext';
import {
Alert,
Container,
DataGridColumnHeader,
DataGridInner,
@ -65,17 +64,14 @@ const AddDialog = () => {
const [customers, setCustomers] = useState<CustomerProps[]>([]);
const { reload } = useDataGrid();
const { PostData, PutData } = useCallApi();
const [alert, setAlert] = useState({
show: false,
message: ''
});
const [errors, setErrors] = useState<Record<string, string>>({});
const initialState = {
name: '',
description: '',
wallet_origin: '',
wallet_destination: '',
minimum_amount: 0,
maximum_amount: 0,
max_transaction_per_day: 0,
@ -92,38 +88,39 @@ const AddDialog = () => {
const resetForm = () => {
setFormField(initialState);
setErrors({});
};
const parsedUser = getAuth()?.user;
const validateForm = () => {
const requiredFields = [
'name',
'description',
'wallet_origin',
'wallet_destination',
'status',
'status_approval',
'status_kind'
{ key: 'name', label: 'Transfer Type Name' },
{ key: 'description', label: 'Description' },
{ key: 'wallet_origin', label: 'From Account' },
{ key: 'wallet_destination', label: 'To Account' },
{ key: 'status', label: 'Status' },
{ key: 'status_approval', label: 'Status Approval' },
{ key: 'status_kind', label: 'Status Kind' }
];
const missingFields = requiredFields.filter(
(field) =>
formField[field as keyof typeof formField] === '' ||
formField[field as keyof typeof formField] === null ||
formField[field as keyof typeof formField] === undefined
);
const newErrors: Record<string, string> = {};
let isValid = true;
if (missingFields.length > 0) {
setAlert({
show: true,
message: `Please fill out all required fields: ${missingFields.join(', ')}`
});
return false;
}
requiredFields.forEach(({ key, label }) => {
if (
formField[key as keyof typeof formField] === '' ||
formField[key as keyof typeof formField] === null ||
formField[key as keyof typeof formField] === undefined
) {
newErrors[key] = `${label} is required`;
toast.error(`${label} is required`);
isValid = false;
}
});
setAlert({ show: false, message: '' });
return true;
setErrors(newErrors);
return isValid;
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
@ -162,20 +159,17 @@ const AddDialog = () => {
const response = await PostData(`${API_URL}/transactiontype/create`, data);
if (response?.status) {
setAlert({ show: false, message: '' });
return true;
} else {
setAlert({ show: true, message: response?.message || 'Failed to create transfer type' });
toast.error(response?.message || 'Failed to create transfer type');
return false;
}
} catch (error) {
setAlert({
show: true,
message:
error instanceof Error
? error.message
: 'An error occurred while creating transfer type'
});
toast.error(
error instanceof Error
? error.message
: 'An error occurred while creating transfer type'
);
return false;
}
},
@ -226,7 +220,6 @@ const AddDialog = () => {
order_direction: 'ASC'
};
const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, params);
// console.log(response)
if (response?.status && response?.data) {
setWallets(response.data.list);
} else {
@ -238,7 +231,13 @@ const AddDialog = () => {
if (!showAddDialog) return;
fetchWallets();
}, [showAddDialog]);
// console.log(formField)
useEffect(() => {
if (!showAddDialog) {
resetForm();
}
}, [showAddDialog]);
return (
<Dialog open={showAddDialog} onOpenChange={(open) => handleAddDialog(open)}>
<DialogContent className="container-fixed max-w-[1080px] flex flex-col p-5 overflow-hidden [&>button]:hidden">
@ -256,7 +255,6 @@ const AddDialog = () => {
className="cursor-pointer hover:opacity-100 opacity-50"
onClick={() => {
handleAddDialog(false);
resetForm();
}}
>
<KeenIcon icon="cross" className="text-1.5xl" />
@ -265,13 +263,6 @@ const AddDialog = () => {
</DialogHeader>
<DialogBody className="scrollable-y px-0 pb-0" ref={parentRef}>
<div className="flex flex-col px-0">
{alert.show && (
<div className="sticky top-0 z-10 bg-white p-3">
<Alert variant="danger" className="mb-3">
<h3>{alert.message}</h3>
</Alert>
</div>
)}
<form action="" onSubmit={handleSubmit}>
<div className="card-body grid gap-5 p-0">
<div className="w-full">
@ -280,16 +271,20 @@ const AddDialog = () => {
Transfer Type Name
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Input
className="input"
className={`input ${errors.name ? 'border-red-500' : ''}`}
type="text"
autoComplete="off"
value={formField.name}
onChange={({ target }) =>
setFormField((prev) => ({ ...prev, name: target.value }))
}
onChange={({ target }) => {
setFormField((prev) => ({ ...prev, name: target.value }));
if (target.value) {
setErrors((prev) => ({ ...prev, name: '' }));
}
}}
/>
{errors.name && <span className="text-red-500 text-xs mt-1">{errors.name}</span>}
</div>
</div>
</div>
@ -300,16 +295,20 @@ const AddDialog = () => {
Description
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Input
className="input"
className={`input ${errors.description ? 'border-red-500' : ''}`}
type="text"
autoComplete="off"
value={formField.description}
onChange={({ target }) =>
setFormField((prev) => ({ ...prev, description: target.value }))
}
onChange={({ target }) => {
setFormField((prev) => ({ ...prev, description: target.value }));
if (target.value) {
setErrors((prev) => ({ ...prev, description: '' }));
}
}}
/>
{errors.description && <span className="text-red-500 text-xs mt-1">{errors.description}</span>}
</div>
</div>
</div>
@ -390,24 +389,26 @@ const AddDialog = () => {
From Account
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.wallet_origin}
onValueChange={(wallet_origin) =>
setFormField((prev) => ({ ...prev, wallet_origin }))
}
onValueChange={(wallet_origin) => {
setFormField((prev) => ({ ...prev, wallet_origin }));
setErrors((prev) => ({ ...prev, wallet_origin: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.wallet_origin ? 'border-red-500' : ''}>
<SelectValue placeholder="Select Wallet" />
</SelectTrigger>
<SelectContent>
{wallets.map((wallet, idx) => (
{wallets.map((wallet) => (
<SelectItem value={wallet.id} key={wallet.name}>
{wallet.name}
</SelectItem>
))}
</SelectContent>
</Select>
{errors.wallet_origin && <span className="text-red-500 text-xs mt-1">{errors.wallet_origin}</span>}
</div>
</div>
</div>
@ -418,24 +419,26 @@ const AddDialog = () => {
To Account
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.wallet_destination}
onValueChange={(wallet_destination) =>
setFormField((prev) => ({ ...prev, wallet_destination }))
}
onValueChange={(wallet_destination) => {
setFormField((prev) => ({ ...prev, wallet_destination }));
setErrors((prev) => ({ ...prev, wallet_destination: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.wallet_destination ? 'border-red-500' : ''}>
<SelectValue placeholder="Select Wallet" />
</SelectTrigger>
<SelectContent>
{wallets.map((wallet, idx) => (
{wallets.map((wallet) => (
<SelectItem value={wallet.id} key={wallet.id}>
{wallet.name}
</SelectItem>
))}
</SelectContent>
</Select>
{errors.wallet_destination && <span className="text-red-500 text-xs mt-1">{errors.wallet_destination}</span>}
</div>
</div>
</div>
@ -447,14 +450,15 @@ const AddDialog = () => {
<span className="text-red-500"> *</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.type}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, type: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, type: value }));
setErrors((prev) => ({ ...prev, type: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.type ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -480,6 +484,7 @@ const AddDialog = () => {
<SelectItem value="IC">Income Merchant</SelectItem>
</SelectContent>
</Select>
{errors.type && <span className="text-red-500 text-xs mt-1">{errors.type}</span>}
</div>
</div>
</div>
@ -490,14 +495,15 @@ const AddDialog = () => {
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.status_approval}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, status_approval: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, status_approval: value }));
setErrors((prev) => ({ ...prev, status_approval: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.status_approval ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -505,6 +511,7 @@ const AddDialog = () => {
<SelectItem value="N">No</SelectItem>
</SelectContent>
</Select>
{errors.status_approval && <span className="text-red-500 text-xs mt-1">{errors.status_approval}</span>}
</div>
</div>
</div>
@ -515,14 +522,15 @@ const AddDialog = () => {
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.status_kind}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, status_kind: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, status_kind: value }));
setErrors((prev) => ({ ...prev, status_kind: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.status_kind ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -534,6 +542,7 @@ const AddDialog = () => {
<SelectItem value="N">Top Up Patner</SelectItem>
</SelectContent>
</Select>
{errors.status_kind && <span className="text-red-500 text-xs mt-1">{errors.status_kind}</span>}
</div>
</div>
</div>
@ -545,14 +554,15 @@ const AddDialog = () => {
<span className="text-red-500"> *</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.status}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, status: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, status: value }));
setErrors((prev) => ({ ...prev, status: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.status ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -560,6 +570,7 @@ const AddDialog = () => {
<SelectItem value="N">Inactive</SelectItem>
</SelectContent>
</Select>
{errors.status && <span className="text-red-500 text-xs mt-1">{errors.status}</span>}
</div>
</div>
</div>
@ -587,4 +598,4 @@ const AddDialog = () => {
);
};
export default AddDialog;
export default AddDialog;

View File

@ -67,6 +67,10 @@ const EditDialog = () => {
show: false,
message: ''
});
const [errors, setErrors] = useState<Record<string, string>>({});
const [isLoadingWallets, setIsLoadingWallets] = useState(false);
const initialState: {
name: string;
@ -106,6 +110,7 @@ const EditDialog = () => {
setFormField(initialState);
setSelectedGroups([]);
setAlert({ show: false, message: '' });
setErrors({});
};
const handleGroupChange = (groupId: string) => {
@ -128,42 +133,33 @@ const EditDialog = () => {
const validateForm = () => {
const requiredFields = [
'name',
'description',
'wallet_origin',
'wallet_destination',
'status',
'status_approval',
'status_kind',
'type'
{ key: 'name', label: 'Transfer Type Name' },
{ key: 'description', label: 'Description' },
{ key: 'wallet_origin', label: 'From Account' },
{ key: 'wallet_destination', label: 'To Account' },
{ key: 'status', label: 'Status' },
{ key: 'status_approval', label: 'Status Approval' },
{ key: 'status_kind', label: 'Status Kind' }
];
const missingFields = requiredFields.filter((field) => {
return (
formField[field as keyof typeof formField] === '' ||
formField[field as keyof typeof formField] === null ||
formField[field as keyof typeof formField] === undefined
);
const newErrors: Record<string, string> = {};
let isValid = true;
requiredFields.forEach(({ key, label }) => {
if (
formField[key as keyof typeof formField] === '' ||
formField[key as keyof typeof formField] === null ||
formField[key as keyof typeof formField] === undefined
) {
newErrors[key] = `${label} is required`;
// Show toast for each required field
toast.error(`${label} is required`);
isValid = false;
}
});
if (missingFields.length > 0) {
setAlert({
show: true,
message: `Please fill out all required fields: ${missingFields.join(', ')}`
});
return false;
}
if (formField.permission.length === 0) {
setAlert({
show: true,
message: 'Please select at least one group permission'
});
return false;
}
setAlert({ show: false, message: '' });
return true;
setErrors(newErrors);
return isValid;
};
useEffect(() => {
@ -202,7 +198,7 @@ const EditDialog = () => {
const createActivity = {
module: 'Manage Transfer Type',
description: `Edit Transfer Type => ${selectedTransferType}`,
description: `Edit Transfer Type => ${formField.name}`,
action: 'U'
};
@ -227,17 +223,18 @@ const EditDialog = () => {
);
if (response?.status) {
setAlert({ show: false, message: '' });
return true;
} else {
setAlert({ show: true, message: response?.message || 'Failed to update transfer type' });
toast.error(response?.message || 'Failed to update transfer type');
return false;
}
} catch (error) {
toast.error(
error instanceof Error ? error.message : 'Failed to Update Transfer Type'
);
setAlert({
show: true,
message:
error instanceof Error ? error.message : 'An error occurred while updating transfer type'
message: error instanceof Error ? error.message : 'Failed to Update Transfer Type'
});
return false;
}
@ -376,6 +373,37 @@ const EditDialog = () => {
resetForm();
}
}, [showEditDialog]);
const renderSelectWithLoading = (
value: string,
onChangeHandler: (value: string) => void,
options: { id: string; name: string }[] | null,
placeholder: string,
isLoading: boolean
) => {
return (
<Select value={value} onValueChange={onChangeHandler} disabled={isLoading}>
<SelectTrigger>
{isLoading ? (
<div className="flex items-center">
<div className="animate-pulse bg-gray-200 h-4 w-24 rounded"></div>
<span className="ml-2">Loading...</span>
</div>
) : (
<SelectValue placeholder={placeholder} />
)}
</SelectTrigger>
<SelectContent>
{options &&
options.map((option) => (
<SelectItem value={option.id} key={option.id}>
{option.name}
</SelectItem>
))}
</SelectContent>
</Select>
);
};
return (
<Dialog open={showEditDialog} onOpenChange={(open) => handleEditDialog(open, null)}>
@ -418,36 +446,48 @@ const EditDialog = () => {
Transfer Type Name
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Input
className="input"
className={`input ${errors.name ? 'border-red-500' : ''}`}
type="text"
autoComplete="off"
value={formField.name}
onChange={({ target }) =>
setFormField((prev) => ({ ...prev, name: target.value }))
}
onChange={({ target }) => {
setFormField((prev) => ({ ...prev, name: target.value }));
if (target.value) {
setErrors((prev) => ({ ...prev, name: '' }));
}
}}
/>
{errors.name && (
<span className="text-red-500 text-xs mt-1">{errors.name}</span>
)}
</div>
</div>
</div>
<div className="w-full">
<div className="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<div className="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label className="form-label flex items-center gap-1 max-w-56">
Description
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Input
className="input"
className={`input ${errors.description ? 'border-red-500' : ''}`}
type="text"
autoComplete="off"
value={formField.description}
onChange={({ target }) =>
setFormField((prev) => ({ ...prev, description: target.value }))
}
onChange={({ target }) => {
setFormField((prev) => ({ ...prev, description: target.value }));
if (target.value) {
setErrors((prev) => ({ ...prev, description: '' }));
}
}}
/>
{errors.description && (
<span className="text-red-500 text-xs mt-1">{errors.description}</span>
)}
</div>
</div>
</div>
@ -528,24 +568,17 @@ const EditDialog = () => {
From Account
<span className="text-red-500">*</span>
</label>
<div className="grow">
<Select
value={formField.wallet_origin}
onValueChange={(wallet_origin) =>
setFormField((prev) => ({ ...prev, wallet_origin }))
}
>
<SelectTrigger>
<SelectValue placeholder="Select Wallet" />
</SelectTrigger>
<SelectContent>
{wallets.map((wallet) => (
<SelectItem value={wallet.id} key={wallet.id}>
{wallet.name}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="grow flex flex-col">
{renderSelectWithLoading(
formField.wallet_origin,
(value) => setFormField({ ...formField, wallet_origin: value }),
wallets,
'Select Wallet',
isLoadingWallets
)}
{errors.wallet_origin && (
<span className="text-red-500 text-xs mt-1">{errors.wallet_origin}</span>
)}
</div>
</div>
</div>
@ -556,14 +589,15 @@ const EditDialog = () => {
To Account
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.wallet_destination}
onValueChange={(wallet_destination) =>
setFormField((prev) => ({ ...prev, wallet_destination }))
}
onValueChange={(wallet_destination) => {
setFormField((prev) => ({ ...prev, wallet_destination }));
setErrors((prev) => ({ ...prev, wallet_destination: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.wallet_destination ? 'border-red-500' : ''}>
<SelectValue placeholder="Select Wallet" />
</SelectTrigger>
<SelectContent>
@ -574,6 +608,9 @@ const EditDialog = () => {
))}
</SelectContent>
</Select>
{errors.wallet_destination && (
<span className="text-red-500 text-xs mt-1">{errors.wallet_destination}</span>
)}
</div>
</div>
</div>
@ -584,14 +621,15 @@ const EditDialog = () => {
Status Transaction Type
<span className="text-red-500"> *</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.type}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, type: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, type: value }));
setErrors((prev) => ({ ...prev, type: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.type ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -617,6 +655,9 @@ const EditDialog = () => {
<SelectItem value="IC">Income Merchant</SelectItem>
</SelectContent>
</Select>
{errors.type && (
<span className="text-red-500 text-xs mt-1">{errors.type}</span>
)}
</div>
</div>
</div>
@ -627,14 +668,15 @@ const EditDialog = () => {
Status Approval
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.status_approval}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, status_approval: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, status_approval: value }));
setErrors((prev) => ({ ...prev, status_approval: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.status_approval ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -642,6 +684,9 @@ const EditDialog = () => {
<SelectItem value="N">No</SelectItem>
</SelectContent>
</Select>
{errors.status_approval && (
<span className="text-red-500 text-xs mt-1">{errors.status_approval}</span>
)}
</div>
</div>
</div>
@ -652,14 +697,15 @@ const EditDialog = () => {
<span className="text-red-500">*</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.status_kind}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, status_kind: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, status_kind: value }));
setErrors((prev) => ({ ...prev, status_kind: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.status_kind ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -671,6 +717,9 @@ const EditDialog = () => {
<SelectItem value="N">Top Up Patner</SelectItem>
</SelectContent>
</Select>
{errors.status_kind && (
<span className="text-red-500 text-xs mt-1">{errors.status_kind}</span>
)}
</div>
</div>
</div>
@ -680,14 +729,15 @@ const EditDialog = () => {
Status
<span className="text-red-500"> *</span>
</label>
<div className="grow">
<div className="grow flex flex-col">
<Select
value={formField.status}
onValueChange={(value) =>
setFormField((prev) => ({ ...prev, status: value }))
}
onValueChange={(value) => {
setFormField((prev) => ({ ...prev, status: value }));
setErrors((prev) => ({ ...prev, status: '' }));
}}
>
<SelectTrigger>
<SelectTrigger className={errors.status ? 'border-red-500' : ''}>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
@ -695,6 +745,9 @@ const EditDialog = () => {
<SelectItem value="N">Inactive</SelectItem>
</SelectContent>
</Select>
{errors.status && (
<span className="text-red-500 text-xs mt-1">{errors.status}</span>
)}
</div>
</div>
</div>
@ -738,6 +791,13 @@ const EditDialog = () => {
</div>
<div className="flex justify-end pt-2.5 gap-5">
<Button
variant={'outline'}
type="button"
onClick={() => resetForm()}
>
Reset
</Button>
<Button variant={'default'} type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Saving...' : 'Save Changes'}
</Button>
@ -761,4 +821,4 @@ const EditDialog = () => {
);
};
export { EditDialog };
export { EditDialog };

View File

@ -346,7 +346,7 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React
setSearchTerm
}}
>
<Toaster expand visibleToasts={9} duration={3000} />
{/* <Toaster expand visibleToasts={9} duration={3000} /> */}
<div className="px-4">
<DataGridProvider