This commit is contained in:
Vitalii Kiiko
2024-08-20 12:57:23 +02:00
parent e0399608ee
commit 74d2da78d6
10 changed files with 519 additions and 299 deletions

View File

@@ -40,6 +40,14 @@
} }
} }
} }
.appForm__oneCol {
display: flex;
flex-direction: column;
label {
font-weight: 400;
}
}
.appForm__twoCols { .appForm__twoCols {
display: flex; display: flex;
gap: 1rem; gap: 1rem;

View File

@@ -14,6 +14,7 @@
.appPageSection { .appPageSection {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start;
h2 { h2 {
color: var(--Black); color: var(--Black);

View File

@@ -1,7 +1,9 @@
import React from 'react'; import React from 'react';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { isEmpty, isNil } from 'ramda';
// components
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
import { isNil } from 'ramda';
import { Calendar } from 'primereact/calendar'; import { Calendar } from 'primereact/calendar';
const DatepickerRange = ({ const DatepickerRange = ({
@@ -15,6 +17,7 @@ const DatepickerRange = ({
minDate = null, minDate = null,
maxDate = null maxDate = null
}) => { }) => {
const datesDefaultValue = !isNil(defaultValue) && !isEmpty(defaultValue) && defaultValue.length ? defaultValue.map(v => new Date(v)) : [];
return ( return (
<> <>
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}> <label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
@@ -23,16 +26,24 @@ const DatepickerRange = ({
<Controller <Controller
name={fieldName} name={fieldName}
control={control} control={control}
defaultValue={defaultValue} defaultValue={datesDefaultValue}
rules={config} rules={config}
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Calendar id={field.name} <Calendar id={field.name}
value={field.value} value={field.value}
onChange={(e) => field.onChange(e.value)} onChange={(e) => {
dateFormat="dd/mm/yy" mask="99/99/9999" const formattedValues = e.value.map(d => d ? d.toISOString() : d);
console.log('formattedValues', formattedValues);
field.onChange(formattedValues)
}}
dateFormat="dd/mm/yy"
mask="99/99/9999"
showIcon showIcon
minDate={minDate} maxDate={maxDate} minDate={minDate}
selectionMode="range" readOnlyInput hideOnRangeSelection maxDate={maxDate}
selectionMode="range"
readOnlyInput
hideOnRangeSelection
className={classNames({ 'p-invalid': fieldState.invalid })}/> className={classNames({ 'p-invalid': fieldState.invalid })}/>
)}/> )}/>
{infoText ? <small>{infoText}</small> : null} {infoText ? <small>{infoText}</small> : null}

View File

@@ -15,7 +15,8 @@ const Fileupload = ({
accept = 'image/*', accept = 'image/*',
api = '/api/upload', api = '/api/upload',
emptyText = __('Trascina qui il tuo file', 'gepafin'), emptyText = __('Trascina qui il tuo file', 'gepafin'),
chooseLabel = __('Aggiungi immagine', 'gepafin') chooseLabel = __('Aggiungi immagine', 'gepafin'),
multiple = false
}) => { }) => {
return ( return (
<> <>
@@ -32,7 +33,7 @@ const Fileupload = ({
id={field.name} id={field.name}
name={`${field.name}[]`} name={`${field.name}[]`}
url={api} url={api}
multiple multiple={multiple}
accept={accept} accept={accept}
maxFileSize={1000000} maxFileSize={1000000}
emptyTemplate={<p>{emptyText}</p>} emptyTemplate={<p>{emptyText}</p>}

View File

@@ -1,6 +1,9 @@
import React, { useRef, useEffect, useState } from 'react'; import React, { useRef, useEffect, useState } from 'react';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { head } from 'ramda';
// components
import { InputText } from 'primereact/inputtext'; import { InputText } from 'primereact/inputtext';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { Menu } from 'primereact/menu'; import { Menu } from 'primereact/menu';
@@ -19,6 +22,7 @@ const FormFieldRepeaterCriteria = ({
}) => { }) => {
const forMenu = useRef(null); const forMenu = useRef(null);
const [stateFieldData, setStateFieldData] = useState([]); const [stateFieldData, setStateFieldData] = useState([]);
const [threshold, setThreshold] = useState(0);
const menuItems = [ const menuItems = [
{ {
type: 'existing', type: 'existing',
@@ -42,14 +46,19 @@ const FormFieldRepeaterCriteria = ({
} }
const selectItem = (e, index) => { const selectItem = (e, index) => {
const targetedOption = head(options.filter(o => o.value === e.value));
if (targetedOption) {
const newData = stateFieldData.map((o, i) => { const newData = stateFieldData.map((o, i) => {
if (i === index) { if (i === index) {
o.value = e.value; o.value = targetedOption.value;
o.score = targetedOption.score;
} }
return o; return o;
}) });
console.log('newData', newData)
setStateFieldData(newData); setStateFieldData(newData);
} }
}
const onInputChange = (value, index, name) => { const onInputChange = (value, index, name) => {
const newData = stateFieldData.map((o, i) => { const newData = stateFieldData.map((o, i) => {
@@ -61,6 +70,10 @@ const FormFieldRepeaterCriteria = ({
setStateFieldData(newData); setStateFieldData(newData);
} }
const onThresholdChange = (value) => {
setThreshold(value);
}
const properField = (item, i) => { const properField = (item, i) => {
return item.status === 'new' return item.status === 'new'
? <InputText value={item.value} onInput={(e) => onInputChange(e.target.value, i, 'value')}/> ? <InputText value={item.value} onInput={(e) => onInputChange(e.target.value, i, 'value')}/>
@@ -78,6 +91,7 @@ const FormFieldRepeaterCriteria = ({
const storeFieldData = data[fieldName] ?? []; const storeFieldData = data[fieldName] ?? [];
const newData = storeFieldData.map(o => ({ ...o, status: o.id ? 'existing' : 'new' })) const newData = storeFieldData.map(o => ({ ...o, status: o.id ? 'existing' : 'new' }))
setStateFieldData(newData); setStateFieldData(newData);
setThreshold(data['threshold'])
register(fieldName) register(fieldName)
}, []) }, [])
@@ -90,23 +104,15 @@ const FormFieldRepeaterCriteria = ({
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}> <label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
{label} {label}
</label> </label>
{stateFieldData.map((o, i) => <div key={i} className={classNames("appForm__field", 'appForm__repeaterItem')}> <div className="appForm__oneCol">
<div className="appForm__twoCols">
<div>
<label htmlFor="criterionTotal">{__('Punteggio Totale', 'gepafin')}</label>
<InputNumber inputId="criterionTotal"
value={o.total}
showButtons
onValueChange={(e) => onInputChange(e.value, i, 'total')}/>
</div>
<div>
<label htmlFor="criterionThreshold">{__('Punteggio minimo per lammissione', 'gepafin')}</label> <label htmlFor="criterionThreshold">{__('Punteggio minimo per lammissione', 'gepafin')}</label>
<InputNumber inputId="criterionThreshold" <InputNumber inputId="criterionThreshold"
value={o.threshold} value={threshold}
showButtons showButtons
onValueChange={(e) => onInputChange(e.value, i, 'threshold')}/> onValueChange={(e) => onThresholdChange(e.value)}/>
</div>
</div> </div>
{stateFieldData.map((o, i) => <div key={i}
className={classNames('appForm__field', 'appForm__repeaterItem')}>
<div className="appForm__twoCols"> <div className="appForm__twoCols">
<div> <div>
<label>{__('Nome criterio di valutazione', 'gepafin')}</label> <label>{__('Nome criterio di valutazione', 'gepafin')}</label>
@@ -117,18 +123,11 @@ const FormFieldRepeaterCriteria = ({
{o.status === 'new' && infoText ? <small>{infoText}</small> : null} {o.status === 'new' && infoText ? <small>{infoText}</small> : null}
</div> </div>
<div> <div>
<label htmlFor="criterionMin">{__('Punteggio minimo', 'gepafin')}</label> <label htmlFor="criterionMin">{__('Punteggio', 'gepafin')}</label>
<InputNumber inputId="criterionMin" <InputNumber inputId="criterionMin"
value={o.min} value={o.score}
showButtons showButtons
onValueChange={(e) => onInputChange(e.value, i, 'min')}/> onValueChange={(e) => onInputChange(e.value, i, 'score')}/>
</div>
<div>
<label htmlFor="criterionMax">{__('Punteggio massimo', 'gepafin')}</label>
<InputNumber inputId="criterionMax"
value={o.max}
showButtons
onValueChange={(e) => onInputChange(e.value, i, 'max')}/>
</div> </div>
</div> </div>
</div>)} </div>)}

View File

@@ -1,254 +0,0 @@
import React, { useState, useEffect, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { useParams } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form';
import { classNames } from 'primereact/utils';
// components
import { InputText } from 'primereact/inputtext';
import { InputTextarea } from 'primereact/inputtextarea';
import getBandoLabel from '../../helpers/getBandoLabel';
import { Button } from 'primereact/button';
import { Dropdown } from 'primereact/dropdown';
import { Menu } from 'primereact/menu';
import FormField from '../../components/FormField';
import FormFieldRepeater from '../../components/FormFieldRepeater';
import { Skeleton } from 'primereact/skeleton';
import FormFieldRepeaterCriteria from '../../components/FormFieldRepeaterCriteria';
import FormFieldRepeaterFaq from '../../components/FormFieldRepeaterFaq';
const Bando = () => {
const { id } = useParams();
const [data, setData] = useState({});
const [isFormLoading, setIsFormLoading] = useState(true);
const [selectedTemplate, setSelectedTemplate] = useState(null);
const [templates, setTemplate] = useState(null);
const {
control,
reset,
handleSubmit,
formState: { errors },
getValues,
setValue,
register
} = useForm(data);
let minDateStart = new Date();
const onSubmit = formData => console.log(formData);
// temp
const exampleOfAimedToOptions = [{ id: 11, value: 'PMI con sede in Umbria' }];
const exampleOfCriteriaOptions = [{ id: 15, value: 'Innovatività del progetto' }];
const exampleOfFaqOptions = [
{ id: 2, question: 'Question 1?', answer: 'Lorem ipsum dolor' }
];
const exampleOfChecklistOptions = [
{ id: 9, value: 'Requisiti di ammissibilità soddisfatti' },
{ id: 9, value: 'Documentazione completa' }
];
const onPublish = () => {
console.log('click onPublish');
}
useEffect(() => {
const parsed = parseInt(id)
const bandoId = !isNaN(parsed) ? parsed : 0;
setTimeout(() => {
const data = 0 === bandoId
? {
status: 'draft',
name: '',
description: ''
}
: {
name: 'Bando Innovazione 2024',
description: '',
start_date: '2024-08-08T00:00:00+00:00',
end_date: '2024-08-30T00:00:00+00:00',
submissions: 24,
status: 'publish',
id: 11
}
setData(data);
reset();
const templates = [
{ name: 'Il mio template', value: 22 },
{ name: 'Template #11', value: 11 },
];
setTemplate(templates);
setIsFormLoading(false);
}, 3000);
}, [id]);
return (
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Creazione/Modifica Bando', 'gepafin')}</h1>
<p>
{__('Stato:', 'gepafin')}
<span>{getBandoLabel(data.status)}</span>
</p>
</div>
<div className="appPage__spacer"></div>
{!isFormLoading
? <div className="pageBando__templateSelection">
<div className="appForm__field">
<label htmlFor="template">
{__('Usa Template Salvato', 'gepafin')}
</label>
<Dropdown
id="template"
value={selectedTemplate}
onChange={(e) => setSelectedTemplate(e.value)}
options={templates}
optionLabel="name"
placeholder={__('Seleziona template', 'gepafin')}/>
</div>
<Button
onClick={() => console.log('use template')}
label={__('Applica', 'gepafin')}
icon="pi pi-check"
iconPos="right"/>
</div> : null}
<div className="appPage__spacer"></div>
{!isFormLoading
? <form className="appForm" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="textinput"
fieldName="name"
label={__('Titolo del Bando', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['name']}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
<FormField
type="textarea"
fieldName="description"
label={__('Descrizione', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['description']}
config={{
required: __('È obbligatorio', 'gepafin'),
minLength: 200
}}
infoText={__('Almeno 200 caratteri', 'gepafin')}
/>
<FormFieldRepeater
data={data}
setDataFn={setValue}
fieldName="aimedTo"
options={exampleOfAimedToOptions}
errors={errors}
register={register}
label={<>{__('A chi si rivolge', 'gepafin')}*
<span>{__('(almeno 1 tipo di destinatari)', 'gepafin')}</span></>}
/>
<FormField
type="datepickerrange"
fieldName="dates"
label={__('Dati di pubblicazione', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['dates']}
config={{ required: __('È obbligatorio', 'gepafin') }}
minDate={minDateStart}
/>
<FormField
type="numberinput"
fieldName="amount"
label={__('Dotazione del Bando', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['amount']}
config={{ required: __('È obbligatorio', 'gepafin') }}
inputgroup={true}
icon="€"
/>
<FormFieldRepeaterCriteria
data={data}
setDataFn={setValue}
fieldName="criteria"
options={exampleOfCriteriaOptions}
errors={errors}
register={register}
label={<>{__('Criteri di valutazione', 'gepafin')}*
<span>{__('(almeno 1 criterio di valutazione)', 'gepafin')}</span></>}/>
<FormField
type="fileupload"
fieldName="documentation"
label={__('Documentazione', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['documentation']}
config={{ required: __('È obbligatorio', 'gepafin') }}
accept="application/pdf,application/vnd.ms-excel"
chooseLabel={__('Aggiungi documento', 'gepafin')}
/>
<FormField
type="fileupload"
fieldName="images"
label={__('Immagine del Bando', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['documentation']}
/>
<FormFieldRepeaterFaq
data={data}
setDataFn={setValue}
fieldName="faq"
options={exampleOfFaqOptions}
errors={errors}
register={register}
label={__('FAQ', 'gepafin')}/>
<FormFieldRepeater
data={data}
setDataFn={setValue}
fieldName="checklist"
options={exampleOfChecklistOptions}
errors={errors}
register={register}
label={<>{__('Checklist valutazione Pre-Istruttoria', 'gepafin')}*
<span>{__('(almeno 1 elemento)', 'gepafin')}</span></>}
/>
<div className="appPageSection">
<div className="appPageSection__actions">
<Button
type="submit"
label={__('Salva Bozza', 'gepafin')} icon="pi pi-save" iconPos="right"/>
<Button
type="button"
onClick={onPublish}
label={__('Pubblica', 'gepafin')} icon="pi pi-upload" iconPos="right"/>
</div>
</div>
</form>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem"></Skeleton>
</>}
</div>
)
}
export default Bando;

View File

@@ -0,0 +1,318 @@
import React, { useState, useEffect, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { useForm } from 'react-hook-form';
// components
import getBandoLabel from '../../helpers/getBandoLabel';
import { Button } from 'primereact/button';
import { Dropdown } from 'primereact/dropdown';
import FormField from '../../components/FormField';
import FormFieldRepeater from '../../components/FormFieldRepeater';
import { Skeleton } from 'primereact/skeleton';
import FormFieldRepeaterCriteria from '../../components/FormFieldRepeaterCriteria';
import FormFieldRepeaterFaq from '../../components/FormFieldRepeaterFaq';
const BandoEdit = () => {
const navigate = useNavigate();
const { id } = useParams();
const [data, setData] = useState({});
const [isLoading, setIsLoading] = useState(true);
const [selectedTemplate, setSelectedTemplate] = useState(null);
const [templates, setTemplate] = useState(null);
const {
control,
reset,
handleSubmit,
formState: { errors },
setValue,
register
} = useForm(data);
let minDateStart = new Date();
const onSubmit = formData => console.log(formData);
// temp
const exampleOfAimedToOptions = [{ id: 11, value: 'PMI con sede in Umbria' }];
const exampleOfCriteriaOptions = [
{ id: 15, value: 'Innovatività del progetto', score: 9 },
{ id: 16, value: 'Impatto sulla competitività dell\'azienda', score: 3 },
{ id: 17, value: 'Sostenibilità economico-finanziaria', score: 5 }
];
const exampleOfFaqOptions = [
{ id: 2, question: 'Question 1?', answer: 'Lorem ipsum dolor' }
];
const exampleOfChecklistOptions = [
{ id: 15, value: 'Innovatività del progetto' }
];
const openPreview = () => {
navigate('/bandi/preview/11');
}
const openPreviewEvaluation = () => {
navigate('/bandi/preview-evaluation/11');
}
const openBandoFormManagement = () => {
navigate('/bandi/11/forms');
}
useEffect(() => {
const parsed = parseInt(id)
const bandoId = !isNaN(parsed) ? parsed : 0;
setTimeout(() => {
const data = 0 === bandoId
? {
status: 'draft',
name: ''
}
: {
name: 'Bando Innovazione 2024',
description: '',
start_date: '2024-08-08T00:00:00+00:00',
end_date: '2024-08-30T00:00:00+00:00',
submissions: 24,
status: 'publish',
id: 11
}
setData(data);
reset();
const templates = [
{ name: 'Il mio template', value: 22 },
{ name: 'Template #11', value: 11 },
];
setTemplate(templates);
setIsLoading(false);
}, 3000);
}, [id]);
return (
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Creazione/Modifica Bando', 'gepafin')}</h1>
<p>
{__('Stato:', 'gepafin')}
<span>{getBandoLabel(data.status)}</span>
</p>
</div>
<div className="appPage__spacer"></div>
{!isLoading
? <div className="pageBando__templateSelection">
<div className="appForm__field">
<label htmlFor="template">
{__('Usa Template Salvato', 'gepafin')}
</label>
<Dropdown
id="template"
value={selectedTemplate}
onChange={(e) => setSelectedTemplate(e.value)}
options={templates}
optionLabel="name"
placeholder={__('Seleziona template', 'gepafin')}/>
</div>
<Button
onClick={() => console.log('use template')}
label={__('Applica', 'gepafin')}
icon="pi pi-check"
iconPos="right"/>
</div> : null}
<div className="appPage__spacer"></div>
{!isLoading
? <>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="textinput"
fieldName="name"
label={__('Titolo del Bando', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['name']}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
<FormField
type="textarea"
fieldName="descriptionShort"
label={__('Descrizione breve', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['descriptionShort']}
config={{
required: __('È obbligatorio', 'gepafin')
}}
/>
<FormField
type="textarea"
fieldName="descriptionLong"
label={__('Descrizione completa', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['descriptionLong']}
config={{
required: __('È obbligatorio', 'gepafin'),
minLength: 200
}}
infoText={__('Almeno 200 caratteri', 'gepafin')}
/>
<FormFieldRepeater
data={data}
setDataFn={setValue}
fieldName="aimedTo"
options={exampleOfAimedToOptions}
errors={errors}
register={register}
label={<>{__('A chi si rivolge', 'gepafin')}*
<span>{__('(almeno 1 tipo di destinatari)', 'gepafin')}</span></>}
/>
<FormField
type="textarea"
fieldName="documentationRequested"
label={__('Documentazione richiesta', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['documentationRequested']}
config={{
required: __('È obbligatorio', 'gepafin')
}}
/>
<FormField
type="datepickerrange"
fieldName="dates"
label={__('Dati di pubblicazione', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['dates']}
config={{ required: __('È obbligatorio', 'gepafin') }}
minDate={minDateStart}
/>
<div className="appForm__twoCols">
<FormField
type="numberinput"
fieldName="amount"
label={__('Dotazione del Bando', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['amount']}
config={{ required: __('È obbligatorio', 'gepafin') }}
inputgroup={true}
icon="€"
/>
<FormField
type="numberinput"
fieldName="amountMax"
label={__('Importo massimo per Progetto', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['amountMax']}
config={{ required: __('È obbligatorio', 'gepafin') }}
inputgroup={true}
icon="€"
/>
</div>
<FormFieldRepeaterCriteria
data={data}
setDataFn={setValue}
fieldName="criteria"
options={exampleOfCriteriaOptions}
errors={errors}
register={register}
label={<>{__('Criteri di valutazione', 'gepafin')}*
<span>{__('(almeno 1 criterio di valutazione)', 'gepafin')}</span></>}/>
<FormField
type="fileupload"
fieldName="documentation"
label={__('Documentazione', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['documentation']}
config={{ required: __('È obbligatorio', 'gepafin') }}
accept="application/pdf,application/vnd.ms-excel"
chooseLabel={__('Aggiungi documento', 'gepafin')}
multiple={true}
/>
<FormField
type="fileupload"
fieldName="images"
label={__('Immagine del Bando', 'gepafin')}
control={control}
errors={errors}
defaultValue={data['documentation']}
/>
<FormFieldRepeaterFaq
data={data}
setDataFn={setValue}
fieldName="faq"
options={exampleOfFaqOptions}
errors={errors}
register={register}
label={__('FAQ', 'gepafin')}/>
<FormFieldRepeater
data={data}
setDataFn={setValue}
fieldName="checklist"
options={exampleOfChecklistOptions}
errors={errors}
register={register}
label={<>{__('Checklist valutazione Pre-Istruttoria', 'gepafin')}*
<span>{__('(almeno 1 elemento)', 'gepafin')}</span></>}
/>
<div className="appPageSection">
<div className="appPageSection__actions">
<Button
type="submit"
label={__('Salva bozza', 'gepafin')} icon="pi pi-save" iconPos="right"/>
<Button
type="button"
onClick={openPreview}
label={__('Anteprima beneficiario', 'gepafin')} icon="pi pi-eye" iconPos="right"/>
<Button
type="button"
onClick={openPreviewEvaluation}
label={__('Anteprima pre-istruttoria', 'gepafin')} icon="pi pi-eye"
iconPos="right"/>
</div>
</div>
</form>
<div className="appPageSection">
<h2>{__('Crea o modifica il Form compilabile dal Beneficiario', 'gepafin')}</h2>
<Button
type="button"
onClick={openBandoFormManagement}
label={__('Crea/modifica form', 'gepafin')}/>
</div>
</>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem"></Skeleton>
</>}
</div>
)
}
export default BandoEdit;

View File

@@ -0,0 +1,34 @@
import React, { useState, useEffect, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { useParams } from 'react-router-dom';
import { Skeleton } from 'primereact/skeleton';
import getBandoLabel from '../../helpers/getBandoLabel';
// components
const BandoEditForms = () => {
const { id } = useParams();
//const [data, setData] = useState({});
//const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const parsed = parseInt(id)
const bandoId = !isNaN(parsed) ? parsed : 0;
// TODO
}, [id]);
return (
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Crea o modifica form per il Bando', 'gepafin')}</h1>
<p>
{__('Scegli come vuoi procedere:', 'gepafin')}
</p>
</div>
</div>
)
}
export default BandoEditForms;

View File

@@ -0,0 +1,97 @@
import React, { useState, useEffect, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { useParams } from 'react-router-dom';
import { Skeleton } from 'primereact/skeleton';
// components
const BandoView = () => {
const { id } = useParams();
const [data, setData] = useState({});
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const parsed = parseInt(id)
const bandoId = !isNaN(parsed) ? parsed : 0;
setTimeout(() => {
const data = {
name: 'Bando Innovazione 2024',
descriptionShort: 'Supporto alle PMI per progetti di digitalizzazione e innovazione tecnologica.',
descriptionLong: 'Il bando "Innovazione Digitale 2024" mira a sostenere le PMI nell\'adozione di tecnologie digitali innovative. I progetti finanziabili includono l\'implementazione di soluzioni di intelligenza artificiale, blockchain, IoT, e altre tecnologie avanzate che possono migliorare la competitività delle imprese.',
dates: [ "2024-08-20T22:00:00.000Z", "2024-08-28T22:00:00.000Z" ],
amount: 10000000,
amountMax: 2000,
aimedTo: [
{ id: 11, value: 'PMI con sede in Umbria' },
{ id: 12, value: 'Almeno 2 anni di attività' },
{ id: 15, value: 'Fatturato annuo non superiore a € 50 milioni' }
],
documentationRequested: 'Some text',
threshold: 12,
criteria: [
{ id: 15, value: 'Innovatività del progetto', score: 9 },
{ id: 16, value: 'Impatto sulla competitività dell\'azienda', score: 3 },
{ id: 17, value: 'Sostenibilità economico-finanziaria', score: 5 }
],
faq: [
{id: 2, question: 'È possibile presentare più di un progetto?', answer: 'No, ogni azienda può presentare un solo progetto per questo bando.'}
],
checklist: [
{ id: 9, value: 'Requisiti di ammissibilità soddisfatti' },
{ id: 21, value: 'Documentazione completa' }
],
docs: [
{id: 12, url: '#', name: 'file_name'}
],
images: [
{id: 15, url: '#', name: 'file_name'}
],
status: 'draft',
id: 11,
created: '2024-08-07T00:00:00+00:00'
}
setData(data);
setIsLoading(false)
}, 3000);
}, [id]);
return (
<div className="appPage">
{!isLoading
? <div className="appPage__pageHeader">
<h1>{data.name}</h1>
<p>
{__('Data:', 'gepafin')}
<span>{data.created}</span>
</p>
</div>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
</>}
<div className="appPage__spacer"></div>
{!isLoading
? <>
<div className="appPageSection">
Preview beneficiario
</div>
</>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
<Skeleton width="100%" height="4rem"></Skeleton>
</>}
</div>
)
}
export default BandoView;

View File

@@ -7,14 +7,19 @@ import ProtectedRoute from './components/ProtectedRoute';
import Dashboard from './pages/Dashboard'; import Dashboard from './pages/Dashboard';
import DefaultLayout from './layouts/DefaultLayout'; import DefaultLayout from './layouts/DefaultLayout';
import Bandi from './pages/Bandi'; import Bandi from './pages/Bandi';
import Bando from './pages/Bando'; import BandoEdit from './pages/BandoEdit';
import BandoView from './pages/BandoView';
import BandoEditForms from './pages/BandoEditForms';
const routes = () => ( const routes = () => (
<Routes> <Routes>
<Route element={<ProtectedRoute/>}> <Route element={<ProtectedRoute/>}>
<Route path="/" element={<DefaultLayout><Dashboard/></DefaultLayout>}/> <Route path="/" element={<DefaultLayout><Dashboard/></DefaultLayout>}/>
<Route path="/bandi" element={<DefaultLayout><Bandi/></DefaultLayout>}/> <Route path="/bandi" element={<DefaultLayout><Bandi/></DefaultLayout>}/>
<Route path="/bandi/:id" element={<DefaultLayout><Bando/></DefaultLayout>}/> <Route path="/bandi/preview/:id" element={<DefaultLayout><BandoView/></DefaultLayout>}/>
<Route path="/bandi/preview-evaluation/:id" element={<DefaultLayout><BandoView/></DefaultLayout>}/>
<Route path="/bandi/:id" element={<DefaultLayout><BandoEdit/></DefaultLayout>}/>
<Route path="/bandi/:id/forms" element={<DefaultLayout><BandoEditForms/></DefaultLayout>}/>
</Route> </Route>
<Route exact path="/login" element={<Login/>}/> <Route exact path="/login" element={<Login/>}/>
{/*<Route exact path="/forgot-password" element={<ForgotPassword/>}/>*/} {/*<Route exact path="/forgot-password" element={<ForgotPassword/>}/>*/}