From 1e7b583e41cb8d9b6834ea3871f11113982f3384 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu, 11 Jul 2024 23:13:43 +0530 Subject: [PATCH] cleaned up --- .../sample/src/pages/StepperForm.jsx | 442 +++++++----------- micro-frontends/sample/src/pages/TabForm.jsx | 438 +++++------------ micro-frontends/sample/src/pages/test.jsx | 23 - .../sample/src/pages/utils/FormComposer.jsx | 215 +++++---- 4 files changed, 394 insertions(+), 724 deletions(-) diff --git a/micro-frontends/sample/src/pages/StepperForm.jsx b/micro-frontends/sample/src/pages/StepperForm.jsx index fa9ec082618..f956776489c 100644 --- a/micro-frontends/sample/src/pages/StepperForm.jsx +++ b/micro-frontends/sample/src/pages/StepperForm.jsx @@ -1,300 +1,176 @@ -import React, { useState } from 'react'; -import { useForm, Controller, useFieldArray } from 'react-hook-form'; -import Stepper from 'react-stepper-horizontal'; +// src/components/JsonSchemaForm.js +import React from "react"; +import { useUserState } from "../state/useUserState"; +import FormComposer from "./utils/FormComposer"; +import CustomDatePicker from "./CustomCheck"; // Import the custom component -const RenderField = ({ control, register, name, property, uiSchema, errors }) => { - if (property.type === 'object') { - return ( -
-

{property.title}

