From 58a7ce20a7ddebdbff8384380ed8a2d846df2337 Mon Sep 17 00:00:00 2001 From: Pier-Paolo Mammi Date: Mon, 27 Apr 2026 12:42:18 +0200 Subject: [PATCH] major refactor rename classes added props configuration for custom fields Co-authored-by: Copilot --- scelta-carriera/src/App.jsx | 112 +++++++++++++++--- ...le.scss => ElixFormsComponent.module.scss} | 2 +- .../src/components/ElixFormsComponent.tsx | 16 +++ ...act.tsx => ElixFormsComponentAbstract.tsx} | 104 +++++++++------- ...ixFormElement.tsx => ElixFormsElement.tsx} | 2 +- .../src/components/ElixFormsReact.tsx | 16 --- ...lixFormsComponentCustomFormFieldFactory.ts | 10 ++ .../IElixFormsComponentFormState.tsx | 4 + ...ps.ts => IElixFormsComponentProperties.ts} | 8 +- .../components/IElixFormsReactFormState.tsx | 4 - 10 files changed, 197 insertions(+), 81 deletions(-) rename scelta-carriera/src/components/{ElixFormsReact.module.scss => ElixFormsComponent.module.scss} (97%) create mode 100644 scelta-carriera/src/components/ElixFormsComponent.tsx rename scelta-carriera/src/components/{ElixFormsReactAbstract.tsx => ElixFormsComponentAbstract.tsx} (70%) rename scelta-carriera/src/components/{ElixFormElement.tsx => ElixFormsElement.tsx} (92%) delete mode 100644 scelta-carriera/src/components/ElixFormsReact.tsx create mode 100644 scelta-carriera/src/components/IElixFormsComponentCustomFormFieldFactory.ts create mode 100644 scelta-carriera/src/components/IElixFormsComponentFormState.tsx rename scelta-carriera/src/components/{IElixFormsReactProps.ts => IElixFormsComponentProperties.ts} (80%) delete mode 100644 scelta-carriera/src/components/IElixFormsReactFormState.tsx diff --git a/scelta-carriera/src/App.jsx b/scelta-carriera/src/App.jsx index 8a354fd..e3af9df 100644 --- a/scelta-carriera/src/App.jsx +++ b/scelta-carriera/src/App.jsx @@ -3,25 +3,109 @@ import reactLogo from './assets/react.svg' import viteLogo from './assets/vite.svg' import heroImg from './assets/hero.png' import './App.css' -import * as ElixForms from './components/ElixFormsReact'; +import * as ElixForms from './components/ElixFormsComponent'; function App() { const [count, setCount] = useState(0) + /** @type {import('./components/ElixFormsComponent').ElixFormsReact} */ var myElixFormsReact = new ElixForms.ElixFormsReact(); - myElixFormsReact.addTextInput("name", "Name", true); - myElixFormsReact.addTextAreaInput("description", "Description"); - myElixFormsReact.addNumberInput("age", "Age"); - myElixFormsReact.addDropdownInput("country", "Country", new Map([ - [1, "Italy"], - [2, "USA"], - [3, "UK"] - ])); - myElixFormsReact.addCheckboxInput("hobbies", "Hobbies", new Map([ - [1, "Sports"], - [2, "Music"], - [3, "Traveling"] - ])); + + myElixFormsReact.props = { + description: "This is a custom form created with ElixFormsReact component.", + isDarkTheme: false, + environmentMessage: "TESTING!", + additionalFieldsJson: JSON.stringify([ + { + "key": "COL0002", + "type": "text", + "label": "Campo STRING", + "required": false + }, + { + "key": "COL0003", + "type": "textarea", + "label": "Campo TEXTAREA", + "required": false + }, + { + "key": "COL0004", + "type": "boolean", + "label": "Campo Boolean", + "required": false + }, + { + "key": "COL0005", + "type": "radio", + "label": "Campo _RADIO_", + "required": false, + "options": [ + { "value": 1, "label": "Opzione 1" }, + { "value": 2, "label": "Opzione 2" }, + { "value": 3, "label": "Altra opzione" } + ] + }, + { + "key": "COL0006", + "type": "checkbox", + "label": "Campo CHECKBOX", + "options": [ + { "value": 4, "label": "Check 1" }, + { "value": 5, "label": "Check due" }, + { "value": 6, "label": "Altro check" } + ] + }, + { + "key": "COL0015", + "type": "dropdown", + "label": "Validazione lista", + "required": true, + "options": [ + { "value": 0, "label": "Not applicable" }, + { "value": 1, "label": "Goal 1: No poverty" }, + { "value": 2, "label": "Goal 2: Zero hunger" }, + { "value": 3, "label": "Goal 3: Good health and well-being" }, + { "value": 4, "label": "Goal 4: Quality education" }, + { "value": 5, "label": "Goal 5: Gender equality" }, + { "value": 6, "label": "Goal 6: Clean water and sanitation" }, + { "value": 7, "label": "Goal 7: Affordable and clean energy" }, + { "value": 8, "label": "Goal 8: Decent work and economic growth" }, + { "value": 9, "label": "Goal 9: Industry, Innovation, and Infrastructure" }, + { "value": 10, "label": "Goal 10: Reduced inequalities" }, + { "value": 11, "label": "Goal 11: Sustainable cities and communities" }, + { "value": 12, "label": "Goal 12: Responsible consumption and production" }, + { "value": 13, "label": "Goal 13: Climate action" }, + { "value": 14, "label": "Goal 14: Life below water" }, + { "value": 15, "label": "Goal 15: Life on land" }, + { "value": 16, "label": "Goal 16: Peace, justice and strong institutions" }, + { "value": 17, "label": "Goal 17: Partnerships for the goals" } + ] + } + ]), + customFormFieldsConfiguration: ( + /** @type {import('./components/IElixFormsComponentProperties').ICustomFormFieldFactory} */ + formFieldFactory + ) => ( + <> + {formFieldFactory.createTextInput("name", "Name", true)} + {formFieldFactory.createTextAreaInput("description", "Description")} + + ) + }; + + // myElixFormsReact.addTextInput("name", "Name", true); + // myElixFormsReact.addTextAreaInput("description", "Description"); + // myElixFormsReact.addNumberInput("age", "Age"); + // myElixFormsReact.addDropdownInput("country", "Country", new Map([ + // [1, "Italy"], + // [2, "USA"], + // [3, "UK"] + // ])); + // myElixFormsReact.addCheckboxInput("hobbies", "Hobbies", new Map([ + // [1, "Sports"], + // [2, "Music"], + // [3, "Traveling"] + // ])); return myElixFormsReact.render(); } diff --git a/scelta-carriera/src/components/ElixFormsReact.module.scss b/scelta-carriera/src/components/ElixFormsComponent.module.scss similarity index 97% rename from scelta-carriera/src/components/ElixFormsReact.module.scss rename to scelta-carriera/src/components/ElixFormsComponent.module.scss index f68de66..3caff90 100644 --- a/scelta-carriera/src/components/ElixFormsReact.module.scss +++ b/scelta-carriera/src/components/ElixFormsComponent.module.scss @@ -1,6 +1,6 @@ @import '~@fluentui/react/dist/sass/References.scss'; -.elixFormsReact { +.elixFormsComponent { overflow: hidden; padding: 1em; color: "[theme:bodyText, default: #323130]"; diff --git a/scelta-carriera/src/components/ElixFormsComponent.tsx b/scelta-carriera/src/components/ElixFormsComponent.tsx new file mode 100644 index 0000000..510271f --- /dev/null +++ b/scelta-carriera/src/components/ElixFormsComponent.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import ElixFormsComponentAbstract from './ElixFormsComponentAbstract'; + +export default class ElixFormsComponent extends ElixFormsComponentAbstract { + // public override createCustomFormFields(): React.ReactElement { + // // const textTest = this.CreateTextInput("COL0018", "TEXT INPUT"); + // // const checkTest = this.CreateCheckboxInput("COL0090", "CHECKBOX INPUT", new Map([ [1, "Option 1"], [2, "Option 2"], [3, "Option 3"] ])); + // // const radioTest = this.CreateRadioInput("COL0091", "RADIO INPUT", new Map([ [1, "Option 1"], [2, "Option 2"], [3, "Option 3"] ])); + // // const boolTest = this.CreateBooleanInput("COL0092", "BOOLEAN INPUT"); + // // const textareaTest = this.CreateTextAreaInput("COL0093", "TEXTAREA INPUT"); + + // return (<>); + // } +} + +export { ElixFormsComponent as ElixFormsReact }; \ No newline at end of file diff --git a/scelta-carriera/src/components/ElixFormsReactAbstract.tsx b/scelta-carriera/src/components/ElixFormsComponentAbstract.tsx similarity index 70% rename from scelta-carriera/src/components/ElixFormsReactAbstract.tsx rename to scelta-carriera/src/components/ElixFormsComponentAbstract.tsx index a951b6a..abb75bf 100644 --- a/scelta-carriera/src/components/ElixFormsReactAbstract.tsx +++ b/scelta-carriera/src/components/ElixFormsComponentAbstract.tsx @@ -1,13 +1,14 @@ import * as FluentUI from '@fluentui/react'; -import { IElixFormsReactFormState } from './IElixFormsReactFormState'; -import { IElixFormsReactProps } from './IElixFormsReactProps'; -import { ElixFormElement } from './ElixFormElement'; +import { IElixFormsComponentFormState } from './IElixFormsComponentFormState'; +import { IElixFormsComponentProperties } from './IElixFormsComponentProperties'; +import { ElixFormsElement } from './ElixFormsElement'; import { QueryParamHelper } from './QueryParamHelper'; import { Component, FormEvent, JSX } from 'react'; import React from 'react'; +import { IElixFormsComponentCustomFormFieldFactory } from './IElixFormsComponentCustomFormFieldFactory'; -export default abstract class ElixFormsReactAbstract extends Component { - constructor(props: IElixFormsReactProps) { +export default abstract class ElixFormsComponentAbstract extends Component { + constructor(props: IElixFormsComponentProperties) { super(props); this.state = { @@ -56,24 +57,38 @@ export default abstract class ElixFormsReactAbstract extends Component([ [1, "Option 1"], [2, "Option 2"], [3, "Option 3"] ])); - // const radioTest = this.CreateRadioInput("COL0091", "RADIO INPUT", new Map([ [1, "Option 1"], [2, "Option 2"], [3, "Option 3"] ])); - // const boolTest = this.CreateBooleanInput("COL0092", "BOOLEAN INPUT"); - // const textareaTest = this.CreateTextAreaInput("COL0093", "TEXTAREA INPUT"); + public createCustomFormFields(callback: (formFieldFactory: IElixFormsComponentCustomFormFieldFactory) => JSX.Element = () => <>): JSX.Element { + const formFieldFactory = { + createBooleanInput: (name: string, label: string, required: boolean = false) => + this.createBooleanInput(name, label, required), + createCheckboxInput: (name: string, label: string, options: Map, required: boolean = false) => + this.createCheckboxInput(name, label, options, required), + createDropdownInput: (name: string, label: string, options: Map, required: boolean = false) => + this.createDropdownInput(name, label, options, required), + createHiddenInput: (name: string) => + this.createHiddenInput(name), + createNumberInput: (name: string, label: string, required: boolean = false) => + this.createNumberInput(name, label, required), + createRadioInput: (name: string, label: string, options: Map, required: boolean = false) => + this.createRadioInput(name, label, options, required), + createTextInput: (name: string, label: string, required: boolean = false) => + this.createTextInput(name, label, required), + createTextAreaInput: (name: string, label: string, required: boolean = false) => + this.createTextAreaInput(name, label, required), + }; - return (<>); + return callback(formFieldFactory); } - public override render(): React.ReactElement { + public override render(): React.ReactElement { const { description, isDarkTheme, environmentMessage, hasTeamsContext, userDisplayName, - additionalFieldsJson + additionalFieldsJson, + customFormFieldsConfiguration } = this.props; const queryParams = new URLSearchParams(window.location.search); @@ -82,17 +97,18 @@ export default abstract class ElixFormsReactAbstract extends Component {/* className={`${styles.elixFormsReact} ${hasTeamsContext ? styles.teams : ''}`} */}
{environmentMessage}
+
{description}
{this.createMandatoryFormFields(queryParams)} {this.createAdditionalFormFields()} - {this.createCustomFormFields()} + {this.createCustomFormFields(customFormFieldsConfiguration)}
); } - private createCheckboxInput(paramName: string, label: string, values: Map, required: boolean = false) : ElixFormElement { + private createCheckboxInput(paramName: string, label: string, values: Map, required: boolean = false) : JSX.Element { const checkedValues = QueryParamHelper.getCheckedFromQuery(paramName); if (!this.checkboxValues.get(paramName)) { @@ -120,17 +136,17 @@ export default abstract class ElixFormsReactAbstract extends Component{label}, <> {checkboxes} - ); + ).render(); } - private createRadioInput(paramName: string, label: string, values: Map, required: boolean = false) : ElixFormElement { + private createRadioInput(paramName: string, label: string, values: Map, required: boolean = false) : JSX.Element { const radioValue = QueryParamHelper.getOptionFromQuery(paramName); const radios: FluentUI.IChoiceGroupOption[] = []; @@ -147,7 +163,7 @@ export default abstract class ElixFormsReactAbstract extends Component, - ); + ).render(); } - private createBooleanInput(paramName: string, label: string, required: boolean = false) : ElixFormElement { + private createBooleanInput(paramName: string, label: string, required: boolean = false) : JSX.Element { const boolValue = QueryParamHelper.getOptionFromQuery(paramName); const radios: FluentUI.IChoiceGroupOption[] = []; @@ -176,7 +192,7 @@ export default abstract class ElixFormsReactAbstract extends Component, - ); + ).render(); } - private createTextAreaInput(paramName: string, label: string, required: boolean = false) : ElixFormElement { + private createTextAreaInput(paramName: string, label: string, required: boolean = false) : JSX.Element { const textareaValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; - return new ElixFormElement( + return new ElixFormsElement( {label}, - ); + ).render(); } - private createTextInput(paramName: string, label: string, required: boolean = false) : ElixFormElement { + private createTextInput(paramName: string, label: string, required: boolean = false) : JSX.Element { const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; - return new ElixFormElement( + return new ElixFormsElement( {label}, - ); + ).render(); } private createHiddenInput(paramName: string) : JSX.Element { const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; - return ; + return <>
; } - private createNumberInput(paramName: string, label: string, required: boolean = false) : ElixFormElement { + private createNumberInput(paramName: string, label: string, required: boolean = false) : JSX.Element { const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? ""; - return new ElixFormElement( + return new ElixFormsElement( {label}, - ); + ).render(); } - private createDropdownInput(paramName: string, label: string, values: Map, required: boolean = false): ElixFormElement { + private createDropdownInput(paramName: string, label: string, values: Map, required: boolean = false): JSX.Element { const selectedValue = QueryParamHelper.getOptionFromQuery(paramName); const options = Array.from(values).map(([num, val]) => ({ key: num.toString(), text: val })); - return new ElixFormElement( + return new ElixFormsElement( {label}, - ); + ).render(); } private renderField(field: any): JSX.Element { @@ -235,25 +251,25 @@ export default abstract class ElixFormsReactAbstract extends Component(field.options.map((o: any) => [o.value, o.label])), field.required ?? false).render(); + return this.createRadioInput(field.key, field.label, new Map(field.options.map((o: any) => [o.value, o.label])), field.required ?? false); case "boolean": - return this.createBooleanInput(field.key, field.label, field.required ?? false).render(); + return this.createBooleanInput(field.key, field.label, field.required ?? false); case "checkbox": - return this.createCheckboxInput(field.key, field.label, new Map(field.options.map((o: any) => [o.value, o.label])), field.required ?? false).render(); + return this.createCheckboxInput(field.key, field.label, new Map(field.options.map((o: any) => [o.value, o.label])), field.required ?? false); case "number": - return this.createNumberInput(field.key, field.label, field.required ?? false).render(); + return this.createNumberInput(field.key, field.label, field.required ?? false); case "dropdown": - return this.createDropdownInput(field.key, field.label, new Map(field.options.map((o: any) => [o.value, o.label])), field.required ?? false).render(); + return this.createDropdownInput(field.key, field.label, new Map(field.options.map((o: any) => [o.value, o.label])), field.required ?? false); default: return <>; diff --git a/scelta-carriera/src/components/ElixFormElement.tsx b/scelta-carriera/src/components/ElixFormsElement.tsx similarity index 92% rename from scelta-carriera/src/components/ElixFormElement.tsx rename to scelta-carriera/src/components/ElixFormsElement.tsx index 48613aa..a3630eb 100644 --- a/scelta-carriera/src/components/ElixFormElement.tsx +++ b/scelta-carriera/src/components/ElixFormsElement.tsx @@ -1,7 +1,7 @@ import React, { JSX } from "react"; // Class to encapsulate the label and input elements -export class ElixFormElement { +export class ElixFormsElement { label: JSX.Element; input: JSX.Element; separator: string; diff --git a/scelta-carriera/src/components/ElixFormsReact.tsx b/scelta-carriera/src/components/ElixFormsReact.tsx deleted file mode 100644 index ba14699..0000000 --- a/scelta-carriera/src/components/ElixFormsReact.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from 'react'; -import ElixFormsReactAbstract from './ElixFormsReactAbstract'; - -export default class ElixFormsReact extends ElixFormsReactAbstract { - public override createCustomFormFields(): React.ReactElement { - // const textTest = this.CreateTextInput("COL0018", "TEXT INPUT"); - // const checkTest = this.CreateCheckboxInput("COL0090", "CHECKBOX INPUT", new Map([ [1, "Option 1"], [2, "Option 2"], [3, "Option 3"] ])); - // const radioTest = this.CreateRadioInput("COL0091", "RADIO INPUT", new Map([ [1, "Option 1"], [2, "Option 2"], [3, "Option 3"] ])); - // const boolTest = this.CreateBooleanInput("COL0092", "BOOLEAN INPUT"); - // const textareaTest = this.CreateTextAreaInput("COL0093", "TEXTAREA INPUT"); - - return (<>); - } -} - -export { ElixFormsReact }; \ No newline at end of file diff --git a/scelta-carriera/src/components/IElixFormsComponentCustomFormFieldFactory.ts b/scelta-carriera/src/components/IElixFormsComponentCustomFormFieldFactory.ts new file mode 100644 index 0000000..c250479 --- /dev/null +++ b/scelta-carriera/src/components/IElixFormsComponentCustomFormFieldFactory.ts @@ -0,0 +1,10 @@ +import { JSX } from "react"; + + +export type IElixFormsComponentCustomFormFieldFactory = { + createTextInput: (name: string, label: string, required?: boolean) => JSX.Element; + createTextAreaInput: (name: string, label: string, required?: boolean) => JSX.Element; + createNumberInput: (name: string, label: string, required?: boolean) => JSX.Element; + createDropdownInput: (name: string, label: string, options: Map, required?: boolean) => JSX.Element; + createCheckboxInput: (name: string, label: string, options: Map, required?: boolean) => JSX.Element; +}; diff --git a/scelta-carriera/src/components/IElixFormsComponentFormState.tsx b/scelta-carriera/src/components/IElixFormsComponentFormState.tsx new file mode 100644 index 0000000..7a1c88b --- /dev/null +++ b/scelta-carriera/src/components/IElixFormsComponentFormState.tsx @@ -0,0 +1,4 @@ + +export interface IElixFormsComponentFormState { + formData: { [key: string]: any; }; +} diff --git a/scelta-carriera/src/components/IElixFormsReactProps.ts b/scelta-carriera/src/components/IElixFormsComponentProperties.ts similarity index 80% rename from scelta-carriera/src/components/IElixFormsReactProps.ts rename to scelta-carriera/src/components/IElixFormsComponentProperties.ts index 65ce7a4..5c7559e 100644 --- a/scelta-carriera/src/components/IElixFormsReactProps.ts +++ b/scelta-carriera/src/components/IElixFormsComponentProperties.ts @@ -1,10 +1,16 @@ -export interface IElixFormsReactProps { +import { JSX } from "react"; +import { IElixFormsComponentCustomFormFieldFactory } from "./IElixFormsComponentCustomFormFieldFactory"; + +export type ICustomFormFieldsConfiguration = (formFieldFactory: IElixFormsComponentCustomFormFieldFactory) => JSX.Element; + +export interface IElixFormsComponentProperties { description: string; isDarkTheme: boolean; environmentMessage: string; hasTeamsContext: boolean; userDisplayName: string; additionalFieldsJson?: string; + customFormFieldsConfiguration?: ICustomFormFieldsConfiguration; } // Additional Fields JSON Schema diff --git a/scelta-carriera/src/components/IElixFormsReactFormState.tsx b/scelta-carriera/src/components/IElixFormsReactFormState.tsx deleted file mode 100644 index abcc9b2..0000000 --- a/scelta-carriera/src/components/IElixFormsReactFormState.tsx +++ /dev/null @@ -1,4 +0,0 @@ - -export interface IElixFormsReactFormState { - formData: { [key: string]: any; }; -}