429 lines
19 KiB
JavaScript
429 lines
19 KiB
JavaScript
import React, { useState, useEffect, useRef } from 'react';
|
|
import { __ } from '@wordpress/i18n';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import { isEmpty } from 'ramda';
|
|
import { wrap } from 'object-path-immutable';
|
|
|
|
// store
|
|
import { storeSet, useStoreValue } from '../../store';
|
|
|
|
// api
|
|
import AmendmentsService from '../../service/amendments-service';
|
|
|
|
// tools
|
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
|
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
|
|
|
|
// components
|
|
import { Skeleton } from 'primereact/skeleton';
|
|
import { Button } from 'primereact/button';
|
|
import { Checkbox } from 'primereact/checkbox';
|
|
import { Editor } from 'primereact/editor';
|
|
import { InputNumber } from 'primereact/inputnumber';
|
|
import BlockingOverlay from '../../components/BlockingOverlay';
|
|
import { Toast } from 'primereact/toast';
|
|
import { InputSwitch } from 'primereact/inputswitch';
|
|
import ApplicationEvaluationService from '../../service/application-evaluation-service';
|
|
import { Dialog } from 'primereact/dialog';
|
|
import { FileUpload } from 'primereact/fileupload';
|
|
import { defaultMaxFileSize, mimeTypes } from '../../configData';
|
|
|
|
const SoccorsoAddInstructorManager = () => {
|
|
const isAsyncRequest = useStoreValue('isAsyncRequest');
|
|
const { id } = useParams();
|
|
const navigate = useNavigate();
|
|
const [data, setData] = useState({});
|
|
const [evaluationId, setEvaluationId] = useState(0);
|
|
const [formData, setFormData] = useState({});
|
|
const [isVisibleConfirmDialog, setIsVisibleConfirmDialog] = useState(false);
|
|
const toast = useRef(null);
|
|
const ammendmentFilesRef = useRef(null);
|
|
|
|
const goToEvaluationPage = () => {
|
|
navigate(`/mie-domande/${id}`);
|
|
}
|
|
|
|
useEffect(() => {
|
|
const parsed = parseInt(id)
|
|
const entityId = !isNaN(parsed) ? parsed : 0;
|
|
|
|
storeSet('setAsyncRequest');
|
|
ApplicationEvaluationService.getEvaluationByApplId(getCallbackEvaluation, errGetCallback, [
|
|
['applicationId', entityId]
|
|
]);
|
|
}, [id]);
|
|
|
|
const getCallbackEvaluation = (data) => {
|
|
if (data.status === 'SUCCESS') {
|
|
setEvaluationId(data.data.id);
|
|
AmendmentsService.getSoccorsoByApplEvalId(data.data.id, getCallback, errGetCallback)
|
|
}
|
|
}
|
|
|
|
const getCallback = (data) => {
|
|
if (data.status === 'SUCCESS') {
|
|
setData(data.data);
|
|
setFormData(getFormattedFormData(data.data));
|
|
}
|
|
storeSet('unsetAsyncRequest');
|
|
}
|
|
|
|
const errGetCallback = (data) => {
|
|
if (toast.current && data.message) {
|
|
toast.current.show({
|
|
severity: 'error',
|
|
summary: '',
|
|
detail: data.message
|
|
});
|
|
}
|
|
set404FromErrorResponse(data);
|
|
storeSet('unsetAsyncRequest');
|
|
}
|
|
|
|
const getFormattedFormData = (data) => {
|
|
let newData = {};
|
|
newData.formFields = data.formFields;
|
|
newData.responseDays = 10;
|
|
newData.note = '';
|
|
newData.isSendNotification = true;
|
|
newData.isSendEmail = true;
|
|
return newData;
|
|
};
|
|
|
|
const renderHeader = () => {
|
|
return (
|
|
<span className="ql-formats">
|
|
<button className="ql-bold" aria-label="Bold"></button>
|
|
<button className="ql-italic" aria-label="Italic"></button>
|
|
<button className="ql-underline" aria-label="Underline"></button>
|
|
<button className="ql-link" aria-label="Link"></button>
|
|
<button className="ql-list" value="ordered"></button>
|
|
<button className="ql-header" value="2"></button>
|
|
<button className="ql-header" value="3"></button>
|
|
<button className="ql-blockquote"></button>
|
|
<button className="ql-list" value="bullet"></button>
|
|
<button className="ql-indent" value="-1"></button>
|
|
<button className="ql-indent" value="+1"></button>
|
|
</span>
|
|
);
|
|
};
|
|
|
|
const header = renderHeader();
|
|
|
|
const updateEvaluationValue = (value, path, maxValue) => {
|
|
let finalValue = value;
|
|
|
|
if (maxValue) {
|
|
finalValue = value > maxValue ? maxValue : value;
|
|
}
|
|
|
|
const newData = wrap(formData).set(path.split('.'), finalValue).value();
|
|
|
|
setFormData(newData);
|
|
}
|
|
|
|
const doCreate = () => {
|
|
storeSet('setAsyncRequest');
|
|
const updatedFormData = { ...formData };
|
|
delete updatedFormData.files;
|
|
delete updatedFormData.formFields;
|
|
|
|
const formDataToSend = new FormData();
|
|
|
|
const jsonBlob = new Blob([JSON.stringify(updatedFormData)], {
|
|
type: 'application/json'
|
|
});
|
|
formDataToSend.append('applicationAmendmentRequest', jsonBlob);
|
|
|
|
if (formData.files && formData.files.length > 0) {
|
|
formData.files.forEach((file) => {
|
|
formDataToSend.append('files', file);
|
|
});
|
|
}
|
|
|
|
AmendmentsService.createSoccorso(formDataToSend, createCallback, errCreateCallback, [
|
|
['applicationEvaluationId', evaluationId]
|
|
]);
|
|
}
|
|
|
|
const createCallback = (data) => {
|
|
if (data.status === 'SUCCESS') {
|
|
if (toast.current) {
|
|
toast.current.show({
|
|
severity: 'success',
|
|
summary: '',
|
|
detail: data.message
|
|
});
|
|
}
|
|
setTimeout(() => {
|
|
navigate(`/mie-domande/${id}/soccorso/${data.data.id}`);
|
|
}, 1000)
|
|
}
|
|
storeSet('unsetAsyncRequest');
|
|
}
|
|
|
|
const errCreateCallback = (data) => {
|
|
if (toast.current && data.message) {
|
|
toast.current.show({
|
|
severity: 'error',
|
|
summary: '',
|
|
detail: data.message
|
|
});
|
|
}
|
|
set404FromErrorResponse(data);
|
|
storeSet('unsetAsyncRequest');
|
|
}
|
|
|
|
const initCreationProcess = () => {
|
|
setIsVisibleConfirmDialog(true);
|
|
}
|
|
|
|
const headerConfirmDialog = () => {
|
|
return <span>{__('Richiesta di conferma', 'gepafin')}</span>;
|
|
}
|
|
|
|
const hideConfirmDialog = () => {
|
|
setIsVisibleConfirmDialog(false);
|
|
}
|
|
|
|
const footerConfirmDialog = () => {
|
|
return <div>
|
|
<Button type="button" label={__('No', 'gepafin')} onClick={goToEvaluationPage} outlined/>
|
|
<Button
|
|
type="button"
|
|
label={__('Si', 'gepafin')} onClick={doConfirm}/>
|
|
</div>
|
|
}
|
|
|
|
const doConfirm = () => {
|
|
setIsVisibleConfirmDialog(false);
|
|
doCreate();
|
|
}
|
|
|
|
return (
|
|
<div className="appPage">
|
|
<div className="appPage__pageHeader">
|
|
<h1>{__('Richiesta Integrazione Documentale', 'gepafin')}</h1>
|
|
</div>
|
|
|
|
<div className="appPage__spacer"></div>
|
|
<Toast ref={toast}/>
|
|
<BlockingOverlay shouldDisplay={isAsyncRequest}/>
|
|
|
|
<div className="appPageSection__row">
|
|
<Button
|
|
type="button"
|
|
outlined
|
|
onClick={goToEvaluationPage}
|
|
label={__('Indietro', 'gepafin')}
|
|
icon="pi pi-arrow-left" iconPos="left"/>
|
|
</div>
|
|
|
|
<div className="appPage__spacer"></div>
|
|
|
|
{!isAsyncRequest && !isEmpty(data)
|
|
? <div className="appPage__content">
|
|
<div className="appPageSection__withBorder column">
|
|
<p className="appPageSection__pMeta">
|
|
<span>{__('ID domanda', 'gepafin')}</span>
|
|
<span>{data.applicationId}</span>
|
|
</p>
|
|
<p className="appPageSection__pMeta">
|
|
<span>{__('Bando', 'gepafin')}</span>
|
|
<span>{data.callName}</span>
|
|
</p>
|
|
<p className="appPageSection__pMeta">
|
|
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
|
<span>{data.beneficiaryName}</span>
|
|
</p>
|
|
</div>
|
|
|
|
<div className="appPageSection">
|
|
<div className="appPageSection columns">
|
|
<div>
|
|
<h3>{__('Pec/Email', 'gepafin')}</h3>
|
|
<div style={{marginBottom: '30px'}} translate="no">
|
|
<Editor
|
|
value={formData.note}
|
|
placeholder={__('Digita qui il messagio', 'gepafin')}
|
|
headerTemplate={header}
|
|
onTextChange={(e) => updateEvaluationValue(
|
|
e.htmlValue,
|
|
'note'
|
|
)}
|
|
style={{ height: 80 * 3, width: '100%' }}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{marginBottom: '30px'}}>
|
|
<div className="appForm__field">
|
|
<label>
|
|
{__('Allegati PEC', 'gepafin')}
|
|
</label>
|
|
<FileUpload
|
|
ref={ammendmentFilesRef}
|
|
name="files[]"
|
|
multiple
|
|
accept={mimeTypes.map(o => o.code).join(',')}
|
|
maxFileSize={defaultMaxFileSize}
|
|
auto={false}
|
|
customUpload={true}
|
|
onSelect={(e) => {
|
|
updateEvaluationValue(e.files, 'files');
|
|
}}
|
|
onRemove={(e) => {
|
|
const updatedFiles = ammendmentFilesRef.current.getFiles();
|
|
updateEvaluationValue(updatedFiles, 'files');
|
|
}}
|
|
headerTemplate={(options) => {
|
|
const { chooseButton } = options;
|
|
return (
|
|
<div className="p-fileupload-buttonbar" data-pc-section="buttonbar">
|
|
{chooseButton}
|
|
</div>
|
|
);
|
|
}}
|
|
chooseOptions={{
|
|
label: __('Aggiungi i file', 'gepafin'),
|
|
icon: 'pi pi-plus'
|
|
}}
|
|
itemTemplate={(file, props) => {
|
|
return(
|
|
<div className="p-fileupload-row" data-pc-section="file">
|
|
<div data-pc-section="details" style={{display: 'flex', flexDirection: 'column', gap: '10px', textAlign: 'left'}}>
|
|
<div className="p-fileupload-filename" data-pc-section="filename">
|
|
{file.name}
|
|
</div>
|
|
<span data-pc-section="filesize">{getFormatedFileSizeText(file.size)}</span>
|
|
</div>
|
|
<div data-pc-section="actions">
|
|
<Button
|
|
type="button"
|
|
icon="pi pi-times"
|
|
className="p-button-rounded p-button-danger p-button-text"
|
|
onClick={() => props.onRemove()}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)
|
|
}}
|
|
emptyTemplate={<p className="m-0">{__('Trascina i file qua')}</p>}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>{__('Tempo per la Risposta (giorni)', 'gepafin')}</h3>
|
|
<div style={{marginBottom: '30px'}}>
|
|
<InputNumber
|
|
keyfilter="int"
|
|
value={formData.responseDays}
|
|
showButtons
|
|
onChange={(e) => updateEvaluationValue(
|
|
e.value,
|
|
'responseDays',
|
|
9999
|
|
)}/>
|
|
</div>
|
|
|
|
<h3>{__('Notifica', 'gepafin')}</h3>
|
|
<div className="appPageSection__withBorder grey">
|
|
<div className="appForm__field row">
|
|
<InputSwitch
|
|
inputId="notify_email"
|
|
checked={formData.isSendEmail}
|
|
onChange={(e) => updateEvaluationValue(
|
|
e.value,
|
|
'isSendEmail'
|
|
)}/>
|
|
<label htmlFor="notify_email">{__('Notifiche Email', 'gepafin')}</label>
|
|
</div>
|
|
<div className="appForm__field row">
|
|
<InputSwitch
|
|
inputId="notify_push"
|
|
checked={formData.isSendNotification}
|
|
onChange={(e) => updateEvaluationValue(
|
|
e.value,
|
|
'isSendNotification'
|
|
)}/>
|
|
<label htmlFor="notify_push">{__('Notifiche Push', 'gepafin')}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{formData.formFields
|
|
? <div>
|
|
<h3>{__('Documenti da Integrare', 'gepafin')}</h3>
|
|
<div className="appPageSection__withBorder grey">
|
|
<div className="appPageSection__checklist">
|
|
{formData.formFields.map((o, i) => <div key={o.fieldId}>
|
|
<Checkbox
|
|
inputId={`checklist_${o.fieldId}`}
|
|
onChange={(e) => updateEvaluationValue(
|
|
e.checked,
|
|
`formFields.${i}.selected`
|
|
)}
|
|
checked={o.selected}></Checkbox>
|
|
<label htmlFor={`checklist_${o.fieldId}`}>{o.label}</label>
|
|
</div>)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
: null}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="appPageSection__message warning">
|
|
<i className="pi pi-exclamation-triangle"></i>
|
|
<span className="summary">{__('Attenzione', 'gepafin')}</span>
|
|
<span>{__('L\'invio della richiesta di integrazione sospenderà il termine di valutazione della domanda.', 'gepafin')}</span>
|
|
</div>
|
|
|
|
<div className="appPageSection__hr">
|
|
<span>{__('Azioni', 'gepafin')}</span>
|
|
</div>
|
|
|
|
<div className="appPageSection">
|
|
<div className="appPageSection__actions">
|
|
<Button
|
|
type="button"
|
|
outlined
|
|
onClick={goToEvaluationPage}
|
|
label={__('Annulla', 'gepafin')}
|
|
icon="pi pi-times" iconPos="right"/>
|
|
<Button
|
|
type="button"
|
|
onClick={initCreationProcess}
|
|
label={__('Invia richiesta', 'gepafin')}
|
|
icon="pi pi-check" iconPos="right"/>
|
|
</div>
|
|
</div>
|
|
|
|
<Dialog
|
|
visible={isVisibleConfirmDialog}
|
|
modal
|
|
header={headerConfirmDialog}
|
|
footer={footerConfirmDialog}
|
|
style={{ maxWidth: '600px', width: '100%' }}
|
|
onHide={hideConfirmDialog}>
|
|
<div className="appForm__field">
|
|
<p>{__('Soccorso istruttorio autorizzato dal direttore e autorizzazione caricata su portale a seguito del quale parte l\'email?', 'gepafin')}</p>
|
|
</div>
|
|
</Dialog>
|
|
|
|
</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 SoccorsoAddInstructorManager;
|