diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index 4f98387..6c2e5e2 100644 --- a/src/assets/scss/components/appPage.scss +++ b/src/assets/scss/components/appPage.scss @@ -11,7 +11,7 @@ font-weight: 600; line-height: normal; } - + .appPageLogin__wrapper { h1 { text-align: center; @@ -89,6 +89,7 @@ } .appPageSection { + position: relative; display: flex; flex-direction: column; align-items: flex-start; @@ -99,7 +100,7 @@ gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); width: 100%; - + /*> div { max-width: 50%; }*/ @@ -130,7 +131,7 @@ padding: 5px 0; width: 100%; } - + .col { display: flex; flex-direction: column; @@ -188,7 +189,7 @@ ul, ol { padding-left: 1rem; - + li { color: var(--global-textColor); } @@ -217,7 +218,7 @@ .appPageSection__pMeta { margin-bottom: 1em; - + span:nth-of-type(1) { max-width: 30%; } @@ -263,7 +264,7 @@ display: flex; flex-direction: column; gap: 1.2rem; - + div { display: flex; gap: 0.5rem; @@ -294,11 +295,11 @@ color: var(--message-info-color); border-color: var(--message-info-color); } - + .summary { font-weight: bold; } - + a { color: inherit; } @@ -401,7 +402,7 @@ gap: 10px; align-items: center; flex-wrap: wrap; - + &.lessGap { gap: 12px; } @@ -418,7 +419,7 @@ background-color: transparent; color: var(--global-textColor); padding: 0; - + &:hover { cursor: pointer; color: var(--message-info-color); @@ -449,4 +450,4 @@ grid-template-columns: 1fr; } } -} \ No newline at end of file +} diff --git a/src/pages/DomandaEditInstructorManager/index.js b/src/pages/DomandaEditInstructorManager/index.js new file mode 100644 index 0000000..589dab1 --- /dev/null +++ b/src/pages/DomandaEditInstructorManager/index.js @@ -0,0 +1,961 @@ +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { __, sprintf } from '@wordpress/i18n'; +import { useNavigate, useParams } from 'react-router-dom'; +import { is, isEmpty, isNil, sum, pathOr, head } from 'ramda'; +import { klona } from 'klona'; +import { wrap } from 'object-path-immutable'; + +// store +import { storeGet, storeSet, useStore } from '../../store'; + +// api +import ApplicationEvaluationService from '../../service/application-evaluation-service'; +import AmendmentsService from '../../service/amendments-service'; +import AppointmentService from '../../service/appointment-service'; + +// tools +import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; +import getBandoLabel from '../../helpers/getBandoLabel'; +import getDateFromISOstring from '../../helpers/getDateFromISOstring'; + +// components +import { Skeleton } from 'primereact/skeleton'; +import { Button } from 'primereact/button'; +import { Tag } from 'primereact/tag'; +import { Checkbox } from 'primereact/checkbox'; +import { Editor } from 'primereact/editor'; +import { InputNumber } from 'primereact/inputnumber'; +import { Toast } from 'primereact/toast'; +import { Dialog } from 'primereact/dialog'; +import HelpIcon from '../../icons/HelpIcon'; +import BlockingOverlay from '../../components/BlockingOverlay'; +import { classNames } from 'primereact/utils'; +import { InputTextarea } from 'primereact/inputtextarea'; +import { InputText } from 'primereact/inputtext'; +import DownloadApplicationArchive from '../DomandaEditPreInstructor/components/DownloadApplicationArchive'; +import DownloadCompanyDelegation from '../DomandaEditPreInstructor/components/DownloadCompanyDelegation'; +import DownloadSignedApplication from '../DomandaEditPreInstructor/components/DownloadSignedApplication'; +import ListOfFiles from '../DomandaEditPreInstructor/components/ListOfFiles'; +import RepeaterFields from '../DomandaEditPreInstructor/components/RepeaterFields'; + +const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID; + +const DomandaEditPreInstructor = () => { + const isAsyncRequest = useStore().main.isAsyncRequest(); + const { id } = useParams(); + const navigate = useNavigate(); + const [data, setData] = useState({}); + const [isVisibleCriterionData, setIsVisibleCriterionData] = useState(0); + const [criterionDataTitle, setCriterionDataTitle] = useState(''); + const [criterionDataContent, setCriterionDataContent] = useState(''); + const [isAdmissible, setIsAdmissible] = useState(false); + const [connectedSoccorsoId, setConnectedSoccorsoId] = useState(0); + const toast = useRef(null); + const [loading, setLoading] = useState(false); + const [isVisibleCompleteDialog, setIsVisibleCompleteDialog] = useState(false); + const [operationType, setOperationType] = useState(''); + const [motivation, setMotivation] = useState(''); + const [isVisibleAppointmentDialog, setIsVisibleAppointmentDialog] = useState(false); + const [allFilesRated, setAllFilesRated] = useState(false); + const [atLeastOneChecked, setAtLeastOneChecked] = useState(false); + const [allChecksChecked, setAllChecksChecked] = useState(false); + const [appointmentData, setAppointmentData] = useState({ + title: '', + text: '', + duration: 0, + amount: 0 + }); + + const goToEvaluationsPage = () => { + navigate('/domande'); + } + + const updateFlagsForSoccorso = (data) => { + let nonRatedFilesLength = 0; + + if (data.files) { + const nonRatedFiles = data.files + .map(el => el.valid) + .filter(v => isNil(v)); + nonRatedFilesLength = nonRatedFiles.length; + } + + if (data.amendmentDetails) { + const nonRatedFiles = data.amendmentDetails + .map(el => el.valid) + .filter(v => isNil(v)); + nonRatedFilesLength = nonRatedFiles.length; + } + + setAllFilesRated(nonRatedFilesLength === 0); + + if (data.checklist) { + const checkedChecklistItems = data.checklist + .map(el => el.valid) + .filter(v => v); + setAtLeastOneChecked(checkedChecklistItems.length > 0); + setAllChecksChecked(checkedChecklistItems.length === data.checklist.length) + } + } + + const doNewSoccorso = () => { + if (connectedSoccorsoId !== 0) { + navigate(`/domande/${id}/soccorso/${connectedSoccorsoId}`); + } else { + doSaveDraft(`/domande/${id}/aggiungi-soccorso/`) + } + } + + const getCallback = (data) => { + if (data.status === 'SUCCESS') { + setData(getFormattedData(data.data)); + setMotivation(data.data.motivation); + updateFlagsForSoccorso(data.data); + } + storeSet.main.unsetAsyncRequest(); + } + + const errGetCallback = (data) => { + if (toast.current && data.message) { + toast.current.show({ + severity: 'error', + summary: '', + detail: data.message + }); + } + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + const getFormattedData = (data) => { + data.submissionDate = is(String, data.submissionDate) ? new Date(data.submissionDate) : (data.submissionDate ? data.submissionDate : ''); + data.evaluationDate = is(String, data.evaluationDate) ? new Date(data.evaluationDate) : (data.evaluationDate ? data.evaluationDate : ''); + return data; + }; + + const renderHeader = () => { + return ( + + + + + + + + + + + + + + ); + }; + + const header = renderHeader(); + + const updateEvaluationValue = (value, path, maxValue = null) => { + let finalValue = value; + + if (maxValue || maxValue === 0) { + finalValue = value > maxValue ? maxValue : value; + } + + const newData = wrap(data).set(path, finalValue).value(); + setData(newData); + updateFlagsForSoccorso(newData); + } + + const doSaveDraft = useCallback((doRedirect = '') => { + const formData = { + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + evaluationDocument: klona(data.evaluationDocument.map(o => ({ + ...o, + fileValue: o.fileValue[0] ? o.fileValue[0].id : '' + }) + )), + amendmentDetails: klona(data.amendmentDetails), + note: data.note + } + + ApplicationEvaluationService.updateEvaluation( + data.assignedApplicationId, + formData, + (data) => updateCallback(data, doRedirect), + errUpdateCallback + ); + }, [data]); + + const updateCallback = (data, doRedirect = '') => { + if (data.status === 'SUCCESS') { + setData(getFormattedData(data.data)); + if (toast.current) { + toast.current.show({ + severity: 'success', + summary: '', + detail: data.message + }); + } + if (!isEmpty(doRedirect)) { + navigate(doRedirect); + } + } + storeSet.main.unsetAsyncRequest(); + } + + const errUpdateCallback = (data) => { + if (toast.current && data.message) { + toast.current.show({ + severity: 'error', + summary: '', + detail: data.message + }); + } + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + const doApprove = () => { + const formData = { + applicationStatus: 'APPROVED', + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + note: data.note, + motivation + } + + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback); + } + + const doReject = () => { + const formData = { + applicationStatus: 'REJECTED', + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + note: data.note, + motivation + } + + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback); + } + + const updateStatusCallback = (data) => { + if (data.status === 'SUCCESS') { + setData(getFormattedData(data.data)); + if (toast.current) { + toast.current.show({ + severity: 'success', + summary: '', + detail: data.message + }); + } + } + storeSet.main.unsetAsyncRequest(); + } + + const errUpdateStatusCallback = (data) => { + if (toast.current && data.message) { + toast.current.show({ + severity: 'error', + summary: '', + detail: data.message + }); + } + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + const displayCriterionData = (id) => { + const criterion = head(data.criteria.filter(o => o.id === id)); + setCriterionDataTitle(criterion.label); + const content =
+

