- update to contract functionality;

This commit is contained in:
Vitalii Kiiko
2025-11-10 12:00:44 +01:00
parent afaa750f43
commit 31413399b0
4 changed files with 210 additions and 474 deletions

View File

@@ -1,49 +1,29 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import { head, isEmpty, pathOr } from 'ramda'; import { head, isEmpty, pathOr } from 'ramda';
import NumberFlow from '@number-flow/react'; import NumberFlow from '@number-flow/react';
import { wrap } from 'object-path-immutable';
// store // store
import { storeGet, storeSet, useStoreValue } from '../../store'; import { storeGet, useStoreValue } from '../../store';
// api // api
import DashboardService from '../../service/dashboard-service'; import DashboardService from '../../service/dashboard-service';
import ApplicationContractService from '../../service/application-contract-service';
// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
// components // components
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import ErrorBoundary from '../../components/ErrorBoundary'; import ErrorBoundary from '../../components/ErrorBoundary';
import LatestBandiBeneficiarioTableAsync from './components/LatestBandiBeneficiarioTableAsync'; import LatestBandiBeneficiarioTableAsync from './components/LatestBandiBeneficiarioTableAsync';
import MyLatestSubmissionsTableAsync from './components/MyLatestSubmissionsTableAsync'; import MyLatestSubmissionsTableAsync from './components/MyLatestSubmissionsTableAsync';
import { classNames } from 'primereact/utils';
import { FileUpload } from 'primereact/fileupload';
import { defaultMaxFileSize, mimeTypes } from '../../configData';
import { Dialog } from 'primereact/dialog';
import { Toast } from 'primereact/toast';
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID; const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const DashboardBeneficiario = () => { const DashboardBeneficiario = () => {
const isAsyncRequest = useStoreValue('isAsyncRequest');
const navigate = useNavigate(); const navigate = useNavigate();
const [mainStats, setMainStats] = useState({}); const [mainStats, setMainStats] = useState({});
const [contractsData, setContractsData] = useState([]);
const companies = useStoreValue('companies'); const companies = useStoreValue('companies');
const chosenCompanyId = useStoreValue('chosenCompanyId'); const chosenCompanyId = useStoreValue('chosenCompanyId');
const company = head(companies.filter(o => o.id === chosenCompanyId)); const company = head(companies.filter(o => o.id === chosenCompanyId));
const [isVisibleContractForm, setIsVisibleContractForm] = useState(false);
const [contractFormData, setContractFormData] = useState({
subject: '',
text: ''
});
const contractFormFilesRef = useRef(null);
const toast = useRef(null);
const goToAllSubmissions = () => { const goToAllSubmissions = () => {
navigate('/bandi'); navigate('/bandi');
@@ -62,112 +42,12 @@ const DashboardBeneficiario = () => {
const errGetStats = () => { const errGetStats = () => {
} }
const getContracts = (data) => {
if (data.status === 'SUCCESS') {
setContractsData(data.data);
}
}
const errGetContracts = () => {
}
const openSendContractForm = useCallback((id) => {
const contract = head(contractsData.filter(o => o.id === id));
if (contract) {
setContractFormData(contract)
setIsVisibleContractForm(true);
}
}, [contractsData]);
const headerContractDialog = () => {
return <span>{__('Invia il contratto', 'gepafin')}</span>;
}
const hideContractDialog = () => {
setIsVisibleContractForm(false);
setContractFormData({
subject: '',
text: ''
});
}
const footerContractDialog = useCallback(() => {
let isDisabled = !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.files && !isEmpty(contractFormData.files) && !isAsyncRequest) {
const formDataToSend = new FormData();
if (contractFormData.files && contractFormData.files.length > 0) {
contractFormData.files.forEach((file) => {
formDataToSend.append('beneficiaryContractDocuments', file);
});
}
storeSet('setAsyncRequest');
ApplicationContractService.updateApplicationContract(
contractFormData.id,
formDataToSend,
getUploadApplicationContractCallback,
errGetUploadApplicationContractCallback
);
}
}, [contractFormData]);
const getUploadApplicationContractCallback = (data) => {
if (data.status === 'SUCCESS') {
setContractsData(null);
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');
}
useEffect(() => { useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId)); const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany) { if (existingCompany) {
DashboardService.getBeneficiaryStatsForCompany(existingCompany.id, getStats, errGetStats); DashboardService.getBeneficiaryStatsForCompany(existingCompany.id, getStats, errGetStats);
const userData = storeGet('userData'); const userData = storeGet('userData');
ApplicationContractService.getContractByUserId(getContracts, errGetContracts, [
['userId', userData.id]
]);
} }
}, [companies, chosenCompanyId]); }, [companies, chosenCompanyId]);
@@ -178,29 +58,6 @@ const DashboardBeneficiario = () => {
{company ? <span className="companyName">{company.companyName}</span> : null} {company ? <span className="companyName">{company.companyName}</span> : null}
</div> </div>
{contractsData && !isEmpty(contractsData)
? <>
<div className="appPage__spacer"></div>
<div className="appPageSection__message warning">
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, width: '100%' }}>
<div style={{ display: 'flex', gap: 10 }}>
<i className="pi pi-info-circle"></i>
<span className="summary">{__('Contratti in attesa:', 'gepafin')}</span>
</div>
<ul>
{contractsData.map(o => <li key={o.id}>
<a href="#" onClick={() => openSendContractForm(o.id)}>
{o.callName} - Domanda #{o.applicationId}
</a>
</li>)}
</ul>
</div>
</div>
</> : null}
<div className="appPage__spacer"></div>
<Toast ref={toast}/>
<div className="appPageSection statsBigBadges"> <div className="appPageSection statsBigBadges">
<h2>{__('Panoramica di Sistema', 'gepafin')}</h2> <h2>{__('Panoramica di Sistema', 'gepafin')}</h2>
<div className="statsBigBadges__grid"> <div className="statsBigBadges__grid">
@@ -304,88 +161,6 @@ const DashboardBeneficiario = () => {
label={__('Contatta assistenza', 'gepafin')} icon="pi pi-envelope" iconPos="right"/>*/} label={__('Contatta assistenza', 'gepafin')} icon="pi pi-envelope" iconPos="right"/>*/}
</div> </div>
</div> </div>
<Dialog
visible={isVisibleContractForm}
modal
header={headerContractDialog}
footer={footerContractDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideContractDialog}>
<div className="appForm__field">
<p>Scarica il contratto:</p>
<ul>
{contractFormData?.instructorDocuments
? contractFormData.instructorDocuments.map(o => <li key={o.id}>
<a href={o.filePath} target="_blank" rel="noreferrer">{o.name}</a>
</li>)
: null}
</ul>
<p>Firmalo digitalmente e ricaricalo</p>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': !contractFormData.files || isEmpty(contractFormData.files) })}>
{__('Files', 'gepafin')}* (p7m)
</label>
<FileUpload
ref={contractFormFilesRef}
name="files[]"
multiple
accept='.p7m,application/pkcs7-mime,application/x-pkcs7-mime'
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> </div>
) )
} }

