dquote> - updated registartion page, added gdpr and marketing checkboxes;

dquote> - fixed number input;
dquote> - updated latest submissions table component;
This commit is contained in:
Vitalii Kiiko
2024-10-07 11:06:35 +02:00
parent c687bec8d5
commit ad42ed6326
9 changed files with 254 additions and 78 deletions

View File

@@ -9,12 +9,20 @@
flex-direction: column;
align-items: center;
width: 100%;
max-width: 540px;
max-width: 600px;
padding: 24px;
.appForm {
width: 100%;
}
.p-panel-content {
font-size: 14px;
.appForm__col {
gap: 1em;
}
}
}
.appPageLogin__spidBtn.appPageLogin__spidBtn {
@@ -38,3 +46,17 @@
line-height: 15px;
}
}
.reverseSwitchField {
gap: 1em;
.appForm__field.switch {
width: auto;
> .appForm__row {
display: flex;
justify-content: flex-end;
flex-direction: row-reverse;
}
}
}

View File

@@ -91,7 +91,7 @@
padding: 0.5rem;
}
.p-message-detail, .p-progressbar-label {
.p-message-detail.p-message-detail, .p-progressbar-label.p-progressbar-label {
color: white;
}

View File

@@ -22,7 +22,6 @@ const NumberInput = ({
disabled = false,
useGrouping = false
}) => {
console.log('defaultValue', defaultValue);
const input = <Controller
name={fieldName}
control={control}

View File

@@ -1,9 +1,10 @@
export const mimeTypes = [
{ name: 'PDF', code: 'application/pdf' },
{ name: 'Firmato PDF o Word', code: 'application/pkcs7-mime' },
{ name: 'ZIP', code: 'application/zip' },
{ name: 'Immagine', code: 'image/*' },
{
name: 'Word doc',
name: 'Word',
code: 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'
},
{ name: 'Excel doc', code: 'application/vnd.ms-excel' }

View File

@@ -2,6 +2,9 @@ import { __ } from '@wordpress/i18n';
const getBandoLabel = (status) => {
switch (status) {
case 'SUBMIT':
return __('Inviato', 'gepafin');
case 'PUBLISH':
return __('Pubblicato', 'gepafin');

View File

@@ -1,5 +1,10 @@
import { __ } from '@wordpress/i18n';
const getBandoSeverity = (status) => {
switch (status) {
case 'SUBMIT':
return 'success';
case 'PUBLISH':
return 'success';

View File

@@ -42,6 +42,7 @@ const BandoApplication = () => {
const [formId, setFormId] = useState('');
const [totalSteps, setTotalSteps] = useState(0);
const [completedSteps, setCompletedSteps] = useState(0);
const [applicationStatus, setApplicationStatus] = useState('');
const [activeStep, setActiveStep] = useState(1);
const isAsyncRequest = useStore().main.isAsyncRequest();
const toast = useRef(null);
@@ -86,6 +87,9 @@ const BandoApplication = () => {
detail: __('La domanda è stata presentata!', 'gepafin')
});
}
if (data.data.applicationStatus) {
setApplicationStatus(data.data.applicationStatus);
}
}
storeSet.main.unsetAsyncRequest();
}
@@ -126,24 +130,24 @@ const BandoApplication = () => {
const newFormValues = Object.keys(formValues)
.filter(v => usedFieldsIds.includes(v))
.reduce((acc, cur) => {
const formField = head(formData.filter(o => o.id === cur));
let fieldVal = formValues[cur];
const formField = head(formData.filter(o => o.id === cur));
let fieldVal = formValues[cur];
if (formValues[cur] && formValues[cur].toISOString) {
const tzAwareDate = new TZDate(formValues[cur], 'Europe/Berlin');
fieldVal = tzAwareDate.toISOString().substring(0, 19);
}
if (formValues[cur] && formValues[cur].toISOString) {
const tzAwareDate = new TZDate(formValues[cur], 'Europe/Berlin');
fieldVal = tzAwareDate.toISOString().substring(0, 19);
}
fieldVal = !fieldVal ? null : fieldVal;
if (formField && formField.name === 'fileupload') {
fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : fieldVal;
}
acc.push({
'fieldId': cur,
'fieldValue': fieldVal
});
return acc;
}, []);
fieldVal = !fieldVal ? null : fieldVal;
if (formField && formField.name === 'fileupload') {
fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : fieldVal;
}
acc.push({
'fieldId': cur,
'fieldValue': fieldVal
});
return acc;
}, []);
const submitData = {
formFields: newFormValues
}
@@ -167,7 +171,8 @@ const BandoApplication = () => {
return !isNaN(parsed) ? parsed : 0;
}
const saveDraftCallback = (data, saveAndMove) => {
const saveDraftCallback = (data, saveAndMove = '') => {
storeSet.main.unsetAsyncRequest();
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
@@ -176,18 +181,16 @@ const BandoApplication = () => {
detail: __('Salvato!', 'gepafin')
});
}
if (!isEmpty(saveAndMove)) {
if (!isEmpty(saveAndMove) && is(String, saveAndMove)) {
storeSet.main.setAsyncRequest();
ApplicationService.getApplicationForm(data.data.id, getApplFormCallback, errGetApplFormCallbacks, [
['formId', formId],
['action', saveAndMove]
]);
} else {
// update info about application completeness
ApplicationService.getApplicationForm(data.data.id, getStatusCheckCallback, errGetStatusCheckCallbacks);
}
}
storeSet.main.unsetAsyncRequest();
}
const errSaveDraftCallback = (data) => {
@@ -221,26 +224,10 @@ const BandoApplication = () => {
const goBackward = () => {
saveDraft('PREVIOUS');
/*if (formId) {
const applId = getApplicationId();
storeSet.main.setAsyncRequest();
ApplicationService.getApplicationForm(applId, getApplFormCallback, errGetApplFormCallbacks, [
['formId', formId],
['action', 'PREVIOUS']
]);
}*/
}
const goForward = () => {
saveDraft('NEXT');
/*if (formId) {
const applId = getApplicationId();
storeSet.main.setAsyncRequest();
ApplicationService.getApplicationForm(applId, getApplFormCallback, errGetApplFormCallbacks, [
['formId', formId],
['action', 'NEXT']
]);
}*/
}
const getApplFormCallback = (data) => {
@@ -250,6 +237,7 @@ const BandoApplication = () => {
setFormId(data.data.formId);
setTotalSteps(data.data.totalFormSteps);
setCompletedSteps(data.data.completedSteps);
setApplicationStatus(data.data.applicationStatus)
setActiveStep(data.data.currentStep);
if (data.data.applicationFormResponse.formFields) {
@@ -361,24 +349,24 @@ const BandoApplication = () => {
return ['paragraph'].includes(o.name) && text
? <div className="appForm__content" key={o.id}>{renderHtmlContent(text.value)}</div>
: <FormField
key={o.id}
type={o.name}
fieldName={o.id}
label={label ? label.value : ''}
placeholder={placeholder ? placeholder.value : ''}
control={control}
register={register}
errors={errors}
defaultValue={values[o.id]}
maxFractionDigits={step ? step.value : 0}
accept={mimeValue}
config={validations}
options={options ? options.value : []}
setDataFn={setValue}
sourceId={getApplicationId()}
useGrouping={false}
tableColumns={tableColumns ? tableColumns.value : {}}
/>
key={o.id}
type={o.name}
fieldName={o.id}
label={label ? label.value : ''}
placeholder={placeholder ? placeholder.value : ''}
control={control}
register={register}
errors={errors}
defaultValue={values[o.id]}
maxFractionDigits={step ? step.value : 0}
accept={mimeValue}
config={validations}
options={options ? options.value : []}
setDataFn={setValue}
sourceId={getApplicationId()}
useGrouping={false}
tableColumns={tableColumns ? tableColumns.value : {}}
/>
})}
<div className="appPage__spacer"></div>
@@ -392,26 +380,28 @@ const BandoApplication = () => {
{activeStep > 1 && activeStep <= totalSteps
? <Button
type="button"
disabled={'SUBMIT' === applicationStatus}
onClick={goBackward}
label={__('Vai indietro', 'gepafin')}
icon="pi pi-arrow-left"
iconPos="left"/> : null}
<Button
type="button"
disabled={isAsyncRequest}
disabled={isAsyncRequest || 'SUBMIT' === applicationStatus}
onClick={saveDraft}
outlined
label={__('Salva bozza', 'gepafin')} icon="pi pi-save" iconPos="right"/>
{activeStep < totalSteps
//&& activeStep === completedSteps
//&& activeStep === completedSteps
? <Button
type="button"
disabled={'SUBMIT' === applicationStatus}
onClick={goForward}
label={__('Vai avanti', 'gepafin')}
icon="pi pi-arrow-right"
iconPos="right"/> : null}
<Button
disabled={completedSteps === 0 || completedSteps !== totalSteps}
disabled={completedSteps === 0 || completedSteps !== totalSteps || 'SUBMIT' === applicationStatus}
label={__('Invia', 'gepafin')}
icon="pi pi-check"
iconPos="right"/>

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect} from 'react';
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { uniq } from 'ramda';
@@ -39,7 +39,7 @@ const MyLatestSubmissionsTable = () => {
const getApplCallback = (data) => {
if (data.status === 'SUCCESS') {
if(data.data.length) {
if (data.data.length) {
setItems(getFormattedBandiData(data.data));
setStatuses(uniq(items.map(o => o.status)))
initFilters();
@@ -87,9 +87,18 @@ const MyLatestSubmissionsTable = () => {
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
callTitle: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
modifiedDate: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
callEndDate: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
callTitle: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
},
modifiedDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
callEndDate: {
operator: FilterOperator.AND,
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
},
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
});
setGlobalFilterValue('');
@@ -98,10 +107,12 @@ const MyLatestSubmissionsTable = () => {
const renderHeader = () => {
return (
<div className="appTableHeader">
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
onClick={clearFilter}/>
<IconField iconPosition="left">
<InputIcon className="pi pi-search" />
<InputText value={globalFilterValue} onChange={onGlobalFilterChange} placeholder={__('Cerca', 'gepafin')} />
<InputIcon className="pi pi-search"/>
<InputText value={globalFilterValue} onChange={onGlobalFilterChange}
placeholder={__('Cerca', 'gepafin')}/>
</IconField>
</div>
);
@@ -116,7 +127,8 @@ const MyLatestSubmissionsTable = () => {
};
const dateFilterTemplate = (options) => {
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)}
dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999"/>;
};
const statusBodyTemplate = (rowData) => {
@@ -124,7 +136,10 @@ const MyLatestSubmissionsTable = () => {
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder="Select One" className="p-column-filter" showClear />;
return <Dropdown value={options.value} options={statuses}
onChange={(e) => options.filterCallback(e.value, options.index)}
itemTemplate={statusItemTemplate} placeholder="Select One" className="p-column-filter"
showClear/>;
};
const progressBodyTemplate = (options) => {
@@ -132,18 +147,20 @@ const MyLatestSubmissionsTable = () => {
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
const actionsBodyTemplate = (rowData) => {
return <Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small" iconPos="right" />
</Link>
return 'DRAFT' === rowData.status
? <Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
iconPos="right"/>
</Link> : null
}
const header = renderHeader();
return(
return (
<div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={isAsyncRequest} dataKey="id"
filters={filters}

View File

@@ -9,7 +9,7 @@ import { useSearchParams } from 'react-router-dom';
import AuthenticationService from '../../service/authentication-service';
// tools
import { isCodiceFiscale, isEmail } from '../../helpers/validators';
import { isEmail } from '../../helpers/validators';
// store
import { storeSet, useStore } from '../../store';
@@ -19,6 +19,7 @@ import FormField from '../../components/FormField';
import LogoIcon from '../../icons/LogoIcon';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
import { Panel } from 'primereact/panel';
const Registration = () => {
const token = useStore().main.token();
@@ -29,8 +30,10 @@ const Registration = () => {
control,
handleSubmit,
formState: { errors },
setValue
setValue,
getValues
} = useForm({ mode: 'onChange' });
const values = getValues();
const onSubmit = (formData) => {
errorMsgs.current.clear();
@@ -100,6 +103,18 @@ const Registration = () => {
setLoading(false);
}
const disableAllChecks = () => {
setValue('marketing1', false);
setValue('marketing2', false);
setValue('marketing3', false);
}
const enableAllChecks = () => {
setValue('marketing1', true);
setValue('marketing2', true);
setValue('marketing3', true);
}
useEffect(() => {
if (!isEmpty(token)) {
setLoading(true);
@@ -207,6 +222,130 @@ const Registration = () => {
/>
</div>
<Panel
headerTemplate={(options) => {
return (
<div className={classNames(['p-panel-header', 'reverseSwitchField'])}>
<FormField
type="switch"
fieldName="privacy"
label={__('Ho letto e accetto lInformativa sulla Privacy (Necessario)', 'gepafin')}
control={control}
errors={errors}
defaultValue={values['privacy']}
onLabel={''}
offLabel={''}
config={{
required: __('È obbligatorio', 'gepafin'),
}}
/>
<div>
{options.togglerElement}
</div>
</div>
);
}}
toggleable>
<p className="m-0">
{__('Dichiaro di aver preso visione, prima dell\'accesso al portale https://bandi.gepafin.it, dell\' "Informativa Privacy" all\'interno dell\'Appendice 10 dell\'Avviso secondo il Regolamento UE 2016/679 relativo alla protezione delle persone fisiche con riguardo al trattamento dei dati personale, nonché alla libera circolazione di tali dati e che abroga la Direttiva 95/46 CE.', 'gepafin')}
</p>
</Panel>
<Panel
headerTemplate={(options) => {
return (
<div className={classNames(['p-panel-header', 'reverseSwitchField'])}>
<FormField
type="switch"
fieldName="terms"
label={__('Ho letto e accetto Termini e condizioni (Necessario)', 'gepafin')}
control={control}
errors={errors}
defaultValue={values['terms']}
onLabel={''}
offLabel={''}
config={{
required: __('È obbligatorio', 'gepafin'),
}}
/>
<div>
{options.togglerElement}
</div>
</div>
);
}}
toggleable>
<p className="m-0">
{__('Termini e condizioni', 'gepafin')}
</p>
</Panel>
<Panel
header={__('Altri consensi (facoltativo)', 'gepafin')}
toggleable>
<div className="appForm__col">
<div className={classNames(['appForm__row', 'reverseSwitchField'])}>
<FormField
type="switch"
fieldName="marketing"
label={''}
control={control}
errors={errors}
defaultValue={values['marketing']}
onLabel={''}
offLabel={''}
/>
<div>
{__('Invio di materiale pubblicitario, vendita diretta, compimento di ricerche di mercato o comunicazione commerciale riguardanti promozione e vendita di prodotti e servizi della Gepafin, mediante modalità di contatto automatizzate (posta elettronica, PEC, messaggi tramite canali informatici, network ed applicazioni web) e tradizionali (come posta cartacea e chiamate telefoniche con operatore)', 'gepafin')}
</div>
</div>
<div className={classNames(['appForm__row', 'reverseSwitchField'])}>
<FormField
type="switch"
fieldName="offers"
label={''}
control={control}
errors={errors}
defaultValue={values['offers']}
onLabel={''}
offLabel={''}
/>
<div>
{__('Elaborazione, in forma elettronica, dei dati relativi ai rapporti e servizi forniti, per lanalisi di comportamenti e preferenze della clientela, da utilizzare a scopo commerciale, per la individuazione ed offerta di prodotti e servizi di suo interesse', 'gepafin')}
</div>
</div>
<div className={classNames(['appForm__row', 'reverseSwitchField'])}>
<FormField
type="switch"
fieldName="thirdparty"
label={''}
control={control}
errors={errors}
defaultValue={values['thirdparty']}
onLabel={''}
offLabel={''}
/>
<div>
{__('Comunicazione dei miei dati ad altre società in ambito bancario, finanziario od assicurativo e enti pubblici che li tratteranno per invio di materiale pubblicitario, vendita diretta, compimento di ricerche di mercato o comunicazione commerciale riguardanti loro prodotti o servizi, mediante le modalità automatizzate e tradizionali di comunicazione sopra indicate', 'gepafin')}
</div>
</div>
<div className="appForm__cols">
<Button
type="button"
severity="info"
onClick={disableAllChecks}
outlined
label={__('Nega tutti', 'gepafin')}/>
<Button
type="button"
severity="info"
onClick={enableAllChecks}
label={__('Attiva tutti', 'gepafin')}/>
</div>
</div>
</Panel>
<Button
label={__('Accedi', 'gepafin')}
disabled={loading}/>