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 (
-
- );
-};
-
-
-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 (
-
- );
-};
-
-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"],