Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a77f6f19cf | ||
|
|
746c43c7b4 | ||
|
|
85b51dfbc4 | ||
|
|
1aacb21b1b | ||
|
|
1c02e3d1b2 | ||
|
|
bad919a98a | ||
|
|
fefb45505c | ||
|
|
c3d4c2a660 | ||
|
|
1943252422 | ||
|
|
4cd22396d9 |
@@ -12,7 +12,7 @@ description: >
|
||||
|
||||
## Panoramica
|
||||
|
||||
La cartella `react/common/` contiene la libreria condivisa di componenti React/TypeScript usata da tutte le pagine custom. È basata su **Fluent UI React v8** e implementa un sistema di form con campi dinamici.
|
||||
La cartella `react/common/` contiene la libreria condivisa di componenti React/TypeScript usata da tutte le pagine custom. È basata su **Bootstrap Italia + HTML nativo** e implementa un sistema di form con campi dinamici.
|
||||
|
||||
## Architettura dei Componenti
|
||||
|
||||
@@ -103,7 +103,7 @@ var myElixFormsReact = new ElixForms.ElixFormsReact({
|
||||
|
||||
### Tipi di Campo Supportati
|
||||
|
||||
| Metodo Factory | Componente FluentUI | HTML Output |
|
||||
| Metodo Factory | Componente Bootstrap Italia | HTML Output |
|
||||
|---|---|---|
|
||||
| `createTextInput` | `TextField` | Text input |
|
||||
| `createTextAreaInput` | `TextField` (multiline) | Textarea |
|
||||
|
||||
@@ -50,7 +50,7 @@ npm install -D sass-embedded
|
||||
}
|
||||
```
|
||||
|
||||
> **Nota**: React, ReactDOM e FluentUI NON vanno nel package.json della pagina.
|
||||
> **Nota**: React e ReactDOM NON vanno nel package.json della pagina.
|
||||
> Sono nel `react/package.json` root e vengono risolti via hoisting di npm.
|
||||
|
||||
## Step 3: Configurare vite.config.js
|
||||
|
||||
@@ -130,7 +130,7 @@ Le pagine seguono un layout standard elixForms con classi CSS specifiche:
|
||||
| `iuTypeString` | Tipo di input stringa |
|
||||
| `iuClearContainer` | Clearfix interno |
|
||||
|
||||
### Classi Input FluentUI Custom
|
||||
### Classi Input Bootstrap Italia Custom
|
||||
| Classe | Componente |
|
||||
|---|---|
|
||||
| `isiportalPartialAdminFormFieldSingleLineText` | TextField singola riga |
|
||||
@@ -143,20 +143,13 @@ Le pagine seguono un layout standard elixForms con classi CSS specifiche:
|
||||
|
||||
`ElixFormsComponent.module.scss`:
|
||||
```scss
|
||||
@import '~@fluentui/react/dist/sass/References.scss';
|
||||
|
||||
.elixFormsComponent {
|
||||
overflow: hidden;
|
||||
padding: 1em;
|
||||
color: "[theme:bodyText, default: #323130]";
|
||||
color: var(--bodyText);
|
||||
&.teams {
|
||||
font-family: $ms-font-family-fallbacks;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Nota**: Gli stili usano il **theming di FluentUI** con variabili CSS e placeholder di tema SharePoint.
|
||||
> **Nota**: Gli stili usano classi Bootstrap Italia e CSS del design system UniPR, senza dipendenze da FluentUI.
|
||||
|
||||
## Logo e Risorse Esterne
|
||||
|
||||
|
||||
@@ -118,13 +118,13 @@ I valori verranno letti da `QueryParamHelper` e pre-popoleranno i campi del form
|
||||
|
||||
```
|
||||
react/ ← npm install qui per dipendenze condivise
|
||||
├── node_modules/ ← react, react-dom, @fluentui/react
|
||||
├── node_modules/ ← react, react-dom
|
||||
├── package.json
|
||||
└── scelta-carriera/ ← npm install qui per devDependencies
|
||||
├── node_modules/ ← vite, eslint, plugin, sass-embedded
|
||||
└── package.json
|
||||
```
|
||||
|
||||
> **Nota**: Le dipendenze runtime (React, FluentUI) sono nel `package.json` root.
|
||||
> **Nota**: Le dipendenze runtime (React, ReactDOM) sono nel `package.json` root.
|
||||
> Le dipendenze di sviluppo (Vite, ESLint) sono nel `package.json` della pagina.
|
||||
> npm risolve le dipendenze risalendo la gerarchia delle cartelle (hoisting).
|
||||
|
||||
@@ -12,7 +12,7 @@ description: >
|
||||
|
||||
## Panoramica
|
||||
|
||||
Questo progetto è un **monorepo** per la creazione di pagine web React custom destinate alla piattaforma **elixForms** dell'Università di Parma (UniPR). Ogni pagina è un micro-progetto indipendente che produce un **singolo file JS bundle** contenente React, Fluent UI, CSS e il codice custom, da pubblicare su un server remoto.
|
||||
Questo progetto è un **monorepo** per la creazione di pagine web React custom destinate alla piattaforma **elixForms** dell'Università di Parma (UniPR). Ogni pagina è un micro-progetto indipendente che produce un **singolo file JS bundle** contenente React, Bootstrap Italia e il codice custom, da pubblicare su un server remoto.
|
||||
|
||||
## Struttura del Workspace
|
||||
|
||||
@@ -21,7 +21,7 @@ elixforms-custom-pages/ ← Root del workspace (VS Code)
|
||||
├── .vscode/ ← Configurazioni VS Code (launch, tasks)
|
||||
├── docs/ ← Documentazione (PDF manuali)
|
||||
└── react/ ← Root del monorepo React
|
||||
├── package.json ← Dipendenze condivise (React, ReactDOM, FluentUI)
|
||||
├── package.json ← Dipendenze condivise (React, ReactDOM)
|
||||
├── tsconfig.base.json ← Configurazione TypeScript base condivisa
|
||||
├── .gitignore
|
||||
├── common/ ← Libreria condivisa di componenti ElixForms
|
||||
@@ -58,7 +58,7 @@ Ogni pagina (es. `scelta-carriera/`) è un progetto Vite completamente autonomo
|
||||
|
||||
1. **Importa dalla libreria `common/`** tramite alias `@common` configurato in `vite.config.js`
|
||||
2. **Ha le proprie dipendenze** nel suo `package.json` (solo devDependencies e plugin Vite)
|
||||
3. **Condivide le dipendenze runtime** (React, ReactDOM, FluentUI) dal `package.json` root di `react/`
|
||||
3. **Condivide le dipendenze runtime** (React, ReactDOM) dal `package.json` root di `react/`
|
||||
4. **Produce un singolo file JS** tramite la configurazione Rollup in `vite.config.js`
|
||||
5. **Estende il tsconfig base** per avere configurazione TypeScript coerente
|
||||
|
||||
@@ -67,7 +67,6 @@ Ogni pagina (es. `scelta-carriera/`) è un progetto Vite completamente autonomo
|
||||
Le dipendenze runtime sono hoisted al livello `react/`:
|
||||
- `react` ^19.2.7
|
||||
- `react-dom` ^19.2.5
|
||||
- `@fluentui/react` ^8.125.6
|
||||
|
||||
## Configurazione TypeScript
|
||||
|
||||
@@ -121,7 +120,7 @@ server.fs.allow: [".."] // Permette import da common/
|
||||
|
||||
Le pagine caricano CSS dal server remoto elixForms tramite `@import url(...)` in `App.css`:
|
||||
- CSS da `console-unipr.elixforms.it` per il design system dell'università
|
||||
- I componenti FluentUI usano stili inline/theme nativi
|
||||
- I componenti Bootstrap Italia usano classi HTML e CSS del design system UniPR
|
||||
- SCSS modules sono usati in `common/` per stili dei componenti condivisi
|
||||
- `sass-embedded` è installato come devDependency per supporto SCSS
|
||||
|
||||
|
||||
@@ -106,9 +106,6 @@ import { IElixFormsComponentProperties } from './IElixFormsComponentProperties';
|
||||
### Import di Moduli
|
||||
|
||||
```tsx
|
||||
// Fluent UI - import tutto il namespace
|
||||
import * as FluentUI from '@fluentui/react';
|
||||
|
||||
// React - import specifici
|
||||
import { Component, type FormEvent, type JSX, useState } from 'react';
|
||||
import React from 'react';
|
||||
@@ -167,8 +164,8 @@ declare module "*.png";
|
||||
- Usare `this.setState` con spread operator per update immutabili
|
||||
- I checkbox mantengono un `Map<string, number[]>` separato
|
||||
|
||||
5. **Fluent UI**:
|
||||
- Usare Fluent UI React v8 (`@fluentui/react`)
|
||||
- Componenti: `TextField`, `Checkbox`, `ChoiceGroup`, `Dropdown`, `Label`, `Stack`
|
||||
- Le opzioni radio usano `IChoiceGroupOption[]`
|
||||
- Le opzioni dropdown usano `IDropdownOption[]`
|
||||
5. **Bootstrap Italia**:
|
||||
- Usare markup HTML nativo con classi Bootstrap Italia e del design system UniPR
|
||||
- Per i campi testuali usare `input`, `textarea`, `select` con classi `form-control`/`form-select`
|
||||
- Per i checkbox/radio usare `input type="checkbox"`/`input type="radio"` con classi `form-check-input`
|
||||
- Il layout dei campi deve rimanere compatibile con `ElixFormsElement`
|
||||
|
||||
@@ -105,7 +105,7 @@ npm run lint
|
||||
|
||||
```
|
||||
dist/
|
||||
<nome-pagina>.js ← Bundle unico (React + FluentUI + CSS + codice)
|
||||
<nome-pagina>.js ← Bundle unico (React + CSS + codice)
|
||||
<nome-pagina>.js.map ← Source map
|
||||
*.png, *.svg ← Asset referenziati nel codice
|
||||
```
|
||||
@@ -121,10 +121,10 @@ dist/
|
||||
- **Fix**: Verificare `resolve.alias` e che la cartella `common/` esista
|
||||
|
||||
### Bundle troppo grande
|
||||
- **Causa**: FluentUI include molti componenti
|
||||
- **Causa**: l'uso di componenti UI pesanti o CSS non ottimizzati
|
||||
- **Fix possibili**:
|
||||
- Tree shaking (import specifici: `import { TextField } from '@fluentui/react'`)
|
||||
- Considerare `@fluentui/react-components` (v9) per bundle più piccoli
|
||||
- Mantenere i CSS locali limitati e affidarsi ai CSS remoti del design system
|
||||
- Evitare dipendenze UI pesanti per le pagine custom
|
||||
- Esternalizzare React se la pagina host lo fornisce già
|
||||
|
||||
### CSS non applicato in produzione
|
||||
|
||||
@@ -52,3 +52,6 @@ obj
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Configuration files
|
||||
**/config.json
|
||||
Generated
+21
-1
@@ -7,7 +7,27 @@
|
||||
"": {
|
||||
"name": "@elixforms/common",
|
||||
"version": "0.0.1",
|
||||
"license": "ISC"
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
|
||||
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,8 @@
|
||||
"license": "ISC",
|
||||
"author": "",
|
||||
"type": "commonjs",
|
||||
"main": "index.js"
|
||||
"main": "index.js",
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.17"
|
||||
}
|
||||
}
|
||||
|
||||
+10
-41
@@ -1,4 +1,12 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:wght@300;400;600;700&display=swap');
|
||||
@import url("https://fonts.googleapis.com/css2?family=Titillium+Web:wght@300;400;600;700&display=swap");
|
||||
@import url("https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css");
|
||||
@import url("https://cdn.jsdelivr.net/npm/bootstrap-italia@2.18.2/dist/css/bootstrap-italia.min.css");
|
||||
|
||||
/* elixForms styles customizations */
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/util.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/themes/blu-italia.css");
|
||||
|
||||
/* These are here for future imports...
|
||||
@import url("https://console-unipr.elixforms.it/elixFormsCustom/css/elixForms.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/bootstrap_adaptation.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/bootstrap_overrides.css");
|
||||
@@ -11,45 +19,6 @@
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/responsive.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/style-bs.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/style.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/design-bs/util.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/plugins/modaldisplay.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/css/themes/blu-italia.css");
|
||||
@import url("https://console-unipr.elixforms.it/rwe2/isipcss/css/grid_fluid.css");
|
||||
|
||||
/* Submit button styling (elixForms main submit) */
|
||||
.mainview .container .submit {
|
||||
width: auto;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mainview .container form input[type="submit"] {
|
||||
background-color: #0066cc;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 10px 20px;
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
box-shadow: none;
|
||||
transition:
|
||||
transform 120ms ease,
|
||||
opacity 120ms ease;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mainview .container form input[type="submit"]:hover {
|
||||
background-color: #0053a6;
|
||||
}
|
||||
|
||||
.mainview .container form input[type="submit"]:active {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.mainview .container form input[type="submit"] {
|
||||
width: 100%;
|
||||
padding-left: 18px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
@import '~@fluentui/react/dist/sass/References.scss';
|
||||
|
||||
.elixFormsComponent {
|
||||
overflow: hidden;
|
||||
padding: 1em;
|
||||
color: "[theme:bodyText, default: #323130]";
|
||||
color: var(--bodyText);
|
||||
&.teams {
|
||||
font-family: $ms-font-family-fallbacks;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome {
|
||||
text-align: center;
|
||||
.autocompleteDropdown {
|
||||
margin-top: 0.5rem;
|
||||
border: 1px solid #c9d1d9;
|
||||
border-radius: 0.5rem;
|
||||
background: #fff;
|
||||
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.welcomeImage {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
.autocompleteItem {
|
||||
padding: 0.75rem 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.links {
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: "[theme:link, default:#03787c]";
|
||||
color: var(--link); // note: CSS Custom Properties support is limited to modern browsers only
|
||||
.autocompleteItem:hover,
|
||||
.autocompleteItem.isHighlighted {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: "[theme:linkHovered, default: #014446]";
|
||||
color: var(--linkHovered); // note: CSS Custom Properties support is limited to modern browsers only
|
||||
}
|
||||
}
|
||||
.autocompleteStatus {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.95rem;
|
||||
color: #5c6f82;
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import './App.css'
|
||||
import * as FluentUI from '@fluentui/react';
|
||||
import './App.css';
|
||||
|
||||
import type { IElixFormsComponentFormState } from './IElixFormsComponentFormState';
|
||||
import type { IElixFormsComponentProperties } from './IElixFormsComponentProperties';
|
||||
import { ElixFormsElement } from './ElixFormsElement';
|
||||
import { QueryParamHelper } from './QueryParamHelper';
|
||||
import { Component, type FormEvent, type JSX, useState } from 'react';
|
||||
import React from 'react';
|
||||
import type { IElixFormsComponentCustomFormFieldFactory } from './IElixFormsComponentCustomFormFieldFactory';
|
||||
import type { ElixFormsCheckboxOption, ElixFormsDropdownOption, ElixFormsRadioOption } from './ElixFormsTypes';
|
||||
import { ElixFormsElement } from './ElixFormsElement';
|
||||
import { QueryParamHelper } from './QueryParamHelper';
|
||||
import { Component, type JSX } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export default abstract class ElixFormsComponentAbstract extends Component<IElixFormsComponentProperties, IElixFormsComponentFormState> {
|
||||
constructor(props: IElixFormsComponentProperties) {
|
||||
@@ -16,57 +16,26 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
this.state = {
|
||||
formData: {}
|
||||
};
|
||||
|
||||
// const [formData, setFormData] = useState({});
|
||||
// const handleAnyInputChange = (name: string) => (event: any, valueOrOption: any) => { //ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement> | SyntheticEvent<HTMLElement, Event>
|
||||
// let value: any = null;
|
||||
// // Fluent UI Dropdown passes (event, option)
|
||||
// if (valueOrOption && valueOrOption.key !== undefined) {
|
||||
// value = valueOrOption.key;
|
||||
// }
|
||||
// // Fluent UI TextField passes (event, newValue)
|
||||
// else if (typeof valueOrOption === "string") {
|
||||
// value = valueOrOption;
|
||||
// }
|
||||
// // Fluent UI Checkbox passes (event, checked)
|
||||
// else if (typeof valueOrOption === "boolean") {
|
||||
// value = valueOrOption;
|
||||
// }
|
||||
// // Native HTML inputs
|
||||
// else if (event?.target) {
|
||||
// value = event.target.type === "checkbox"
|
||||
// ? event.target.checked
|
||||
// : event.target.value;
|
||||
// }
|
||||
// setFormData(prev => ({
|
||||
// ...prev,
|
||||
// [name]: value
|
||||
// }));
|
||||
// console.log(`Input ${name} changed to ${value}. Current form data:`, JSON.stringify(formData));
|
||||
// };
|
||||
}
|
||||
|
||||
private checkboxValues = new Map<string, number[]>();
|
||||
|
||||
private mandatoryFormFieldNames: string[] = [
|
||||
"RWE2_MODULE_ID",
|
||||
"RWE2_REQUEST_ID",
|
||||
"custom-workflow-back-url",
|
||||
"custom-workflow-generic-id",
|
||||
"custom-workflow-current-tabrel-genid",
|
||||
"custom-workflow-source-field",
|
||||
"crc",
|
||||
"MODULE_TESTMODE_KEY",
|
||||
"ELANG"
|
||||
'RWE2_MODULE_ID',
|
||||
'RWE2_REQUEST_ID',
|
||||
'custom-workflow-back-url',
|
||||
'custom-workflow-generic-id',
|
||||
'custom-workflow-current-tabrel-genid',
|
||||
'custom-workflow-source-field',
|
||||
'crc',
|
||||
'MODULE_TESTMODE_KEY',
|
||||
'ELANG'
|
||||
];
|
||||
|
||||
private createMandatoryFormFields(queryParams: URLSearchParams): JSX.Element {
|
||||
const hiddenInputs: JSX.Element[] = [];
|
||||
|
||||
// Create a hidden input for each mandatory Elix parameter
|
||||
this.mandatoryFormFieldNames.forEach(paramName => {
|
||||
const value = queryParams.get(paramName) ?? "";
|
||||
// Create the input element
|
||||
hiddenInputs.push(this.createHiddenInput(paramName));
|
||||
});
|
||||
|
||||
@@ -74,7 +43,7 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
}
|
||||
|
||||
private createAdditionalFormFields(): React.ReactElement {
|
||||
const schema = JSON.parse(this.props.additionalFieldsJson || "[]");
|
||||
const schema = JSON.parse(this.props.additionalFieldsJson || '[]');
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -124,17 +93,18 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
|
||||
public override render(): React.ReactElement<IElixFormsComponentProperties> {
|
||||
const {
|
||||
description,
|
||||
isDarkTheme,
|
||||
environmentMessage,
|
||||
hasTeamsContext,
|
||||
userDisplayName,
|
||||
additionalFieldsJson,
|
||||
moduleName,
|
||||
headerTitle,
|
||||
pageTitle,
|
||||
pageDescription,
|
||||
submitDescription,
|
||||
heroImageSrc
|
||||
headerHeroImageSrc: headerTitleImageSrc,
|
||||
cardTitle,
|
||||
cardDescription,
|
||||
alertInfoTitle,
|
||||
alertInfoMessage,
|
||||
instructionsTitle,
|
||||
instructionsMessage,
|
||||
submitText,
|
||||
} = this.props;
|
||||
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
@@ -142,66 +112,138 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
const hasAuthenticationError = missingMandatoryParams.length > 0;
|
||||
|
||||
return (
|
||||
<div className="container_12" id="pageBody">
|
||||
<div className="grid_12">
|
||||
<div id="userConsole" className="fe-behaviour">
|
||||
<header>
|
||||
<div className="neutral">
|
||||
<div className="grid_12">
|
||||
<div className="console_header">
|
||||
<div className="leftDiv">
|
||||
<h1>elixForms</h1>
|
||||
<div className="logo"><a href="https://www.unipr.it/" title="Torna alla homepage dell'Università: di Parma"><img src="https://console-unipr.elixforms.it/elixFormsCustom/images/logo.png" alt="Logo Università: di Parma" /></a>
|
||||
<div>
|
||||
<header className="it-header-wrapper text-white">
|
||||
{userDisplayName &&
|
||||
<div className="it-header-slim-wrapper">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="it-header-slim-wrapper-content">
|
||||
{/* <a className="d-none d-lg-block navbar-brand" href="#">Ente appartenenza</a> */}
|
||||
<div className="nav-mobile">
|
||||
{/* <nav aria-label="Navigazione accessoria">
|
||||
<a className="it-opener d-lg-none" data-bs-toggle="collapse" href="#menu1a" role="button"
|
||||
aria-expanded="false" aria-controls="menu4">
|
||||
<span>Ente appartenenza</span>
|
||||
<svg className="icon" aria-hidden="true">
|
||||
<use href="/bootstrap-italia/dist/svg/sprites.svg#it-expand"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<div className="link-list-wrapper collapse" id="menu1a">
|
||||
<ul className="link-list">
|
||||
<li><a className="dropdown-item list-item" href="#">Link 1</a></li>
|
||||
<li><a className="list-item active" href="#" aria-current="page">Link 2 (Attivo)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav> */}
|
||||
</div>
|
||||
<div className="it-header-slim-right-zone">
|
||||
{/* <div className="nav-item dropdown">
|
||||
<a className="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<span className="visually-hidden">Selezione lingua: lingua selezionata</span>
|
||||
<span>ITA</span>
|
||||
<svg className="icon d-none d-lg-block">
|
||||
<use href="/bootstrap-italia/dist/svg/sprites.svg#it-expand"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<div className="dropdown-menu">
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="link-list-wrapper">
|
||||
<ul className="link-list">
|
||||
<li><a className="dropdown-item list-item" href="#"><span>ITA <span
|
||||
className="visually-hidden">selezionata</span></span></a></li>
|
||||
<li><a className="dropdown-item list-item" href="#"><span>ENG</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rightDiv">
|
||||
<div className="rightDivInside info padding_r">
|
||||
<div className="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="clear"></div>
|
||||
</div> */}
|
||||
<div className="it-access-top-wrapper">
|
||||
{userDisplayName}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<div className="it-header-center-wrapper">
|
||||
<div className="container">
|
||||
<div className="it-header-center-content-wrapper">
|
||||
<div className="it-brand-wrapper">
|
||||
<a href="https://www.unipr.it/" title="Torna alla homepage dell'Università di Parma">
|
||||
<img className='icon' src="https://procedure.unipr.it/UploadImgs/12_marchio_UNIPR_neg_b1_squareLogo.png" alt="Università di Parma" />
|
||||
<div className="it-brand-text">
|
||||
<p className="h2 no_toc">Università di Parma</p>
|
||||
{/* <p className="h3 no_toc d-none d-md-block">Procedure Online</p> */}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="it-right-zone">
|
||||
{/* <div className="it-search-wrapper">
|
||||
<span className="d-none d-md-block">Cerca</span>
|
||||
<button className="search-link" aria-label="Cerca">
|
||||
<span className="it-search"></span>
|
||||
</button>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="clear"></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="grid_12 console_main">
|
||||
<div className="inside">
|
||||
{headerTitle && (
|
||||
<div>
|
||||
<div className="fe-module-header-container">
|
||||
<h2>{headerTitle}</h2>
|
||||
<div className="container my-2 mx-4">
|
||||
<div className='cmp-breadcrumb' role='navigation'>
|
||||
<nav className="breadcrumb-container" aria-label="breadcrumb">
|
||||
<ol className="breadcrumb">
|
||||
<li className='breadcrumb-item'>Procedure Online<span className="separator">></span></li>
|
||||
<li className="breadcrumb-item active" aria-current="page">{moduleName}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="mainview">
|
||||
<div className="container">
|
||||
{pageTitle && <h1>{pageTitle}</h1>}
|
||||
{heroImageSrc && <img src={heroImageSrc} alt="Hero Image" className="hero-image" />}
|
||||
{pageDescription && <p>{pageDescription}</p>}
|
||||
|
||||
{environmentMessage && <div>{environmentMessage}</div>}
|
||||
{description && <div>{description}</div>}
|
||||
{headerTitleImageSrc && <img src={headerTitleImageSrc} alt="Hero Image" className="hero-image img-fluid mb-3" />}
|
||||
{headerTitle && (<p className='h2'>{headerTitle}</p>)}
|
||||
|
||||
<div className="container">
|
||||
<div className="card shadow-sm mb-4">
|
||||
<div className="card-body">
|
||||
{cardTitle && <p className="h3 mb-3">{cardTitle}</p>}
|
||||
{cardDescription && <p className="lead text-secondary">{cardDescription}</p>}
|
||||
|
||||
{(alertInfoTitle || alertInfoMessage) &&
|
||||
<div className="custom-alert custom-alert-warning" role="status">
|
||||
{alertInfoTitle && <div><b>{alertInfoTitle}</b></div>}
|
||||
{alertInfoMessage && <div className='small'>{alertInfoMessage}</div>}
|
||||
</div>}
|
||||
|
||||
{hasAuthenticationError ? (
|
||||
<FluentUI.MessageBar messageBarType={FluentUI.MessageBarType.error} isMultiline={false}>
|
||||
Accesso non autorizzato. Parametri obbligatori mancanti ({missingMandatoryParams.join(', ')}).
|
||||
</FluentUI.MessageBar>
|
||||
<div className="alert alert-danger" role="alert">Accesso non autorizzato!</div>
|
||||
) : (
|
||||
<>
|
||||
{this.renderExtraContentPre()}
|
||||
|
||||
<form action="https://procedure.unipr.it/rwe2/ComeBackToElixAndSave" method="post" acceptCharset="ISO-8859-1">
|
||||
{(instructionsTitle || instructionsMessage) &&
|
||||
<div className="custom-alert custom-alert-info" role="status">
|
||||
{instructionsTitle && <div><b>{instructionsTitle}</b></div>}
|
||||
{instructionsMessage && <div className='small'>{instructionsMessage}</div>}
|
||||
</div>
|
||||
}
|
||||
<form action="https://procedure.unipr.it/rwe2/ComeBackToElixAndSave" method="post" acceptCharset="ISO-8859-1" className="mt-3">
|
||||
{this.createMandatoryFormFields(queryParams)}
|
||||
{this.createAdditionalFormFields()}
|
||||
{this.renderCustomFormFields()}
|
||||
<br />
|
||||
<div className='submit'>
|
||||
<input type="submit" value={submitDescription ?? 'Submit'} />
|
||||
<div className="mt-4 d-flex justify-content-end">
|
||||
<button type="submit" className="btn btn-primary">{submitText ?? 'INVIA'} <span className="it-arrow-right text-white ms-2"></span></button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{this.renderExtraContentPost()}
|
||||
</>
|
||||
)}
|
||||
@@ -210,26 +252,23 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="clear"></div>
|
||||
|
||||
<footer className="it-footer">
|
||||
<div className="it-footer-main">
|
||||
<footer className="it-footer text-white">
|
||||
<div className="it-footer-small-prints clearfix">
|
||||
<div className="container">
|
||||
<section>
|
||||
<div className="row clearfix">
|
||||
<div className="col-sm-12">
|
||||
<div className="footer-content">
|
||||
<div className="footer-content text-center p-2">
|
||||
<div className="subfooter-top">powered by <span className="highlight">elixForms</span></div>
|
||||
<div className="subfooter-bottom"><div>versione 1.24.0</div></div>
|
||||
{/* <div className="subfooter-bottom"><div>versione 1.24.0</div></div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div className="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -240,158 +279,180 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
this.checkboxValues.set(paramName, checkedValues);
|
||||
}
|
||||
|
||||
const checkboxes: React.ReactElement[] = [];
|
||||
const stackTokens = { childrenGap: 10 };
|
||||
|
||||
values.forEach((entry, entryIndex) => {
|
||||
const id = `${paramName}_${entryIndex}`;
|
||||
checkboxes.push(
|
||||
<FluentUI.Checkbox title={label} key={id} id={id} label={entry.label} required={entry.required ?? false} defaultChecked={checkedValues.indexOf(entryIndex) !== -1} className='isiportalPartialAdminCheckboxFieldItem'
|
||||
onChange={(event, checked) => {
|
||||
const currentCheckboxValues = this.checkboxValues.get(paramName)!;
|
||||
const checkboxIndex = currentCheckboxValues.indexOf(entryIndex);
|
||||
if (checked && checkboxIndex === -1) {
|
||||
currentCheckboxValues.push(entryIndex);
|
||||
} else if (!checked && checkboxIndex !== -1) {
|
||||
currentCheckboxValues.splice(checkboxIndex, 1);
|
||||
}
|
||||
const newValue = currentCheckboxValues.join(',').trim();
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: newValue } }, () => {
|
||||
console.log(`Checkbox ${id} changed to ${checked}. Current values for ${paramName}: ${this.state.formData[paramName]}`);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? this.state.formData[paramName]
|
||||
: (this.checkboxValues.get(paramName)?.join(',').trim() ?? '');
|
||||
|
||||
const selectedValues = (currentValue || '').split(',').filter(Boolean).map((value: string) => Number(value));
|
||||
|
||||
return new ElixFormsElement(
|
||||
<><FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label></>,
|
||||
<><FluentUI.Stack tokens={stackTokens}>
|
||||
{checkboxes}
|
||||
</FluentUI.Stack>
|
||||
<input type='hidden' id={paramName} name={paramName} value={currentValue} />
|
||||
<label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
|
||||
<>
|
||||
<div className="d-flex flex-column gap-2" role="group" aria-label={label}>
|
||||
{values.map((entry, entryIndex) => {
|
||||
const id = `${paramName}_${entryIndex}`;
|
||||
const isChecked = selectedValues.includes(entryIndex);
|
||||
|
||||
return (
|
||||
<div className="form-check" key={id}>
|
||||
<input
|
||||
id={id}
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={isChecked}
|
||||
onChange={(event) => {
|
||||
const currentCheckboxValues = this.checkboxValues.get(paramName) ?? [];
|
||||
const checkboxIndex = currentCheckboxValues.indexOf(entryIndex);
|
||||
const nextValues = [...currentCheckboxValues];
|
||||
|
||||
if (event.target.checked && checkboxIndex === -1) {
|
||||
nextValues.push(entryIndex);
|
||||
} else if (!event.target.checked && checkboxIndex !== -1) {
|
||||
nextValues.splice(checkboxIndex, 1);
|
||||
}
|
||||
|
||||
this.checkboxValues.set(paramName, nextValues);
|
||||
const newValue = nextValues.join(',').trim();
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: newValue } });
|
||||
}}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor={id}>{entry.label}</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<input type="hidden" id={paramName} name={paramName} value={currentValue} />
|
||||
</>
|
||||
).render();
|
||||
}
|
||||
|
||||
private createRadioInput(paramName: string, label: string, values: Array<ElixFormsRadioOption>, required: boolean = false): JSX.Element {
|
||||
const radioValue = QueryParamHelper.getOptionFromQuery(paramName);
|
||||
const radios: FluentUI.IChoiceGroupOption[] = [];
|
||||
|
||||
values.forEach((entry, _) => {
|
||||
const id = `${paramName}_${entry.value}`;
|
||||
radios.push(
|
||||
{
|
||||
key: id,
|
||||
text: entry.label,
|
||||
id: id,
|
||||
name: paramName,
|
||||
value: entry.value,
|
||||
className: 'isiportalPartialAdminFormFieldRadio'
|
||||
}
|
||||
);
|
||||
});
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? String(this.state.formData[paramName])
|
||||
: String(QueryParamHelper.getOptionFromQuery(paramName) ?? '');
|
||||
|
||||
return new ElixFormsElement(
|
||||
<></>,
|
||||
<FluentUI.ChoiceGroup
|
||||
<span className="form-label fw-semibold">{label}</span>,
|
||||
<div className="d-flex flex-column gap-2" role="radiogroup" aria-label={label}>
|
||||
{values.map((entry) => {
|
||||
const id = `${paramName}_${entry.value}`;
|
||||
return (
|
||||
<div className="form-check" key={id}>
|
||||
<input
|
||||
id={id}
|
||||
className="form-check-input"
|
||||
type="radio"
|
||||
name={paramName}
|
||||
label={label}
|
||||
options={radios}
|
||||
required={required}
|
||||
defaultSelectedKey={`${paramName}_${radioValue}`}
|
||||
onChange={(event, option) => {
|
||||
const value = option?.value ?? '';
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
|
||||
console.log(`Radio ${option?.id} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
|
||||
);
|
||||
value={entry.value}
|
||||
checked={currentValue === String(entry.value)}
|
||||
onChange={() => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: String(entry.value) } });
|
||||
}}
|
||||
required={required}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor={id}>{entry.label}</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
).render();
|
||||
}
|
||||
|
||||
private createBooleanInput(paramName: string, label: string, required: boolean = false): JSX.Element {
|
||||
const boolValue = QueryParamHelper.getOptionFromQuery(paramName);
|
||||
const radios: FluentUI.IChoiceGroupOption[] = [];
|
||||
|
||||
[{ "value": "true", "label": "Sì" }, { "value": "false", "label": "No" }].forEach((val) => {
|
||||
const id = `${paramName}_${val.value}`;
|
||||
radios.push(
|
||||
{
|
||||
key: id,
|
||||
text: val.label,
|
||||
id: id,
|
||||
name: paramName,
|
||||
value: val.value,
|
||||
className: 'isiportalPartialAdminFormFieldRadio'
|
||||
}
|
||||
);
|
||||
});
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? String(this.state.formData[paramName])
|
||||
: String(QueryParamHelper.getOptionFromQuery(paramName) ?? '');
|
||||
|
||||
return new ElixFormsElement(
|
||||
<></>,
|
||||
<FluentUI.ChoiceGroup
|
||||
<span className="form-label fw-semibold">{label}</span>,
|
||||
<div className="d-flex flex-column gap-2" role="radiogroup" aria-label={label}>
|
||||
{[{ value: 'true', label: 'Sì' }, { value: 'false', label: 'No' }].map((val) => {
|
||||
const id = `${paramName}_${val.value}`;
|
||||
return (
|
||||
<div className="form-check" key={id}>
|
||||
<input
|
||||
id={id}
|
||||
className="form-check-input"
|
||||
type="radio"
|
||||
name={paramName}
|
||||
label={label}
|
||||
options={radios}
|
||||
required={required}
|
||||
defaultSelectedKey={`${paramName}_${boolValue}`}
|
||||
onChange={(event, option) => {
|
||||
const value = option?.value ?? '';
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
|
||||
console.log(`Boolean ${option?.id} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
|
||||
);
|
||||
value={val.value}
|
||||
checked={currentValue === val.value}
|
||||
onChange={() => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: val.value } });
|
||||
}}
|
||||
required={required}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor={id}>{val.label}</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
).render();
|
||||
}
|
||||
|
||||
private createTextAreaInput(paramName: string, label: string, required: boolean = false): JSX.Element {
|
||||
const textareaValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? String(this.state.formData[paramName])
|
||||
: (QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '');
|
||||
|
||||
return new ElixFormsElement(
|
||||
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
|
||||
<FluentUI.TextField id={paramName} name={paramName} defaultValue={textareaValue} multiline rows={4} required={required} className='isiportalPartialAdminFormFieldMultiLineText'
|
||||
onChange={(event, value) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
|
||||
console.log(`TextArea ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
|
||||
);
|
||||
<label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
|
||||
<textarea
|
||||
id={paramName}
|
||||
name={paramName}
|
||||
className="form-control"
|
||||
rows={4}
|
||||
required={required}
|
||||
value={currentValue}
|
||||
onChange={(event) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
|
||||
}}
|
||||
/>
|
||||
).render();
|
||||
}
|
||||
|
||||
private createTextInput(paramName: string, label: string, required: boolean = false): JSX.Element {
|
||||
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? String(this.state.formData[paramName])
|
||||
: (QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '');
|
||||
|
||||
return new ElixFormsElement(
|
||||
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
|
||||
<FluentUI.TextField id={paramName} name={paramName} defaultValue={textValue} required={required} className='isiportalPartialAdminFormFieldSingleLineText'
|
||||
onChange={(event, value) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
|
||||
console.log(`TextInput ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
|
||||
);
|
||||
<label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
|
||||
<input
|
||||
id={paramName}
|
||||
name={paramName}
|
||||
className="form-control"
|
||||
type="text"
|
||||
required={required}
|
||||
value={currentValue}
|
||||
onChange={(event) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
|
||||
}}
|
||||
/>
|
||||
).render();
|
||||
}
|
||||
|
||||
private createHiddenInput(paramName: string): JSX.Element {
|
||||
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
|
||||
return <input type="hidden" id={`${paramName}_hidden`} name={paramName} defaultValue={textValue} />;
|
||||
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '';
|
||||
return <input type="hidden" id={`${paramName}_hidden`} name={paramName} value={textValue} />;
|
||||
}
|
||||
|
||||
private createNumberInput(paramName: string, label: string, required: boolean = false): JSX.Element {
|
||||
const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? "";
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? String(this.state.formData[paramName])
|
||||
: (QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '');
|
||||
|
||||
return new ElixFormsElement(
|
||||
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
|
||||
<FluentUI.TextField id={paramName} name={paramName} defaultValue={textValue} type="number" required={required} className='isiportalPartialAdminFormFieldSingleLineText'
|
||||
onChange={(event, value) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
|
||||
console.log(`NumberInput ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
|
||||
);
|
||||
<label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
|
||||
<input
|
||||
id={paramName}
|
||||
name={paramName}
|
||||
className="form-control"
|
||||
type="number"
|
||||
required={required}
|
||||
value={currentValue}
|
||||
onChange={(event) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
|
||||
}}
|
||||
/>
|
||||
).render();
|
||||
@@ -400,72 +461,55 @@ export default abstract class ElixFormsComponentAbstract extends Component<IElix
|
||||
private createDropdownInput(paramName: string, label: string, values: Array<ElixFormsDropdownOption>, required: boolean = false): JSX.Element {
|
||||
const queryValue = QueryParamHelper.getOptionFromQuery(paramName);
|
||||
const currentValue = this.state.formData[paramName] !== undefined
|
||||
? this.state.formData[paramName]
|
||||
? String(this.state.formData[paramName])
|
||||
: (queryValue?.toString() ?? '');
|
||||
|
||||
const options: FluentUI.IDropdownOption[] = [];
|
||||
|
||||
values.forEach(entry => {
|
||||
options.push(
|
||||
{
|
||||
key: entry.value.toString(),
|
||||
text: entry.label
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return new ElixFormsElement(
|
||||
<FluentUI.Label htmlFor={paramName}>{label}</FluentUI.Label>,
|
||||
<>
|
||||
<FluentUI.Dropdown
|
||||
<label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
|
||||
<select
|
||||
id={paramName}
|
||||
options={options}
|
||||
selectedKey={currentValue}
|
||||
placeholder='---'
|
||||
name={paramName}
|
||||
className="form-select"
|
||||
required={required}
|
||||
className='isiportalPartialAdminFormFieldSelect'
|
||||
onChange={(event, option) => {
|
||||
if (option) {
|
||||
const value = option.key.toString();
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: value } }, () =>
|
||||
console.log(`Dropdown ${paramName} changed to ${value}. Current value for ${paramName}: ${this.state.formData[paramName]}`)
|
||||
);
|
||||
}
|
||||
value={currentValue}
|
||||
onChange={(event) => {
|
||||
this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
|
||||
}}
|
||||
/>
|
||||
<input type="hidden" name={paramName} id={paramName + '_hidden'} value={currentValue} />
|
||||
</>
|
||||
>
|
||||
<option value="">Seleziona...</option>
|
||||
{values.map(entry => (
|
||||
<option key={entry.value} value={entry.value}>{entry.label}</option>
|
||||
))}
|
||||
</select>
|
||||
).render();
|
||||
}
|
||||
|
||||
private renderField(field: any): JSX.Element {
|
||||
//const value = this.state.formData[field.key] || "";
|
||||
|
||||
switch (field.type) {
|
||||
case "text":
|
||||
case 'text':
|
||||
return this.createTextInput(field.key, field.label, field.required ?? false);
|
||||
|
||||
case "textarea":
|
||||
case 'textarea':
|
||||
return this.createTextAreaInput(field.key, field.label, field.required ?? false);
|
||||
|
||||
case "radio":
|
||||
case 'radio':
|
||||
return this.createRadioInput(field.key, field.label,
|
||||
new Array<ElixFormsRadioOption>().concat(...field.options.map((o: any) => [[o.value, o.label]])),
|
||||
field.options.map((o: any) => ({ value: o.value, label: o.label })),
|
||||
field.required ?? false);
|
||||
|
||||
case "boolean":
|
||||
case 'boolean':
|
||||
return this.createBooleanInput(field.key, field.label, field.required ?? false);
|
||||
|
||||
case "checkbox":
|
||||
case 'checkbox':
|
||||
return this.createCheckboxInput(field.key, field.label,
|
||||
new Array<ElixFormsCheckboxOption>().concat(...field.options.map((o: any) => [[o.value, o.label, o.required ?? false]])));
|
||||
field.options.map((o: any) => ({ value: o.value, label: o.label, required: o.required ?? false })));
|
||||
|
||||
case "number":
|
||||
case 'number':
|
||||
return this.createNumberInput(field.key, field.label, field.required ?? false);
|
||||
|
||||
case "dropdown":
|
||||
case 'dropdown':
|
||||
return this.createDropdownInput(field.key, field.label,
|
||||
new Array<ElixFormsDropdownOption>().concat(...field.options.map((o: any) => [[o.value, o.label]])),
|
||||
field.options.map((o: any) => ({ value: o.value, label: o.label })),
|
||||
field.required ?? false);
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import React, { type JSX } from "react";
|
||||
import React, { type JSX } from 'react';
|
||||
|
||||
// Class to encapsulate the label and input elements
|
||||
export class ElixFormsElement {
|
||||
label: JSX.Element;
|
||||
input: JSX.Element;
|
||||
separator: string;
|
||||
constructor(labelElement: React.ReactElement, inputElement: React.ReactElement, separator: string = "")
|
||||
{
|
||||
|
||||
constructor(labelElement: React.ReactElement, inputElement: React.ReactElement, separator: string = '') {
|
||||
if (!labelElement || !inputElement) {
|
||||
throw new Error("labelElement and inputElement are required.");
|
||||
throw new Error('labelElement and inputElement are required.');
|
||||
}
|
||||
|
||||
this.label = labelElement;
|
||||
@@ -16,15 +15,18 @@ export class ElixFormsElement {
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
// Optional: render both elements together
|
||||
render() : JSX.Element {
|
||||
return (<><div className="iuFieldContainer">
|
||||
<div className="attrDisplay_left attrDisplay_label"><div className="iuLabelContainer"><div className="attrDisplay_center"><div className="attrDisplay_middle">
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div className="row mb-3 align-items-start">
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="text-md-end pe-md-3 mt-2">
|
||||
{this.label}{this.separator}
|
||||
</div></div><div className="iuClearContainer"> </div></div></div>
|
||||
<div className="attrDisplay_right attrDisplay_input"><div className="iuInputContainer iuTypeString"><div className="attrDisplay_center"><div className="attrDisplay_middle">
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-8">
|
||||
{this.input}
|
||||
</div></div><div className="iuClearContainer"> </div></div></div>
|
||||
</div></>);
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
export interface IElixFormsComponentProperties {
|
||||
description: string;
|
||||
isDarkTheme: boolean;
|
||||
environmentMessage: string;
|
||||
hasTeamsContext: boolean;
|
||||
userDisplayName: string;
|
||||
isDarkTheme?: boolean;
|
||||
userDisplayName?: string;
|
||||
additionalFieldsJson?: string;
|
||||
|
||||
// Layout Properties
|
||||
moduleName: string;
|
||||
headerTitle?: string;
|
||||
pageTitle?: string;
|
||||
pageDescription?: string;
|
||||
submitDescription?: string;
|
||||
heroImageSrc?: string;
|
||||
headerHeroImageSrc?: string;
|
||||
cardTitle: string;
|
||||
cardDescription?: string;
|
||||
alertInfoTitle?: string;
|
||||
alertInfoMessage?: string;
|
||||
instructionsTitle?: string;
|
||||
instructionsMessage?: string;
|
||||
submitText?: string;
|
||||
}
|
||||
|
||||
// Additional Fields JSON Schema
|
||||
|
||||
Generated
+325
-244
@@ -5,265 +5,279 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@fluentui/react": "^8.125.6",
|
||||
"bootstrap-italia": "^2.18.2",
|
||||
"react": "^19.2.7",
|
||||
"react-dom": "^19.2.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/date-time-utilities": {
|
||||
"version": "8.6.11",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-8.6.11.tgz",
|
||||
"integrity": "sha512-zq49tveFzmzwgaJ73rVvxu9+rqhPBIAJSbevciIQnmvv6dlh2GzZcL14Zevk9QV+q6CWaF6yzvhT11E2TpAv8Q==",
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
|
||||
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/dom-utilities": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/dom-utilities/-/dom-utilities-2.3.10.tgz",
|
||||
"integrity": "sha512-6WDImiLqTOpkEtfUKSStcTDpzmJfL6ZammomcjawN9xH/8u8G3Hx72CIt2MNck9giw/oUlNLJFdWRAjeP3rmPQ==",
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/font-icons-mdl2": {
|
||||
"version": "8.5.74",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.74.tgz",
|
||||
"integrity": "sha512-q3QiQ2CuFdMjtiP9U5+Qi8LMhxKqWEi7C8R+O6SuaGbGS+3YOO/1iuenhKtt961OHn5ev/0M4j4okUZ1112GSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/style-utilities": "^8.15.2",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/foundation-legacy": {
|
||||
"version": "8.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/foundation-legacy/-/foundation-legacy-8.6.7.tgz",
|
||||
"integrity": "sha512-mu1wHlkom+XT+mlaGe7GW4eIZeIT9OjgdXg2Az/P670N7JA1OKcjHd8F/9ktMb5FGrXJ287AjQDNCDfWnjnCYA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/merge-styles": "^8.6.14",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/style-utilities": "^8.15.2",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/keyboard-key": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/keyboard-key/-/keyboard-key-0.4.23.tgz",
|
||||
"integrity": "sha512-9GXeyUqNJUdg5JiQUZeGPiKnRzMRi9YEUn1l9zq6X/imYdMhxHrxpVZS12129cBfgvPyxt9ceJpywSfmLWqlKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/merge-styles": {
|
||||
"version": "8.6.14",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/merge-styles/-/merge-styles-8.6.14.tgz",
|
||||
"integrity": "sha512-vghuHFAfQgS9WLIIs4kgDOCh/DHd5vGIddP4/bzposhlAVLZR6wUBqldm9AuCdY88r5LyCRMavVJLV+Up3xdvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/react": {
|
||||
"version": "8.125.7",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react/-/react-8.125.7.tgz",
|
||||
"integrity": "sha512-MsputVjgAZEcSzfr6nXBghfZnqu+GKT4NCBwLeSL8yyQEugUxyZJNp4TVZblGdMognyRDbobNn+/zIhEK4sxNQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/date-time-utilities": "^8.6.11",
|
||||
"@fluentui/font-icons-mdl2": "^8.5.74",
|
||||
"@fluentui/foundation-legacy": "^8.6.7",
|
||||
"@fluentui/merge-styles": "^8.6.14",
|
||||
"@fluentui/react-focus": "^8.10.7",
|
||||
"@fluentui/react-hooks": "^8.10.2",
|
||||
"@fluentui/react-portal-compat-context": "^9.0.15",
|
||||
"@fluentui/react-window-provider": "^2.3.2",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/style-utilities": "^8.15.2",
|
||||
"@fluentui/theme": "^2.7.2",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"@microsoft/load-themed-styles": "^1.10.26",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"@types/react-dom": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0",
|
||||
"react-dom": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/react-focus": {
|
||||
"version": "8.10.7",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-8.10.7.tgz",
|
||||
"integrity": "sha512-Uf0wliddeVPEYylNvbBqYu2V2ofCQ/YhC5JHIFT4RwBkZil1Ta3X+9EFhJMO1LejyLXTKnMMimPxdPS1XzLTGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/keyboard-key": "^0.4.23",
|
||||
"@fluentui/merge-styles": "^8.6.14",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/style-utilities": "^8.15.2",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/react-hooks": {
|
||||
"version": "8.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react-hooks/-/react-hooks-8.10.2.tgz",
|
||||
"integrity": "sha512-HAd5cX50yKW/LljWlwt+FpSpdS/pNJutk9kMb7FyzxfoGBulL7sj6vX2HvxhSKyJMRKuTstXTdfJmsh22+3W3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/react-window-provider": "^2.3.2",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/react-portal-compat-context": {
|
||||
"version": "9.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react-portal-compat-context/-/react-portal-compat-context-9.0.15.tgz",
|
||||
"integrity": "sha512-DpV+qtFvM3dmH1j8ZD+YcM5vaTvmQPHUAx6tQnnmIoYJWs2R0wU/L5p2EajXy7zSg74jrDbDRxzaziamoOaJdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.14.0 <20.0.0",
|
||||
"react": ">=16.14.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/react-window-provider": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-2.3.2.tgz",
|
||||
"integrity": "sha512-T15zFPIWr9De8hNkapne7YyvcxclyTK2bMXXHZwbWLkVeH/lGHRG0CIy/calNGKa86wuzMJhq8iqFW2W6+EwVQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/set-version": {
|
||||
"version": "8.2.24",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.2.24.tgz",
|
||||
"integrity": "sha512-8uNi2ThvNgF+6d3q2luFVVdk/wZV0AbRfJ85kkvf2+oSRY+f6QVK0w13vMorNhA5puumKcZniZoAfUF02w7NSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/style-utilities": {
|
||||
"version": "8.15.2",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/style-utilities/-/style-utilities-8.15.2.tgz",
|
||||
"integrity": "sha512-rss7pkgiyNQuo1OpS7R2X6IJXIwDzQ0fxQxIeBB7Xp7lM+AwcKn5V7fzgIgCyE7BI6TWSy2TeQJ9Jtr/4fYEaw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/merge-styles": "^8.6.14",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/theme": "^2.7.2",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"@microsoft/load-themed-styles": "^1.10.26",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/theme": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/theme/-/theme-2.7.2.tgz",
|
||||
"integrity": "sha512-UXGNfGa/1bLmYrOpmHXdvyc7CzlNSKUQAADweTncbNoMF1DvscWEjPj5kxFgCmOU8wVtvvn4GraNNUSWtNxeeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/merge-styles": "^8.6.14",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"@fluentui/utilities": "^8.17.2",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/utilities": {
|
||||
"version": "8.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/utilities/-/utilities-8.17.2.tgz",
|
||||
"integrity": "sha512-TmeWVtGN+Lk0mch7tuRcbkeMdrBwltI68fvQbPwcNLo4igFtTInMmjEnVJGa7pBQN5lQAmHYqB9IJI6RZU/t6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fluentui/dom-utilities": "^2.3.10",
|
||||
"@fluentui/merge-styles": "^8.6.14",
|
||||
"@fluentui/react-window-provider": "^2.3.2",
|
||||
"@fluentui/set-version": "^8.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8.0 <20.0.0",
|
||||
"react": ">=16.8.0 <20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/load-themed-styles": {
|
||||
"version": "1.10.295",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz",
|
||||
"integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==",
|
||||
"node_modules/@splidejs/splide": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@splidejs/splide/-/splide-4.1.4.tgz",
|
||||
"integrity": "sha512-5I30evTJcAJQXt6vJ26g2xEkG+l1nXcpEw4xpKh0/FWQ8ozmAeTbtniVtVmz2sH1Es3vgfC4SS8B2X4o5JMptA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.23",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
|
||||
"integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
|
||||
"node_modules/@types/bootstrap": {
|
||||
"version": "5.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.11.tgz",
|
||||
"integrity": "sha512-69ykbLiNzQxi6Q/y/aYJLrlzI5QkLQjhIYW2U+cxujBxAmaBtmXKtxnFes59Ttfpt936as6xJU0dYnmVpcwIwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@videojs/http-streaming": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.17.5.tgz",
|
||||
"integrity": "sha512-PRRQVu0hYW5h0XvRWpIyIpEatpMZzZtf7L1avV89Hnu+69f+0c7oLsSL9jwpg2nbvzGkdX5rQxQkz5Vc7tFR9w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.2",
|
||||
"aes-decrypter": "^4.0.2",
|
||||
"global": "^4.4.0",
|
||||
"m3u8-parser": "^7.2.0",
|
||||
"mpd-parser": "^1.4.0",
|
||||
"mux.js": "7.1.0",
|
||||
"video.js": "^7 || ^8"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
|
||||
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
"video.js": "^8.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"node_modules/@videojs/vhs-utils": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-4.1.2.tgz",
|
||||
"integrity": "sha512-1Dsv5dtWOq0LP1G37O46FQFA2tKAZON5UMe6dFPxT7JvPhEx8QIXcFQxan8+hHI3fX6aomFRFrUBJNgRYQDSXA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/@videojs/xhr": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.7.0.tgz",
|
||||
"integrity": "sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"global": "~4.4.0",
|
||||
"is-function": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.8.13",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz",
|
||||
"integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aes-decrypter": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-4.0.2.tgz",
|
||||
"integrity": "sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.1",
|
||||
"global": "^4.4.0",
|
||||
"pkcs7": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/animejs": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/animejs/-/animejs-3.2.2.tgz",
|
||||
"integrity": "sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bootstrap-italia": {
|
||||
"version": "2.18.2",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-italia/-/bootstrap-italia-2.18.2.tgz",
|
||||
"integrity": "sha512-qoOrq8lDfmELVS46PJekZVacWCkVqG+PF4g41QBevbIWgw2LII6mESrE+ntADMrEKhDAVYPHt0Z9viHhabzXFw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@splidejs/splide": "^4.1.4",
|
||||
"@types/bootstrap": "^5.2.6",
|
||||
"animejs": "^3.2.1",
|
||||
"design-tokens-italia": "^1.3.3",
|
||||
"just-validate": "^4.3.0",
|
||||
"minimasonry": "^1.3.2",
|
||||
"progressbar.js": "^1.1.0",
|
||||
"uuid": "^14.0.0",
|
||||
"video.js": "^8.23.7"
|
||||
}
|
||||
},
|
||||
"node_modules/design-tokens-italia": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/design-tokens-italia/-/design-tokens-italia-1.3.3.tgz",
|
||||
"integrity": "sha512-9vdoT91ln2H/mppLO1LkTD9q18YPbT+BX9seJxzAC8r7gPlDRmbPJwsmt8dqXnULaH8Lqkp1KEdL8HW3Ah6K6A==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/dom-walk": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/global": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"min-document": "^2.19.0",
|
||||
"process": "^0.11.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-function": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
|
||||
"integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/just-validate": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/just-validate/-/just-validate-4.3.0.tgz",
|
||||
"integrity": "sha512-9yS7ZnFk95vq+O7CAa7XZEJvZN5i6jTQWNhLwOjtgkSqiLxo7GZJhK8ViylP76fXPfHLs8tYWqi81XgxPF3OGA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/m3u8-parser": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-7.2.0.tgz",
|
||||
"integrity": "sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.1",
|
||||
"global": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/min-document": {
|
||||
"version": "2.19.2",
|
||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz",
|
||||
"integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dom-walk": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimasonry": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/minimasonry/-/minimasonry-1.3.2.tgz",
|
||||
"integrity": "sha512-ygvf5JIR4NT1LbM6o8z1oz1icTkta72gXKwidvSqIVxuzVd/P21UI0Wbq1J+MStAu50Vvr8qWYNSz1W4uycqMQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mpd-parser": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.4.0.tgz",
|
||||
"integrity": "sha512-blbA7XpAaOdC/PR0Tu8GiUxlx6CpBuRowQPYV7lhi9Yr9G9+dkPXIUjqjzc/NCn/uZZPopluaJlIYntIEI/VLw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.2",
|
||||
"@xmldom/xmldom": "^0.8.3",
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"mpd-to-m3u8-json": "bin/parse.js"
|
||||
}
|
||||
},
|
||||
"node_modules/mux.js": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.1.0.tgz",
|
||||
"integrity": "sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"muxjs-transmux": "bin/transmux.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/pkcs7": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz",
|
||||
"integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5"
|
||||
},
|
||||
"bin": {
|
||||
"pkcs7": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/progressbar.js": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/progressbar.js/-/progressbar.js-1.1.1.tgz",
|
||||
"integrity": "sha512-FBsw3BKsUbb+hNeYfiP3xzvAAQrPi4DnGDw66bCmfuRCDLcslxyxv2GyYUdBSKFGSIBa73CUP5WMcl6F8AAXlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash.merge": "^4.6.2",
|
||||
"shifty": "^2.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.7",
|
||||
@@ -292,11 +306,78 @@
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"node_modules/shifty": {
|
||||
"version": "2.20.4",
|
||||
"resolved": "https://registry.npmjs.org/shifty/-/shifty-2.20.4.tgz",
|
||||
"integrity": "sha512-4Y0qRkg8ME5XN8yGNAwmFOmsIURGFKT9UQfNL6DDJQErYtN5HsjyoBuJn41ZQfTkuu2rIbRMn9qazjKsDpO2TA==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"fsevents": "^2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "14.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz",
|
||||
"integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/video.js": {
|
||||
"version": "8.23.9",
|
||||
"resolved": "https://registry.npmjs.org/video.js/-/video.js-8.23.9.tgz",
|
||||
"integrity": "sha512-3UCqyFW4wIusQu4TuhgRUxqtbzbj0WPT9hps0XIEXST43QBD11zb+bG7tBPrinrZztwVYdXCiOBo2pcGj9L05w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@videojs/http-streaming": "^3.17.5",
|
||||
"@videojs/vhs-utils": "^4.1.2",
|
||||
"@videojs/xhr": "2.7.0",
|
||||
"aes-decrypter": "^4.0.2",
|
||||
"global": "4.4.0",
|
||||
"m3u8-parser": "^7.2.0",
|
||||
"mpd-parser": "^1.4.0",
|
||||
"mux.js": "^7.0.1",
|
||||
"videojs-contrib-quality-levels": "4.1.0",
|
||||
"videojs-font": "4.2.0",
|
||||
"videojs-vtt.js": "0.15.5"
|
||||
}
|
||||
},
|
||||
"node_modules/videojs-contrib-quality-levels": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.1.0.tgz",
|
||||
"integrity": "sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16",
|
||||
"npm": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": "^8"
|
||||
}
|
||||
},
|
||||
"node_modules/videojs-font": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-4.2.0.tgz",
|
||||
"integrity": "sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/videojs-vtt.js": {
|
||||
"version": "0.15.5",
|
||||
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz",
|
||||
"integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"global": "^4.3.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@fluentui/react": "^8.125.6",
|
||||
"bootstrap-italia": "^2.18.2",
|
||||
"react": "^19.2.7",
|
||||
"react-dom": "^19.2.5"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import url('https://cdn.jsdelivr.net/npm/bootstrap-italia@2.0.0/dist/css/bootstrap-italia.min.css');
|
||||
|
||||
/* ===== Autocomplete Component Styles ===== */
|
||||
|
||||
.autocomplete-wrapper {
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import './App.css'
|
||||
import RecuperoPropostaCctDaContrattiComponent from './RecuperoPropostaCctDaContrattiComponent';
|
||||
import config from './config.json';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<RecuperoPropostaCctDaContrattiComponent
|
||||
description=""
|
||||
isDarkTheme={false}
|
||||
environmentMessage=""
|
||||
hasTeamsContext={false}
|
||||
userDisplayName=""
|
||||
headerTitle="Modulo - Placeholder Titolo Modulo"
|
||||
pageTitle="Recupero Proposta CCT da Contratti"
|
||||
pageDescription=""
|
||||
submitDescription='CONFERMA E PROSEGUI'
|
||||
moduleName={config.component.moduleName}
|
||||
headerTitle={config.component.headerTitle}
|
||||
headerHeroImageSrc={config.component.headerHeroImageSrc}
|
||||
cardTitle={config.component.cardTitle}
|
||||
cardDescription={config.component.cardDescription}
|
||||
alertInfoTitle={config.component.alertInfoTitle}
|
||||
alertInfoMessage={config.component.alertInfoMessage}
|
||||
instructionsTitle={config.component.instructionsTitle}
|
||||
instructionsMessage={config.component.instructionsMessage}
|
||||
submitText={config.component.submitText}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+46
-102
@@ -1,12 +1,10 @@
|
||||
import React, { type JSX } from 'react';
|
||||
import * as FluentUI from '@fluentui/react';
|
||||
import ElixFormsComponentAbstract from '@common/src/ElixFormsComponentAbstract';
|
||||
import type { IElixFormsComponentCustomFormFieldFactory } from '@common/src/IElixFormsComponentCustomFormFieldFactory';
|
||||
import { ElixFormsElement } from '@common/src/ElixFormsElement';
|
||||
import { QueryParamHelper } from '@common/src/QueryParamHelper';
|
||||
import config from './config.json';
|
||||
|
||||
/** Singolo risultato restituito dall'API esterna */
|
||||
interface ContrattoResult {
|
||||
idContratto: string;
|
||||
titoloContratto: string;
|
||||
@@ -14,7 +12,6 @@ interface ContrattoResult {
|
||||
idRicevuta: string;
|
||||
}
|
||||
|
||||
/** State aggiuntivo per gestire l'autocomplete */
|
||||
interface RecuperoPropostaState {
|
||||
searchText: string;
|
||||
searchResults: ContrattoResult[];
|
||||
@@ -26,7 +23,6 @@ interface RecuperoPropostaState {
|
||||
}
|
||||
|
||||
export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsComponentAbstract {
|
||||
/** Stato locale per l'autocomplete (separato dal formData gestito dall'abstract) */
|
||||
private autocompleteState: RecuperoPropostaState = {
|
||||
searchText: '',
|
||||
searchResults: [],
|
||||
@@ -37,29 +33,25 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
errorMessage: '',
|
||||
};
|
||||
|
||||
/** Timer per il debounce della ricerca */
|
||||
private debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
/** Ref al container per gestire il click-outside */
|
||||
private autocompleteRef: React.RefObject<HTMLDivElement | null> = React.createRef();
|
||||
|
||||
private static readonly formFieldKeys = {
|
||||
idContratto: 'COL0010',
|
||||
titoloContratto: 'COL0020',
|
||||
idDomanda: 'COL0030',
|
||||
idRicevuta: 'COL0040',
|
||||
codiceContratto: config.elixForms.outputs.codiceContratto,
|
||||
titoloContratto: config.elixForms.outputs.titoloContratto,
|
||||
idDomanda: config.elixForms.outputs.idDomanda,
|
||||
idRicevuta: config.elixForms.outputs.idRicevuta,
|
||||
} as const;
|
||||
|
||||
/** Codice fiscale letto dalla query string (COL0009), usato solo per la chiamata API */
|
||||
private codiceFiscale: string;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.codiceFiscale = QueryParamHelper.getDecodedTextFromQuery('COL0009') ?? '';
|
||||
this.codiceFiscale = QueryParamHelper.getDecodedTextFromQuery(config.elixForms.inputs.codiceFiscale) ?? '';
|
||||
}
|
||||
|
||||
override componentDidMount(): void {
|
||||
// Listener per chiudere il dropdown al click fuori dall'autocomplete
|
||||
document.addEventListener('mousedown', this.handleClickOutside);
|
||||
}
|
||||
|
||||
@@ -71,37 +63,30 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
}
|
||||
|
||||
private handleClickOutside = (event: MouseEvent): void => {
|
||||
if (
|
||||
this.autocompleteRef.current &&
|
||||
!this.autocompleteRef.current.contains(event.target as Node)
|
||||
) {
|
||||
if (this.autocompleteRef.current && !this.autocompleteRef.current.contains(event.target as Node)) {
|
||||
this.autocompleteState.isDropdownOpen = false;
|
||||
this.forceUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Chiama l'API esterna per ottenere i contratti corrispondenti al testo di ricerca.
|
||||
* Autenticazione: Basic Auth (username:password) + header X-Api-Key.
|
||||
*/
|
||||
private async fetchContratti(searchTerm: string): Promise<void> {
|
||||
this.autocompleteState.isLoading = true;
|
||||
this.autocompleteState.errorMessage = '';
|
||||
this.forceUpdate();
|
||||
|
||||
try {
|
||||
const url = new URL(config.apiUrl);
|
||||
const url = new URL(config.contrattiWS.apiUrl);
|
||||
url.searchParams.set('cod_fis', this.codiceFiscale);
|
||||
url.searchParams.set('term', searchTerm);
|
||||
|
||||
const credentials = btoa(`${config.apiUsername}:${config.apiPassword}`);
|
||||
const credentials = btoa(`${config.contrattiWS.apiUsername}:${config.contrattiWS.apiPassword}`);
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Basic ${credentials}`,
|
||||
'X-Api-Key': config.apiKey,
|
||||
'Accept': 'application/json',
|
||||
Authorization: `Basic ${credentials}`,
|
||||
'X-Api-Key': config.contrattiWS.apiKey,
|
||||
Accept: 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -121,21 +106,15 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
this.autocompleteState.searchResults = [];
|
||||
this.autocompleteState.isDropdownOpen = false;
|
||||
this.autocompleteState.isLoading = false;
|
||||
this.autocompleteState.errorMessage =
|
||||
error instanceof Error ? error.message : 'Errore durante la ricerca';
|
||||
this.autocompleteState.errorMessage = error instanceof Error ? error.message : 'Errore durante la ricerca';
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestisce il cambio testo nell'input di ricerca.
|
||||
* Applica debounce e chiama l'API al raggiungimento del minimo di caratteri.
|
||||
*/
|
||||
private handleSearchChange = (_event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string): void => {
|
||||
const text = newValue ?? '';
|
||||
private handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const text = event.target.value;
|
||||
this.autocompleteState.searchText = text;
|
||||
|
||||
// Se l'utente cancella il testo, resetta anche la selezione
|
||||
if (text.length === 0) {
|
||||
this.autocompleteState.searchResults = [];
|
||||
this.autocompleteState.isDropdownOpen = false;
|
||||
@@ -146,12 +125,11 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
return;
|
||||
}
|
||||
|
||||
// Debounce della ricerca
|
||||
if (this.debounceTimer) {
|
||||
clearTimeout(this.debounceTimer);
|
||||
}
|
||||
|
||||
if (text.length >= config.minCharsForSearch) {
|
||||
if (text.length >= config.component.minCharsForSearch) {
|
||||
this.debounceTimer = setTimeout(() => {
|
||||
this.fetchContratti(text);
|
||||
}, 300);
|
||||
@@ -163,10 +141,7 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gestisce la navigazione da tastiera nel dropdown (frecce, Invio, Escape).
|
||||
*/
|
||||
private handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
|
||||
private handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
|
||||
const { searchResults, isDropdownOpen, highlightedIndex } = this.autocompleteState;
|
||||
|
||||
if (!isDropdownOpen || searchResults.length === 0) return;
|
||||
@@ -174,10 +149,7 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
switch (event.key) {
|
||||
case 'ArrowDown':
|
||||
event.preventDefault();
|
||||
this.autocompleteState.highlightedIndex = Math.min(
|
||||
highlightedIndex + 1,
|
||||
searchResults.length - 1
|
||||
);
|
||||
this.autocompleteState.highlightedIndex = Math.min(highlightedIndex + 1, searchResults.length - 1);
|
||||
this.forceUpdate();
|
||||
break;
|
||||
|
||||
@@ -202,9 +174,6 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Seleziona un contratto dal dropdown e popola i campi hidden del form.
|
||||
*/
|
||||
private selectContract(contract: ContrattoResult): void {
|
||||
this.autocompleteState.selectedContract = contract;
|
||||
this.autocompleteState.searchText = `[${contract.idContratto}] ${contract.titoloContratto}`;
|
||||
@@ -212,31 +181,24 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
this.autocompleteState.searchResults = [];
|
||||
this.autocompleteState.highlightedIndex = -1;
|
||||
|
||||
// Aggiorna il formData con i valori selezionati
|
||||
this.setState({
|
||||
formData: {
|
||||
...this.state.formData,
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idContratto]: contract.idContratto,
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.codiceContratto]: contract.idContratto,
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.titoloContratto]: contract.titoloContratto,
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idDomanda]: contract.idDomanda,
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idRicevuta]: contract.idRicevuta,
|
||||
},
|
||||
}, () => {
|
||||
console.log('Contratto selezionato:', contract);
|
||||
console.log('Form data aggiornato:', this.state.formData);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resetta la selezione e svuota i campi hidden.
|
||||
*/
|
||||
private clearSelection(): void {
|
||||
this.autocompleteState.selectedContract = null;
|
||||
|
||||
this.setState({
|
||||
formData: {
|
||||
...this.state.formData,
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idContratto]: '',
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.codiceContratto]: '',
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.titoloContratto]: '',
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idDomanda]: '',
|
||||
[RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idRicevuta]: '',
|
||||
@@ -244,42 +206,41 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizza il componente autocomplete completo (label + input + dropdown).
|
||||
*/
|
||||
private renderAutocomplete(): JSX.Element {
|
||||
const { searchResults, isLoading, isDropdownOpen, highlightedIndex, errorMessage, searchText } = this.autocompleteState;
|
||||
|
||||
const autocompleteInput = (
|
||||
<>
|
||||
<div className="autocomplete-wrapper" ref={this.autocompleteRef}>
|
||||
<FluentUI.TextField
|
||||
<div className="position-relative" ref={this.autocompleteRef}>
|
||||
<input
|
||||
id="autocomplete-search"
|
||||
name="autocomplete-search"
|
||||
className="form-control"
|
||||
type="text"
|
||||
placeholder="Digita almeno 3 caratteri per cercare..."
|
||||
value={searchText}
|
||||
onChange={this.handleSearchChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
className="isiportalPartialAdminFormFieldSingleLineText"
|
||||
autoComplete="off"
|
||||
/>
|
||||
|
||||
{isLoading && (
|
||||
<div className="autocomplete-dropdown">
|
||||
<div className="autocomplete-loading">
|
||||
<FluentUI.Spinner size={FluentUI.SpinnerSize.small} label="Ricerca in corso..." />
|
||||
</div>
|
||||
<div className="autocompleteDropdown mt-2 p-3 text-muted">
|
||||
<span className="me-2">
|
||||
<span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
</span>
|
||||
Ricerca in corso...
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isLoading && isDropdownOpen && searchResults.length > 0 && (
|
||||
<div className="autocomplete-dropdown">
|
||||
<div className="autocompleteDropdown mt-2">
|
||||
{searchResults.map((contract, index) => (
|
||||
<div
|
||||
key={`${contract.idContratto}_${index}`}
|
||||
className={`autocomplete-dropdown-item${index === highlightedIndex ? ' highlighted' : ''}`}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault(); // Previene blur del TextField
|
||||
className={`autocompleteItem${index === highlightedIndex ? ' isHighlighted' : ''}`}
|
||||
onMouseDown={(event) => {
|
||||
event.preventDefault();
|
||||
this.selectContract(contract);
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
@@ -287,41 +248,31 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
this.forceUpdate();
|
||||
}}
|
||||
>
|
||||
<span className="contract-id">[{contract.idContratto}]</span>{' '}
|
||||
<span className="contract-title">{contract.titoloContratto}</span>
|
||||
<span className="fw-semibold">[{contract.idContratto}]</span>{' '}
|
||||
<span>{contract.titoloContratto}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isLoading && isDropdownOpen && searchResults.length === 0 && (
|
||||
<div className="autocomplete-dropdown">
|
||||
<div className="autocomplete-no-results">Nessun risultato trovato</div>
|
||||
</div>
|
||||
<div className="autocompleteDropdown mt-2 p-3 text-muted">Nessun risultato trovato</div>
|
||||
)}
|
||||
|
||||
{errorMessage && (
|
||||
<div className="autocomplete-error">{errorMessage}</div>
|
||||
<div className="custom-alert custom-alert-danger mt-2">{errorMessage}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{this.autocompleteState.selectedContract && (
|
||||
<div className="selected-contract-summary">
|
||||
<div className="summary-row">
|
||||
<span className="summary-label">ID Contratto:</span>
|
||||
<span className="summary-value">{this.autocompleteState.selectedContract.idContratto}</span>
|
||||
<div className="card mt-3">
|
||||
<div className="card-body">
|
||||
<div className="row g-2">
|
||||
<div className="col-12 col-md-6"><strong>ID Contratto:</strong> {this.autocompleteState.selectedContract.idContratto}</div>
|
||||
<div className="col-12 col-md-6"><strong>Titolo:</strong> {this.autocompleteState.selectedContract.titoloContratto}</div>
|
||||
<div className="col-12 col-md-6"><strong>ID Domanda:</strong> {this.autocompleteState.selectedContract.idDomanda}</div>
|
||||
<div className="col-12 col-md-6"><strong>ID Ricevuta:</strong> {this.autocompleteState.selectedContract.idRicevuta}</div>
|
||||
</div>
|
||||
<div className="summary-row">
|
||||
<span className="summary-label">Titolo:</span>
|
||||
<span className="summary-value">{this.autocompleteState.selectedContract.titoloContratto}</span>
|
||||
</div>
|
||||
<div className="summary-row">
|
||||
<span className="summary-label">ID Domanda:</span>
|
||||
<span className="summary-value">{this.autocompleteState.selectedContract.idDomanda}</span>
|
||||
</div>
|
||||
<div className="summary-row">
|
||||
<span className="summary-label">ID Ricevuta:</span>
|
||||
<span className="summary-value">{this.autocompleteState.selectedContract.idRicevuta}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -329,19 +280,14 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
);
|
||||
|
||||
return new ElixFormsElement(
|
||||
<FluentUI.Label htmlFor="autocomplete-search">Cerca Contratto</FluentUI.Label>,
|
||||
<label className="form-label fw-semibold" htmlFor="autocomplete-search">Cerca Contratto</label>,
|
||||
autocompleteInput
|
||||
).render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override del metodo factory per definire i campi custom del form.
|
||||
* - Autocomplete per la ricerca contratti
|
||||
* - 4 campi hidden (COL0010, COL0020, COL0030, COL0040) per i dati da rimandare a elixForms
|
||||
*/
|
||||
protected override createCustomFormFields(formFieldFactory: IElixFormsComponentCustomFormFieldFactory): JSX.Element {
|
||||
const fieldKeys = RecuperoPropostaCctDaContrattiComponent.formFieldKeys;
|
||||
const idContratto = this.state.formData[fieldKeys.idContratto] ?? '';
|
||||
const idContratto = this.state.formData[fieldKeys.codiceContratto] ?? '';
|
||||
const titoloContratto = this.state.formData[fieldKeys.titoloContratto] ?? '';
|
||||
const idDomanda = this.state.formData[fieldKeys.idDomanda] ?? '';
|
||||
const idRicevuta = this.state.formData[fieldKeys.idRicevuta] ?? '';
|
||||
@@ -349,9 +295,7 @@ export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsCo
|
||||
return (
|
||||
<>
|
||||
{this.renderAutocomplete()}
|
||||
|
||||
{/* Campi hidden per i dati del contratto selezionato — verranno inviati nel POST a elixForms */}
|
||||
<input type="hidden" id="idContratto_hidden" name={fieldKeys.idContratto} value={idContratto} />
|
||||
<input type="hidden" id="idContratto_hidden" name={fieldKeys.codiceContratto} value={idContratto} />
|
||||
<input type="hidden" id="titoloContratto_hidden" name={fieldKeys.titoloContratto} value={titoloContratto} />
|
||||
<input type="hidden" id="idDomanda_hidden" name={fieldKeys.idDomanda} value={idDomanda} />
|
||||
<input type="hidden" id="idRicevuta_hidden" name={fieldKeys.idRicevuta} value={idRicevuta} />
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"apiUrl": "http://localhost:8000/contratti/cerca",
|
||||
"apiUsername": "your-username",
|
||||
"apiPassword": "your-password",
|
||||
"apiKey": "your-api-key",
|
||||
"minCharsForSearch": 3
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"component": {
|
||||
"minCharsForSearch": 3,
|
||||
"moduleName": "Ripartizione Utili / Compensi - Presentazione Proposta",
|
||||
"headerTitle": "",
|
||||
"headerHeroImageSrc": "",
|
||||
"cardTitle": "Recupero Proposta CCT da Contratti",
|
||||
"cardDescription": "",
|
||||
"alertInfoTitle": "",
|
||||
"alertInfoMessage": "",
|
||||
"instructionsTitle": "Istruzioni di compilazione",
|
||||
"instructionsMessage": "Completa i campi richiesti per procedere con la richiesta.",
|
||||
"submitText": "CONFERMA E PROSEGUI"
|
||||
},
|
||||
"elixForms": {
|
||||
"inputs": {
|
||||
"codiceFiscale": "COL000A"
|
||||
},
|
||||
"outputs": {
|
||||
"idDomanda": "COL00B1",
|
||||
"idRicevuta": "COL00B2",
|
||||
"codiceContratto": "COL00B3",
|
||||
"titoloContratto": "COL00B4"
|
||||
}
|
||||
},
|
||||
"contrattiWS": {
|
||||
"apiUrl": "http://localhost:8000/contratti/cerca",
|
||||
"apiUsername": "username",
|
||||
"apiPassword": "password",
|
||||
"apiKey": "apitoken"
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,24 @@ import react from '@vitejs/plugin-react'
|
||||
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
|
||||
import path from "path";
|
||||
|
||||
const ASSETS_DIR = 'assets';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
cssInjectedByJsPlugin() // forza l'iniezione del CSS nel JS
|
||||
],
|
||||
base: './',
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
cssCodeSplit: false, // evita file CSS separati
|
||||
rollupOptions: {
|
||||
input: 'src/main.jsx',
|
||||
output: {
|
||||
codeSplitting: false, // forza tutto in un singolo bundle
|
||||
manualChunks: undefined, // disabilita la creazione di chunk multipli
|
||||
entryFileNames: 'recupero-proposta-cct-da-contratti.js',
|
||||
assetFileNames: '[name].[ext]'
|
||||
entryFileNames: `${ASSETS_DIR}/recupero-proposta-cct-da-contratti.js`,
|
||||
assetFileNames: `${ASSETS_DIR}/[name].[ext]`,
|
||||
},
|
||||
},
|
||||
sourcemap: true,
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:wght@300;400;600;700&display=swap');
|
||||
@import url('https://cdn.jsdelivr.net/npm/bootstrap-italia@2.0.0/dist/css/bootstrap-italia.min.css');
|
||||
|
||||
:root {
|
||||
--font-family-sans-serif: "Titillium Web", "Segoe UI", Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Titillium Web", "Segoe UI", Arial, sans-serif;
|
||||
}
|
||||
/*
|
||||
@import url('https://console-unipr.elixforms.it/elixFormsCustom/css/elixForms.css');
|
||||
@import url('https://console-unipr.elixforms.it/rwe2/css/design-bs/bootstrap_adaptation.css');
|
||||
@import url('https://console-unipr.elixforms.it/rwe2/css/design-bs/bootstrap_overrides.css');
|
||||
@@ -14,6 +25,7 @@
|
||||
@import url('https://console-unipr.elixforms.it/rwe2/css/plugins/modaldisplay.css');
|
||||
@import url('https://console-unipr.elixforms.it/rwe2/css/themes/blu-italia.css');
|
||||
@import url('https://console-unipr.elixforms.it/rwe2/isipcss/css/grid_fluid.css');
|
||||
*/
|
||||
|
||||
/*
|
||||
.counter {
|
||||
|
||||
@@ -5,15 +5,13 @@ import SceltaCarrieraComponent from './SceltaCarrieraComponent';
|
||||
function App() {
|
||||
return (
|
||||
<SceltaCarrieraComponent
|
||||
description=""
|
||||
isDarkTheme={false}
|
||||
environmentMessage=""
|
||||
hasTeamsContext={false}
|
||||
moduleName=""
|
||||
alertInfoMessage=""
|
||||
userDisplayName="John Doe"
|
||||
headerTitle="Modulo A/13 - Richiesta di Certificato"
|
||||
pageTitle="Scelta Carriera"
|
||||
pageDescription="Benvenuto nella piattaforma di scelta carriera! Esplora le tue opzioni e trova la strada giusta per te."
|
||||
heroImageSrc={heroImg}
|
||||
cardTitle="Scelta Carriera"
|
||||
cardDescription="Benvenuto nella piattaforma di scelta carriera! Esplora le tue opzioni e trova la strada giusta per te."
|
||||
headerHeroImageSrc={heroImg}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,44 +6,44 @@ export default class SceltaCarrieraComponent extends ElixFormsComponentAbstract
|
||||
protected override createCustomFormFields(formFieldFactory: IElixFormsComponentCustomFormFieldFactory): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{formFieldFactory.createDropdownInput("COL0015", "COL0015 Goals", [
|
||||
{ "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" }
|
||||
{formFieldFactory.createDropdownInput('COL0015', 'COL0015 Goals', [
|
||||
{ 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' }
|
||||
], true)}
|
||||
{formFieldFactory.createTextInput("COL0002", "Campo STRING", true)}
|
||||
{formFieldFactory.createTextAreaInput("COL0003", "Campo TEXTAREA", true)}
|
||||
{formFieldFactory.createBooleanInput("COL0004", "Campo BOOLEAN", true)}
|
||||
{formFieldFactory.createRadioInput("COL0005", "Campo RADIO", [
|
||||
{ "value": 1, "label": "Opzione 1" },
|
||||
{ "value": 2, "label": "Opzione 2" },
|
||||
{ "value": 3, "label": "Altra opzione" }
|
||||
{formFieldFactory.createTextInput('COL0002', 'Campo STRING', true)}
|
||||
{formFieldFactory.createTextAreaInput('COL0003', 'Campo TEXTAREA', true)}
|
||||
{formFieldFactory.createBooleanInput('COL0004', 'Campo BOOLEAN', true)}
|
||||
{formFieldFactory.createRadioInput('COL0005', 'Campo RADIO', [
|
||||
{ value: 1, label: 'Opzione 1' },
|
||||
{ value: 2, label: 'Opzione 2' },
|
||||
{ value: 3, label: 'Altra opzione' }
|
||||
], true)}
|
||||
{formFieldFactory.createCheckboxInput("COL0006", "Campo CHECKBOX", [
|
||||
{ "value": 4, "label": "Check 1" },
|
||||
{ "value": 5, "label": "Check 2" },
|
||||
{ "value": 6, "label": "Altro check" }
|
||||
{formFieldFactory.createCheckboxInput('COL0006', 'Campo CHECKBOX', [
|
||||
{ value: 4, label: 'Check 1' },
|
||||
{ value: 5, label: 'Check 2' },
|
||||
{ value: 6, label: 'Altro check' }
|
||||
])}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
protected override renderExtraContentPost(): JSX.Element {
|
||||
return <p>Altre cose</p>;
|
||||
return <div className="alert alert-info mt-4">Questa pagina è stata ristrutturata con i componenti Bootstrap Italia.</div>;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user