Skip to content

Commit

Permalink
continue
Browse files Browse the repository at this point in the history
  • Loading branch information
emile-bex committed Aug 8, 2023
1 parent 7fb2b24 commit 8f18bb4
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 106 deletions.
132 changes: 91 additions & 41 deletions src/components/forms/FormSchema/FormSchema.types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RadioTypes } from 'src/components/utils/Inputs/Radio/Radio.types';
import { FilterConstant } from 'src/constants';
import { AnyToFix } from 'src/utils/Types';
import { AnyToFix, StrictUnion } from 'src/utils/Types';

const FormComponents = {
DATEPICKER: 'datepicker',
Expand All @@ -20,8 +20,10 @@ const FormComponents = {
MULTIPLE_FIELDS: 'multiple-fields',
} as const;

/*
export type FormComponent =
(typeof FormComponents)[keyof typeof FormComponents];
*/

export type FieldValue =
| string
Expand All @@ -36,8 +38,7 @@ type MultiFilterConstant<M extends boolean> = M extends true
? FilterConstant
: FilterConstant | FilterConstant[];

interface FormComponentValues<M extends boolean>
extends Record<FormComponent, FieldValue> {
export interface FormComponentValues<M extends boolean> {
[FormComponents.DATEPICKER]: string;
[FormComponents.TEXT_INPUT]: string;
[FormComponents.TEL_INPUT]: string;
Expand All @@ -51,6 +52,24 @@ interface FormComponentValues<M extends boolean>
[FormComponents.RADIO_ASYNC]: string | number;
}

// TODO remove boolean
export type FormComponent = keyof FormComponentValues<boolean>;

export type SchemaComponents = {
[K in string]: FormComponent;
};

export type FormFieldName<S extends SchemaComponents> = keyof S & string;

type FormComponentValue<
S extends SchemaComponents,
FieldName extends FormFieldName<S>
> = FormComponentValues<boolean>[S[FieldName]];

export type SchemaValidation<S extends SchemaComponents> = {
[K in FormFieldName<S>]: FormComponentValue<S, K>;
};

export const TextInputComponents = [
FormComponents.DATEPICKER,
FormComponents.TEXT_INPUT,
Expand Down Expand Up @@ -98,40 +117,51 @@ type InputComponent =
| SelectComponent
| SelectRequestComponent;

// export type FormFieldName<S> = keyof S & string;

interface FormFieldCommonProperties<S> {
id: S;
name: S;
interface FormFieldCommonProperties<S extends SchemaComponents> {
id: FormFieldName<S>;
name: FormFieldName<S>;
component: FormComponentValue<S, FormFieldName<S>>;
}

// export type GetValueType = (name: FormFieldName<S>) => S[FormFieldName<S>];
export type GetValueType<
S extends SchemaComponents,
N extends FormFieldName<S>
> = (name: N) => SchemaValidation<S>[N];

export type GetValueType = (name: string) => AnyToFix;
// export type GetValueType<S, FormFieldName<S>> = (name: string) => AnyToFix;

interface Rule<T extends InputComponent, S, M extends boolean> {
method: (fieldValue: FormComponentValues<M>[T], fieldValues: S) => boolean;
interface Rule<T extends InputComponent, M extends boolean> {
method: (
fieldValue: FormComponentValues<M>[T],
fieldValues: AnyToFix
) => boolean;
args?: AnyToFix[];
message: string;
}

interface FormFieldInputCommonProperties<
T extends InputComponent,
S,
S extends SchemaComponents,
M extends boolean = boolean
> extends FormFieldCommonProperties<S> {
isRequired?: boolean;
rules?: Rule<T, S, M>[];
title: string | JSX.Element | ((getValue: GetValueType) => string);
rules?: Rule<T, M>[];
title:
| string
| JSX.Element
| ((getValue: GetValueType<S, FormFieldName<S>>) => string);
disabled?: boolean;
disable?: (getValue: GetValueType) => boolean;
disable?: (getValue: GetValueType<S, FormFieldName<S>>) => boolean;
hidden?: boolean;
hide?: (getValue: GetValueType, fieldOptions?: AnyToFix) => boolean;
hide?: (
getValue: GetValueType<S, FormFieldName<S>>,
fieldOptions?: AnyToFix
) => boolean;
placeholder?: string;
showLabel?: boolean;
}

export interface FormFieldTextInput<S>
export interface FormFieldTextInput<S extends SchemaComponents>
extends FormFieldInputCommonProperties<TextInputComponent, S> {
component: TextInputComponent;
type?: 'text' | 'email' | 'password';
Expand All @@ -142,100 +172,120 @@ export interface FormFieldTextInput<S>
max?: string;
}

export interface FormFieldCheckBox<S>
export interface FormFieldCheckBox<S extends SchemaComponents>
extends FormFieldInputCommonProperties<CheckBoxComponent, S> {
component: CheckBoxComponent;
}

export interface FormFieldSelect<S>
export interface FormFieldSelect<S extends SchemaComponents>
extends FormFieldInputCommonProperties<SelectComponent, S> {
component: SelectComponent;
dynamicFilter?: (getValue: GetValueType) => string;
dynamicFilter?: (getValue: GetValueType<S, FormFieldName<S>>) => string;
fieldsToReset?: string[];
options?: FilterConstant[];
loadOptions?: (
callback: (options: FilterConstant[] | RadioTypes[]) => void,
inputValue?: string,
getValue?: GetValueType
getValue?: GetValueType<S, FormFieldName<S>>
) => Promise<void> | void;
errorMessage?: string;
limit?: number;
}
export interface FormFieldSelectRequestCommon<S, M extends boolean>
extends FormFieldInputCommonProperties<SelectRequestComponent, S, M> {
export interface FormFieldSelectRequestCommon<
S extends SchemaComponents,
M extends boolean
> extends FormFieldInputCommonProperties<SelectRequestComponent, S, M> {
component: SelectRequestComponent;
fieldsToReset?: string[];
options?: FilterConstant[];
loadOptions?: (
callback: (options: FilterConstant[] | RadioTypes[]) => void,
inputValue?: string,
getValue?: GetValueType
getValue?: GetValueType<S, FormFieldName<S>>
) => Promise<void> | void;
openMenuOnClick?: boolean;
}

// TODO fix type depending on is Multi
interface FormFieldSelectRequestMulti<S>
interface FormFieldSelectRequestMulti<S extends SchemaComponents>
extends FormFieldSelectRequestCommon<S, true> {
isMulti: true;
}

interface FormFieldSelectRequestSingle<S>
interface FormFieldSelectRequestSingle<S extends SchemaComponents>
extends FormFieldSelectRequestCommon<S, false> {
isMulti: false;
}

interface FormFieldSelectRequestMethod<S>
interface FormFieldSelectRequestMethod<S extends SchemaComponents>
extends FormFieldSelectRequestCommon<S, boolean> {
isMulti: (getValue: (name: string) => AnyToFix) => boolean;
}

type FormFieldSelectRequestOmit<S> = Omit<
type FormFieldSelectRequestOmit<S extends SchemaComponents> = Omit<
FormFieldSelectRequestCommon<S, false>,
'isMulti'
>;

export type FormFieldSelectRequest<S> =
export type FormFieldSelectRequest<S extends SchemaComponents> =
| FormFieldSelectRequestMulti<S>
| FormFieldSelectRequestSingle<S>
| FormFieldSelectRequestOmit<S>
| FormFieldSelectRequestMethod<S>;

export type FormFieldInput<S> =
export type FormFieldInput<S extends SchemaComponents> =
| FormFieldTextInput<S>
| FormFieldCheckBox<S>
| FormFieldSelect<S>
| FormFieldSelectRequest<S>;

export interface FormFieldText<S> extends FormFieldCommonProperties<S> {
title: string | ((getValue: GetValueType) => string);
export interface FormFieldText<S extends SchemaComponents>
extends FormFieldCommonProperties<S> {
title: string | ((getValue: GetValueType<S, FormFieldName<S>>) => string);
component: TextComponent;
hide?: (getValue: GetValueType, fieldOptions?: AnyToFix) => boolean;
hide?: (
getValue: GetValueType<S, FormFieldName<S>>,
fieldOptions?: AnyToFix
) => boolean;
hidden?: boolean;
}

export interface FormFieldMultiple<S> extends FormFieldCommonProperties<S> {
export interface FormFieldMultiple<S extends SchemaComponents>
extends FormFieldCommonProperties<S> {
action: string;
component: MultipleComponent;
fields: FormFieldInput<S>[];
hide?: (getValue: GetValueType) => boolean;
hide?: (getValue: GetValueType<S, FormFieldName<S>>) => boolean;
hidden?: boolean;
}

export interface FormFieldGroup<S> extends FormFieldCommonProperties<S> {
export interface FormFieldGroup<S extends SchemaComponents>
extends FormFieldCommonProperties<S> {
component: GroupComponent;
fields: (FormFieldInput<S> | FormFieldText<S>)[];
hide?: (getValue: GetValueType) => boolean;
hide?: (getValue: GetValueType<S, FormFieldName<S>>) => boolean;
hidden?: boolean;
}

export type FormField<S> =
export type FormField<S extends SchemaComponents> =
| FormFieldInput<S>
| FormFieldText<S>
| FormFieldMultiple<S>
| FormFieldGroup<S>;

export interface FormSchema {
export interface FormSchema<S extends SchemaComponents> {
id: string;
fields: FormField<string>[];
fields: FormField<S>[];
}

export type FormSchemaValidation<R> = R extends FormSchema<
infer S extends SchemaComponents
>
? SchemaValidation<S>
: never;

export type FormSchemaComponent<R> = R extends FormSchema<
infer S extends SchemaComponents
>
? S
: never;
16 changes: 13 additions & 3 deletions src/components/forms/FormSchema/FormSchema.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,32 @@ import {
FormFieldCheckBox,
FormFieldGroup,
FormFieldMultiple,
FormFieldSelect, FormFieldSelectRequest,
FormFieldSelect,
FormFieldSelectRequest,
FormFieldText,
FormFieldTextInput,
FormSchema,
GroupComponent,
GroupComponents,
MultipleComponent,
MultipleComponents,
SchemaComponents,
SelectComponent,
SelectComponents,
SelectRequestComponent,
SelectRequestComponents,
TextComponent,
TextComponents,
TextInputComponent,
TextInputComponents
} from "./FormSchema.types";
TextInputComponents,
} from './FormSchema.types';

export function createFormSchema<T extends SchemaComponents>(
schemaComponents: T,
formSchema: FormSchema<T>
) {
return formSchema;
}

export function isFormFieldTextInput(
field: FormField
Expand Down
32 changes: 19 additions & 13 deletions src/components/forms/FormWithValidation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,30 @@ import {
isFormFieldMultiple,
isFormFieldSelect,
isFormFieldText,
} from './FormSchema';
SchemaComponents, SchemaValidation, FormSchemaValidation, FormFieldName, FormSchemaComponent
} from "./FormSchema";
import { StyledForm } from './Forms.styles';
import { formAddUser } from "./schemas/formAddUser";
import { formResetPassword } from "./schemas/formResetPassword";

interface FormWithValidationProps<S> {
interface FormWithValidationProps<S extends FormSchema<AnyToFix>> {
defaultValues?: AnyToFix; // to be typed
onCancel?: () => void;
onSubmit: (arg1: AnyToFix, arg2: AnyToFix) => void; // to be typed
onError?: (any) => void;
formSchema: FormSchema<S>;
formSchema: S;
submitText?: string;
cancelText?: string;
enterToSubmit?: boolean;
ref?: React.Ref<{ resetForm: () => void }>;
}

export const FormWithValidation = forwardRef<
{ resetForm: () => void },
FormWithValidationProps<S>
>(
(
type Test = FormWithValidationProps<typeof formResetPassword>['formSchema']
type Name = FormFieldName<FormSchemaComponent<Test>>
type Test3 = FormSchemaValidation<Test>['confirmPassword']


export function FormWithValidation<S extends FormSchema<AnyToFix>>(
{
formSchema,
defaultValues = {},
Expand All @@ -49,9 +54,10 @@ export const FormWithValidation = forwardRef<
onCancel,
enterToSubmit = false,
onError,
}: FormWithValidationProps<S>,
ref
) => {
ref,
}: FormWithValidationProps<S>){


const { id: formId, fields } = formSchema;

const [error, setError] = useState<string>();
Expand All @@ -65,7 +71,7 @@ export const FormWithValidation = forwardRef<
);

const { handleSubmit, control, reset, getValues, resetField, watch } =
useForm<S>({
useForm<FormSchemaValidation<S>>({
defaultValues,
shouldUnregister: true,
});
Expand Down Expand Up @@ -183,7 +189,7 @@ export const FormWithValidation = forwardRef<
}

return !shouldHideField ? (
<GenericField
<GenericField>
watch={watch}
resetField={resetField}
control={control}
Expand Down
Loading

0 comments on commit 8f18bb4

Please sign in to comment.