75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import { ZodObject } from 'zod';
|
|
import { Flex, rem } from '@mantine/core';
|
|
import BooleanField from '@/components/ObjectForm/Fields/BooleanField/BooleanField';
|
|
import NumberField from '@/components/ObjectForm/Fields/NumberField/NumberField';
|
|
import StringField from '@/components/ObjectForm/Fields/StringField/StringField';
|
|
|
|
type EditProps<T> = {
|
|
object: T;
|
|
onChange: (item: T) => void;
|
|
};
|
|
type CreateProps<T> = {
|
|
onCreate: (item: T) => void;
|
|
};
|
|
type SchemaLabels<S extends ZodObject<any>> = Partial<Record<keyof S['shape'], string>>;
|
|
type RestProps<S extends ZodObject<any>> =
|
|
| {
|
|
schema: S;
|
|
labels?: SchemaLabels<S>;
|
|
excludeKeys?: (keyof S['shape'])[];
|
|
includeKeys?: never;
|
|
}
|
|
| {
|
|
schema: S;
|
|
labels?: SchemaLabels<S>;
|
|
includeKeys?: (keyof S['shape'])[];
|
|
excludeKeys?: never;
|
|
};
|
|
|
|
type Props<ObjectType, ObjectSchema extends ZodObject> = (
|
|
| EditProps<ObjectType>
|
|
| CreateProps<ObjectType>
|
|
) &
|
|
RestProps<ObjectSchema>;
|
|
|
|
const RenderField = (key: string, value: any, label?: string) => {
|
|
const getField = () => {
|
|
switch (value.type) {
|
|
case 'string':
|
|
return <StringField label={label ? label : key} />;
|
|
case 'number':
|
|
return <NumberField label={label ? label : key} />;
|
|
case 'boolean':
|
|
return <BooleanField label={label ? label : key} />;
|
|
default:
|
|
return <></>;
|
|
}
|
|
};
|
|
return <div key={key}>{getField()}</div>;
|
|
};
|
|
|
|
function ObjectForm<ObjectType, ObjectSchema extends ZodObject<any, any>>(
|
|
props: Props<ObjectType, ObjectSchema>
|
|
) {
|
|
const processKeyValue = (key: string, val: any) => {
|
|
const keyTyped = key as keyof typeof props.schema.shape;
|
|
if (props.excludeKeys && props.excludeKeys.includes(keyTyped)) {
|
|
return <></>;
|
|
}
|
|
|
|
if (props.includeKeys && !props.includeKeys.includes(keyTyped)) {
|
|
return <></>;
|
|
}
|
|
const label = props.labels ? props.labels[keyTyped] : undefined;
|
|
return RenderField(key, val, label);
|
|
};
|
|
return (
|
|
<Flex gap={rem(10)} direction="column">
|
|
{Object.entries(props.schema.shape).map(([key, val]) => {
|
|
return processKeyValue(key, val);
|
|
})}
|
|
</Flex>
|
|
);
|
|
}
|
|
export default ObjectForm;
|