{__('I campi correlati')}

+ {criterion.criteriaMappedFields ? criterion.criteriaMappedFields.map(o => criteriaDataItem(o)) : null} +
; + setCriterionDataContent(content); + setIsVisibleCriterionData(id); + } + + const criteriaDataItem = (item) => { + let content = ''; + + switch (item.fieldName) { + case 'fileupload' : + content = ; + break; + case 'table' : + const th = Object.keys(item.fieldValue[0]); + content = + + + {th.map(v => )} + + + + {item.fieldValue + ? item.fieldValue.map((o, i) => + {Object.values(o).map(v => )} + ) + : null} + +
{v}
{v}
; + break; + default : + content = item.fieldValue; + break; + } + + return
+ {item.fieldLabel} + {content} +
+ } + + const hideCriterionData = () => { + setIsVisibleCriterionData(0); + setCriterionDataTitle(''); + setCriterionDataContent(''); + } + + const getAmendmentsCallback = (data) => { + if (data.status === 'SUCCESS') { + if (data.data.length) { + setConnectedSoccorsoId(data.data[0].id); + } + } + } + + const errGetAmendmentsCallback = () => { + if (toast.current && data.message) { + toast.current.show({ + severity: 'error', + summary: '', + detail: data.message + }); + } + set404FromErrorResponse(data); + } + + const shouldDisableField = (fieldName) => { + return !['EVALUATION'].includes(data.applicationStatus) + || (['ADMISSIBLE'].includes(data.applicationStatus) && fieldName !== 'criteria') + } + + const headerCompleteDialog = () => { + return 'approve' === operationType + ? {__('Confermare l\'approvazione', 'gepafin')} + : {__('Confermare il rifiuto', 'gepafin')}; + } + + const hideCompleteDialog = () => { + setIsVisibleCompleteDialog(false); + setOperationType(''); + setMotivation(''); + } + + const footerCompleteDialog = () => { + return
+
+ } + + const initiateApproving = () => { + setOperationType('approve'); + setIsVisibleCompleteDialog(true); + + } + + const initiateRejecting = () => { + setOperationType('reject'); + setIsVisibleCompleteDialog(true); + } + + const doCheckNDG = () => { + storeSet.main.setAsyncRequest(); + doSaveDraft(); + setTimeout(() => { + AppointmentService.getNdg(id, getNdgCallback, errGetNdgCallback); + }, 100); + } + + const getNdgCallback = (data) => { + if (data.status === 'SUCCESS') { + if (toast.current && data.message) { + toast.current.show({ + severity: 'success', + summary: '', + detail: data.message + }); + } + } + storeSet.main.unsetAsyncRequest(); + } + + const errGetNdgCallback = (data) => { + if (toast.current && data.message) { + toast.current.show({ + severity: data.status === 'SUCCESS' ? 'info' : 'error', + summary: '', + detail: data.message + }); + } + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + const doCreateAppointment = () => { + setAppointmentData({ + title: '', + text: '', + duration: 0, + amount: 0 + }); + setIsVisibleAppointmentDialog(true); + } + + const setValue = (name, value) => { + const newData = wrap(appointmentData).set(name, value).value(); + setAppointmentData(newData); + } + + const headerAppointmentDialog = () => { + return {__('Crea appuntamento', 'gepafin')}; + } + + const hideAppointmentDialog = () => { + setIsVisibleAppointmentDialog(false); + setAppointmentData({}); + } + + const footerAppointmentDialog = () => { + return
+
+ } + + const doCreateAppointmentRequest = () => { + if ( + !isEmpty(appointmentData.title) && !isEmpty(appointmentData.text) && !isEmpty(appointmentData.amount) + && !isEmpty(appointmentData.duration) && appointmentData.duration !== 0 && appointmentData.amount !== 0 + ) { + storeSet.main.setAsyncRequest(); + const submitData = { + 'importoBreveTermine': appointmentData.amount, + 'durataMesiFinanziamento': appointmentData.duration, + 'nota': { + 'titolo': appointmentData.title, + 'testo': appointmentData.text + } + } + + AppointmentService.createAppointment(id, submitData, getAppointemntCallback, errGetAppointemntCallback); + } + } + + const getAppointemntCallback = (data) => { + if (data.status === 'SUCCESS') { + if (toast.current && data.message) { + toast.current.show({ + severity: 'success', + summary: '', + detail: data.message + }); + } + } + setIsVisibleAppointmentDialog(false); + storeSet.main.unsetAsyncRequest(); + } + + const errGetAppointemntCallback = (data) => { + if (toast.current && data.message) { + toast.current.show({ + severity: data.status === 'SUCCESS' ? 'info' : 'error', + summary: '', + detail: data.message + }); + } + setIsVisibleAppointmentDialog(false); + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + const doMakeAdmisible = () => { + // TODO + } + + const evaluationShouldBeBlocked = (data = {}) => { + const userData = storeGet.main.userData() + return isAsyncRequest || userData.id !== data.assignedUserId; + } + + useEffect(() => { + const maxScore = pathOr(0, ['minScore'], data); + const criteria = pathOr([], ['criteria'], data); + const scoreSum = sum(criteria.map(o => o.score)); + + setIsAdmissible(scoreSum !== 0 && scoreSum >= maxScore); + }, [data]); + + useEffect(() => { + const parsed = parseInt(id) + const entityId = !isNaN(parsed) ? parsed : 0; + + storeSet.main.setAsyncRequest(); + ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [ + ['applicationId', entityId] + ]); + AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [ + ['statuses', 'AWAITING'] + ]); + }, [id]); + + return ( +
+
+

{__('Valuta domanda', 'gepafin')}

+
+ +
+ + +
+
+ +
+ + {!isAsyncRequest && !isEmpty(data) + ?
+
+

+ {__('ID domanda', 'gepafin')} + {data.applicationId} +

+

+ {__('Protocollo', 'gepafin')} + {data.protocolNumber} +

+

+ {__('NDG', 'gepafin')} + {data.ndg} +

+

+ {__('Appuntamento', 'gepafin')} + {data.appointmentId} +

+

+ {__('Bando', 'gepafin')} + {data.callName} +

+

+ {__('Referente Aziendale', 'gepafin')} + {data.beneficiary} +

+

+ {__('Azienda Beneficiaria', 'gepafin')} + {data.companyName} +

+

+ {__('Data ricezione', 'gepafin')} + {getDateFromISOstring(data.submissionDate)} +

+

+ {__('Data assegnazione', 'gepafin')} + {getDateFromISOstring(data.assignedAt)} +

+

+ {__('Scadenza Valutazione', 'gepafin')} + {getDateFromISOstring(data.evaluationEndDate)} +

+

+ {__('Stato', 'gepafin')} + {getBandoLabel(data.applicationStatus)} +

+
+ +
+

{__('Scarica documenti della domanda', 'gepafin')}

+
+ + + +
+
+ +
+

{__('Documenti aggiuntivi', 'gepafin')}

+ updateEvaluationValue( + data, + ['evaluationDocument'] + )} + shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)} + sourceId={data.assignedApplicationId} + sourceName="evaluation"/> +
+ +
+

{__('Checklist Valutazione', 'gepafin')}

+
+
+

{__('Lista', 'gepafin')}

+
+
+ {data.checklist.map((o, i) =>
+ updateEvaluationValue( + e.checked, + ['checklist', i, 'valid'] + )} + checked={o.valid}> + +
)} +
+
+ +

