diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index fc1ea38..20ca516 100644 --- a/src/assets/scss/components/appPage.scss +++ b/src/assets/scss/components/appPage.scss @@ -320,6 +320,10 @@ a { color: inherit; } + + ul li { + color: inherit; + } } @container section_with_border (max-width: 600px) { diff --git a/src/components/FormField/components/NumberInput/index.js b/src/components/FormField/components/NumberInput/index.js index 7ec9c46..f11e5f4 100644 --- a/src/components/FormField/components/NumberInput/index.js +++ b/src/components/FormField/components/NumberInput/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { classNames } from 'primereact/utils'; import { Controller } from 'react-hook-form'; -import { is, isEmpty } from 'ramda'; +import { is, isEmpty, isNil } from 'ramda'; import { InputNumber } from 'primereact/inputnumber'; import { isNaN } from 'mathjs'; @@ -18,7 +18,7 @@ const NumberInput = ({ icon = null, locale = 'it-IT', minFractionDigits = 0, - maxFractionDigits = 1, + maxFractionDigits = 0, min, max, disabled = false, @@ -27,6 +27,7 @@ const NumberInput = ({ }) => { const minAttr = config.min ? config.min : min; const maxAttr = config.max ? config.max : max; + const input = field.onChange(e.value)} min={minAttr} max={maxAttr} + mode="decimal" locale={locale} showButtons - useGrouping={useGrouping} + useGrouping={!isNil(maxFractionDigits) && parseInt(maxFractionDigits) !== 0} maxFractionDigits={!isNaN(parseInt(maxFractionDigits)) ? parseInt(maxFractionDigits) : 0} minFractionDigits={!isNaN(parseInt(minFractionDigits)) ? parseInt(minFractionDigits) : 0} className={classNames({ 'p-invalid': fieldState.invalid })}/> diff --git a/src/configData.js b/src/configData.js index f4c5cc6..7dbd299 100644 --- a/src/configData.js +++ b/src/configData.js @@ -237,6 +237,11 @@ export const classificationType = [ 'name': 'FATTURA', 'idTipoprotocollo': 2 }, + { + 'idClassificazione': 200, + 'name': 'LETTERA ACCETTAZIONE DELIBERA', + 'idTipoprotocollo': 1 + }, { 'idClassificazione': 201, 'name': 'LETTERA ESITO DELIBERA', @@ -247,6 +252,11 @@ export const classificationType = [ 'name': 'LETTERA TRASPARENZA', 'idTipoprotocollo': 2 }, + { + 'idClassificazione': 212, + 'name': 'LETTERA ACCETTAZIONE DELIBERA PROTOCOLLO', + 'idTipoprotocollo': 2 + }, { 'idClassificazione': 205, 'name': 'CONTRATTO', @@ -288,21 +298,25 @@ export const rejectionReasons = [ export const amendmentRequestedDocs = { NESSUNA_GARANZIA: [ - 'Lettera di accettazione firmata' + 'Lettera di accettazione firmata', + 'Visura Centrale Rischi' ], GARANZIA_MCC: [ 'Lettera di accettazione firmata', - 'Modulo di domanda della agevolazione (ex allegato 4)' + 'Modulo di domanda della agevolazione (ex allegato 4)', + 'Visura Centrale Rischi' ], MCC_START_UP: [ 'Lettera di accettazione firmata', 'Modulo di domanda della agevolazione (ex allegato 4)', 'Modello di valutazione bilanci previsionali', - 'Modello valutazione start up' + 'Modello valutazione start up', + 'Visura Centrale Rischi' ], ALTRE_GARANZIE: [ 'Lettera di accettazione firmata', 'Modello privacy', - 'Autocertificazione e altri eventuali in zip/p7m' + 'Autocertificazione e altri eventuali in zip/p7m', + 'Visura Centrale Rischi' ], } \ No newline at end of file diff --git a/src/helpers/getBandoLabel.js b/src/helpers/getBandoLabel.js index f827156..bc4d043 100644 --- a/src/helpers/getBandoLabel.js +++ b/src/helpers/getBandoLabel.js @@ -33,10 +33,10 @@ const getBandoLabel = (status) => { return __('Ammisibile', 'gepafin'); case 'TECHNICAL_EVALUATION': - return __('Valutazione technico-finanziaria', 'gepafin'); + return __('Valutazione tecnico-finanziaria', 'gepafin'); case 'AWAITING_TECHNICAL_EVALUATION': - return __('Pre valutazione technico-finanziaria', 'gepafin'); + return __('Post valutazione tecnico-finanziaria', 'gepafin'); case 'DUE': return __('In scadenza', 'gepafin'); @@ -76,6 +76,12 @@ const getBandoLabel = (status) => { case 'TECHNICAL_EVALUATION_REJECTED': return __('Respinto Tec-Fin', 'gepafin'); + + case 'AWAITING_CONTRACT': + return __('In attesa di contratto', 'gepafin'); + + case 'CONTRACT_SIGNED': + return __('Contratto firmato', 'gepafin'); default: return ''; diff --git a/src/helpers/getBandoSeverity.js b/src/helpers/getBandoSeverity.js index 3002c37..38a2d97 100644 --- a/src/helpers/getBandoSeverity.js +++ b/src/helpers/getBandoSeverity.js @@ -75,6 +75,12 @@ const getBandoSeverity = (status) => { case 'TECHNICAL_EVALUATION_REJECTED': return 'danger'; + case 'AWAITING_CONTRACT': + return 'warning'; + + case 'CONTRACT_SIGNED': + return 'success'; + default: return 'info'; } diff --git a/src/pages/DashboardBeneficiario/index.js b/src/pages/DashboardBeneficiario/index.js index b4a887d..eae7547 100644 --- a/src/pages/DashboardBeneficiario/index.js +++ b/src/pages/DashboardBeneficiario/index.js @@ -1,29 +1,49 @@ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; import { Link, useNavigate } from 'react-router-dom'; import { head, isEmpty, pathOr } from 'ramda'; import NumberFlow from '@number-flow/react'; +import { wrap } from 'object-path-immutable'; // store -import { useStoreValue } from '../../store'; +import { storeGet, storeSet, useStoreValue } from '../../store'; // api 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 import { Button } from 'primereact/button'; import ErrorBoundary from '../../components/ErrorBoundary'; import LatestBandiBeneficiarioTableAsync from './components/LatestBandiBeneficiarioTableAsync'; 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 DashboardBeneficiario = () => { + const isAsyncRequest = useStoreValue('isAsyncRequest'); const navigate = useNavigate(); const [mainStats, setMainStats] = useState({}); + const [contractsData, setContractsData] = useState([]); const companies = useStoreValue('companies'); const chosenCompanyId = useStoreValue('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 = () => { navigate('/bandi'); @@ -42,11 +62,112 @@ const DashboardBeneficiario = () => { 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 {__('Invia il contratto', 'gepafin')}; + } + + const hideContractDialog = () => { + setIsVisibleContractForm(false); + setContractFormData({ + subject: '', + text: '' + }); + } + + const footerContractDialog = useCallback(() => { + let isDisabled = !contractFormData.files || isEmpty(contractFormData.files) || isAsyncRequest; + + return
+
+ }, [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(() => { const existingCompany = head(companies.filter(o => o.id === chosenCompanyId)); if (existingCompany) { DashboardService.getBeneficiaryStatsForCompany(existingCompany.id, getStats, errGetStats); + const userData = storeGet('userData'); + + ApplicationContractService.getContractByUserId(getContracts, errGetContracts, [ + ['userId', userData.id] + ]); } }, [companies, chosenCompanyId]); @@ -57,7 +178,28 @@ const DashboardBeneficiario = () => { {company ? {company.companyName} : null} + {contractsData && !isEmpty(contractsData) + ? <> +
+
+
+
+ + {__('Contratti in attesa:', 'gepafin')} +
+ +
+
+ : null} +
+

{__('Panoramica di Sistema', 'gepafin')}

@@ -162,6 +304,88 @@ const DashboardBeneficiario = () => { label={__('Contatta assistenza', 'gepafin')} icon="pi pi-envelope" iconPos="right"/>*/}
+ + +
+

Scarica il contratto:

+
    + {contractFormData?.instructorDocuments + ? contractFormData.instructorDocuments.map(o =>
  • + {o.name} +
  • ) + : null} +
+

Firmalo digitalmente e ricaricalo

+
+
+ + { + updateContractFormData(e.files, 'files'); + }} + onRemove={(e) => { + const updatedFiles = contractFormFilesRef.current.getFiles(); + updateContractFormData(updatedFiles, 'files'); + }} + headerTemplate={(options) => { + const { chooseButton } = options; + return ( +
+ {chooseButton} +
+ ); + }} + chooseOptions={{ + label: __('Aggiungi i file', 'gepafin'), + icon: 'pi pi-plus' + }} + itemTemplate={(file, props) => { + return ( +
+
+
+ {file.name} +
+ {getFormatedFileSizeText(file.size)} +
+
+
+
+ ) + }} + emptyTemplate={

{__('Trascina i file qua')}

} + /> +
+
) } diff --git a/src/pages/DashboardBeneficiarioConfidi/index.js b/src/pages/DashboardBeneficiarioConfidi/index.js index 8a16e11..d71d949 100644 --- a/src/pages/DashboardBeneficiarioConfidi/index.js +++ b/src/pages/DashboardBeneficiarioConfidi/index.js @@ -1,29 +1,49 @@ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; import { Link, useNavigate } from 'react-router-dom'; import { head, isEmpty, pathOr } from 'ramda'; import NumberFlow from '@number-flow/react'; +import { wrap } from 'object-path-immutable'; // store -import { useStoreValue } from '../../store'; +import { storeGet, storeSet, useStoreValue } from '../../store'; // api 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 import { Button } from 'primereact/button'; import ErrorBoundary from '../../components/ErrorBoundary'; import MyLatestSubmissionsTableAsync from '../DashboardBeneficiario/components/MyLatestSubmissionsTableAsync'; 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 DashboardBeneficiarioConfidi = () => { + const isAsyncRequest = useStoreValue('isAsyncRequest'); const navigate = useNavigate(); const [mainStats, setMainStats] = useState({}); + const [contractsData, setContractsData] = useState([]); const companies = useStoreValue('companies'); const chosenCompanyId = useStoreValue('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 = () => { navigate('/bandi'); @@ -42,11 +62,112 @@ const DashboardBeneficiarioConfidi = () => { 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 {__('Invia il contratto', 'gepafin')}; + } + + const hideContractDialog = () => { + setIsVisibleContractForm(false); + setContractFormData({ + subject: '', + text: '' + }); + } + + const footerContractDialog = useCallback(() => { + let isDisabled = !contractFormData.files || isEmpty(contractFormData.files) || isAsyncRequest; + + return
+
+ }, [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(() => { const existingCompany = head(companies.filter(o => o.id === chosenCompanyId)); if (existingCompany) { DashboardService.getBeneficiaryStatsForCompany(existingCompany.id, getStats, errGetStats); + const userData = storeGet('userData'); + + ApplicationContractService.getContractByUserId(getContracts, errGetContracts, [ + ['userId', userData.id] + ]); } }, [companies, chosenCompanyId]); @@ -57,7 +178,28 @@ const DashboardBeneficiarioConfidi = () => { {company ? {company.companyName} : null} + {contractsData && !isEmpty(contractsData) + ? <> +
+
+
+
+ + {__('Contratti in attesa:', 'gepafin')} +
+ +
+
+ : null} +
+

{__('Panoramica di Sistema', 'gepafin')}

@@ -102,7 +244,7 @@ const DashboardBeneficiarioConfidi = () => { {__('Attenzione', 'gepafin')} {__('Per applicare ai bandi devi Registare un Azienda clicca', 'gepafin')} - {__('qua', 'gepafin')} + {__('qua', 'gepafin')}
@@ -148,8 +290,102 @@ const DashboardBeneficiarioConfidi = () => {