feat: enhance form validation logic to include table field checks and improve error handling

This commit is contained in:
faisolavolut 2025-02-26 08:19:48 +07:00
parent 6b122bafd8
commit 6c311f4b2e
5 changed files with 114 additions and 43 deletions

View File

@ -57,29 +57,79 @@ export const Form: React.FC<any> = ({
);
try {
const fieldDate: any = local?.fields;
let isError = false;
let error: Record<string, string> = {};
try {
const dateFields = Object.values(fieldDate).filter(
(field: any) => get(field, "type") === "date"
);
if (Array.isArray(dateFields) && dateFields?.length) {
dateFields.map((e: any) => {
if (e?.name)
local.data[e?.name] = normalDate(local.data[e?.name]);
if (dateFields.length) {
dateFields.forEach((e: any) => {
if (e?.name) {
local.data[e.name] = normalDate(local.data[e.name]);
}
});
local.render();
}
} catch (ex) {}
} catch (ex) {
console.error("Error processing date fields:", ex);
}
const fieldRequired = Object.values(fieldDate).filter(
(field: any) => field?.required || field?.type === "table"
);
if (fieldRequired.length) {
fieldRequired.forEach((e: any) => {
let keys = e?.name;
const type = e?.type;
if (type === "table" && e?.fields?.length) {
e.fields.forEach((item: any, index: number) => {
let errorChilds: Record<string, string> = {};
const fieldRequired = Object.values(item?.fields).filter(
(field: any) => field?.required
);
let error = {} as any;
if (Array.isArray(fieldRequired) && fieldRequired?.length) {
fieldRequired.map((e: any) => {
const type = e?.type;
let keys = e?.name;
console.log({ fieldRequired });
fieldRequired.forEach((subField: any) => {
let keySub = subField?.name;
const typeSub = subField?.type;
const val = get(local.data, `${keys}[${index}].${keySub}`);
if (["dropdown-async", "multi-async"].includes(typeSub)) {
keySub = subField?.target || subField?.name;
}
if (
[
"multi-dropdown",
"checkbox",
"multi-upload",
"multi-async",
].includes(typeSub)
) {
if (!Array.isArray(get(local.data, keys)) || !val?.length) {
errorChilds[subField.name] =
"This field requires at least one item.";
isError = true;
}
} else if (!val) {
errorChilds[subField.name] = "Please fill out this field.";
isError = true;
}
console.log({
keySub,
data: get(local.data, `${keys}[${index}]`),
val,
});
});
item.error = errorChilds;
});
} else {
if (["dropdown-async", "multi-async"].includes(type)) {
keys = e?.target || e?.name;
}
const val = get(local.data, keys);
if (
[
"multi-dropdown",
@ -88,27 +138,26 @@ export const Form: React.FC<any> = ({
"multi-async",
].includes(type)
) {
if (
!Array.isArray(get(local.data, keys)) ||
!get(local.data, `${keys}.length`)
) {
error[e?.name] = `This field requires at least one item.`;
if (!Array.isArray(val) || !val?.length) {
error[e.name] = "This field requires at least one item.";
isError = true;
}
} else {
if (!get(local.data, keys)) {
error[e?.name] = `Please fill out this field.`;
} else if (!val) {
error[e.name] = "Please fill out this field.";
isError = true;
}
}
});
}
local.error = error;
local.render();
console.log({ error });
if (Object.keys(error).length) {
throw new Error("please check your input field.");
} else {
await onSubmit(local);
}
console.log(isError);
// if (isError) {
// throw new Error("please check your input field.");
// } else {
// await onSubmit(local);
// }
setTimeout(() => {
toast.success(
<div

View File

@ -285,7 +285,7 @@ export const TypeAsyncDropdown: React.FC<any> = ({
placeholder={disabled ? "" : placeholderField}
isDisabled={disabled}
className={cx(
"rounded-md border-none text-sm",
"rounded-md border-none text-sm w-full",
css`
[role="listbox"] {
padding: 0px !important;

View File

@ -230,6 +230,7 @@ export const TypeInput: React.FC<any> = ({
asSingle={true}
useRange={false}
onChange={(value) => {
console.log(value);
fm.data[name] = value?.startDate
? new Date(value?.startDate)
: null;

View File

@ -154,6 +154,12 @@ export const TableEditBetter: React.FC<any> = ({
local.data = fm?.data[name] || [];
local.render();
console.log(columns);
fm.fields[name] = {
name: name,
type: "table",
fields: [],
};
fm.render();
}, []);
const handleResize = (index: any, width: any) => {
@ -168,9 +174,11 @@ export const TableEditBetter: React.FC<any> = ({
<div className="tbl-wrapper flex flex-grow flex-col">
{!disabledHeader ? (
<div className="head-tbl-list block items-start justify-between bg-white px-0 py-4 sm:flex">
<div className="flex flex-row items-end">
<div className="sm:flex flex flex-col space-y-2">
<div className="flex">{sideLeft ? sideLeft(local) : <></>}</div>
<div className="flex flex-row h-full">
<div className="sm:flex flex flex-col space-y-2 flex-grow">
<div className="flex flex-grow flex-row">
{sideLeft ? sideLeft(local) : <></>}
</div>
</div>
</div>
<div className="ml-auto flex items-center flex-row">
@ -265,10 +273,21 @@ export const TableEditBetter: React.FC<any> = ({
)}
<tbody>
{local.data.map((row: any, index: any) => {
if (
typeof fm.fields?.[name]?.fields?.[index]?.fields !==
"object"
) {
fm.fields[name].fields[index] = {
fields: {},
};
}
const fm_row = {
...fm,
name: name,
type: "table",
data: row,
error: fm.fields?.[name]?.fields?.[index]?.error,
fields: fm.fields?.[name]?.fields?.[index]?.fields,
render: () => {
local.render();
fm.data[name] = local.data;
@ -302,7 +321,9 @@ export const TableEditBetter: React.FC<any> = ({
return (
<td
key={`row_${name}_${index}_${col?.accessorKey}_${idx}`}
className={"table-header-tbl capitalize"}
className={
"table-header-tbl align-top capitalize"
}
>
<div className="p-1">{renderData}</div>
</td>

View File

@ -74,9 +74,7 @@ const Input: React.FC<Props> = (e: Props) => {
const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
const dates = [];
if (asSingle) {
const date = parseFormattedDate(inputValue, displayFormat);
if (dateIsValid(date.toDate())) {
@ -121,6 +119,8 @@ const Input: React.FC<Props> = (e: Props) => {
if (dates[1])
changeDayHover(dayjs(dates[1]).add(-1, "day").format(DATE_FORMAT));
else changeDayHover(dates[0]);
} else {
changeDatepickerValue(null, e.target);
}
changeInputText(e.target.value);