{__('Note', 'gepafin')}

+
+ updateEvaluationValue( + e.htmlValue, + ['note'] + )} + style={{ height: 80 * 3, width: '100%' }} + /> +
+
+
+

{__('Documenti allegati', 'gepafin')}

+ shouldDisableField(name) || evaluationShouldBeBlocked(data)} + name="files" + ndg={data.ndg} + applicationId={id}/> +
+
+
+ + {!isEmpty(data.amendmentDetails) + ?
+

{__('Documenti di soccorso', 'gepafin')}

+ shouldDisableField(name) || evaluationShouldBeBlocked(data)} + name="amendmentDetails" + ndg={data.ndg} + applicationId={id}/> +
: null} + +
+

{__('Punteggi di valutazione', 'gepafin')}

+ {data.criteria + ? + + + + + + + + + {data.criteria.map((o, i) => + + + + )} + + + + + + + + + + + +
{__('Parametro', 'gepafin')}{__('Punteggio', 'gepafin')}{__('Stato', 'gepafin')}
{o.label} +
+ updateEvaluationValue( + e.value, + ['criteria', i, 'score'], + o.criteria + )}/> + + / {o.maxScore} + +
+
+
+ {!isEmpty(o.criteriaMappedFields) + ?
+
{__('Punteggio:', 'gepafin')}{sum(data.criteria.map(o => o.score))} + {isAdmissible + ? : null} + {!isAdmissible + ? : null} +
{sprintf(__('Punteggio minimo per l\'ammissione: %d'), data.minScore)}
: null} +
+ +
+ +
+ {__('Azioni rapide', 'gepafin')} +
+ +
+
+ {['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus) + ?
+
+ + + {criterionDataContent} + + + +
+ + setMotivation(e.htmlValue)} + style={{ height: 80 * 3, width: '100%' }} + /> +
+
+ + +
+ + setValue('amount', e.value)}/> +
+
+ + setValue('duration', e.value)}/> +
+
+ + setValue('title', e.target.value)}/> +
+
+ + setValue('text', e.target.value)} + rows={3} + cols={30}/> +
+
+ +
+ : <> + + + + + + + + + } +
+ ) + +} + +export default DomandaEditPreInstructor; diff --git a/src/pages/DomandaEditPreInstructor/index.js b/src/pages/DomandaEditPreInstructor/index.js index df7742c..9c2c517 100644 --- a/src/pages/DomandaEditPreInstructor/index.js +++ b/src/pages/DomandaEditPreInstructor/index.js @@ -568,11 +568,11 @@ const DomandaEditPreInstructor = () => { {data.callName}

- {__('Beneficiario', 'gepafin')} + {__('Referente Aziendale', 'gepafin')} {data.beneficiary}

- {__('Azienda', 'gepafin')} + {__('Azienda Beneficiaria', 'gepafin')} {data.companyName}

@@ -934,4 +934,4 @@ const DomandaEditPreInstructor = () => { } -export default DomandaEditPreInstructor; \ No newline at end of file +export default DomandaEditPreInstructor; diff --git a/src/pages/Domande/components/AllDomandeTable/index.js b/src/pages/Domande/components/AllDomandeTable/index.js index 8505ff8..6159a66 100644 --- a/src/pages/Domande/components/AllDomandeTable/index.js +++ b/src/pages/Domande/components/AllDomandeTable/index.js @@ -139,7 +139,7 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => { ?