- updated;

This commit is contained in:
Vitalii Kiiko
2026-03-13 18:31:47 +01:00
parent 7200335ace
commit bf18be2b17
4 changed files with 360 additions and 13 deletions

View File

@@ -1302,7 +1302,7 @@ const DomandaEditPreInstructor = () => {
storeSet('setAsyncRequest');
ApplicationEvaluationService.getEvaluationVersionByApplId(entityId, getVersion, errGetVersion);
AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [
['statuses', ['AWAITING', 'RESPONSE_RECEIVED']]
['statuses', ['AWAITING', 'RESPONSE_RECEIVED', 'DRAFT']]
]);
}, [id]);

View File

@@ -66,7 +66,7 @@ const ProfileCompany = () => {
});
const isLegalRepresentant = watch('isLegalRepresentant')
const setEmptyValues = () => {
/*const setEmptyValues = () => {
const formData = {
cap: '',
pec: '',
@@ -77,7 +77,7 @@ const ProfileCompany = () => {
companyName: ''
}
Object.keys(formData).map(k => setValue(k, formData[k]));
}
}*/
const onSubmit = (formData) => {
infoMsgs.current.clear();

View File

@@ -27,10 +27,15 @@ import { Dialog } from 'primereact/dialog';
import FormField from '../../components/FormField';
import { Editor } from 'primereact/editor';
import { InputNumber } from 'primereact/inputnumber';
import { Checkbox } from 'primereact/checkbox';
import { InputSwitch } from 'primereact/inputswitch';
import { FileUpload } from 'primereact/fileupload';
import { Skeleton } from 'primereact/skeleton';
import SoccorsoComunications from './components/SoccorsoComunications';
import SoccorsoResendEmails from './components/SoccorsoResendEmails';
import { amendmentRequestedDocs } from '../../configData';
import { amendmentRequestedDocs, defaultMaxFileSize, mimeTypes } from '../../configData';
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
const SoccorsoEditPreInstructor = () => {
const isAsyncRequest = useStoreValue('isAsyncRequest');
@@ -45,6 +50,9 @@ const SoccorsoEditPreInstructor = () => {
const [internalNote, setInternalNote] = useState('');
const toast = useRef(null);
const [formInitialData, setFormInitialData] = useState({});
const [draftFormData, setDraftFormData] = useState({});
const draftFilesRef = useRef(null);
const [isVisibleDeleteDraftDialog, setIsVisibleDeleteDraftDialog] = useState(false);
const emailSendResponse = pathOr([], ['emailSendResponse'], data);
const {
control,
@@ -67,17 +75,27 @@ const SoccorsoEditPreInstructor = () => {
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setData(getFormattedData(data.data));
let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
if (cur.fieldValue) {
acc[cur.fieldId] = cur.fieldValue;
if (data.data.status === 'DRAFT') {
setDraftFormData({
formFields: data.data.formFields || [],
responseDays: data.data.responseDays || 10,
note: data.data.note || '',
isSendNotification: data.data.isSendNotification ?? true,
isSendEmail: data.data.isSendEmail ?? true,
});
} else {
let formDataInitial = (data.data.applicationFormFields || []).reduce((acc, cur) => {
if (cur.fieldValue) {
acc[cur.fieldId] = cur.fieldValue;
}
return acc;
}, {});
formDataInitial = {
...formDataInitial,
amendmentDocuments: data.data.amendmentDocuments
}
return acc;
}, {});
formDataInitial = {
...formDataInitial,
amendmentDocuments: data.data.amendmentDocuments
setFormInitialData(formDataInitial);
}
setFormInitialData(formDataInitial);
}
storeSet('unsetAsyncRequest');
}
@@ -125,6 +143,99 @@ const SoccorsoEditPreInstructor = () => {
setData(newData);
}
const updateDraftValue = (value, path, maxValue) => {
let finalValue = value;
if (maxValue) {
finalValue = value > maxValue ? maxValue : value;
}
const newData = wrap(draftFormData).set(path.split('.'), finalValue).value();
setDraftFormData(newData);
}
const doSendDraft = () => {
storeSet('setAsyncRequest');
const payload = {
note: draftFormData.note,
responseDays: draftFormData.responseDays,
isSendNotification: draftFormData.isSendNotification,
isSendEmail: draftFormData.isSendEmail,
formFields: draftFormData.formFields,
};
const formDataToSend = new FormData();
const jsonBlob = new Blob([JSON.stringify(payload)], { type: 'application/json' });
formDataToSend.append('applicationAmendmentRequest', jsonBlob);
if (draftFormData.files && draftFormData.files.length > 0) {
draftFormData.files.forEach(file => formDataToSend.append('files', file));
}
AmendmentsService.updateDraftSoccorso(amendmentId, formDataToSend, updateDraftCallback, errUpdateDraftCallback);
};
const updateDraftCallback = (resp) => {
if (resp.status === 'SUCCESS') {
AmendmentsService.updateStatusSoccorso(amendmentId, sendStatusCallback, errSendStatusCallback);
} else {
storeSet('unsetAsyncRequest');
}
};
const sendStatusCallback = (resp) => {
if (resp.status === 'SUCCESS') {
storeSet('setAsyncRequest');
AmendmentsService.getSoccorsoById(getCallback, errGetCallback, [['id', parseInt(amendmentId)]]);
} else {
storeSet('unsetAsyncRequest');
}
};
const errUpdateDraftCallback = (resp) => {
if (toast.current && resp.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: resp.message
});
}
set404FromErrorResponse(resp);
storeSet('unsetAsyncRequest');
};
const errSendStatusCallback = (resp) => {
if (toast.current && resp.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: resp.message
});
}
set404FromErrorResponse(resp);
storeSet('unsetAsyncRequest');
};
const doDeleteDraft = () => {
storeSet('setAsyncRequest');
AmendmentsService.deleteSoccorso(amendmentId, deleteCallback, errDeleteCallback);
};
const deleteCallback = (resp) => {
if (resp.status === 'SUCCESS') {
goToEvaluationPage();
} else {
storeSet('unsetAsyncRequest');
}
};
const errDeleteCallback = (resp) => {
if (toast.current && resp.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: resp.message
});
}
set404FromErrorResponse(resp);
storeSet('unsetAsyncRequest');
};
const onSubmit = () => {
};
@@ -376,6 +487,13 @@ const SoccorsoEditPreInstructor = () => {
AmendmentsService.getSoccorsoById(getCallback, errGetCallback, [['id', soccorsoEntityId]]);
}, [amendmentId]);
useEffect(() => {
if (draftFilesRef.current && data.status === 'DRAFT') {
const existingFiles = data.amendmentInitialDocuments || data.amendmentInitialDocument || [];
draftFilesRef.current.setUploadedFiles(is(Array, existingFiles) ? existingFiles : []);
}
}, [data]);
return (
<div className="appPage">
<div className="appPage__pageHeader">
@@ -398,6 +516,203 @@ const SoccorsoEditPreInstructor = () => {
<div className="appPage__spacer"></div>
<div className="appPage__content">
{!isAsyncRequest && !isEmpty(data) && data.status === 'DRAFT'
? <>
<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={draftFormData.note}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateDraftValue(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={draftFilesRef}
name="files[]"
multiple
accept={mimeTypes.map(o => o.code).join(',')}
maxFileSize={defaultMaxFileSize}
auto={false}
customUpload={true}
onSelect={(e) => {
updateDraftValue(e.files, 'files');
}}
onRemove={() => {
const updatedFiles = draftFilesRef.current.getFiles();
updateDraftValue(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) => {
if (file.id) {
return (
<div className="p-fileupload-row" data-pc-section="file">
<div data-pc-section="details"
style={{
display: 'flex',
flexDirection: 'column',
gap: '10px',
textAlign: 'left'
}}>
<a className="p-fileupload-filename"
href={file.filePath}
target="_blank"
rel="noreferrer">
{file.name}
</a>
</div>
</div>
);
}
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={draftFormData.responseDays}
showButtons
onChange={(e) => updateDraftValue(e.value, 'responseDays', 9999)}/>
</div>
<h3>{__('Notifica', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey">
<div className="appForm__field row">
<InputSwitch
inputId="draft_notify_email"
checked={draftFormData.isSendEmail}
onChange={(e) => updateDraftValue(e.value, 'isSendEmail')}/>
<label
htmlFor="draft_notify_email">{__('Notifiche Email', 'gepafin')}</label>
</div>
<div className="appForm__field row">
<InputSwitch
inputId="draft_notify_push"
checked={draftFormData.isSendNotification}
onChange={(e) => updateDraftValue(e.value, 'isSendNotification')}/>
<label
htmlFor="draft_notify_push">{__('Notifiche Push', 'gepafin')}</label>
</div>
</div>
</div>
{draftFormData.formFields && !isEmpty(draftFormData.formFields)
? <div>
<h3>{__('Documenti da Integrare', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey">
<div className="appPageSection__checklist">
{draftFormData.formFields.map((o, i) => <div key={o.fieldId}>
<Checkbox
inputId={`draft_checklist_${o.fieldId}`}
onChange={(e) => updateDraftValue(
e.checked,
`formFields.${i}.selected`
)}
checked={o.selected}/>
<label
htmlFor={`draft_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={() => setIsVisibleDeleteDraftDialog(true)}
label={__('Annulla', 'gepafin')}
icon="pi pi-times" iconPos="right"/>
<Button
type="button"
onClick={doSendDraft}
disabled={isAsyncRequest}
label={__('Invia richiesta', 'gepafin')}
icon="pi pi-check" iconPos="right"/>
</div>
</div>
</>
: !isAsyncRequest && !isEmpty(data)
? <>
<div className="appPageSection__withBorder columns">
<p className="appPageSection__pMeta">
<span>{__('ID domanda', 'gepafin')}</span>
@@ -573,6 +888,17 @@ const SoccorsoEditPreInstructor = () => {
setDataEmailsSoccorso={updateEmailSendResponses}/>
</div>
</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>
@@ -619,6 +945,19 @@ const SoccorsoEditPreInstructor = () => {
</div>
</div>
</Dialog>
<Dialog
visible={isVisibleDeleteDraftDialog}
modal
header={<span>{__('Elimina bozza', 'gepafin')}</span>}
footer={<div>
<Button type="button" label={__('No', 'gepafin')} onClick={() => setIsVisibleDeleteDraftDialog(false)} outlined/>
<Button type="button" label={__('Sì, elimina', 'gepafin')} onClick={doDeleteDraft} severity="danger"/>
</div>}
style={{ maxWidth: '500px', width: '100%' }}
onHide={() => setIsVisibleDeleteDraftDialog(false)}>
<p>{__('Sei sicuro di voler eliminare questa bozza? L\'operazione non può essere annullata.', 'gepafin')}</p>
</Dialog>
</div>
)

View File

@@ -32,6 +32,14 @@ export default class AmendmentsService {
NetworkService.put(`${API_BASE_URL}/amendments/${id}`, body, callback, errCallback, queryParams);
};
static updateDraftSoccorso = (id, body, callback, errCallback, queryParams) => {
NetworkService.putMultiPart(`${API_BASE_URL}/amendments/${id}`, body, callback, errCallback, queryParams);
};
static deleteSoccorso = (id, callback, errCallback) => {
NetworkService.delete(`${API_BASE_URL}/amendments/${id}`, {}, callback, errCallback);
};
static updateStatusSoccorso = (id, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/amendments/${id}/status`, {}, callback, errCallback, queryParams);
};