85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
![]() |
'use client';
|
||
|
import { DnDFlowValidationSchema } from '@/utils/zod';
|
||
|
import useDnDStore from '@/stores/useDnDStore';
|
||
|
import _ from 'lodash';
|
||
|
import React from 'react';
|
||
|
import { Node } from 'reactflow';
|
||
|
|
||
|
type ErrorObjType = {
|
||
|
[key: string]: {
|
||
|
[key: string]: string;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
type ValidatorContextType = {
|
||
|
errors: ErrorObjType;
|
||
|
validate: (nds: Node[]) => boolean;
|
||
|
};
|
||
|
|
||
|
export const ValidatorContext = React.createContext<ValidatorContextType>({
|
||
|
errors: {},
|
||
|
validate: () => false,
|
||
|
});
|
||
|
|
||
|
type ModalContextProviderProps = {
|
||
|
children: React.JSX.Element;
|
||
|
};
|
||
|
|
||
|
const ValidatorContextProvider = ({ children }: ModalContextProviderProps) => {
|
||
|
const [errors, setErrors] = React.useState<ErrorObjType>({});
|
||
|
const [prev, setPrev] = React.useState<{ [x: string]: string }[]>();
|
||
|
const [nds, setNds] = React.useState<Node[]>([]);
|
||
|
const { nodes } = useDnDStore();
|
||
|
|
||
|
const _getZodData = React.useCallback((nds: Node[]) => {
|
||
|
return nds.map(({ type, data }) => {
|
||
|
return { [type as string]: data };
|
||
|
});
|
||
|
}, []);
|
||
|
|
||
|
const validate = React.useCallback(
|
||
|
(nds: Node[]): boolean => {
|
||
|
setNds(nds);
|
||
|
try {
|
||
|
setErrors({});
|
||
|
const zodData = _getZodData(nds);
|
||
|
setPrev(zodData);
|
||
|
const zodResults = DnDFlowValidationSchema.safeParse(zodData);
|
||
|
// publish errors to consumers
|
||
|
if (!zodResults.success) {
|
||
|
const issues = zodResults.error.issues;
|
||
|
const updatedErrors: ErrorObjType = {};
|
||
|
issues.forEach(({ path, message }) => {
|
||
|
const nodeIndex = path[0] as number;
|
||
|
const nodeId = nds[nodeIndex].id;
|
||
|
const fieldName = path[path.length - 1];
|
||
|
|
||
|
if (!updatedErrors[nodeId as string]) {
|
||
|
updatedErrors[nodeId as string] = {};
|
||
|
}
|
||
|
updatedErrors[nodeId as string][fieldName as string] = message;
|
||
|
});
|
||
|
setErrors(updatedErrors);
|
||
|
}
|
||
|
return zodResults.success;
|
||
|
} catch (err) {
|
||
|
// toast msg
|
||
|
return true;
|
||
|
}
|
||
|
},
|
||
|
[_getZodData],
|
||
|
);
|
||
|
|
||
|
React.useEffect(() => {
|
||
|
const filteredNodes = nodes.filter((node) => nds?.find((n) => n.id === node.id));
|
||
|
if (prev && !_.isEqual(_getZodData(filteredNodes), prev)) {
|
||
|
// after first submission, now validate the nodes has been validated in onChange event.
|
||
|
validate(filteredNodes);
|
||
|
}
|
||
|
}, [_getZodData, nds, nodes, prev, validate]);
|
||
|
|
||
|
return <ValidatorContext.Provider value={{ errors, validate }}>{children}</ValidatorContext.Provider>;
|
||
|
};
|
||
|
|
||
|
export default ValidatorContextProvider;
|