View File

@@ -1,49 +1,29 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import { head, isEmpty, pathOr } from 'ramda'; import { head, isEmpty, pathOr } from 'ramda';
import NumberFlow from '@number-flow/react'; import NumberFlow from '@number-flow/react';
import { wrap } from 'object-path-immutable';
// store // store
import { storeGet, storeSet, useStoreValue } from '../../store'; import { useStoreValue } from '../../store';
// api // api
import DashboardService from '../../service/dashboard-service'; import DashboardService from '../../service/dashboard-service';
import ApplicationContractService from '../../service/application-contract-service';
// tools
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
// components // components
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import ErrorBoundary from '../../components/ErrorBoundary'; import ErrorBoundary from '../../components/ErrorBoundary';
import MyLatestSubmissionsTableAsync from '../DashboardBeneficiario/components/MyLatestSubmissionsTableAsync'; import MyLatestSubmissionsTableAsync from '../DashboardBeneficiario/components/MyLatestSubmissionsTableAsync';
import LatestBandiBeneficiarioTableAsync from '../DashboardBeneficiario/components/LatestBandiBeneficiarioTableAsync'; import LatestBandiBeneficiarioTableAsync from '../DashboardBeneficiario/components/LatestBandiBeneficiarioTableAsync';
import { classNames } from 'primereact/utils';
import { FileUpload } from 'primereact/fileupload';
import { defaultMaxFileSize } from '../../configData';
import { Dialog } from 'primereact/dialog';
import { Toast } from 'primereact/toast';
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID; const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const DashboardBeneficiarioConfidi = () => { const DashboardBeneficiarioConfidi = () => {
const isAsyncRequest = useStoreValue('isAsyncRequest');
const navigate = useNavigate(); const navigate = useNavigate();
const [mainStats, setMainStats] = useState({}); const [mainStats, setMainStats] = useState({});
const [contractsData, setContractsData] = useState([]);
const companies = useStoreValue('companies'); const companies = useStoreValue('companies');
const chosenCompanyId = useStoreValue('chosenCompanyId'); const chosenCompanyId = useStoreValue('chosenCompanyId');
const company = head(companies.filter(o => o.id === chosenCompanyId)); const company = head(companies.filter(o => o.id === chosenCompanyId));
const [isVisibleContractForm, setIsVisibleContractForm] = useState(false);
const [contractFormData, setContractFormData] = useState({
subject: '',
text: ''
});
const contractFormFilesRef = useRef(null);
const toast = useRef(null);
const goToAllSubmissions = () => { const goToAllSubmissions = () => {
navigate('/bandi'); navigate('/bandi');
@@ -62,112 +42,11 @@ const DashboardBeneficiarioConfidi = () => {
const errGetStats = () => { const errGetStats = () => {
} }
const getContracts = (data) => {
if (data.status === 'SUCCESS') {
setContractsData(data.data);
}
}
const errGetContracts = () => {
}
const openSendContractForm = useCallback((id) => {
const contract = head(contractsData.filter(o => o.id === id));
if (contract) {
setContractFormData(contract)
setIsVisibleContractForm(true);
}
}, [contractsData]);
const headerContractDialog = () => {
return <span>{__('Invia il contratto', 'gepafin')}</span>;
}
const hideContractDialog = () => {
setIsVisibleContractForm(false);
setContractFormData({
subject: '',
text: ''
});
}
const footerContractDialog = useCallback(() => {
let isDisabled = !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.files && !isEmpty(contractFormData.files) && !isAsyncRequest) {
const formDataToSend = new FormData();
if (contractFormData.files && contractFormData.files.length > 0) {
contractFormData.files.forEach((file) => {
formDataToSend.append('beneficiaryContractDocuments', file);
});
}
storeSet('setAsyncRequest');
ApplicationContractService.updateApplicationContract(
contractFormData.id,
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');
}
useEffect(() => { useEffect(() => {
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId)); const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
if (existingCompany) { if (existingCompany) {
DashboardService.getBeneficiaryStatsForCompany(existingCompany.id, getStats, errGetStats); DashboardService.getBeneficiaryStatsForCompany(existingCompany.id, getStats, errGetStats);
const userData = storeGet('userData');
ApplicationContractService.getContractByUserId(getContracts, errGetContracts, [
['userId', userData.id]
]);
} }
}, [companies, chosenCompanyId]); }, [companies, chosenCompanyId]);
@@ -178,28 +57,7 @@ const DashboardBeneficiarioConfidi = () => {
{company ? <span className="companyName">{company.companyName}</span> : null} {company ? <span className="companyName">{company.companyName}</span> : null}
</div> </div>
{contractsData && !isEmpty(contractsData)
? <>
<div className="appPage__spacer"></div>
<div className="appPageSection__message warning">
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, width: '100%' }}>
<div style={{ display: 'flex', gap: 10 }}>
<i className="pi pi-info-circle"></i>
<span className="summary">{__('Contratti in attesa:', 'gepafin')}</span>
</div>
<ul>
{contractsData.map(o => <li key={o.id}>
<a href="#" onClick={() => openSendContractForm(o.id)}>
{o.callName} - Domanda #{o.applicationId}
</a>
</li>)}
</ul>
</div>
</div>
</> : null}
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
<Toast ref={toast}/>
<div className="appPageSection statsBigBadges"> <div className="appPageSection statsBigBadges">
<h2>{__('Panoramica di Sistema', 'gepafin')}</h2> <h2>{__('Panoramica di Sistema', 'gepafin')}</h2>
@@ -304,88 +162,6 @@ const DashboardBeneficiarioConfidi = () => {
label={__('Contatta assistenza', 'gepafin')} icon="pi pi-envelope" iconPos="right"/>*/} label={__('Contatta assistenza', 'gepafin')} icon="pi pi-envelope" iconPos="right"/>*/}
</div> </div>
</div> </div>
<Dialog
visible={isVisibleContractForm}
modal
header={headerContractDialog}
footer={footerContractDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideContractDialog}>
<div className="appForm__field">
<p>Scarica il contratto:</p>
<ul>
{contractFormData?.instructorDocuments
? contractFormData.instructorDocuments.map(o => <li key={o.id}>
<a href={o.filePath} target="_blank" rel="noreferrer">{o.name}</a>
</li>)
: null}
</ul>
<p>Firmalo digitalmente e ricaricalo</p>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': !contractFormData.files || isEmpty(contractFormData.files) })}>
{__('Files', 'gepafin')}* (p7m)
</label>
<FileUpload
ref={contractFormFilesRef}
name="files[]"
multiple
accept='.p7m,application/pkcs7-mime,application/x-pkcs7-mime'
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> </div>
) )
} }

