From 97129d62b1ecfe5dc0296ed17880aa12a58c1999 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Thu, 8 May 2025 22:27:32 +0700 Subject: [PATCH 1/9] changing response on edit and add in mater data module --- src/pages/master/aldeias/blocks/AddDialog.tsx | 145 +++-- .../master/aldeias/blocks/EditDialog.tsx | 59 +- .../master/municipios/blocks/AddDialog.tsx | 55 +- .../master/municipios/blocks/EditDialog.tsx | 90 ++- .../master/postoadms/blocks/AddDialog.tsx | 143 +++-- .../master/postoadms/blocks/EditDialog.tsx | 141 +++-- .../master/products/blocks/AddDialog.tsx | 572 ++++++++++-------- .../master/products/blocks/EditDialog.tsx | 352 +++++++---- .../master/profession/blocks/AddDialog.tsx | 51 +- .../master/profession/blocks/EditDialog.tsx | 42 +- .../master/provider/blocks/AddDialog.tsx | 187 ++++-- .../master/provider/blocks/EditDialog.tsx | 199 +++--- src/pages/master/sucos/blocks/AddDialog.tsx | 146 +++-- src/pages/master/sucos/blocks/EditDialog.tsx | 59 +- .../transfer/transferfee/blocks/AddDialog.tsx | 1 + .../transfertype/blocks/EditDialog.tsx | 7 +- 16 files changed, 1461 insertions(+), 788 deletions(-) diff --git a/src/pages/master/aldeias/blocks/AddDialog.tsx b/src/pages/master/aldeias/blocks/AddDialog.tsx index bd4fe9a..f2ad4b5 100644 --- a/src/pages/master/aldeias/blocks/AddDialog.tsx +++ b/src/pages/master/aldeias/blocks/AddDialog.tsx @@ -46,12 +46,18 @@ const AddDialog = () => { show: false, message: '' }); - const initialState = { + const initialState: { + name: string; + sucosId: number | null; + created_by: string; + created_at: string; + } = { name: '', - sucosId: 0, + sucosId: null, created_by: '', created_at: '' }; + const [errors, setErrors] = useState>({}); const [formField, setFormField] = useState(initialState); const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); @@ -59,9 +65,32 @@ const AddDialog = () => { const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Aldeia Name' }, + { key: 'sucosId', label: 'Sucos ID' } + ]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; + }; const doCreateAldeias = useCallback( async (e: React.FormEvent) => { e.preventDefault(); @@ -117,14 +146,12 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - if (formField.name === '' || formField.sucosId === 0) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } - doCreateAldeias(e); - console.log(formField); - setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -169,12 +196,20 @@ const AddDialog = () => { - setFormField({ ...formField, name: e.target.value })} - /> +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && {errors.name}} +
@@ -183,46 +218,50 @@ const AddDialog = () => { - - - + + e.stopPropagation()} > - {sucos.find((suco) => suco.id === formField.sucosId)?.name || - 'Select Sucos'} - - - e.stopPropagation()} - > - - - - No Sucos found. - - {sucos.map((suco) => ( - { - setFormField({ - ...formField, - sucosId: suco.id - }); - setOpen(false); - }} - > - {suco.name} - - ))} - - - - - + + + + No Sucos found. + + {sucos.map((suco) => ( + { + setFormField({ + ...formField, + sucosId: suco.id + }); + setOpen(false); + setErrors((prev) => ({ ...prev, sucosId: '' })); + }} + > + {suco.name} + + ))} + + + + + + {errors.sucosId && {errors.sucosId}} + diff --git a/src/pages/master/aldeias/blocks/EditDialog.tsx b/src/pages/master/aldeias/blocks/EditDialog.tsx index 502a6c2..4f5f2d9 100644 --- a/src/pages/master/aldeias/blocks/EditDialog.tsx +++ b/src/pages/master/aldeias/blocks/EditDialog.tsx @@ -56,12 +56,35 @@ const EditDialog = () => { const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const [isSubmitting, setIsSubmitting] = useState(false); - + const [errors, setErrors] = useState>({}); const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Aldeia Name' }, + { key: 'sucosId', label: 'Sucos ID' } + ]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; + }; const doUpdateAldeias = useCallback( async (e: React.FormEvent) => { e.preventDefault(); @@ -139,15 +162,13 @@ const EditDialog = () => { const handleUpdate = (e: React.FormEvent) => { e.preventDefault(); - - if (formField.name === '' || formField.sucosId === 0) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } doUpdateAldeias(e); - console.log(formField); - setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -212,12 +233,19 @@ const EditDialog = () => { - setFormField({ ...formField, name: e.target.value })} - /> +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} /> + {errors.name && {errors.name}} +
@@ -226,6 +254,7 @@ const EditDialog = () => { +
diff --git a/src/pages/master/municipios/blocks/AddDialog.tsx b/src/pages/master/municipios/blocks/AddDialog.tsx index ca2f96b..bd0cee5 100644 --- a/src/pages/master/municipios/blocks/AddDialog.tsx +++ b/src/pages/master/municipios/blocks/AddDialog.tsx @@ -41,10 +41,30 @@ const AddDialog = () => { const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const [isSubmitting, setIsSubmitting] = useState(false); - + const [errors, setErrors] = useState>({}); const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); + }; + const validateForm = () => { + const requiredFields = [{ key: 'name', label: 'Municipio Name' }]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; }; const doCreateMunicipio = useCallback( @@ -82,16 +102,17 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - - if (formField.name.trim() === '') { - setAlert({ show: true, message: 'Please fill name field.' }); + setIsSubmitting(true); + if(!validateForm()) { + setIsSubmitting(false); return; } + doCreateMunicipio(e); - console.log(parsedUser.email); - console.log(formField); - setAlert({ show: false, message: '' }); + // console.log(parsedUser.email); + // console.log(formField); + // setAlert({ show: false, message: '' }); }; const handleReset = () => { @@ -133,21 +154,29 @@ const AddDialog = () => {
-
+
setFormField({ ...formField, name: e.target.value })} + onChange={({target})=>{ + setFormField((prev) => ({...prev,name:target.value})) + if (target.value){ + setErrors((prev)=> ({...prev,name: ''})) + } + } + } /> + {errors.name && {errors.name}}
-
) : ( - +
-
-
- +
+
+ +
setFormField({ ...formField, name: e.target.value })} + onChange={({ target }) => { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} /> + {errors.name && ( + {errors.name} + )}
+
- - e.stopPropagation()} - > - - - - No Municipio found. - - {municipios.map((municipio) => ( - { - setFormField({ - ...formField, - municipio_id: municipio.id - }); - setOpen(false); - }} - > - {municipio.name} - - ))} - - - - - +
+ + + + + e.stopPropagation()} + > + + + + No Municipio found. + + {municipios.map((municipio) => ( + { + setFormField({ ...formField, municipio_id: municipio.id }); + setErrors((prev) => ({ ...prev, municipio_id: '' })); + setOpen(false); + }} + > + {municipio.name} + + ))} + + + + + + {errors.municipio_id && ( + {errors.municipio_id} + )} +
diff --git a/src/pages/master/postoadms/blocks/EditDialog.tsx b/src/pages/master/postoadms/blocks/EditDialog.tsx index 7200831..edb43fb 100644 --- a/src/pages/master/postoadms/blocks/EditDialog.tsx +++ b/src/pages/master/postoadms/blocks/EditDialog.tsx @@ -45,7 +45,7 @@ const EditDialog = () => { const [isLoading, setIsLoading] = useState(false); const [municipios, setMunicipios] = useState([]); const [isSubmitting, setIsSubmitting] = useState(false); - + const [errors, setErrors] = useState>({}); const [alert, setAlert] = useState({ show: false, message: '' @@ -62,7 +62,28 @@ const EditDialog = () => { const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); + }; + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Postu Administrativo Name' }, + { key: 'municipio_id', label: 'Municipio Name' } + ]; + const newErrors: Record = {}; + let isValid = true; + + requiredFields.forEach(({ key, label }) => { + const value = formField[key as keyof typeof formField]; + const isEmpty = value === '' || value === null || value === undefined || value === 0; + if (isEmpty) { + newErrors[key] = `${label} is required`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; }; const doUpdatePostoAdm = useCallback( @@ -147,15 +168,12 @@ const EditDialog = () => { const handleUpdate = (e: React.FormEvent) => { e.preventDefault(); - - if (formField.name.trim() === '' || formField.municipio_id === 0) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } - doUpdatePostoAdm(e); - console.log(formField); - setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -218,57 +236,80 @@ const EditDialog = () => {
-
+
- setFormField({ ...formField, name: e.target.value })} - /> +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && ( + {errors.name} + )} +
- - - - - - - - - No Municipio found. - - {municipios.map((municipio) => ( - { - setFormField({ - ...formField, - municipio_id: municipio.id - }); - setOpen(false); - }} - > - {municipio.name} - - ))} - - - - - +
+ + + + + e.stopPropagation()} + > + + + + No Municipio found. + + {municipios.map((municipio) => ( + { + setFormField({ ...formField, municipio_id: municipio.id }); + setErrors((prev) => ({ ...prev, municipio_id: '' })); // Clear error + setOpen(false); + }} + > + {municipio.name} + + ))} + + + + + + {errors.municipio_id && ( + {errors.municipio_id} + )} +
diff --git a/src/pages/master/products/blocks/AddDialog.tsx b/src/pages/master/products/blocks/AddDialog.tsx index f20e8dc..b2e2851 100644 --- a/src/pages/master/products/blocks/AddDialog.tsx +++ b/src/pages/master/products/blocks/AddDialog.tsx @@ -76,11 +76,41 @@ const AddDialog = () => { const [isSubmitting, setIsSubmitting] = useState(false); const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); - + const [errors, setErrors] = useState>({}); const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; + const validateForm = () => { + const requiredFields = [ + {key:'name', label: 'Name'}, + {key:'type', label: 'Type'}, + {key:'code', label: 'Code'}, + {key:'description', label: 'Description'}, + {key:'price_point', label: 'Price Point'}, + {key:'price_cash', label: 'Price Cash'}, + {key:'cashback_point', label: 'Cashback Point'}, + {key:'cashback_cash', label: 'Cashback Cash'}, + {key:'status', label: 'Status'}, + {key:'provider', label: 'Provider'}, + {key:'process_on_third_party', label: 'Process On Third Party'} + ] + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + setErrors(newErrors); + return isValid; + } const doCreateProduct = useCallback( async (e: React.FormEvent) => { @@ -136,28 +166,15 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - if ( - formField.name.trim() === '' || - formField.type.trim() === '' || - formField.code.trim() === '' || - formField.description.trim() === '' || - formField.price_point === null || - formField.price_cash === null || - formField.cashback_point === null || - formField.cashback_cash === null || - formField.status.trim() === '' || - formField.provider.trim() === '' || - formField.process_on_third_party.trim() === '' || - formField.created_by.trim() === '' || - formField.created_at.trim() === '' - ) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } doCreateProduct(e); // console.log(formField); - setAlert({ show: false, message: '' }); + // setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -197,234 +214,317 @@ const AddDialog = () => {
)} - -
-
-
- - setFormField({ ...formField, name: e.target.value })} - /> -
-
+ +
+
+
+ +
+ { + setFormField({ ...formField, name: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && {errors.name}} +
+
+
-
-
- - setFormField({ ...formField, type: e.target.value })} - /> -
-
+
+
+ +
+ { + setFormField({ ...formField, type: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, type: '' })); + } + }} + /> + {errors.type && {errors.type}} +
+
+
-
-
- - setFormField({ ...formField, code: e.target.value })} - /> -
-
+
+
+ +
+ { + setFormField({ ...formField, code: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, code: '' })); + } + }} + /> + {errors.code && {errors.code}} +
+
+
-
-
- - setFormField({ ...formField, description: e.target.value })} - /> -
-
+
+
+ +
+ { + setFormField({ ...formField, description: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, description: '' })); + } + }} + /> + {errors.description && ( + {errors.description} + )} +
+
+
-
-
- - { - setFormField((prev) => ({ - ...prev, - price_point: values.floatValue !== undefined ? values.floatValue : '' - })); - }} - placeholder="Enter Price Point" - /> -
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + price_point: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, price_point: '' })); + } + }} + placeholder="Enter Price Point" + /> + {errors.price_point && ( + {errors.price_point} + )} +
+
+
-
-
- - { - setFormField((prev) => ({ - ...prev, - price_cash: values.floatValue !== undefined ? values.floatValue : '' - })); - }} - placeholder="Enter Price Cash" - /> -
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + price_cash: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, price_cash: '' })); + } + }} + placeholder="Enter Price Cash" + /> + {errors.price_cash && ( + {errors.price_cash} + )} +
+
+
-
-
- - { - setFormField((prev) => ({ - ...prev, - cashback_point: values.floatValue !== undefined ? values.floatValue : '' - })); - }} - placeholder="Enter Cashback Point" - /> -
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + cashback_point: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, cashback_point: '' })); + } + }} + placeholder="Enter Cashback Point" + /> + {errors.cashback_point && ( + {errors.cashback_point} + )} +
+
+
-
-
- - { - setFormField((prev) => ({ - ...prev, - cashback_cash: values.floatValue !== undefined ? values.floatValue : '' - })); - }} - placeholder="Enter Cashback Cash" - /> -
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + cashback_cash: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, cashback_cash: '' })); + } + }} + placeholder="Enter Cashback Cash" + /> + {errors.cashback_cash && ( + {errors.cashback_cash} + )} +
+
+
-
-
- - -
-
+
+
+ +
+ + {errors.status && {errors.status}} +
+
+
-
-
- - -
-
+
+
+ +
+ + {errors.provider && {errors.provider}} +
+
+
-
-
- - -
-
+
+
+ +
+ + {errors.process_on_third_party && ( + {errors.process_on_third_party} + )} +
+
+
+ +
+ + +
+
+ -
- - -
-
-
diff --git a/src/pages/master/products/blocks/EditDialog.tsx b/src/pages/master/products/blocks/EditDialog.tsx index e9e3a81..2d6ebb3 100644 --- a/src/pages/master/products/blocks/EditDialog.tsx +++ b/src/pages/master/products/blocks/EditDialog.tsx @@ -81,7 +81,37 @@ const EditDialog = () => { setFormField(initialState); setAlert({ show: false, message: '' }); }; - + const[errors, setErrors] = useState>({}); + const validateForm = () => { + const requiredFields = [ + {key:'name', label: 'Name'}, + {key:'type', label: 'Type'}, + {key:'code', label: 'Code'}, + {key:'description', label: 'Description'}, + {key:'price_point', label: 'Price Point'}, + {key:'price_cash', label: 'Price Cash'}, + {key:'cashback_point', label: 'Cashback Point'}, + {key:'cashback_cash', label: 'Cashback Cash'}, + {key:'status', label: 'Status'}, + {key:'provider', label: 'Provider'}, + {key:'process_on_third_party', label: 'Process On Third Party'} + ] + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + setErrors(newErrors); + return isValid; + } const doUpdateProduct = useCallback( async (e: React.FormEvent) => { e.preventDefault(); @@ -164,29 +194,14 @@ const EditDialog = () => { const handleUpdate = (e: React.FormEvent) => { e.preventDefault(); - - if ( - formField.name.trim() === '' || - formField.type.trim() === '' || - formField.code.trim() === '' || - formField.description.trim() === '' || - formField.price_point === null || - formField.price_cash === null || - formField.cashback_point === null || - formField.cashback_cash === null || - formField.status.trim() === '' || - formField.provider.trim() === '' || - formField.process_on_third_party.trim() === '' || - formField.updated_by.trim() === '' || - formField.updated_at.trim() === '' - ) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } - doUpdateProduct(e); // console.log(formField); - setAlert({ show: false, message: '' }); + // setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -245,72 +260,102 @@ const EditDialog = () => {
) : (
-
-
-
- +
+ {/* Name */} +
+
+ +
setFormField({ ...formField, name: e.target.value })} + onChange={(e) => { + setFormField({ ...formField, name: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, name: '' })); + }} /> + {errors.name && {errors.name}}
- -
-
- +
+ + {/* Type */} +
+
+ +
setFormField({ ...formField, type: e.target.value })} + onChange={(e) => { + setFormField({ ...formField, type: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, type: '' })); + }} /> + {errors.type && {errors.type}}
- -
-
- +
+ + {/* Code */} +
+
+ +
setFormField({ ...formField, code: e.target.value })} + onChange={(e) => { + setFormField({ ...formField, code: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, code: '' })); + }} /> + {errors.code && {errors.code}}
- -
-
- +
+ + {/* Description */} +
+
+ +
- setFormField({ ...formField, description: e.target.value }) - } + onChange={(e) => { + setFormField({ ...formField, description: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, description: '' })); + }} /> + {errors.description && ( + {errors.description} + )}
- -
-
- +
+ + {/* Price Point */} +
+
+ +
{ onValueChange={(values) => { setFormField((prev) => ({ ...prev, - price_point: values.floatValue !== undefined ? values.floatValue : '' + price_point: values.floatValue ?? '' })); + if (values.floatValue !== undefined) + setErrors((prev) => ({ ...prev, price_point: '' })); }} placeholder="Enter Price Point" /> + {errors.price_point && ( + {errors.price_point} + )}
- -
-
- +
+ + {/* Price Cash */} +
+
+ +
{ onValueChange={(values) => { setFormField((prev) => ({ ...prev, - price_cash: values.floatValue !== undefined ? values.floatValue : '' + price_cash: values.floatValue ?? '' })); + if (values.floatValue !== undefined) + setErrors((prev) => ({ ...prev, price_cash: '' })); }} placeholder="Enter Price Cash" /> + {errors.price_cash && ( + {errors.price_cash} + )}
- -
-
- +
+ + {/* Cashback Point */} +
+
+ +
{ onValueChange={(values) => { setFormField((prev) => ({ ...prev, - cashback_point: values.floatValue !== undefined ? values.floatValue : '' + cashback_point: values.floatValue ?? '' })); + if (values.floatValue !== undefined) + setErrors((prev) => ({ ...prev, cashback_point: '' })); }} placeholder="Enter Cashback Point" /> + {errors.cashback_point && ( + {errors.cashback_point} + )}
- -
-
- +
+ + {/* Cashback Cash */} +
+
+ +
{ onValueChange={(values) => { setFormField((prev) => ({ ...prev, - cashback_cash: values.floatValue !== undefined ? values.floatValue : '' + cashback_cash: values.floatValue ?? '' })); + if (values.floatValue !== undefined) + setErrors((prev) => ({ ...prev, cashback_cash: '' })); }} placeholder="Enter Cashback Cash" /> + {errors.cashback_cash && ( + {errors.cashback_cash} + )}
- -
-
- +
+ + {/* Status */} +
+
+ +
+ {errors.status && ( + {errors.status} + )}
- -
-
- +
+ + {/* Provider */} +
+
+ +
+ {errors.provider && ( + {errors.provider} + )}
- -
-
- +
+ + {/* Process on Third Party */} +
+
+ +
+ {errors.process_on_third_party && ( + {errors.process_on_third_party} + )}
- -
- -
- + +
+ +
+
+ + )}
diff --git a/src/pages/master/profession/blocks/AddDialog.tsx b/src/pages/master/profession/blocks/AddDialog.tsx index 929041e..3510140 100644 --- a/src/pages/master/profession/blocks/AddDialog.tsx +++ b/src/pages/master/profession/blocks/AddDialog.tsx @@ -29,7 +29,7 @@ const AddDialog = () => { show: false, message: '' }); - + const [errors, setErrors] = useState>({}); const initialState = { name: '', created_by: '', @@ -40,9 +40,31 @@ const AddDialog = () => { const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + const validateForm = () => { + const requiredFields = [{ key: 'name', label: 'Profession Name' }]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; + }; + const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; const doCreateProfession = useCallback( @@ -81,15 +103,13 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - - if (!formField.name.trim()) { - setAlert({ show: true, message: 'Please fill name field.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } doCreateProfession(e); - console.log(formField); - setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -130,12 +150,21 @@ const AddDialog = () => { +
+ setFormField({ ...formField, name: e.target.value })} - /> + onChange={({ target }) => { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} /> + {errors.name && {errors.name}} +
diff --git a/src/pages/master/profession/blocks/EditDialog.tsx b/src/pages/master/profession/blocks/EditDialog.tsx index 3b6fa0b..4800f05 100644 --- a/src/pages/master/profession/blocks/EditDialog.tsx +++ b/src/pages/master/profession/blocks/EditDialog.tsx @@ -38,12 +38,29 @@ const EditDialog = () => { updated_at: '' }; const [formField, setFormField] = useState(initialState); - + const [errors, setErrors] = useState>({}); const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; + const validateForm = () => { + const requiredFields = [{ key: 'name', label: 'Profession Name' }]; + const newErrors: Record = {}; + let isValid = true; + requiredFields.forEach(({ key, label }) => { + if ( + formField[key as keyof typeof formField] === '' || + formField[key as keyof typeof formField] === undefined + ) { + newErrors[key] = `${label} is required`; + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; + }; const doUpdateProfession = useCallback( async (e: React.FormEvent) => { e.preventDefault(); @@ -101,14 +118,13 @@ const EditDialog = () => { const handleUpdate = (e: React.FormEvent) => { e.preventDefault(); - if (formField.name.trim() === '') { - setAlert({ show: true, message: 'Please fill name field.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } doUpdateProfession(e); - console.log(formField); - setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -169,12 +185,22 @@ const EditDialog = () => { +
+ setFormField({ ...formField, name: e.target.value })} + onChange={({ target }) => { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} /> + {errors.name && {errors.name}} +
diff --git a/src/pages/master/provider/blocks/AddDialog.tsx b/src/pages/master/provider/blocks/AddDialog.tsx index 83666d9..028f6ce 100644 --- a/src/pages/master/provider/blocks/AddDialog.tsx +++ b/src/pages/master/provider/blocks/AddDialog.tsx @@ -63,7 +63,31 @@ const AddDialog = () => { show: false, message: '' }); - + const [errors, setErrors] = useState>({}); + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Name' }, + { key: 'description', label: 'Description' }, + { key: 'type', label: 'Type' }, + { key: 'status', label: 'Status' }, + { key: 'transaction_type', label: 'Transaction Type' } + ]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + setErrors(newErrors); + return isValid; + }; const initialState: { name: string; description: string; @@ -130,21 +154,13 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - - if ( - formField.name.trim() === '' || - formField.description.trim() === '' || - formField.type.trim() === '' || - formField.status.trim() === '' || - formField.transaction_type === '' - ) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } - // console.log(formField); doCreateProvider(e); - setAlert({ show: false, message: '' }); }; const getTransactionTypeList = async (sorting: any) => { @@ -225,12 +241,20 @@ const AddDialog = () => { - setFormField({ ...formField, name: e.target.value })} - /> +
+ { + setFormField({ ...formField, name: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, name: '' })); + }} + /> + {errors.name && ( + {errors.name} + )} +
@@ -239,12 +263,20 @@ const AddDialog = () => { - setFormField({ ...formField, description: e.target.value })} - /> +
+ { + setFormField({ ...formField, description: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, description: '' })); + }} + /> + {errors.description && ( + {errors.description} + )} +
@@ -253,38 +285,53 @@ const AddDialog = () => { - +
+ + {errors.type && ( + {errors.type} + )} +
-
- +
+ + {errors.status && ( + {errors.status} + )} +
@@ -293,23 +340,31 @@ const AddDialog = () => { - +
+ + {errors.transaction_type && ( + {errors.transaction_type} + )} +
diff --git a/src/pages/master/provider/blocks/EditDialog.tsx b/src/pages/master/provider/blocks/EditDialog.tsx index 1a34f96..780599f 100644 --- a/src/pages/master/provider/blocks/EditDialog.tsx +++ b/src/pages/master/provider/blocks/EditDialog.tsx @@ -53,7 +53,31 @@ const EditDialog = () => { show: false, message: '' }); - + const [errors, setErrors] = useState>({}); + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Name' }, + { key: 'description', label: 'Description' }, + { key: 'type', label: 'Type' }, + { key: 'status', label: 'Status' }, + { key: 'transaction_type', label: 'Transaction Type' } + ]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + setErrors(newErrors); + return isValid; + }; const initialState: { name: string; description: string; @@ -81,7 +105,7 @@ const EditDialog = () => { const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; const doUpdateProvider = useCallback( @@ -177,22 +201,14 @@ const EditDialog = () => { const handleUpdate = (e: React.FormEvent) => { e.preventDefault(); - - if ( - formField.name.trim() === '' || - formField.description.trim() === '' || - formField.type.trim() === '' || - formField.status.trim() === '' || - formField.transaction_type.trim() === '' || - formField.agent === null - ) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } - doUpdateProvider(e); // console.log(formField); - setAlert({ show: false, message: '' }); + // setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -258,30 +274,43 @@ const EditDialog = () => { - - setFormField((prev) => ({ ...prev, name: target.value })) - } - /> +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) setErrors((prev) => ({ ...prev, name: '' })); + }} + /> + {errors.name && ( + {errors.name} + )} +
+ {/* Description */}
- - setFormField({ ...formField, description: e.target.value }) - } - /> +
+ { + setFormField({ ...formField, description: e.target.value }); + if (e.target.value) setErrors((prev) => ({ ...prev, description: '' })); + }} + /> + {errors.description && ( + {errors.description} + )} +
@@ -290,18 +319,26 @@ const EditDialog = () => { - +
+ + {errors.type && ( + {errors.type} + )} +
@@ -310,18 +347,28 @@ const EditDialog = () => { - +
+ + {errors.status && ( + {errors.status} + )} +
@@ -330,23 +377,33 @@ const EditDialog = () => { - +
+ + {errors.transaction_type && ( + + {errors.transaction_type} + + )} +
diff --git a/src/pages/master/sucos/blocks/AddDialog.tsx b/src/pages/master/sucos/blocks/AddDialog.tsx index 5452053..14fb63a 100644 --- a/src/pages/master/sucos/blocks/AddDialog.tsx +++ b/src/pages/master/sucos/blocks/AddDialog.tsx @@ -46,12 +46,18 @@ const AddDialog = () => { show: false, message: '' }); - const initialState = { + const initialState: { + name: string; + postoId: number | null; + created_by: string; + created_at: string; + } = { name: '', - postoId: 0, + postoId: null, created_by: '', created_at: '' }; + const [errors, setErrors] = useState>({}); const [formField, setFormField] = useState(initialState); const created_time = new Date(); @@ -59,7 +65,31 @@ const AddDialog = () => { const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); + }; + + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Sucos Name' }, + { key: 'postoId', label: 'Posto Administrativo Name' } + ]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; }; const doCreateSucos = useCallback( @@ -97,15 +127,14 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - - if (formField.name.trim() === '' || formField.postoId === 0) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } doCreateSucos(e); - console.log(formField); - setAlert({ show: false, message: '' }); + // console.log(formField); }; useEffect(() => { @@ -168,12 +197,23 @@ const AddDialog = () => { - setFormField({ ...formField, name: e.target.value })} - /> +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && ( + {errors.name} + )} +
@@ -182,42 +222,48 @@ const AddDialog = () => { - - - - - e.stopPropagation()} - > - - - - No Postu Administrativo Found. - - {posto_adms.map((posto) => ( - { - setFormField({ - ...formField, - postoId: posto.PostoAdms_id - }); - setOpen(false); - }} - > - {posto.PostoAdms_name} - - ))} - - - - - +
+ + + + + e.stopPropagation()} + > + + + + No Postu Administrativo Found. + + {posto_adms.map((posto) => ( + { + setFormField({ + ...formField, + postoId: posto.PostoAdms_id + }); + setOpen(false); + setErrors((prev) => ({ ...prev, postoId: '' })); + }} + > + {posto.PostoAdms_name} + + ))} + + + + + + {errors.postoId && ( + {errors.postoId} + )} +
{/* { const [isSubmitting, setIsSubmitting] = useState(false); const [isLoading, setIsLoading] = useState(false); const [postoadms, setPostoadms] = useState([]); - + const [errors, setErrors] = useState>({}); const [alert, setAlert] = useState({ show: false, message: '' }); - + const initialState = { name: '', postoId: 0, @@ -62,12 +62,31 @@ const EditDialog = () => { const resetForm = () => { setFormField(initialState); - setAlert({ - show: false, - message: '' - }); + setErrors({}); }; + const validateForm = () => { + const requiredFields = [ + { key: 'name', label: 'Sucos Name' }, + { key: 'postoId', label: 'Posto Administrativo Name' } + ]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; + } const doUpdateSucos = useCallback( async (e: React.FormEvent) => { e.preventDefault(); @@ -144,15 +163,15 @@ const EditDialog = () => { const handleUpdate = (e: React.FormEvent) => { e.preventDefault(); - - if (formField.name.trim() === '' || formField.postoId === 0) { - setAlert({ show: true, message: 'Please fill in all required fields.' }); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); return; } + // console.log('Form Field before update:', formField); doUpdateSucos(e); - setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -217,12 +236,24 @@ const EditDialog = () => { +
+ setFormField({ ...formField, name: e.target.value })} - /> + onChange={({ target }) => { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && ( + {errors.name} + )} +
diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx index 6b73eed..3e2a99e 100644 --- a/src/pages/transfer/transferfee/blocks/AddDialog.tsx +++ b/src/pages/transfer/transferfee/blocks/AddDialog.tsx @@ -90,6 +90,7 @@ const AddFeeDialog = () => { id: customer.id, name: customer.username })); + const [errors, setErrors] = useState>({}); const initialState = { name: '', description: '', diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index 4ba5874..01c3f10 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -109,7 +109,6 @@ const EditDialog = () => { const resetForm = () => { setFormField(initialState); setSelectedGroups([]); - setAlert({ show: false, message: '' }); setErrors({}); }; @@ -231,11 +230,7 @@ const EditDialog = () => { } catch (error) { toast.error( error instanceof Error ? error.message : 'Failed to Update Transfer Type' - ); - setAlert({ - show: true, - message: error instanceof Error ? error.message : 'Failed to Update Transfer Type' - }); + ) return false; } }, [formField, selectedTransferType]); From b792ee2f6118414a869b06e91e941695727600e1 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Fri, 9 May 2025 11:30:02 +0700 Subject: [PATCH 2/9] change hard delete to soft delete on manage user andmanage position --- .../settings/user/manage-position/blocks/DeleteDialog.tsx | 6 +++--- src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/user/manage-position/blocks/DeleteDialog.tsx b/src/pages/settings/user/manage-position/blocks/DeleteDialog.tsx index 2a15a2f..76f92fe 100644 --- a/src/pages/settings/user/manage-position/blocks/DeleteDialog.tsx +++ b/src/pages/settings/user/manage-position/blocks/DeleteDialog.tsx @@ -35,7 +35,7 @@ const DeleteDialog = () => { return; } const response = await DeleteData( - `${API_URL}/user_role/delete/${selectedPosition.id}/${enforce}`, + `${API_URL}/user_role/delete/${selectedPosition.id}/false`, { id: selectedPosition.id } @@ -65,7 +65,7 @@ const DeleteDialog = () => {

Are you sure?

you will delete this data! -
+ {/*
{ setEnforce(e.target.checked); }} /> -
+
*/}
{alert.show && ( diff --git a/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx b/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx index c00daba..f16da88 100644 --- a/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx @@ -31,7 +31,7 @@ const DeleteDialog = () => { /* actions */ const doDeleteData = useCallback(async () => { - const response = await DeleteData(`${API_URL}/user/delete/${selectedUser}/${enforce}`, { + const response = await DeleteData(`${API_URL}/user/delete/${selectedUser}/false`, { id: selectedUser }); // console.log('Delete Response User:', response); From 930d6f1434cbbabf3f63e0d7ed1682f104fb41e6 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Fri, 9 May 2025 11:41:20 +0700 Subject: [PATCH 3/9] change form reseponse on manage position --- .../user/manage-position/blocks/AddDialog.tsx | 76 +++++++++++++------ .../manage-position/blocks/EditDialog.tsx | 58 ++++++++++---- 2 files changed, 94 insertions(+), 40 deletions(-) diff --git a/src/pages/settings/user/manage-position/blocks/AddDialog.tsx b/src/pages/settings/user/manage-position/blocks/AddDialog.tsx index 654bb4b..a0ea607 100644 --- a/src/pages/settings/user/manage-position/blocks/AddDialog.tsx +++ b/src/pages/settings/user/manage-position/blocks/AddDialog.tsx @@ -17,6 +17,7 @@ import { toast } from 'sonner'; import { useCallApi } from '@/hooks'; import { Checkbox } from '@/components/ui/checkbox'; import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { set } from 'date-fns'; const API_URL = apiConfig.service_dashboard; @@ -74,7 +75,7 @@ const AddDialog = () => { }); const [selectMenus, setSelectMenus] = useState([]); const [formField, setFormField] = useState(initialState); - + const [errors, setErrors] = useState>({}); /* actions */ const handleCheckboxChange = useCallback((key: string) => { setSelectMenus((prev) => @@ -82,21 +83,48 @@ const AddDialog = () => { ); }, []); + const [isSubmitting, setIsSubmitting] = useState(false); + const resetForm = () => { setFormField(() => ({ name: '' })); - setAlert({ show: false, message: '' }); + setErrors(() => ({})); setSelectMenus([]); }; + const validateForm = () => { + const requiredFields = [{ key: 'name', label: 'Position Name' }]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + setErrors(newErrors); + return isValid; + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); + return; + } + + doCreatePosition(e); + }; + const doCreatePosition = useCallback( async (e: React.FormEvent) => { e.preventDefault(); - if (formField.name.trim() === '') { - setAlert({ show: true, message: 'Please fill in all required fields.' }); - return; - } - const response = await PostData(`${API_URL}/user_role/create`, { name: formField.name, roles: selectMenus, @@ -150,29 +178,29 @@ const AddDialog = () => { Close
- {alert.show && ( -
- -

{alert.message}

-
-
- )}
-
+
- - - setFormField((prev) => ({ ...prev, name: target.value })) - } - /> + +
+ + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> + {errors.name && ( + {errors.name} + )} +
diff --git a/src/pages/settings/user/manage-position/blocks/EditDialog.tsx b/src/pages/settings/user/manage-position/blocks/EditDialog.tsx index f0dc3db..0bcc443 100644 --- a/src/pages/settings/user/manage-position/blocks/EditDialog.tsx +++ b/src/pages/settings/user/manage-position/blocks/EditDialog.tsx @@ -81,7 +81,35 @@ const EditDialog = () => { name: '', status: '' }); + const [errors, setErrors] = useState>({}); + const validateForm = () => { + const requiredFields = [{ key: 'name', label: 'Position Name' }]; + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + setErrors(newErrors); + return isValid; + }; + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + if (!validateForm()) { + setIsSubmitting(false); + return; + } + doEditPosition(e); + }; /* actions */ const handleCheckboxChange = useCallback((key: string) => { setSelectMenus((prev) => @@ -94,11 +122,6 @@ const EditDialog = () => { e.preventDefault(); setIsSubmitting(true); - if (formField.name.trim() === '') { - setAlert((prev) => ({ ...prev, show: true, message: 'Please fill name field.' })); - return; - } - if (!selectedPosition) { toast.success('Please Select Position'); return; @@ -164,29 +187,32 @@ const EditDialog = () => {
- {alert.show && ( + {/* {alert.show && (

{alert.message}

- )} + )} */}
- +
- - setFormField((prev) => ({ ...prev, name: target.value })) - } - /> +
+ + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> + {errors.name && {errors.name}} +
From 8a3a574a805439fd39e98c86b11ba97c08b01451 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Fri, 9 May 2025 11:42:00 +0700 Subject: [PATCH 4/9] fix some sub module in master data --- .../master/products/blocks/AddDialog.tsx | 643 +++++++++--------- .../products/hooks/ManageProductsContext.tsx | 2 - .../master/provider/blocks/AddDialog.tsx | 2 +- 3 files changed, 331 insertions(+), 316 deletions(-) diff --git a/src/pages/master/products/blocks/AddDialog.tsx b/src/pages/master/products/blocks/AddDialog.tsx index b2e2851..12c53c2 100644 --- a/src/pages/master/products/blocks/AddDialog.tsx +++ b/src/pages/master/products/blocks/AddDialog.tsx @@ -83,18 +83,18 @@ const AddDialog = () => { }; const validateForm = () => { const requiredFields = [ - {key:'name', label: 'Name'}, - {key:'type', label: 'Type'}, - {key:'code', label: 'Code'}, - {key:'description', label: 'Description'}, - {key:'price_point', label: 'Price Point'}, - {key:'price_cash', label: 'Price Cash'}, - {key:'cashback_point', label: 'Cashback Point'}, - {key:'cashback_cash', label: 'Cashback Cash'}, - {key:'status', label: 'Status'}, - {key:'provider', label: 'Provider'}, - {key:'process_on_third_party', label: 'Process On Third Party'} - ] + { key: 'name', label: 'Name' }, + { key: 'type', label: 'Type' }, + { key: 'code', label: 'Code' }, + { key: 'description', label: 'Description' }, + { key: 'price_point', label: 'Price Point' }, + { key: 'price_cash', label: 'Price Cash' }, + { key: 'cashback_point', label: 'Cashback Point' }, + { key: 'cashback_cash', label: 'Cashback Cash' }, + { key: 'status', label: 'Status' }, + { key: 'provider', label: 'Provider' }, + { key: 'process_on_third_party', label: 'Process On Third Party' } + ]; const newErrors: Record = {}; let isValid = true; requiredFields.forEach(({ key, label }) => { @@ -110,7 +110,7 @@ const AddDialog = () => { }); setErrors(newErrors); return isValid; - } + }; const doCreateProduct = useCallback( async (e: React.FormEvent) => { @@ -214,317 +214,334 @@ const AddDialog = () => {
)} - -
-
-
- -
- { - setFormField({ ...formField, name: e.target.value }); - if (e.target.value) { - setErrors((prev) => ({ ...prev, name: '' })); - } - }} - /> - {errors.name && {errors.name}} -
-
-
+ +
+
+
+ +
+ { + setFormField({ ...formField, name: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && ( + {errors.name} + )} +
+
+
-
-
- -
- { - setFormField({ ...formField, type: e.target.value }); - if (e.target.value) { - setErrors((prev) => ({ ...prev, type: '' })); - } - }} - /> - {errors.type && {errors.type}} -
-
-
+
+
+ +
+ { + setFormField({ ...formField, type: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, type: '' })); + } + }} + /> + {errors.type && ( + {errors.type} + )} +
+
+
-
-
- -
- { - setFormField({ ...formField, code: e.target.value }); - if (e.target.value) { - setErrors((prev) => ({ ...prev, code: '' })); - } - }} - /> - {errors.code && {errors.code}} -
-
-
+
+
+ +
+ { + setFormField({ ...formField, code: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, code: '' })); + } + }} + /> + {errors.code && ( + {errors.code} + )} +
+
+
-
-
- -
- { - setFormField({ ...formField, description: e.target.value }); - if (e.target.value) { - setErrors((prev) => ({ ...prev, description: '' })); - } - }} - /> - {errors.description && ( - {errors.description} - )} -
-
-
+
+
+ +
+ { + setFormField({ ...formField, description: e.target.value }); + if (e.target.value) { + setErrors((prev) => ({ ...prev, description: '' })); + } + }} + /> + {errors.description && ( + {errors.description} + )} +
+
+
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - price_point: values.floatValue !== undefined ? values.floatValue : '' - })); - if (values.floatValue !== undefined) { - setErrors((prev) => ({ ...prev, price_point: '' })); - } - }} - placeholder="Enter Price Point" - /> - {errors.price_point && ( - {errors.price_point} - )} -
-
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + price_point: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, price_point: '' })); + } + }} + placeholder="Enter Price Point" + /> + {errors.price_point && ( + {errors.price_point} + )} +
+
+
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - price_cash: values.floatValue !== undefined ? values.floatValue : '' - })); - if (values.floatValue !== undefined) { - setErrors((prev) => ({ ...prev, price_cash: '' })); - } - }} - placeholder="Enter Price Cash" - /> - {errors.price_cash && ( - {errors.price_cash} - )} -
-
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + price_cash: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, price_cash: '' })); + } + }} + placeholder="Enter Price Cash" + /> + {errors.price_cash && ( + {errors.price_cash} + )} +
+
+
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - cashback_point: values.floatValue !== undefined ? values.floatValue : '' - })); - if (values.floatValue !== undefined) { - setErrors((prev) => ({ ...prev, cashback_point: '' })); - } - }} - placeholder="Enter Cashback Point" - /> - {errors.cashback_point && ( - {errors.cashback_point} - )} -
-
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + cashback_point: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, cashback_point: '' })); + } + }} + placeholder="Enter Cashback Point" + /> + {errors.cashback_point && ( + {errors.cashback_point} + )} +
+
+
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - cashback_cash: values.floatValue !== undefined ? values.floatValue : '' - })); - if (values.floatValue !== undefined) { - setErrors((prev) => ({ ...prev, cashback_cash: '' })); - } - }} - placeholder="Enter Cashback Cash" - /> - {errors.cashback_cash && ( - {errors.cashback_cash} - )} -
-
-
+
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + cashback_cash: values.floatValue !== undefined ? values.floatValue : '' + })); + if (values.floatValue !== undefined) { + setErrors((prev) => ({ ...prev, cashback_cash: '' })); + } + }} + placeholder="Enter Cashback Cash" + /> + {errors.cashback_cash && ( + {errors.cashback_cash} + )} +
+
+
-
-
- -
- - {errors.status && {errors.status}} -
-
-
+
+
+ +
+ + {errors.status && ( + {errors.status} + )} +
+
+
-
-
- -
- - {errors.provider && {errors.provider}} -
-
-
+
+
+ +
+ + {errors.provider && ( + {errors.provider} + )} +
+
+
-
-
- -
- - {errors.process_on_third_party && ( - {errors.process_on_third_party} - )} -
-
-
- -
- - -
-
- +
+
+ +
+ + {errors.process_on_third_party && ( + + {errors.process_on_third_party} + + )} +
+
+
+
+ + +
+
+
diff --git a/src/pages/master/products/hooks/ManageProductsContext.tsx b/src/pages/master/products/hooks/ManageProductsContext.tsx index f785421..2ee7f37 100644 --- a/src/pages/master/products/hooks/ManageProductsContext.tsx +++ b/src/pages/master/products/hooks/ManageProductsContext.tsx @@ -273,8 +273,6 @@ const ManageProductsContextProvider = ({ children }: { children: React.ReactNode getProductsLists }} > - - { const resetForm = () => { setFormField(initialState); - setAlert({ show: false, message: '' }); + setErrors({}); }; const doCreateProvider = useCallback( From fc9beeeaa216656b839fa5969f4662339f922c83 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Fri, 9 May 2025 14:19:04 +0700 Subject: [PATCH 5/9] fix editdialog transfertype --- .../transfertype/blocks/EditDialog.tsx | 119 +++++++++--------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index 01c3f10..2dab877 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -69,8 +69,7 @@ const EditDialog = () => { }); const [errors, setErrors] = useState>({}); - const [isLoadingWallets, setIsLoadingWallets] = useState(false); - + const [isLoadingWallets, setIsLoadingWallets] = useState(false); const initialState: { name: string; @@ -122,6 +121,10 @@ const EditDialog = () => { permission: prevState.permission.filter((id) => id !== groupId) }; } else { + // Hapus error permission ketika user memilih group + if (errors.permission && prevState.permission.length === 0) { + setErrors((prev) => ({ ...prev, permission: '' })); + } return { ...prevState, permission: [...prevState.permission, groupId] @@ -138,7 +141,8 @@ const EditDialog = () => { { key: 'wallet_destination', label: 'To Account' }, { key: 'status', label: 'Status' }, { key: 'status_approval', label: 'Status Approval' }, - { key: 'status_kind', label: 'Status Kind' } + { key: 'status_kind', label: 'Status Kind' }, + { key: 'permission', label: 'Group' } ]; const newErrors: Record = {}; @@ -146,9 +150,11 @@ const EditDialog = () => { 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 + key === 'permission' + ? !formField[key] || formField[key].length === 0 + : 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 @@ -228,9 +234,7 @@ const EditDialog = () => { return false; } } catch (error) { - toast.error( - error instanceof Error ? error.message : 'Failed to Update Transfer Type' - ) + toast.error(error instanceof Error ? error.message : 'Failed to Update Transfer Type'); return false; } }, [formField, selectedTransferType]); @@ -369,36 +373,35 @@ const EditDialog = () => { } }, [showEditDialog]); const renderSelectWithLoading = ( - value: string, - onChangeHandler: (value: string) => void, - options: { id: string; name: string }[] | null, - placeholder: string, - isLoading: boolean - ) => { - return ( - - ); - }; - + value: string, + onChangeHandler: (value: string) => void, + options: { id: string; name: string }[] | null, + placeholder: string, + isLoading: boolean + ) => { + return ( + + ); + }; return ( handleEditDialog(open, null)}> @@ -462,7 +465,7 @@ const EditDialog = () => {
-
+
- {renderSelectWithLoading( - formField.wallet_origin, - (value) => setFormField({ ...formField, wallet_origin: value }), - wallets, - 'Select Wallet', - isLoadingWallets - )} + {renderSelectWithLoading( + formField.wallet_origin, + (value) => setFormField({ ...formField, wallet_origin: value }), + wallets, + 'Select Wallet', + isLoadingWallets + )} {errors.wallet_origin && ( {errors.wallet_origin} )} @@ -592,7 +595,9 @@ const EditDialog = () => { setErrors((prev) => ({ ...prev, wallet_destination: '' })); }} > - + @@ -604,7 +609,9 @@ const EditDialog = () => { {errors.wallet_destination && ( - {errors.wallet_destination} + + {errors.wallet_destination} + )}
@@ -759,9 +766,11 @@ const EditDialog = () => { placeholder="No groups selected" value={selectedPermissionNames || ''} readOnly - className="bg-gray-100 mb-2" + className={`bg-gray-100 mb-2 ${errors.permission ? 'border-red-500' : ''}`} /> - + {errors.permission && ( + {errors.permission} + )}
{groups.map((group) => ( @@ -786,11 +795,7 @@ const EditDialog = () => {
- - - - - - { - e.currentTarget.scrollTop += e.deltaY; - }} - > - No Customer found. - - {customers.map((customer) => ( - { - setFormField({ - ...formField, - customerid: customer.id - }); - setOpen(false); - }} - > - {customer.username} - - ))} - - - - - -
-
- -
-
- - - setFormField((prev) => ({ ...prev, email: target.value })) - } - /> -
-
- -
-
- - -
- -
-
-
- -
- - -
- -
-
- -
-
- -
- - setFormField((prev) => ({ ...prev, password: target.value })) - } - /> - -
-
-
-
-
- -
-
- - setFormField((prev) => ({ ...prev, retype_password: target.value })) - } - /> - -
-
- {passwordErrors.length > 0 && ( -
- {passwordErrors.map((error, index) => ( -

{error}

- ))} -
- )} -
-
-
-
- -
- -
+ + + {/* Name */} +
+ +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + setErrors((prev) => ({ ...prev, name: '' })); + }} + /> + {errors.name && {errors.name}}
- -
+
+ + {/* Username */} +
+ +
+ { + setFormField((prev) => ({ ...prev, username: target.value })); + setErrors((prev) => ({ ...prev, username: '' })); + }} + /> + {errors.username && ( + {errors.username} + )} +
+
+ + {/* Customer */} +
+ +
+ setDropdownOpen(true)} + className={`input ${errors.customerid ? 'border-red-500' : ''}`} + /> + {dropdownOpen && ( +
+ {filteredCustomer.length > 0 ? ( + filteredCustomer.map((item) => ( +
handleCustomerSelect(item)} + > + {item.fullname} +
+ )) + ) : ( +
+ {isLoading ? 'Loading...' : 'No results found'} +
+ )} +
+ )} + {errors.customerid && ( + {errors.customerid} + )} +
+
+ + {/* Email */} +
+ +
+ { + setFormField((prev) => ({ ...prev, email: target.value })); + setErrors((prev) => ({ ...prev, email: '' })); + }} + /> + {errors.email && {errors.email}} +
+
+ + {/* Role */} +
+ +
+ + {errors.id_role && ( + {errors.id_role} + )} +
+
+ + {/* Status */} +
+ +
+ + {errors.status && ( + {errors.status} + )} +
+
+ + {/* Password */} +
+ +
+
+ { + setFormField((prev) => ({ ...prev, password: target.value })); + setErrors((prev) => ({ ...prev, password: '' })); + }} + /> + +
+ {passwordErrors.length > 0 && ( +
+ {passwordErrors.map((error, index) => ( +

{error}

+ ))} +
+ )} + {errors.password && ( + {errors.password} + )} +
+
+ + {/* Confirm Password */} +
+ +
+
+ 0 ? 'border-red-500' : ''}`} + type={showPassword.retype_password ? 'text' : 'password'} + autoComplete="off" + value={formField.retype_password} + onChange={({ target }) => { + setFormField((prev) => ({ ...prev, retype_password: target.value })); + setErrors((prev) => ({ ...prev, retype_password: '' })); + }} + /> + +
+ {notMatch.length > 0 && ( +
+ {notMatch.map((error, index) => ( +

{error}

+ ))} +
+ )} + {errors.retype_password && ( + {errors.retype_password} + )} +
+
+ + {/* Submit Button */} +
+ +
+
diff --git a/src/pages/settings/user/manage-user/blocks/EditDialog.tsx b/src/pages/settings/user/manage-user/blocks/EditDialog.tsx index 2193020..e26b20e 100644 --- a/src/pages/settings/user/manage-user/blocks/EditDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/EditDialog.tsx @@ -23,7 +23,6 @@ import { DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { CustomerProps } from './AddDialog'; import { useUserContext } from '../hooks'; import { ChevronDown } from 'lucide-react'; import { Input } from '@/components/ui/input'; @@ -33,25 +32,16 @@ import { Alert, KeenIcon, useDataGrid } from '@/components'; import { toast } from 'sonner'; import { useCallApi } from '@/hooks'; import { doSaveLogActivity } from '@/actions/GlobalActions'; - -interface RoleListProps { - id: string; - name: string; - status: string; -} +import { + CustomerProps, + initialStateCreateUser, + RoleListProps, + validateFormCreateUser +} from './Types'; const API_URL_CUSTOMER = apiConfig.service_customer; const API_URL = apiConfig.service_dashboard; -const initialState = { - name: '', - username: '', - email: '', - id_role: '', - status: '', - customerid: '' -}; - const EditDialog = () => { const parentRef = useRef(null); const { showEditDialog, selectedUser, handleEditDialog } = useUserContext(); @@ -61,16 +51,22 @@ const EditDialog = () => { const [roles, setRoles] = useState([]); const [customers, setCustomers] = useState([]); const [isSubmitting, setIsSubmitting] = useState(false); - const [alert, setAlert] = useState({ - show: false, - message: '' - }); + const [isFetching, setIsFetching] = useState(false); - const [formField, setFormField] = useState(initialState); + const [errors, setErrors] = useState>({}); + const [searchTerm, setSearchTerm] = useState(''); + const [selectedCustomerName, setSelectedCustomerName] = useState(''); + const [dropdownOpen, setDropdownOpen] = useState(false); + const [isLoadingCustomer, setIsLoadingCustomer] = useState(false); + const dropdownRef = useRef(null); + + const [formField, setFormField] = useState(initialStateCreateUser); const resetForm = () => { - setFormField(initialState); - setAlert({ show: false, message: '' }); + setFormField(initialStateCreateUser); + setSelectedCustomerName(''); + setSearchTerm(''); + setErrors({}); }; /* actions */ @@ -79,15 +75,8 @@ const EditDialog = () => { e.preventDefault(); setIsSubmitting(true); - if ( - !formField.name.trim() || - !formField.username.trim() || - !formField.email.trim() || - !formField.id_role || - !formField.status || - !formField.customerid - ) { - setAlert({ show: true, message: 'Please fill all required field' }); + if (!validateFormCreateUser(formField, setErrors, 'update')) { + setIsSubmitting(false); return; } @@ -109,7 +98,7 @@ const EditDialog = () => { doSaveLogActivity(createActivity); } else { - setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + toast.error(response?.message); } } catch (error) { toast.error('Something went wrong, please try again.'); @@ -131,35 +120,48 @@ const EditDialog = () => { order_direction: sorting[0].desc == false ? 'ASC' : 'DESC' }); - // console.log('User ID_ROLE:', response?.data.id_role); - // console.log('Role: ', response?.data.list); setRoles(response?.data.list); } catch (error) { console.error('Error fetching role', error); } }, []); - const getCustomerList = async (sorting: any) => { - try { - sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; - const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { - limit: 100, - page: 1, - with_deleted: false, - order_field: sorting[0].id, - order_direction: sorting[0].desc == false ? 'ASC' : 'DESC' - }); + const getCustomerList = async (sorting: any, filterValue: string) => { + const filter: any = + filterValue?.trim().length === 0 ? {} : { fullname: { like: `%${filterValue}%` } }; - // console.log('CUSTOMER: ', response?.data); - setCustomers(response?.data.list); + sorting = sorting.length == 0 ? [{ id: 'created_at', desc: false }] : sorting; + + const query: any = { + limit: 5, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + }; + + if (filter && Object.keys(filter).length > 0) { + query.filter = JSON.stringify(filter); + } + try { + const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, query); + + if (response?.status) { + setCustomers(response?.data.list); + } else { + toast.error(response?.message); + } } catch (error) { - console.error('Error fetching customer', error); + toast.error('Failed to fetch customer list'); + } finally { + setIsLoadingCustomer(false); } }; const doFetchUserData = useCallback(async (id: string) => { + setIsFetching(true); + const response = await GetData(`${API_URL}/user/detail/${id}`, { id }); - // console.log('User detail response:', response?.data); if (response?.status) { setFormField((prev) => ({ @@ -171,44 +173,71 @@ const EditDialog = () => { status: response.data.status, customerid: response.data.customer?.id || '' })); - // console.log('Customer ID from API:', response?.data.customerid); } else { setFormField((prev) => ({ ...prev, name: '', username: '', email: '', - id_role: '0', + id_role: '', status: '', customerid: '' })); } - // console.log('Fetched ID Role:', response?.data.id_role); + setIsFetching(false); }, []); + const handleCustomerSearch = (e: React.ChangeEvent) => { + setIsLoadingCustomer(true); + setSearchTerm(e.target.value); + setSelectedCustomerName(e.target.value); + setDropdownOpen(true); + const timer = setTimeout(() => { + getCustomerList([{ id: 'fullname', desc: false }], e.target.value); + }, 500); + return () => clearTimeout(timer); + }; + + const handleCustomerSelect = (customer: CustomerProps) => { + setFormField({ ...formField, customerid: customer.id }); + setSelectedCustomerName(customer.fullname); + setDropdownOpen(false); + }; + + const filteredCustomer = customers + .filter((item) => item.fullname.toLowerCase().includes(searchTerm.toLowerCase())) + .slice(0, 10); + useEffect(() => { if (showEditDialog === false) { resetForm(); + setDropdownOpen(false); } }, [showEditDialog]); useEffect(() => { - const fetchAllData = async () => { - await getCustomerList([{ id: 'id', desc: false }]); - await doFetchUserRole([{ id: 'name', desc: false }]); - if (selectedUser) { - await doFetchUserData(selectedUser); + getCustomerList([{ id: 'created_at', desc: false }], ''); + doFetchUserRole([{ id: 'name', desc: false }]); + }, []); + + useEffect(() => { + if (selectedUser) { + doFetchUserData(selectedUser); + } + }, [selectedUser]); + + useEffect(() => { + const handleClickOutside = (event: any) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setDropdownOpen(false); } }; - fetchAllData(); - }, [selectedUser]); - - // console.log('ini role: ', roles); - // useEffect(() => { - // console.log('Selected User ID Role:', formField.id_role); - // // console.log('Available Roles:', roles); - // }, [formField.id_role, roles]); + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); return ( handleEditDialog(open, null)}> @@ -231,160 +260,184 @@ const EditDialog = () => {
- {alert.show && ( - -

{alert.message}

-
- )} -
-
-
-
+ {isFetching ? ( +
+
+
+
+
+
+
+
+
+
+

Loading User Details...

+
+ ) : ( + +
+
- - setFormField((prev) => ({ ...prev, name: target.value })) - } - /> +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + setErrors((prev) => ({ ...prev, name: '' })); + }} + /> + {errors.name && ( + {errors.name} + )} +
-
-
-
+ {/* Username */} +
- - setFormField((prev) => ({ ...prev, username: target.value })) - } - /> +
+ { + setFormField((prev) => ({ ...prev, username: target.value })); + setErrors((prev) => ({ ...prev, username: '' })); + }} + /> + {errors.username && ( + {errors.username} + )} +
-
-
-
+ {/* Customer */} +
- - - - - - - - { - e.currentTarget.scrollTop += e.deltaY; - }} - > - No Customer found. - - {customers.map((customer) => ( - { - setFormField({ - ...formField, - customerid: customer.id - }); - setOpen(false); - }} - > - {customer.username} - - ))} - - - - - +
+ setDropdownOpen(true)} + className={`input ${errors.customerid ? 'border-red-500' : ''}`} + /> + {dropdownOpen && ( +
+ {filteredCustomer.length > 0 ? ( + filteredCustomer.map((item) => ( +
handleCustomerSelect(item)} + > + {item.fullname} +
+ )) + ) : ( +
+ {isLoadingCustomer ? 'Loading...' : 'No results found'} +
+ )} +
+ )} + {errors.customerid && ( + {errors.customerid} + )} +
-
-
-
+ {/* Email */} +
- - setFormField((prev) => ({ ...prev, email: target.value })) - } - /> +
+ { + setFormField((prev) => ({ ...prev, email: target.value })); + setErrors((prev) => ({ ...prev, email: '' })); + }} + /> + {errors.email && ( + {errors.email} + )} +
-
-
-
- - -
+ {/* Role */} +
+ +
+ {errors.id_role && ( + {errors.id_role} + )}
-
-
- + {/* Status */} +
+ +
+ + {errors.status && ( + {errors.status} + )} +
+
-
- +
+
- -
- -
-
- + + )}
diff --git a/src/pages/settings/user/manage-user/blocks/Types.ts b/src/pages/settings/user/manage-user/blocks/Types.ts new file mode 100644 index 0000000..e0fa958 --- /dev/null +++ b/src/pages/settings/user/manage-user/blocks/Types.ts @@ -0,0 +1,91 @@ +import { toast } from 'sonner'; + +export interface CustomerProps { + id: string; + msisdn: string; + email: string; + fullname: string; + username: string; +} + +export interface RoleListProps { + id: string; + name: string; + roles: string; + status: string; +} + +export interface CreateUserParams { + email: string; + username: string; + password: string; + retype_password: string; + name: string; + id_role: string; + status: string; +} + +export const initialStateCreateUser: { + email: string; + username: string; + password: string; + retype_password: string; + name: string; + id_role: string; + status: string; + customerid: string; +} = { + email: '', + username: '', + password: '', + retype_password: '', + name: '', + id_role: '', + status: '', + customerid: '' +}; + +export const validateFormCreateUser = ( + formField: typeof initialStateCreateUser, + setErrors: React.Dispatch>>, + mode: 'create' | 'update' = 'create' +) => { + const requiredFields = + mode === 'create' + ? [ + { key: 'name', label: 'Name' }, + { key: 'username', label: 'Username' }, + { key: 'email', label: 'Email' }, + { key: 'customerid', label: 'Customer ID' }, + { key: 'id_role', label: 'Role' }, + { key: 'status', label: 'Status' }, + { key: 'password', label: 'Password' }, + { key: 'retype_password', label: 'Retype Password' } + ] + : [ + { key: 'name', label: 'Name' }, + { key: 'username', label: 'Username' }, + { key: 'customerid', label: 'Customer ID' }, + { key: 'email', label: 'Email' }, + { key: 'id_role', label: 'Role' }, + { key: 'status', label: 'Status' } + ]; + + const newErrors: Record = {}; + 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`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; +}; diff --git a/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx b/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx index 77f68a9..3fd9aec 100644 --- a/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx +++ b/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx @@ -232,8 +232,6 @@ const ManageUserContextProvider = ({ children }: { children: React.ReactNode }) handleDeleteDialog }} > - - Date: Fri, 9 May 2025 15:12:44 +0700 Subject: [PATCH 8/9] set limit customer list to 100 --- src/pages/settings/user/manage-user/blocks/AddDialog.tsx | 2 +- src/pages/settings/user/manage-user/blocks/EditDialog.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/user/manage-user/blocks/AddDialog.tsx b/src/pages/settings/user/manage-user/blocks/AddDialog.tsx index f50022b..5828fc3 100644 --- a/src/pages/settings/user/manage-user/blocks/AddDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/AddDialog.tsx @@ -170,7 +170,7 @@ const AddDialog = () => { sorting = sorting.length == 0 ? [{ id: 'created_at', desc: false }] : sorting; const query: any = { - limit: 5, + limit: 100, page: 1, with_deleted: false, order_field: sorting[0].id, diff --git a/src/pages/settings/user/manage-user/blocks/EditDialog.tsx b/src/pages/settings/user/manage-user/blocks/EditDialog.tsx index e26b20e..22d29d1 100644 --- a/src/pages/settings/user/manage-user/blocks/EditDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/EditDialog.tsx @@ -133,7 +133,7 @@ const EditDialog = () => { sorting = sorting.length == 0 ? [{ id: 'created_at', desc: false }] : sorting; const query: any = { - limit: 5, + limit: 100, page: 1, with_deleted: false, order_field: sorting[0].id, From e783c9a00cbfb7b5cc69b1d2bdf69ce04ba13784 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Fri, 9 May 2025 17:08:49 +0700 Subject: [PATCH 9/9] add DN in status transaction type on transfertype module --- .../transfertype/blocks/AddDialog.tsx | 1 + .../transfertype/blocks/EditDialog.tsx | 739 +++++++++--------- .../hooks/ManageTransferTypeContext.tsx | 38 +- 3 files changed, 405 insertions(+), 373 deletions(-) diff --git a/src/pages/transfer/transfertype/blocks/AddDialog.tsx b/src/pages/transfer/transfertype/blocks/AddDialog.tsx index b57fcab..1458819 100644 --- a/src/pages/transfer/transfertype/blocks/AddDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/AddDialog.tsx @@ -482,6 +482,7 @@ const AddDialog = () => { Disbursment Agent Withdraw Merchant Income Merchant + Donation {errors.type && {errors.type}} diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index 2dab877..4a18331 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -68,6 +68,7 @@ const EditDialog = () => { message: '' }); const [errors, setErrors] = useState>({}); + const [isLoadingData, setIsLoadingData] = useState(true); const [isLoadingWallets, setIsLoadingWallets] = useState(false); @@ -316,6 +317,7 @@ const EditDialog = () => { if (!showEditDialog || !selectedTransferType) return; const fetchTransactionType = async () => { + setIsLoadingData(true); try { const response = await GetData( `${API_URL}/transactiontype/getdata/${selectedTransferType}`, @@ -357,6 +359,8 @@ const EditDialog = () => { show: true, message: 'Failed to load transaction type data' }); + } finally { + setIsLoadingData(false); } }; @@ -414,7 +418,6 @@ const EditDialog = () => {

Update Transaction Type

-
{
+
{alert.show && ( @@ -436,384 +440,415 @@ const EditDialog = () => {
)} -
-
-
-
- -
- { - setFormField((prev) => ({ ...prev, name: target.value })); - if (target.value) { - setErrors((prev) => ({ ...prev, name: '' })); - } - }} - /> - {errors.name && ( - {errors.name} - )} -
-
-
-
-
- -
- { - setFormField((prev) => ({ ...prev, description: target.value })); - if (target.value) { - setErrors((prev) => ({ ...prev, description: '' })); - } - }} - /> - {errors.description && ( - {errors.description} - )} + {isLoadingData ? ( +
+
+ {[...Array(6)].map((_, idx) => ( +
+
+
+
+ ))} +
+

Loading transaction type data...

+
+ ) : ( + +
+
+
+ +
+ { + setFormField((prev) => ({ ...prev, name: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, name: '' })); + } + }} + /> + {errors.name && ( + {errors.name} + )} +
-
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - minimum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Minimum Amount" - /> +
+
+ +
+ { + setFormField((prev) => ({ ...prev, description: target.value })); + if (target.value) { + setErrors((prev) => ({ ...prev, description: '' })); + } + }} + /> + {errors.description && ( + {errors.description} + )} +
-
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - maximum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Maximum Amount" - /> +
+
+ +
+ { + setFormField((prev) => ({ + ...prev, + minimum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Minimum Amount" + /> +
-
-
-
- -
- { - setFormField((prev) => ({ - ...prev, - max_transaction_per_day: values.floatValue || 0 - })); - }} - placeholder="Enter Max Transaction Per Day" - /> -
-
-
-
-
- -
- {renderSelectWithLoading( - formField.wallet_origin, - (value) => setFormField({ ...formField, wallet_origin: value }), - wallets, - 'Select Wallet', - isLoadingWallets - )} - {errors.wallet_origin && ( - {errors.wallet_origin} - )} -
-
-
-
-
- -
- { + setFormField((prev) => ({ ...prev, wallet_destination })); + setErrors((prev) => ({ ...prev, wallet_destination: '' })); + }} > - - - - {wallets.map((wallet) => ( - - {wallet.name} + + + + + {wallets.map((wallet) => ( + + {wallet.name} + + ))} + + + {errors.wallet_destination && ( + + {errors.wallet_destination} + + )} +
+
+
+ +
+
+ +
+ - {errors.wallet_destination && ( - - {errors.wallet_destination} - - )} + + Change Group Emoney Agent to Customer{' '} + + + Change Group Point Agent to Customer{' '} + + Change Group Point Customer to Agent + Return Customer Emoney + Return Agent Deposit + Return Agent Merchant + Return Agent Emoney + Reward Point + Top Up Escrow + Top Up Master Agent + Top Up Agent + Purchase Loja + Disbursment Escrow + Disbursment Master Agent + Disbursment Agent + Withdraw Merchant + Income Merchant + Donation + + + {errors.type && ( + {errors.type} + )} +
-
-
-
- -
- - {errors.type && ( - {errors.type} - )} +
+
+ +
+ + {errors.status_approval && ( + + {errors.status_approval} + + )} +
-
+
+
+ -
-
- -
- - {errors.status_approval && ( - {errors.status_approval} - )} +
+ + {errors.status_kind && ( + {errors.status_kind} + )} +
+
+
+
+
+ +
+ + {errors.status && ( + {errors.status} + )} +
-
-
-
- -
- - {errors.status_kind && ( - {errors.status_kind} - )} -
-
-
-
-
- -
- - {errors.status && ( - {errors.status} - )} -
-
-
- -
-
- -
- - {errors.permission && ( - {errors.permission} - )} -
-
- {groups.map((group) => ( -
- handleGroupChange(group.id)} - /> - -
- ))} +
+
+ +
+ + {errors.permission && ( + {errors.permission} + )} +
+
+ {groups.map((group) => ( +
+ handleGroupChange(group.id)} + /> + +
+ ))} +
-
-
- - +
+ + +
-
- - - -
- -
- - - -
-
+ + )} + + {isLoadingData && ( + + +
+ +
+ + + +
+
+ )}
diff --git a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx index 517b956..c815be0 100644 --- a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx +++ b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx @@ -203,7 +203,8 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React DM: 'Disbursment Master Agent', DA: 'Disbursment Agent', WI: 'Withdraw Merchant', - IC: 'Income Merchant' + IC: 'Income Merchant', + DN: 'Donation' }; return mapping[row.type] || 'Unknown'; @@ -227,20 +228,18 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React { accessorFn: (row: { status_kind: string }) => { const mapping: Record = { - R: "Return", - T: "Transfer", - P: "Purchase", - W: "Withdraw", - U: "Top Up", - N: "Top Up Patner" + R: 'Return', + T: 'Transfer', + P: 'Purchase', + W: 'Withdraw', + U: 'Top Up', + N: 'Top Up Patner' }; return mapping[row.status_kind] || 'Unknown'; }, id: 'status_kind', - header: ({ column }) => ( - - ), + header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' } @@ -295,22 +294,19 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React let filterObject: Record = {}; if (debouncedSearchTerm) { - filterObject["any"] = debouncedSearchTerm.toLowerCase(); + filterObject['any'] = debouncedSearchTerm.toLowerCase(); } if (columnFilters.length > 0) { columnFilters.forEach((filter: any) => { if (filter.id && filter.value) { if (filter.id === 'name') { - filterObject["any"] = filter.value.toLowerCase(); - } - else if (filter.id === 'wallet_origin') { - filterObject["wallet_origin.name"] = filter.value.toLowerCase(); - } - else if (filter.id === 'wallet_destination') { - filterObject["wallet_destination.name"] = filter.value.toLowerCase(); - } - else { + filterObject['any'] = filter.value.toLowerCase(); + } else if (filter.id === 'wallet_origin') { + filterObject['wallet_origin.name'] = filter.value.toLowerCase(); + } else if (filter.id === 'wallet_destination') { + filterObject['wallet_destination.name'] = filter.value.toLowerCase(); + } else { filterObject[filter.id] = filter.value.toLowerCase(); } } @@ -369,4 +365,4 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React }; export { ManageTransferTypeContext, ManageTransferTypeContextProvider }; -export type { TransferType }; \ No newline at end of file +export type { TransferType };