- {Object.keys(property.properties).map(subKey => ( - - ))} -
- ); - } else if (property.type === 'array') { - const { fields, append, remove } = useFieldArray({ - control, - name: name, - }); - - return ( -
-

{property?.title}

- {fields.map((field, index) => ( -
- {Object.keys(property.items.properties).map(subKey => ( - - ))} - -
- ))} - -
- ); - } else { - return ( -
- - ( - - )} - /> - {errors[name] &&
{property.title} is required
} -
- ); - } -}; - -const StepperForm = ({ schema, uiSchema, steps, conditionalSteps }) => { - const [currentStep, setCurrentStep] = useState(0); - const { control, register, handleSubmit, watch, formState: { errors } } = useForm(); - - const onSubmit = data => console.log(data); - - const nextStep = () => setCurrentStep(prev => prev + 1); - const prevStep = () => setCurrentStep(prev => prev - 1); - - const isStepVisible = (step) => { - if (!conditionalSteps[step]) return true; - const condition = conditionalSteps[step]; - const watchValues = watch(condition.fields); - return condition.rule(watchValues); - }; - - return ( -
- ({ title: step.label }))} activeStep={currentStep} /> - - {steps.map((step, index) => ( - index === currentStep && isStepVisible(index) && ( -
-

{step.label}

- {step.fields.map(key => ( - - ))} - {currentStep > 0 && } - {currentStep < steps.length - 1 && } - {currentStep === steps.length - 1 && } -
- ) - ))} - - ); -}; - - -const steps = [ - { label: "Personal Info", fields: ["personalInfo"] }, - { label: "Address", fields: ["address"] }, - { label: "Phones", fields: ["phones"] }, - { label: "Preferences", fields: ["preferences"] } -]; - -const conditionalSteps = { - 3: { - fields: ["preferences.newsletter"], - rule: values => values["preferences.newsletter"] - } -}; - -const StepperFormScreen = () => { - return ( -
- -
- ); -} - -export default StepperFormScreen; - - - const schema = { - "title": "Complex Form", - "type": "object", - "properties": { - "personalInfo": { - "type": "object", - "title": "Personal Information", - "properties": { - "firstName": { - "type": "string", - "title": "First Name" - }, - "lastName": { - "type": "string", - "title": "Last Name" - }, - "age": { - "type": "integer", - "title": "Age" - }, - "email": { - "type": "string", - "format": "email", - "title": "Email" - } - } +const schema = { + title: "Complex Form", + type: "object", + properties: { + personalInfo: { + type: "object", + properties: { + firstName: { type: "string", title: "First Name" }, + lastName: { type: "string", title: "Last Name" }, + dob: { type: "string", format: "date", title: "Date of Birth" }, }, - "address": { - "type": "object", - "title": "Address", - "properties": { - "street": { - "type": "string", - "title": "Street" - }, - "city": { - "type": "string", - "title": "City" - }, - "state": { - "type": "string", - "title": "State" - }, - "zipCode": { - "type": "string", - "title": "Zip Code" - } - } + required: ["firstName", "lastName"], + }, + address: { + type: "object", + properties: { + street: { type: "string", title: "Street" }, + city: { type: "string", title: "City" }, + state: { type: "string", title: "State" }, + zipCode: { type: "string", title: "Zip Code" }, }, - "phones": { - "type": "array", - "title": "Phone Numbers", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "title": "Type", - "enum": ["Home", "Work", "Mobile"] - }, - "number": { - "type": "string", - "title": "Number" - } - } - } + }, + test: { + type: "array", + items: { + type: "string", }, - "preferences": { - "type": "object", - "title": "Preferences", - "properties": { - "newsletter": { - "type": "boolean", - "title": "Receive Newsletter" + }, + phones: { + type: "array", + items: { + type: "object", + properties: { + type: { + type: "string", + title: "Type", + enum: ["Home", "Work", "Mobile"], }, - "notifications": { - "type": "object", - "title": "Notifications", - "properties": { - "email": { - "type": "boolean", - "title": "Email" - }, - "sms": { - "type": "boolean", - "title": "SMS" + number: { type: "string", title: "Number" }, + otherPhones: { + type: "array", + items: { + type: "object", + properties: { + type: { + type: "string", + title: "Type", + enum: ["Home", "Work", "Mobile"], + }, + number: { type: "string", title: "Number" }, }, - "push": { - "type": "boolean", - "title": "Push Notifications" - } - } - } - } - } - }, - "required": ["personalInfo", "email"] - }; - - const uiSchema = { - "ui:groups": { - "personalInfo": ["firstName", "lastName", "age", "email"], - "address": ["street", "city", "state", "zipCode"], - "phones": ["phones"], - "preferences": ["newsletter", "notifications"] - }, - "firstName": { - "ui:widget": "text" + }, + }, + }, + }, }, - "lastName": { - "ui:widget": "text" + newsletter: { + type: "boolean", + title: "Subscribe to Newsletter", }, - "age": { - "ui:widget": "number" + subscriptionFrequency: { + type: "string", + title: "Subscription Frequency", + enum: ["Daily", "Weekly", "Monthly"], }, - "email": { - "ui:widget": "email" + }, + required: ["personalInfo", "address"], +}; +// src/uiSchema.json +const uiSchema = { + "ui:groups": { + personalInfo: { + fields: ["personalInfo"], + "ui:order": ["firstName", "lastName", "dob"], }, - "street": { - "ui:widget": "text" + address: { + fields: ["address"], + "ui:order": ["street", "city", "state", "zipCode"], }, - "city": { - "ui:widget": "text" + phones: { + fields: ["phones"], + "ui:order": ["phones"], }, - "state": { - "ui:widget": "text" + test: { + fields: ["test"], + "ui:order": ["test"], }, - "zipCode": { - "ui:widget": "text" + subscription: { + fields: ["newsletter", "subscriptionFrequency"], + "ui:order": ["newsletter", "subscriptionFrequency"], }, - "phones": { - "items": { - "type": { - "ui:widget": "select" - }, - "number": { - "ui:widget": "text" - } - } - }, - "newsletter": { - "ui:widget": "checkbox" + }, + "ui:layout":{ + layouts: [ + { label: "Personal Info", fields: ["personalInfo"] }, + { label: "Address", fields: ["address"] }, + { label: "Phones", fields: ["phones"] }, + { label: "Preferences", fields: ["preferences"] }, + ], + + conditionalLayout:{ + 3: { + fields: ["preferences.newsletter"], + rule: (values) => values["preferences.newsletter"], }, - "notifications": { - "email": { - "ui:widget": "checkbox" + }, + type:"STEPPER" //"TAB||STEPPER" + }, + personalInfo: { + firstName: { "ui:widget": "text" }, + lastName: { "ui:widget": "text" }, + dob: { "ui:widget": "date" }, + }, + address: { + street: { "ui:widget": "text" }, + city: { "ui:widget": "text" }, + state: { "ui:widget": "text" }, + zipCode: { "ui:widget": "text" }, + }, + phones: { + items: { + type: { "ui:widget": "select" }, + number: { "ui:widget": "text" }, + + mobileNumber: { + "ui:widget": "text", + "ui:dependencies": { + dependentField: "phones[0].type", + expectedValue: "Mobile", }, - "sms": { - "ui:widget": "checkbox" + }, + otherPhones: { + items: { + type: { "ui:widget": "select" }, + number: { "ui:widget": "text" }, }, - "push": { - "ui:widget": "checkbox" - } - } - }; \ No newline at end of file + }, + }, + }, + newsletter: { + "ui:widget": "checkbox", + }, + subscriptionFrequency: { + "ui:dependencies": { + dependentField: "newsletter", + expectedValue: true, + "ui:widget": "select", + }, + }, +}; +const customWidgets = { + date: CustomDatePicker, +}; + + + +const StepperForm = () => { + const { setData, resetData, data } = useUserState(); + return ( + <> +

Hi {data?.name}

+ + + ); +}; +export default StepperForm; diff --git a/micro-frontends/sample/src/pages/TabForm.jsx b/micro-frontends/sample/src/pages/TabForm.jsx index c34074f9778..aa7f852bd93 100644 --- a/micro-frontends/sample/src/pages/TabForm.jsx +++ b/micro-frontends/sample/src/pages/TabForm.jsx @@ -1,213 +1,8 @@ -import React, { useState } from "react"; -import { useForm, Controller, useFieldArray } from "react-hook-form"; -import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; -import "react-tabs/style/react-tabs.css"; +// src/components/JsonSchemaForm.js +import React from "react"; import { useUserState } from "../state/useUserState"; -import { TodoComponent } from "../App"; - -const RenderField = ({ - control, - register, - name, - property, - uiSchema, - errors, -}) => { - if (property.type === "object") { - return ( -
-

{property.title}

- {Object.keys(property.properties).map((subKey) => ( - - ))} -
- ); - } else if (property.type === "array") { - const { fields, append, remove } = useFieldArray({ - control, - name: name, - }); - - return ( -
-

{property.title}

- {fields.map((field, index) => ( -
- {Object.keys(property.items.properties).map((subKey) => ( - - ))} - -
- ))} - -
- ); - } else { - return ( -
- - ( - - )} - /> - {errors[name] && ( -
{property.title} is required
- )} -
- ); - } -}; - -const TabForm = ({ schema, uiSchema, tabs, conditionalTabs }) => { - const [currentTab, setCurrentTab] = useState(0); - const { - control, - register, - handleSubmit, - watch, - formState: { errors }, - } = useForm(); - - const onSubmit = (data) => console.log(data); - - const isTabVisible = (tab) => { - if (!conditionalTabs[tab]) return true; - const condition = conditionalTabs[tab]; - const watchValues = watch(condition.fields); - return condition.rule(watchValues); - }; - - return ( -
- setCurrentTab(index)} - > - - {tabs.map( - (tab, index) => - isTabVisible(index) && {tab.label} - )} - - - {tabs.map( - (tab, index) => - isTabVisible(index) && ( - -

{tab.label}

- {tab.fields.map((key) => ( - - ))} - {currentTab > 0 && ( - - )} - {currentTab < tabs.length - 1 && ( - - )} - {currentTab === tabs.length - 1 && ( - - )} -
- ) - )} -
-
- ); -}; - -const tabs = [ - { label: "Personal Info", fields: ["personalInfo"] }, - { label: "Address", fields: ["address"] }, - { label: "Phones", fields: ["phones"] }, - { label: "Preferences", fields: ["preferences"] }, -]; - -const conditionalTabs = { - 3: { - fields: ["preferences.newsletter"], - rule: (values) => values["preferences.newsletter"], - }, -}; - -const TabFormScreen = () => { - const { setData, resetData, data } = useUserState(); - - return ( -
-

Hi {data?.name}

- - -
- ); -}; - -export default TabFormScreen; +import FormComposer from "./utils/FormComposer"; +import CustomDatePicker from "./CustomCheck"; // Import the custom component const schema = { title: "Complex Form", @@ -215,52 +10,30 @@ const schema = { properties: { personalInfo: { type: "object", - title: "Personal Information", properties: { - firstName: { - type: "string", - title: "First Name", - }, - lastName: { - type: "string", - title: "Last Name", - }, - age: { - type: "integer", - title: "Age", - }, - email: { - type: "string", - format: "email", - title: "Email", - }, + firstName: { type: "string", title: "First Name" }, + lastName: { type: "string", title: "Last Name" }, + dob: { type: "string", format: "date", title: "Date of Birth" }, }, + required: ["firstName", "lastName"], }, address: { type: "object", - title: "Address", properties: { - street: { - type: "string", - title: "Street", - }, - city: { - type: "string", - title: "City", - }, - state: { - type: "string", - title: "State", - }, - zipCode: { - type: "string", - title: "Zip Code", - }, + street: { type: "string", title: "Street" }, + city: { type: "string", title: "City" }, + state: { type: "string", title: "State" }, + zipCode: { type: "string", title: "Zip Code" }, + }, + }, + test: { + type: "array", + items: { + type: "string", }, }, phones: { type: "array", - title: "Phone Numbers", items: { type: "object", properties: { @@ -269,98 +42,133 @@ const schema = { title: "Type", enum: ["Home", "Work", "Mobile"], }, - number: { - type: "string", - title: "Number", - }, - }, - }, - }, - preferences: { - type: "object", - title: "Preferences", - properties: { - newsletter: { - type: "boolean", - title: "Receive Newsletter", - }, - notifications: { - type: "object", - title: "Notifications", - properties: { - email: { - type: "boolean", - title: "Email", - }, - sms: { - type: "boolean", - title: "SMS", - }, - push: { - type: "boolean", - title: "Push Notifications", + number: { type: "string", title: "Number" }, + otherPhones: { + type: "array", + items: { + type: "object", + properties: { + type: { + type: "string", + title: "Type", + enum: ["Home", "Work", "Mobile"], + }, + number: { type: "string", title: "Number" }, + }, }, }, }, }, }, + newsletter: { + type: "boolean", + title: "Subscribe to Newsletter", + }, + subscriptionFrequency: { + type: "string", + title: "Subscription Frequency", + enum: ["Daily", "Weekly", "Monthly"], + }, }, - required: ["personalInfo", "email"], + required: ["personalInfo", "address"], }; - +// src/uiSchema.json const uiSchema = { "ui:groups": { - personalInfo: ["firstName", "lastName", "age", "email"], - address: ["street", "city", "state", "zipCode"], - phones: ["phones"], - preferences: ["newsletter", "notifications"], - }, - firstName: { - "ui:widget": "text", - }, - lastName: { - "ui:widget": "text", - }, - age: { - "ui:widget": "number", - }, - email: { - "ui:widget": "email", - }, - street: { - "ui:widget": "text", + personalInfo: { + fields: ["personalInfo"], + "ui:order": ["firstName", "lastName", "dob"], + }, + address: { + fields: ["address"], + "ui:order": ["street", "city", "state", "zipCode"], + }, + phones: { + fields: ["phones"], + "ui:order": ["phones"], + }, + test: { + fields: ["test"], + "ui:order": ["test"], + }, + subscription: { + fields: ["newsletter", "subscriptionFrequency"], + "ui:order": ["newsletter", "subscriptionFrequency"], + }, }, - city: { - "ui:widget": "text", + "ui:layout": { + layouts: [ + { label: "Personal Info", fields: ["personalInfo"] }, + { label: "Address", fields: ["address"] }, + { label: "Phones", fields: ["phones"] }, + { label: "Preferences", fields: ["preferences"] }, + ], + + conditionalLayout: { + 3: { + fields: ["preferences.newsletter"], + rule: (values) => values["preferences.newsletter"], + }, + }, + type: "TAB", //"TAB||STEPPER" }, - state: { - "ui:widget": "text", + personalInfo: { + firstName: { "ui:widget": "text" }, + lastName: { "ui:widget": "text" }, + dob: { "ui:widget": "date" }, }, - zipCode: { - "ui:widget": "text", + address: { + street: { "ui:widget": "text" }, + city: { "ui:widget": "text" }, + state: { "ui:widget": "text" }, + zipCode: { "ui:widget": "text" }, }, phones: { items: { - type: { - "ui:widget": "select", - }, - number: { + type: { "ui:widget": "select" }, + number: { "ui:widget": "text" }, + + mobileNumber: { "ui:widget": "text", + "ui:dependencies": { + dependentField: "phones[0].type", + expectedValue: "Mobile", + }, + }, + otherPhones: { + items: { + type: { "ui:widget": "select" }, + number: { "ui:widget": "text" }, + }, }, }, }, newsletter: { "ui:widget": "checkbox", }, - notifications: { - email: { - "ui:widget": "checkbox", - }, - sms: { - "ui:widget": "checkbox", - }, - push: { - "ui:widget": "checkbox", + subscriptionFrequency: { + "ui:dependencies": { + dependentField: "newsletter", + expectedValue: true, + "ui:widget": "select", }, }, }; +const customWidgets = { + date: CustomDatePicker, +}; + +const TabForm = () => { + const { setData, resetData, data } = useUserState(); + return ( + <> +