View File

@@ -15,7 +15,6 @@ import { storeGet, storeSet, useStoreValue } from '../../store';
import ApplicationEvaluationService from '../../service/application-evaluation-service'; import ApplicationEvaluationService from '../../service/application-evaluation-service';
import AmendmentsService from '../../service/amendments-service'; import AmendmentsService from '../../service/amendments-service';
import AppointmentService from '../../service/appointment-service'; import AppointmentService from '../../service/appointment-service';
import ApplicationContractService from '../../service/application-contract-service';
// tools // tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
@@ -34,6 +33,7 @@ import getTokens from '../../helpers/getTokens';
import parseCommaDecimal from '../../helpers/parseCommaDecimal'; import parseCommaDecimal from '../../helpers/parseCommaDecimal';
import renderWithDataVars from '../../helpers/renderWithDataVars'; import renderWithDataVars from '../../helpers/renderWithDataVars';
import renderHtmlContent from '../../helpers/renderHtmlContent'; import renderHtmlContent from '../../helpers/renderHtmlContent';
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
// components // components
import { Skeleton } from 'primereact/skeleton'; import { Skeleton } from 'primereact/skeleton';
@@ -60,7 +60,6 @@ import EvaluationReAdmit from './components/EvaluationReAdmit';
import { SplitButton } from 'primereact/splitbutton'; import { SplitButton } from 'primereact/splitbutton';
import { FileUpload } from 'primereact/fileupload'; import { FileUpload } from 'primereact/fileupload';
import { defaultMaxFileSize, mimeTypes, rejectionReasons } from '../../configData'; import { defaultMaxFileSize, mimeTypes, rejectionReasons } from '../../configData';
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
import ArchiveDocument from './components/ArchiveDocument'; import ArchiveDocument from './components/ArchiveDocument';
const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID; const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
@@ -100,12 +99,12 @@ const DomandaEditPreInstructor = () => {
duration: 0, duration: 0,
amount: 0 amount: 0
}); });
const [isVisibleContractForm, setIsVisibleContractForm] = useState(false); /*const [isVisibleContractForm, setIsVisibleContractForm] = useState(false);
const [contractFormData, setContractFormData] = useState({ const [contractFormData, setContractFormData] = useState({
subject: '', subject: '',
text: '' text: ''
}); });
const contractFormFilesRef = useRef(null); const contractFormFilesRef = useRef(null);*/
const [formData, setFormData] = useState([]); const [formData, setFormData] = useState([]);
const [formId, setFormId] = useState(0); const [formId, setFormId] = useState(0);
const [formInitialData, setFormInitialData] = useState(null); const [formInitialData, setFormInitialData] = useState(null);
@@ -1008,14 +1007,12 @@ const DomandaEditPreInstructor = () => {
setData(newData); setData(newData);
}, [data]); }, [data]);
const openSendContractForm = () => { /*const openSendContractForm = () => {
setIsVisibleContractForm(true); setIsVisibleContractForm(true);
} }
const headerContractDialog = () => { const headerContractDialog = () => {
return <span>{__('Invia il contratto', 'gepafin')}</span>; return <span>{__('Invia il contratto', 'gepafin')}</span>;
} }
const hideContractDialog = () => { const hideContractDialog = () => {
setIsVisibleContractForm(false); setIsVisibleContractForm(false);
setContractFormData({ setContractFormData({
@@ -1023,7 +1020,6 @@ const DomandaEditPreInstructor = () => {
text: '' text: ''
}); });
} }
const footerContractDialog = useCallback(() => { const footerContractDialog = useCallback(() => {
let isDisabled = !contractFormData.subject || isEmpty(contractFormData.subject) let isDisabled = !contractFormData.subject || isEmpty(contractFormData.subject)
|| !contractFormData.text || isEmpty(contractFormData.text) || !contractFormData.text || isEmpty(contractFormData.text)
@@ -1037,12 +1033,10 @@ const DomandaEditPreInstructor = () => {
label={__('Invia', 'gepafin')} onClick={doSendContract}/> label={__('Invia', 'gepafin')} onClick={doSendContract}/>
</div> </div>
}, [contractFormData]); }, [contractFormData]);
const updateContractFormData = (value, path) => { const updateContractFormData = (value, path) => {
const newData = wrap(contractFormData).set(path.split('.'), value).value(); const newData = wrap(contractFormData).set(path.split('.'), value).value();
setContractFormData(newData); setContractFormData(newData);
}; };
const doSendContract = useCallback(() => { const doSendContract = useCallback(() => {
if ( if (
contractFormData.subject && !isEmpty(contractFormData.subject) contractFormData.subject && !isEmpty(contractFormData.subject)
@@ -1075,7 +1069,6 @@ const DomandaEditPreInstructor = () => {
); );
} }
}, [contractFormData]); }, [contractFormData]);
const getUploadApplicationContractCallback = (data) => { const getUploadApplicationContractCallback = (data) => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
setData((prev) => ({ setData((prev) => ({
@@ -1094,7 +1087,6 @@ const DomandaEditPreInstructor = () => {
hideContractDialog(); hideContractDialog();
storeSet('unsetAsyncRequest'); storeSet('unsetAsyncRequest');
} }
const errGetUploadApplicationContractCallback = (data) => { const errGetUploadApplicationContractCallback = (data) => {
if (toast.current && data.message) { if (toast.current && data.message) {
toast.current.show({ toast.current.show({
@@ -1106,7 +1098,7 @@ const DomandaEditPreInstructor = () => {
hideContractDialog(); hideContractDialog();
set404FromErrorResponse(data); set404FromErrorResponse(data);
storeSet('unsetAsyncRequest'); storeSet('unsetAsyncRequest');
} }*/
const actionBtns = () => { const actionBtns = () => {
return <div className="appPageSection__actions"> return <div className="appPageSection__actions">
@@ -1243,13 +1235,16 @@ const DomandaEditPreInstructor = () => {
onClick={initiateRejecting} onClick={initiateRejecting}
label={__('Respingi domanda', 'gepafin')} label={__('Respingi domanda', 'gepafin')}
icon="pi pi-times" iconPos="right"/> : null} icon="pi pi-times" iconPos="right"/> : null}
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' && data.applicationStatus === 'APPROVED' {/*
This functionality has been moved
*/}
{/*{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' && data.applicationStatus === 'APPROVED'
? <Button ? <Button
type="button" type="button"
disabled={!data.id} disabled={!data.id}
onClick={openSendContractForm} onClick={openSendContractForm}
label={__('Invia il contratto', 'gepafin')} label={__('Invia il contratto', 'gepafin')}
/> : null} /> : null}*/}
</div> </div>
} }
@@ -2035,7 +2030,10 @@ const DomandaEditPreInstructor = () => {
</div> </div>
</Dialog> </Dialog>
<Dialog {/*
This functionality has been moved
*/}
{/*<Dialog
visible={isVisibleContractForm} visible={isVisibleContractForm}
modal modal
header={headerContractDialog} header={headerContractDialog}
@@ -2130,7 +2128,7 @@ const DomandaEditPreInstructor = () => {
emptyTemplate={<p className="m-0">{__('Trascina i file qua')}</p>} emptyTemplate={<p className="m-0">{__('Trascina i file qua')}</p>}
/> />
</div> </div>
</Dialog> </Dialog>*/}
</div> </div>
: <> : <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton> <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>

View File

@@ -1,12 +1,12 @@
import React, { useEffect, useState, useCallback } from 'react'; import React, { useEffect, useState, useCallback, useRef } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { is } from 'ramda'; import { is, isEmpty } from 'ramda';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import translationStrings from '../../../../translationStringsForComponents'; import translationStrings from '../../../../translationStringsForComponents';
// store // store
import { useStoreValue } from '../../../../store'; import { storeSet, useStoreValue } from '../../../../store';
// api // api
import ApplicationService from '../../../../service/application-service'; import ApplicationService from '../../../../service/application-service';
@@ -25,8 +25,18 @@ import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Dropdown } from 'primereact/dropdown'; import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag'; import { Tag } from 'primereact/tag';
import { Calendar } from 'primereact/calendar'; import { Calendar } from 'primereact/calendar';
import { Toast } from 'primereact/toast';
import { classNames } from 'primereact/utils';
import { FileUpload } from 'primereact/fileupload';
import { defaultMaxFileSize } from '../../../../configData';
import getFormatedFileSizeText from '../../../../helpers/getFormatedFileSizeText';
import { Dialog } from 'primereact/dialog';
import { wrap } from 'object-path-immutable';
import ApplicationContractService from '../../../../service/application-contract-service';
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
const AllDomandeBeneficiarioTableAsync = ({ statuses }) => { const AllDomandeBeneficiarioTableAsync = ({ statuses }) => {
const isAsyncRequest = useStoreValue('isAsyncRequest');
const chosenCompanyId = useStoreValue('chosenCompanyId'); const chosenCompanyId = useStoreValue('chosenCompanyId');
const companies = useStoreValue('companies'); const companies = useStoreValue('companies');
const [localAsyncRequest, setLocalAsyncRequest] = useState(false); const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
@@ -47,6 +57,13 @@ const AllDomandeBeneficiarioTableAsync = ({ statuses }) => {
applicationStatus: { value: null, matchMode: 'equals' } applicationStatus: { value: null, matchMode: 'equals' }
} }
}); });
const [isVisibleContractForm, setIsVisibleContractForm] = useState(false);
const [contractFormData, setContractFormData] = useState({
subject: '',
text: ''
});
const contractFormFilesRef = useRef(null);
const toast = useRef(null);
const getPaginationQuery = useCallback(() => getQueryParamsForPaginatedEndpoint(lazyState, statuses, 'id'), [lazyState]); const getPaginationQuery = useCallback(() => getQueryParamsForPaginatedEndpoint(lazyState, statuses, 'id'), [lazyState]);
@@ -68,7 +85,8 @@ const AllDomandeBeneficiarioTableAsync = ({ statuses }) => {
const getCallback = (resp) => { const getCallback = (resp) => {
if (resp.status === 'SUCCESS') { if (resp.status === 'SUCCESS') {
const { body, totalRecords, const {
body, totalRecords,
//currentPage, totalPages, pageSize //currentPage, totalPages, pageSize
} = resp.data; } = resp.data;
setTotalRecordsNum(totalRecords); setTotalRecordsNum(totalRecords);
@@ -101,6 +119,14 @@ const AllDomandeBeneficiarioTableAsync = ({ statuses }) => {
<Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small" <Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/> iconPos="right"/>
</Link> </Link>
{rowData.status === 'APPROVED'
? <Button severity="success"
label={__('Invia contratto firmato', 'gepafin')}
icon="pi pi-upload" size="small"
iconPos="right" onClick={() => {
openSendContractForm();
}}/>
: null}
</div> </div>
} }
@@ -141,6 +167,91 @@ const AllDomandeBeneficiarioTableAsync = ({ statuses }) => {
return getFormattedDateString(rowData.submissionDate); return getFormattedDateString(rowData.submissionDate);
}; };
const openSendContractForm = () => {
setContractFormData({
subject: '',
text: ''
});
setIsVisibleContractForm(true);
};
const headerContractDialog = () => {
return <span>{__('Invia il contratto', 'gepafin')}</span>;
}
const hideContractDialog = () => {
setIsVisibleContractForm(false);
setContractFormData({
subject: '',
text: ''
});
}
const footerContractDialog = useCallback(() => {
let isDisabled = !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.files && !isEmpty(contractFormData.files) && !isAsyncRequest) {
const formDataToSend = new FormData();
if (contractFormData.files && contractFormData.files.length > 0) {
contractFormData.files.forEach((file) => {
formDataToSend.append('beneficiaryContractDocuments', file);
});
}
storeSet('setAsyncRequest');
ApplicationContractService.updateApplicationContract(
contractFormData.id,
formDataToSend,
getUploadApplicationContractCallback,
errGetUploadApplicationContractCallback
);
}
}, [contractFormData]);
const getUploadApplicationContractCallback = (data) => {
if (data.status === 'SUCCESS') {
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');
}
useEffect(() => { useEffect(() => {
setLocalAsyncRequest(true); setLocalAsyncRequest(true);
const paginationQuery = getPaginationQuery(); const paginationQuery = getPaginationQuery();
@@ -193,6 +304,82 @@ const AllDomandeBeneficiarioTableAsync = ({ statuses }) => {
<Column header={__('Azioni', 'gepafin')} <Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/> body={actionsBodyTemplate}/>
</DataTable> </DataTable>
<Toast ref={toast}/>
<Dialog
visible={isVisibleContractForm}
modal
header={headerContractDialog}
footer={footerContractDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideContractDialog}>
<div className="appForm__field">
<p>Ricarica il contratto formato digitalmente:</p>
</div>
<div className="appForm__field">
<label
className={classNames({ 'p-error': !contractFormData.files || isEmpty(contractFormData.files) })}>
{__('Files', 'gepafin')}* (p7m)
</label>
<FileUpload
ref={contractFormFilesRef}
name="files[]"
multiple
accept=".p7m,application/pkcs7-mime,application/x-pkcs7-mime"
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> </div>
) )
} }