- contract functionality;

This commit is contained in:
Vitalii Kiiko
2025-11-06 09:19:55 +01:00
parent be190b9c99
commit b929f4def1
12 changed files with 1118 additions and 13 deletions

View File

@@ -15,6 +15,7 @@ import { storeGet, storeSet, useStoreValue } from '../../store';
import ApplicationEvaluationService from '../../service/application-evaluation-service';
import AmendmentsService from '../../service/amendments-service';
import AppointmentService from '../../service/appointment-service';
import ApplicationContractService from '../../service/application-contract-service';
// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
@@ -99,6 +100,12 @@ const DomandaEditPreInstructor = () => {
duration: 0,
amount: 0
});
const [isVisibleContractForm, setIsVisibleContractForm] = useState(false);
const [contractFormData, setContractFormData] = useState({
subject: '',
text: ''
});
const contractFormFilesRef = useRef(null);
const [formData, setFormData] = useState([]);
const [formId, setFormId] = useState(0);
const [formInitialData, setFormInitialData] = useState(null);
@@ -1001,6 +1008,102 @@ const DomandaEditPreInstructor = () => {
setData(newData);
}, [data]);
const openSendContractForm = () => {
setIsVisibleContractForm(true);
}
const headerContractDialog = () => {
return <span>{__('Invia il contratto', 'gepafin')}</span>;
}
const hideContractDialog = () => {
setIsVisibleContractForm(false);
setContractFormData({
subject: '',
text: ''
});
}
const footerContractDialog = useCallback(() => {
let isDisabled = !contractFormData.subject || isEmpty(contractFormData.subject)
|| !contractFormData.text || isEmpty(contractFormData.text)
|| !contractFormData.files || isEmpty(contractFormData.files) || isAsyncRequest;
return <div>
<Button type="button" label={__('Annulla', 'gepafin')} onClick={hideContractDialog} outlined/>
<Button
type="button"
disabled={isDisabled}
label={__('Invia', 'gepafin')} onClick={doSendContract}/>
</div>
}, [contractFormData]);
const updateContractFormData = (value, path) => {
const newData = wrap(contractFormData).set(path.split('.'), value).value();
setContractFormData(newData);
};
const doSendContract = useCallback(() => {
if (
contractFormData.subject && !isEmpty(contractFormData.subject)
&& contractFormData.text && !isEmpty(contractFormData.text)
&& contractFormData.files && !isEmpty(contractFormData.files)
) {
const formDataToSend = new FormData();
const contractFormDataTemp = {
...contractFormData
};
delete contractFormDataTemp.files;
const jsonBlob = new Blob([JSON.stringify(contractFormDataTemp)], {
type: 'application/json'
});
formDataToSend.append('applicationContractRequest', jsonBlob);
if (contractFormData.files && contractFormData.files.length > 0) {
contractFormData.files.forEach((file) => {
formDataToSend.append('contractDocuments', file);
});
}
storeSet('setAsyncRequest');
ApplicationContractService.uploadApplicationContract(
data.applicationId,
formDataToSend,
getUploadApplicationContractCallback,
errGetUploadApplicationContractCallback
);
}
}, [contractFormData]);
const getUploadApplicationContractCallback = (data) => {
if (data.status === 'SUCCESS') {
//setData(getFormattedData(data.data));
if (toast.current && data.message) {
toast.current.show({
severity: 'success',
summary: '',
detail: data.message
});
}
}
hideContractDialog();
storeSet('unsetAsyncRequest');
}
const errGetUploadApplicationContractCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: data.status === 'SUCCESS' ? 'info' : 'error',
summary: '',
detail: data.message
});
}
hideContractDialog();
set404FromErrorResponse(data);
storeSet('unsetAsyncRequest');
}
const actionBtns = () => {
return <div className="appPageSection__actions">
{(['SOCCORSO', 'CLOSE', 'EVALUATION', 'NDG', 'APPOINTMENT', 'ADMISSIBLE',
@@ -1136,6 +1239,13 @@ const DomandaEditPreInstructor = () => {
onClick={initiateRejecting}
label={__('Respingi domanda', 'gepafin')}
icon="pi pi-times" iconPos="right"/> : null}
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' && data.applicationStatus === 'APPROVED'
? <Button
type="button"
disabled={!data.id}
onClick={openSendContractForm}
label={__('Invia il contratto', 'gepafin')}
/> : null}
</div>
}
@@ -1330,6 +1440,48 @@ const DomandaEditPreInstructor = () => {
{data.evaluationVersion === 'V2'
? <div className="appPageSection">
<h3>{__('Contratto', 'gepafin')}</h3>
{data.contract && data.contract?.beneficiaryDocuments && !isEmpty(data.contract?.beneficiaryDocuments)
? <ol className="appPageSection__list">
{data.contract?.beneficiaryDocuments.map(o => <li key={o.id} className="appPageSection__listItem">
<div className="appPageSection__listItemRow">
<div>{renderHtmlContent(o.name)}</div>
<div className="appPageSection__iconActions">
<Button icon="pi pi-eye" rounded
onClick={() => {
window.open(o.fileDetail[0].filePath, '_blank').focus()
}}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/>
<ArchiveDocument
ndg={data.ndg}
applicationId={id}
fileDescr={renderHtmlContent(o.name)}
fileId={o.id}
updateFn={(attachId) => {
setData((prev) => {
const newDocuments = data.contract.beneficiaryDocuments
.map(ob => {
return ob.id === o.id
? {...o, documentAttachmentId: attachId}
: o;
});
return {
...prev,
contract: {
...prev.contract,
beneficiaryDocuments: newDocuments
}
}
});
}}
isSignedDocument={true}
docAttachmentId={o.documentAttachmentId}/>
</div>
</div>
</li>)}
</ol>
: <p>{__('Nessun documento firmato', 'gepafin')}</p>}
<h2>{__('Domanda PDF firmato', 'gepafin')}</h2>
{data.signedDocument && !isEmpty(data.signedDocument)
? <ol className="appPageSection__list">
@@ -1345,7 +1497,10 @@ const DomandaEditPreInstructor = () => {
updateFn={(attachId) => {
setData((prev) => ({
...prev,
documentAttachmentId: attachId
signedDocument: {
...prev.signedDocument,
documentAttachmentId: attachId
}
}));
}}
isSignedDocument={true}
@@ -1467,6 +1622,48 @@ const DomandaEditPreInstructor = () => {
</div>
</div>
<div>
<h3>{__('Contratto', 'gepafin')}</h3>
{data.contract && data.contract?.beneficiaryDocuments && !isEmpty(data.contract?.beneficiaryDocuments)
? <ol className="appPageSection__list">
{data.contract?.beneficiaryDocuments.map(o => <li key={o.id} className="appPageSection__listItem">
<div className="appPageSection__listItemRow">
<div>{renderHtmlContent(o.name)}</div>
<div className="appPageSection__iconActions">
<Button icon="pi pi-eye" rounded
onClick={() => {
window.open(o.fileDetail[0].filePath, '_blank').focus()
}}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/>
<ArchiveDocument
ndg={data.ndg}
applicationId={id}
fileDescr={renderHtmlContent(o.name)}
fileId={o.id}
updateFn={(attachId) => {
setData((prev) => {
const newDocuments = data.contract.beneficiaryDocuments
.map(ob => {
return ob.id === o.id
? {...o, documentAttachmentId: attachId}
: o;
});
return {
...prev,
contract: {
...prev.contract,
beneficiaryDocuments: newDocuments
}
}
});
}}
isSignedDocument={true}
docAttachmentId={o.documentAttachmentId}/>
</div>
</div>
</li>)}
</ol>
: <p>{__('Nessun documento firmato', 'gepafin')}</p>}
<h3>{__('Domanda PDF firmato', 'gepafin')}</h3>
{data.signedDocument && !isEmpty(data.signedDocument)
? <ol className="appPageSection__list">
@@ -1474,6 +1671,12 @@ const DomandaEditPreInstructor = () => {
<div className="appPageSection__listItemRow">
<div>{renderHtmlContent(data.signedDocument.fileName)}</div>
<div className="appPageSection__iconActions">
<Button icon="pi pi-eye" rounded
onClick={() => {
window.open(data.signedDocument.filePath, '_blank').focus()
}}
outlined severity="info"
aria-label={__('Mostra', 'gepafin')}/>
<ArchiveDocument
ndg={data.ndg}
applicationId={id}
@@ -1482,7 +1685,10 @@ const DomandaEditPreInstructor = () => {
updateFn={(attachId) => {
setData((prev) => ({
...prev,
documentAttachmentId: attachId
signedDocument: {
...prev.signedDocument,
documentAttachmentId: attachId
}
}));
}}
isSignedDocument={true}
@@ -1825,6 +2031,102 @@ const DomandaEditPreInstructor = () => {
</div>
</Dialog>
<Dialog
visible={isVisibleContractForm}
modal
header={headerContractDialog}
footer={footerContractDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideContractDialog}>
<div className="appForm__field">
<label
className={classNames({ 'p-error': !contractFormData.subject || isEmpty(contractFormData.subject) })}>
{__('Oggetto', 'gepafin')}*
</label>
<InputText
value={contractFormData.subject}
invalid={isEmpty(contractFormData.subject)}
onChange={(e) => updateContractFormData(e.target.value, 'subject')}/>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': !contractFormData.text || isEmpty(contractFormData.text) })}>
{__('Testo', 'gepafin')}*
</label>
<div translate="no">
<Editor
value={contractFormData.text}
readOnly={loading}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateContractFormData(e.htmlValue, 'text')}
style={{ height: 80 * 3, width: '100%' }}
/>
</div>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': !contractFormData.files || isEmpty(contractFormData.files) })}>
{__('Files', 'gepafin')}*
</label>
<FileUpload
ref={contractFormFilesRef}
name="files[]"
multiple
accept={mimeTypes.map(o => o.code).join(',')}
maxFileSize={defaultMaxFileSize}
auto={false}
customUpload={true}
className={classNames({ 'p-invalid': !contractFormData.files || isEmpty(contractFormData.files) })}
onSelect={(e) => {
updateContractFormData(e.files, 'files');
}}
onRemove={(e) => {
const updatedFiles = contractFormFilesRef.current.getFiles();
updateContractFormData(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>
</Dialog>
</div>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>