Skip to content

Commit

Permalink
Merge pull request #178 from Enterprise-CMCS/finsoup
Browse files Browse the repository at this point in the history
Finsoup
  • Loading branch information
pkim-gswell authored Oct 27, 2023
2 parents bb4a4f4 + 1cf6e58 commit 6fffa75
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 94 deletions.
27 changes: 16 additions & 11 deletions src/services/ui/src/components/RHF/FieldArray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@ import { Trash2 } from "lucide-react";
import { RHFSlot } from "./Slot";
import { Button, FormField } from "../Inputs";
import { FieldArrayProps } from "./types";
import { slotReducer } from "./utils";
import { useEffect } from "react";

export const RHFFieldArray = <TFields extends FieldValues>(
props: FieldArrayProps<TFields>
) => {
const fieldArr = useFieldArray({
control: props.control,
name: props.name,
shouldUnregister: true,
});

const onAppend = () => {
fieldArr.append(
props.fields.reduce((ACC, S) => {
ACC[S.name] = "";
return ACC;
}, {} as any)
);
fieldArr.append(props.fields.reduce(slotReducer, {}) as any);
};

useEffect(() => {
if (fieldArr.fields.length) return;
fieldArr.append(props.fields.reduce(slotReducer, {}) as any);
}, []);

return (
<div className="flex flex-col gap-4 w-max">
{fieldArr.fields.map((FLD, index) => {
Expand All @@ -30,10 +33,10 @@ export const RHFFieldArray = <TFields extends FieldValues>(
{props.fields.map((SLOT) => {
return (
<FormField
// shouldUnregister
key={`${SLOT.name}-${index}`}
control={props.control}
name={`${props.name}.${index}.${SLOT.name}` as any}
{...(SLOT.rules && { rules: SLOT.rules })}
render={RHFSlot({
...SLOT,
control: props.control,
Expand All @@ -42,10 +45,12 @@ export const RHFFieldArray = <TFields extends FieldValues>(
/>
);
})}
<Trash2
className="self-end mb-4 cursor-pointer stroke-primary"
onClick={() => fieldArr.remove(index)}
/>
{index >= 1 && (
<Trash2
className="self-end mb-4 cursor-pointer stroke-primary"
onClick={() => fieldArr.remove(index)}
/>
)}
</div>
);
})}
Expand Down
17 changes: 10 additions & 7 deletions src/services/ui/src/components/RHF/FieldGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@ import { Plus } from "lucide-react";
import { RHFSlot } from "./Slot";
import { Button, FormField } from "../Inputs";
import { FieldGroupProps } from "./types";
import { slotReducer } from "./utils";
import { useEffect } from "react";

export const FieldGroup = <TFields extends FieldValues>(
props: FieldGroupProps<TFields>
) => {
const fieldArr = useFieldArray({
control: props.control,
name: props.name,
shouldUnregister: true,
});

const onAppend = () => {
fieldArr.append(
props.fields.reduce((ACC, S) => {
ACC[S.name] = "";
return ACC;
}, {} as any)
);
fieldArr.append(props.fields.reduce(slotReducer, {}) as any);
};

useEffect(() => {
if (fieldArr.fields.length) return;
fieldArr.append(props.fields.reduce(slotReducer, {}) as any);
}, []);

return (
<div className="flex flex-col gap-4 w-max">
{fieldArr.fields.map((FLD, index) => {
Expand All @@ -30,10 +33,10 @@ export const FieldGroup = <TFields extends FieldValues>(
{props.fields.map((SLOT) => {
return (
<FormField
// shouldUnregister
key={`${SLOT.name}-${index}`}
control={props.control}
name={`${props.name}.${index}.${SLOT.name}` as any}
{...(SLOT.rules && { rules: SLOT.rules })}
render={RHFSlot({
...SLOT,
control: props.control,
Expand Down
21 changes: 10 additions & 11 deletions src/services/ui/src/components/RHF/FormGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,16 @@ export const RHFFormGroup = <TFieldValues extends FieldValues>(props: {
</div>
)}
<div className={props.form.wrapperStyling}>
{props.form.slots.map((SLOT) => {
return (
<DependencyWrapper key={SLOT.name} {...SLOT}>
<FormField
control={props.control}
name={SLOT.name as any}
render={RHFSlot({ ...SLOT, control: props.control })}
/>
</DependencyWrapper>
);
})}
{props.form.slots.map((SLOT) => (
<DependencyWrapper key={SLOT.name} {...SLOT}>
<FormField
control={props.control}
name={SLOT.name as any}
{...(SLOT.rules && { rules: SLOT.rules })}
render={RHFSlot({ ...SLOT, control: props.control })}
/>
</DependencyWrapper>
))}
</div>
</div>
</DependencyWrapper>
Expand Down
24 changes: 14 additions & 10 deletions src/services/ui/src/components/RHF/Slot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,16 @@ export const RHFSlot = <
</div>
{field.value === OPT.value &&
OPT.form &&
OPT.form.map((FORM: any, index: any) => (
<div
className="ml-[0.6rem] px-4 border-l-4 border-l-primary"
key={`rhf-form-${index}-${FORM.description}`}
>
<RHFFormGroup form={FORM} control={control} />
</div>
))}
OPT.form.map((FORM: any, index: any) => {
return (
<div
className="ml-[0.6rem] px-4 border-l-4 border-l-primary"
key={`rhf-form-${index}-${FORM.description}`}
>
<RHFFormGroup form={FORM} control={control} />
</div>
);
})}
{field.value === OPT.value &&
OPT.slots &&
OPT.slots.map((SLOT: any, index: any) => (
Expand All @@ -136,7 +138,8 @@ export const RHFSlot = <
<FormField
control={control}
name={SLOT.name}
render={RHFSlot(SLOT)}
{...(SLOT.rules && { rules: SLOT.rules })}
render={RHFSlot({ ...SLOT, control })}
/>
</div>
))}
Expand Down Expand Up @@ -178,7 +181,8 @@ export const RHFSlot = <
<FormField
control={control}
name={SLOT.name}
render={RHFSlot(SLOT)}
{...(SLOT.rules && { rules: SLOT.rules })}
render={RHFSlot({ ...SLOT, control })}
/>
</div>
))}
Expand Down
1 change: 1 addition & 0 deletions src/services/ui/src/components/RHF/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./Document";
export * from "./FormGroup";
export * from "./Section";
export * from "./Slot";
export * from "./utils";
23 changes: 10 additions & 13 deletions src/services/ui/src/components/RHF/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ export type RHFSlotProps = {
labelStyling?: string;
description?: ReactElement | string;
dependency?: DependencyRule;
rules?: RegisterOptions;
} & {
[K in keyof RHFComponentMap]: {
rhf: K;
props?: RHFComponentMap[K];
rules?: RegisterOptions;
fields?: K extends "FieldArray"
? RHFSlotProps[]
: K extends "FieldGroup"
Expand All @@ -33,6 +33,13 @@ export type RHFSlotProps = {
};
}[keyof RHFComponentMap];

export type RHFOption = {
label: string;
value: any;
form?: FormGroup[];
slots?: RHFSlotProps[];
};

export type RHFComponentMap = {
Input: InputProps & {
label?: ReactElement | string;
Expand All @@ -42,21 +49,11 @@ export type RHFComponentMap = {
Switch: SwitchProps;
Select: SelectProps;
Radio: RadioProps & {
options: {
label: string;
value: any;
form?: FormGroup[];
slots?: RHFSlotProps[];
}[];
options: RHFOption[];
};
DatePicker: CalendarProps;
Checkbox: {
options: {
label: string;
value: any;
form?: FormGroup[];
slots?: RHFSlotProps[];
}[];
options: RHFOption[];
};
FieldArray: any;
FieldGroup: {
Expand Down
67 changes: 67 additions & 0 deletions src/services/ui/src/components/RHF/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as T from "@/components/RHF/types";

type GL = Record<string, any>;

export const formGroupReducer = (ACC: GL, FORM: T.FormGroup) => {
FORM.slots.reduce(slotReducer, ACC);
return ACC;
};

export const slotReducer = (ACC: GL, SLOT: T.RHFSlotProps): GL => {
const optionReducer = (OPT: T.RHFOption) => {
if (OPT.form) OPT.form.reduce(formGroupReducer, ACC);
if (OPT.slots) OPT.slots.reduce(slotReducer, ACC);
return ACC;
};

const fieldReducer = (ACC1: GL, SLOT: T.RHFSlotProps): GL => {
if (SLOT.rhf === "FieldArray") {
return { ...ACC1, [SLOT.name]: [SLOT.fields?.reduce(fieldReducer, {})] };
}
if (SLOT.rhf === "FieldGroup") {
return { ...ACC1, [SLOT.name]: [SLOT.fields?.reduce(fieldReducer, {})] };
}

return { ...ACC1, ...slotReducer(ACC1, SLOT) };
};

if (SLOT.rhf === "Input") ACC[SLOT.name] = "";
if (SLOT.rhf === "Textarea") ACC[SLOT.name] = "";
if (SLOT.rhf === "Switch") ACC[SLOT.name] = false;
if (SLOT.rhf === "Radio") {
if (SLOT.props?.options) {
SLOT.props.options.forEach(optionReducer);
const [first] = SLOT.props.options;
ACC[SLOT.name] = first.value;
}
}

if (SLOT.rhf === "Select") {
if (SLOT.props?.options) {
SLOT.props.options.forEach(optionReducer);
const [first] = SLOT.props.options;
ACC[SLOT.name] = first.value;
}
}

if (SLOT.rhf === "Checkbox") {
if (SLOT.props?.options) {
SLOT.props.options.forEach(optionReducer);
ACC[SLOT.name] = [];
}
}

if (SLOT.rhf === "FieldArray")
ACC[SLOT.name] = [SLOT.fields?.reduce(fieldReducer, {})];
if (SLOT.rhf === "FieldGroup")
ACC[SLOT.name] = [SLOT.fields?.reduce(fieldReducer, {})];

return ACC;
};

export const documentInitializer = (document: T.Document) => {
return document.sections.reduce((ACC, SEC) => {
SEC.form.reduce(formGroupReducer, ACC);
return ACC;
}, {} as any);
};
50 changes: 12 additions & 38 deletions src/services/ui/src/pages/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,25 @@
import { ajvResolver } from "@hookform/resolvers/ajv";
import { useForm } from "react-hook-form";
import { Button, Form } from "@/components/Inputs";

import { RHFDocument } from "@/components/RHF";
import { ABP1 } from "./proto";

export const JsonFormSchema = {
type: "object",
properties: {
alt_benefit_plan_population_name: {
type: "string",
minLength: 1,
maxLength: 20,
errorMessage: {
minLength: "This field is required",
},
},
is_enrollment_available: {
type: "string",
},
},
required: ["alt_benefit_plan_population_name"],
additionalProperties: true,
};
import { documentInitializer } from "@/components/RHF";

export function ExampleForm() {
const defaultValues = documentInitializer(ABP1);

const form = useForm({
resolver: ajvResolver(JsonFormSchema as any),
// shouldUnregister: true,
defaultValues: {
alt_benefit_plan_population_name: "",
eligibility_groups: [{}],
is_enrollment_available: "no",
target_criteria: [],
income_target: "",
income_definition: "",
income_definition_specific: "",
income_definition_specific_statewide: [{}],
is_incremental_amount: false,
dollar_incremental_amount: "",
is_geographic_area: "no",
},
defaultValues,
});

const onSubmit = form.handleSubmit((data) => {
console.log(data);
});
const onSubmit = form.handleSubmit(
(data) => {
console.log({ data });
},
(err) => {
console.log({ err });
}
);

return (
<div className="max-w-screen-xl mx-auto p-4 py-8 lg:px-8">
Expand Down
Loading

0 comments on commit 6fffa75

Please sign in to comment.