Hi {data?.name}

+ + + ); +}; +export default TabForm; diff --git a/micro-frontends/sample/src/pages/test.jsx b/micro-frontends/sample/src/pages/test.jsx index 0a5fe5aaf62..ca4a6706628 100644 --- a/micro-frontends/sample/src/pages/test.jsx +++ b/micro-frontends/sample/src/pages/test.jsx @@ -96,22 +96,6 @@ const uiSchema = { "ui:order": ["newsletter", "subscriptionFrequency"], }, }, - "ui:layout":{ - layouts: [ - { label: "Personal Info", fields: ["personalInfo"] }, - { label: "Address", fields: ["address"] }, - { label: "Phones", fields: ["phones"] }, - { label: "Preferences", fields: ["preferences"] }, - ], - - conditionalLayout:{ - 3: { - fields: ["preferences.newsletter"], - rule: (values) => values["preferences.newsletter"], - }, - }, - type:"TAB" //"TAB||STEPPER" - }, personalInfo: { firstName: { "ui:widget": "text" }, lastName: { "ui:widget": "text" }, @@ -158,18 +142,11 @@ const customWidgets = { date: CustomDatePicker, }; - - const Test = () => { const { setData, resetData, data } = useUserState(); - console.log(data, "data"); return ( <>

Hi {data?.name}

- setData({ ...data, name: e.target.value })} /> - { @@ -137,7 +137,7 @@ const RenderDependentField = ({ watch, errors, dependencies, - customWidgets + customWidgets, }) => { return ( { +const FormComposer = ({ schema, uiSchema, customWidgets }) => { const [currentTab, setCurrentTab] = useState(0); const { @@ -319,7 +315,7 @@ const FormComposer = ({ }, [schema, uiSchema, control, errors, watch] ); - const uiLayout=uiSchema?.["ui:layout"] + const uiLayout = uiSchema?.["ui:layout"]; const isTabVisible = (tab) => { if (!uiLayout?.conditionalLayout?.[tab]) return true; const condition = uiLayout?.conditionalLayout?.[tab]; @@ -351,104 +347,117 @@ const FormComposer = ({

{schema.title}

- {uiLayout &&uiLayout?.layouts&& uiLayout?.layouts?.length > 0 ? (uiLayout?.type=="TAB"?(<> ({ title: step.label }))} activeStep={currentTab} /> - - {uiLayout?.layouts.map((tab, index) => { - const updatedUiSchema = React.useMemo( - () => getUpdatedUISchema(index, uiSchema, uiLayout?.layouts), - [index, uiSchema, uiLayout?.layouts] - ); - return ( - isTabVisible(index) && ( -
-

{tab.label}

- {renderGroups( - updatedUiSchema?.["ui:groups"], - schema, - updatedUiSchema, - control, - errors - )} + {uiLayout && uiLayout?.layouts && uiLayout?.layouts?.length > 0 ? ( + uiLayout?.type !== "TAB" ? ( + <> + {" "} + ({ title: step.label }))} + activeStep={currentTab} + /> + {uiLayout?.layouts.map((tab, index) => { + const updatedUiSchema = React.useMemo( + () => getUpdatedUISchema(index, uiSchema, uiLayout?.layouts), + [index, uiSchema, uiLayout?.layouts] + ); + return ( + isTabVisible(index) && + index == currentTab && ( +
+

{tab.label}

+ {renderGroups( + updatedUiSchema?.["ui:groups"], + schema, + updatedUiSchema, + control, + errors + )} - {currentTab > 0 && ( - - )} - {currentTab < uiLayout?.layouts.length - 1 && ( - - )} - {currentTab === uiLayout?.layouts.length - 1 && ( - - )} -
- ) - ); - })} - ) :( - - setCurrentTab(index)} - > - <> - - {uiLayout?.layouts.map( - (tab, index) => - isTabVisible(index) && {tab.label} - )} - + {currentTab > 0 && ( + + )} + {currentTab < uiLayout?.layouts.length - 1 && ( + + )} + {currentTab === uiLayout?.layouts.length - 1 && ( + + )} +
+ ) + ); + })} + + ) : ( + setCurrentTab(index)} + > + <> + + {uiLayout?.layouts.map( + (tab, index) => + isTabVisible(index) && {tab.label} + )} + - {uiLayout?.layouts.map((tab, index) => { - const updatedUiSchema = React.useMemo( - () => getUpdatedUISchema(index, uiSchema, uiLayout?.layouts), - [index, uiSchema, uiLayout?.layouts] - ); - return ( - isTabVisible(index) && ( - -

{tab.label}

- {renderGroups( - updatedUiSchema?.["ui:groups"], - schema, - updatedUiSchema, - control, - errors - )} + {uiLayout?.layouts.map((tab, index) => { + const updatedUiSchema = React.useMemo( + () => getUpdatedUISchema(index, uiSchema, uiLayout?.layouts), + [index, uiSchema, uiLayout?.layouts] + ); - {currentTab > 0 && ( - - )} - {currentTab < uiLayout?.layouts.length - 1 && ( - - )} - {currentTab === uiLayout?.layouts.length - 1 && ( - - )} -
- ) - ); - })} - -
)) : ( + return ( + isTabVisible(index) && ( + +

{tab.label}

+ {renderGroups( + updatedUiSchema?.["ui:groups"], + schema, + updatedUiSchema, + control, + errors + )} + + {currentTab > 0 && ( + + )} + {currentTab < uiLayout?.layouts.length - 1 && ( + + )} + {currentTab === uiLayout?.layouts.length - 1 && ( + + )} +
+ ) + ); + })} + + + ) + ) : ( <> {renderGroups( uiSchema?.["ui:groups"],