diff --git a/environments/dev/dev.env b/environments/dev/dev.env index 9ef0c84..38e36ec 100644 --- a/environments/dev/dev.env +++ b/environments/dev/dev.env @@ -4,4 +4,5 @@ REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit REACT_APP_LOGO_FILENAME=gepafin-logo.svg REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs -REACT_APP_EVALUATION_FLOW_ID=1 \ No newline at end of file +REACT_APP_EVALUATION_FLOW_ID=1 +REACT_APP_LOCAL_DEVELOPMENT=0 \ No newline at end of file diff --git a/environments/prod/prod.env b/environments/prod/prod.env index 1755a33..ecbe860 100644 --- a/environments/prod/prod.env +++ b/environments/prod/prod.env @@ -4,4 +4,5 @@ REACT_APP_API_ADDRESS=https://bandi-api.gepafin.it REACT_APP_LOGO_FILENAME=gepafin-logo.svg REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs -REACT_APP_EVALUATION_FLOW_ID=1 \ No newline at end of file +REACT_APP_EVALUATION_FLOW_ID=1 +REACT_APP_LOCAL_DEVELOPMENT=0 \ No newline at end of file diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index da0721a..9d3de37 100644 --- a/src/assets/scss/components/appPage.scss +++ b/src/assets/scss/components/appPage.scss @@ -43,6 +43,10 @@ margin-left: 10px; text-transform: uppercase; } + + span.companyName { + margin: 0; + } } .appPage__spacer { @@ -258,7 +262,7 @@ .appPageSection__checklist { display: flex; flex-direction: column; - gap: 1rem; + gap: 1.2rem; div { display: flex; diff --git a/src/assets/scss/components/fieldsRepeater.scss b/src/assets/scss/components/fieldsRepeater.scss new file mode 100644 index 0000000..dddc5ba --- /dev/null +++ b/src/assets/scss/components/fieldsRepeater.scss @@ -0,0 +1,45 @@ +.fieldsRepeater { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 10px; + width: 100%; +} + +.fieldsRepeater form { + display: contents; + +} + +.fieldsRepeater__panel { + width: 100%; +} + +.fieldsRepeater__heading { + align-items: center; + display: flex; + justify-content: space-between; + + > span { + width: 100%; + height: 100%; + + &:hover { + cursor: pointer; + color: var(--menuitem-active-background); + } + } + + &[data-hide="true"] { + display: none; + } +} + +.fieldsRepeater__fields { + &[data-hide="true"] { + display: none; + } +} + +.fieldsRepeater__addNew { +} \ No newline at end of file diff --git a/src/assets/scss/theme.scss b/src/assets/scss/theme.scss index 2bd1bad..4ad1ef5 100644 --- a/src/assets/scss/theme.scss +++ b/src/assets/scss/theme.scss @@ -43,4 +43,5 @@ @import "./components/flowBuilder.scss"; @import "./components/error404.scss"; @import "./components/myTable.scss"; -@import "./components/evaluation.scss"; \ No newline at end of file +@import "./components/evaluation.scss"; +@import "./components/fieldsRepeater.scss"; \ No newline at end of file diff --git a/src/components/ErrorBoundary/index.js b/src/components/ErrorBoundary/index.js index 4ac790c..6521776 100644 --- a/src/components/ErrorBoundary/index.js +++ b/src/components/ErrorBoundary/index.js @@ -1,7 +1,5 @@ import React, { Component } from 'react'; -import * as Sentry from '@sentry/browser'; - -const LOCAL_DEVELOPMENT = process.env.REACT_APP_LOCAL_DEVELOPMENT; +import logMsgWithSentry from '../../helpers/logMsgWithSentry'; class ErrorBoundary extends Component { constructor(props) { @@ -14,16 +12,8 @@ class ErrorBoundary extends Component { static getDerivedStateFromError(error) { try { - if (LOCAL_DEVELOPMENT !== '1') { - Sentry.init({ - dsn: "https://e7b2134f7d816f663bb83e51b106a694@o4508381921738752.ingest.de.sentry.io/4508381935501392", - environment: process.env.NODE_ENV || "development" - }); - - Sentry.captureException(error); - } + logMsgWithSentry('', 0, {}, error); } catch (err) { - console.log('err') console.log(err); } return { builderError: true }; diff --git a/src/components/FormField/components/Fileupload/index.js b/src/components/FormField/components/Fileupload/index.js index 70d716d..0bdcfeb 100644 --- a/src/components/FormField/components/Fileupload/index.js +++ b/src/components/FormField/components/Fileupload/index.js @@ -38,7 +38,8 @@ const Fileupload = ({ source = 'application', disabled = false, saveFormCallback = () => { - } + }, + deleteOnBackend = true }) => { // eslint-disable-next-line no-unused-vars const [stateFieldData, setStateFieldData] = useState([]); @@ -97,7 +98,7 @@ const Fileupload = ({ }; const onTemplateRemove = (file) => { - if (file.id) { + if (file.id && deleteOnBackend) { FileUploadService.deleteFile( {}, (data) => deleteCallback(data, file.id), @@ -108,6 +109,11 @@ const Fileupload = ({ const files = inputRef.current.getFiles() const newFiles = files.filter(o => o.lastModified !== file.lastModified && o.name !== file.name); inputRef.current.setFiles(newFiles); + if (file.id) { + const uploadedFiles = inputRef.current.getUploadedFiles(); + const newUploadedFiles = uploadedFiles.filter(o => o.id !== file.id); + inputRef.current.setUploadedFiles(newUploadedFiles); + } } } diff --git a/src/configData.js b/src/configData.js index c8827e7..ba5d649 100644 --- a/src/configData.js +++ b/src/configData.js @@ -67,87 +67,87 @@ export const protocolType = [ export const classificationType = [ { - 'idClassificazione': 101, + 'idClassificazione': 1, 'name': 'BILANCIO', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 102, + 'idClassificazione': 2, 'name': 'DICHHIARAZIONE DEI REDDITI', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 103, + 'idClassificazione': 3, 'name': 'SITUAZIONE CONTABILE', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 104, + 'idClassificazione': 4, 'name': 'PROSPETTO CONTO ECONOMICO', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 105, + 'idClassificazione': 5, 'name': 'CENTRALE DEI RISCHI', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 106, + 'idClassificazione': 6, 'name': 'RELAZIONE AZIENDALE ILLUSTRATIVA (MOD R1C, R1I, R1R, R1R A SECONDO DEI ', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 107, + 'idClassificazione': 7, 'name': 'DOCUMENTO IDENTITA\'', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 108, + 'idClassificazione': 8, 'name': 'MODELLO SP1', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 109, + 'idClassificazione': 9, 'name': 'PRIVACY', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 110, + 'idClassificazione': 10, 'name': 'DOCUMENTAZIONE CHE ATTESTA POSSIBILITA\' DI RILASCIARE GAA FAVORE', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 111, + 'idClassificazione': 11, 'name': 'MODELLO AR1 D.LG 231/2007', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 112, + 'idClassificazione': 12, 'name': 'DOCUMENTO IDENTITA\' FIRMATORIO DICHHIARAZIONE SOSTITUTIVA', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 113, + 'idClassificazione': 13, 'name': 'PRIVACY FIRMATARIO DICHHIARAZIONE SOSTITUTIVA', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 114, + 'idClassificazione': 14, 'name': 'NULLAOSTA ANTIMAFIA', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 201, + 'idClassificazione': 1, 'name': 'LETTERA ESITO DELIBERA', 'idTipoprotocollo': 2 }, { - 'idClassificazione': 202, + 'idClassificazione': 2, 'name': 'LETTERA DI GARANZIA', 'idTipoprotocollo': 1 }, { - 'idClassificazione': 203, + 'idClassificazione': 3, 'name': 'GENERICO', 'idTipoprotocollo': 3 } diff --git a/src/helpers/logMsgWithSentry.js b/src/helpers/logMsgWithSentry.js new file mode 100644 index 0000000..5dee179 --- /dev/null +++ b/src/helpers/logMsgWithSentry.js @@ -0,0 +1,31 @@ +import * as Sentry from '@sentry/browser'; + +const LOCAL_DEVELOPMENT = process.env.REACT_APP_LOCAL_DEVELOPMENT; + +const logMsgWithSentry = (endpoint = '', status = 0, resp = {}, error = null) => { + try { + if (LOCAL_DEVELOPMENT !== '1') { + Sentry.init({ + dsn: 'https://e7b2134f7d816f663bb83e51b106a694@o4508381921738752.ingest.de.sentry.io/4508381935501392', + environment: process.env.NODE_ENV || 'development' + }); + + if (!error) { + const newError = new Error(`Status ${status}`); + Sentry.captureException(`Error in endpoint: ${endpoint}`, { + level: 'error', + extra: { + originalError: newError, + details: resp + } + }); + } else { + Sentry.captureException(error); + } + } + } catch (err) { + console.log(err); + } +} + +export default logMsgWithSentry; \ No newline at end of file diff --git a/src/pages/Applications/index.js b/src/pages/Applications/index.js index ad3393f..21aaf42 100644 --- a/src/pages/Applications/index.js +++ b/src/pages/Applications/index.js @@ -1,6 +1,10 @@ import React from 'react'; import { __ } from '@wordpress/i18n'; import { useNavigate } from 'react-router-dom'; +import { head } from 'ramda'; + +// store +import { storeGet, useStore } from '../../store'; // components import MyLatestSubmissionsTable from '../DashboardBeneficiario/components/MyLatestSubmissionsTable'; @@ -9,6 +13,9 @@ import ErrorBoundary from '../../components/ErrorBoundary'; const Applications = () => { const navigate = useNavigate(); + const chosenCompanyId = useStore().main.chosenCompanyId(); + const companies = useStore().main.companies(); + const company = head(companies.filter(o => o.id === chosenCompanyId)); const gotToBandiDisponibili = () => { navigate('/bandi') @@ -18,6 +25,7 @@ const Applications = () => {

{__('Domande in Lavorazione', 'gepafin')}

+ {company ? {company.companyName} : null}
diff --git a/src/pages/BandiBeneficiario/index.js b/src/pages/BandiBeneficiario/index.js index 5a191be..ec107f7 100644 --- a/src/pages/BandiBeneficiario/index.js +++ b/src/pages/BandiBeneficiario/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { __ } from '@wordpress/i18n'; import { Link } from 'react-router-dom'; -import { isEmpty } from 'ramda'; +import { head, isEmpty } from 'ramda'; // store import { useStore } from '../../store'; @@ -12,11 +12,14 @@ import ErrorBoundary from '../../components/ErrorBoundary'; const BandiBeneficiario = () => { const chosenCompanyId = useStore().main.chosenCompanyId(); + const companies = useStore().main.companies(); + const company = head(companies.filter(o => o.id === chosenCompanyId)); return (

{__('Bandi disponibili', 'gepafin')}

+ {company ? {company.companyName} : null}
diff --git a/src/pages/BandiPreferredBeneficiario/index.js b/src/pages/BandiPreferredBeneficiario/index.js index e6e2063..df1f5a3 100644 --- a/src/pages/BandiPreferredBeneficiario/index.js +++ b/src/pages/BandiPreferredBeneficiario/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { __ } from '@wordpress/i18n'; import { Link } from 'react-router-dom'; -import { isEmpty } from 'ramda'; +import { head, isEmpty } from 'ramda'; // store import { useStore } from '../../store'; @@ -11,11 +11,14 @@ import AllBandiAccordion from '../BandiBeneficiario/components/AllBandiAccordion const BandiPreferredBeneficiario = () => { const chosenCompanyId = useStore().main.chosenCompanyId(); + const companies = useStore().main.companies(); + const company = head(companies.filter(o => o.id === chosenCompanyId)); return (

{__('Bandi osservati', 'gepafin')}

+ {company ? {company.companyName} : null}
diff --git a/src/pages/BandoApplicationPreview/index.js b/src/pages/BandoApplicationPreview/index.js index 74b79d4..cb19582 100644 --- a/src/pages/BandoApplicationPreview/index.js +++ b/src/pages/BandoApplicationPreview/index.js @@ -266,7 +266,6 @@ const BandoApplicationPreview = () => { {activeStep < totalSteps ?
)} -
{stateFieldData .filter(o => o.predefined) @@ -116,19 +133,22 @@ const ElementSettingTableColumns = ({
- {o.rows.map((c, k) => { - const properIndex = findIndex(propEq(o.name, 'name'))(stateFieldData); + {rowsData.map((c, k) => { return
- {properSubField(c, properIndex, k)} -
})} -
)} diff --git a/src/pages/DashboardBeneficiario/index.js b/src/pages/DashboardBeneficiario/index.js index cc12f6e..cec061b 100644 --- a/src/pages/DashboardBeneficiario/index.js +++ b/src/pages/DashboardBeneficiario/index.js @@ -21,6 +21,7 @@ const DashboardBeneficiario = () => { const [mainStats, setMainStats] = useState({}); const companies = useStore().main.companies(); const chosenCompanyId = useStore().main.chosenCompanyId(); + const company = head(companies.filter(o => o.id === chosenCompanyId)); const goToAllSubmissions = () => { navigate('/bandi'); @@ -51,6 +52,7 @@ const DashboardBeneficiario = () => {

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

+ {company ? {company.companyName} : null}
diff --git a/src/pages/DomandaBeneficiario/index.js b/src/pages/DomandaBeneficiario/index.js index 081b39c..e03c2d0 100644 --- a/src/pages/DomandaBeneficiario/index.js +++ b/src/pages/DomandaBeneficiario/index.js @@ -25,6 +25,9 @@ import { Toast } from 'primereact/toast'; import { Dialog } from 'primereact/dialog'; import FormField from '../../components/FormField'; import SoccorsoComunications from '../SoccorsoEditPreInstructor/components/SoccorsoComunications'; +import RepeaterFields from '../DomandaEditPreInstructor/components/RepeaterFields'; +import { wrap } from 'object-path-immutable'; +import { Editor } from 'primereact/editor'; const DomandaBeneficiario = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); @@ -67,12 +70,16 @@ const DomandaBeneficiario = () => { if (data.data.length) { const amendmentObj = data.data[0]; setData(getFormattedData(amendmentObj)); - const formDataInitial = amendmentObj.applicationFormFields.reduce((acc, cur) => { + let formDataInitial = amendmentObj.applicationFormFields.reduce((acc, cur) => { if (cur.fieldValue) { acc[cur.fieldId] = cur.fieldValue; } return acc; }, {}); + formDataInitial = { + ...formDataInitial, + amendmentDocuments: amendmentObj.amendmentDocuments + } setFormInitialData(formDataInitial); storeSet.main.unsetAsyncRequest(); } else { @@ -101,7 +108,7 @@ const DomandaBeneficiario = () => { } const getFormattedData = (data) => { - data.submissionDate = is(String, data.submissionDate) ? new Date(data.submissionDate) : (data.submissionDate ? data.submissionDate : ''); + data.evaluationEndDate = is(String, data.evaluationEndDate) ? new Date(data.evaluationEndDate) : (data.evaluationEndDate ? data.evaluationEndDate : ''); data.startDate = is(String, data.startDate) ? new Date(data.startDate) : (data.startDate ? data.startDate : ''); data.expirationDate = is(String, data.expirationDate) ? new Date(data.expirationDate) : (data.expirationDate ? data.expirationDate : ''); return data; @@ -114,6 +121,7 @@ const DomandaBeneficiario = () => { trigger(); let formValues = klona(getValues()); const newFormValues = Object.keys(formValues) + .filter(v => v !== 'amendmentDocuments') .reduce((acc, cur) => { let fieldVal = formValues[cur]; @@ -126,9 +134,14 @@ const DomandaBeneficiario = () => { }); return acc; }, []); + const newAmendDocs = formValues.amendmentDocuments + ? formValues.amendmentDocuments.map(o => o.id).join(',') + : ''; const submitData = { applicationFormFields: newFormValues, + amendmentDocuments: newAmendDocs, + amendmentNotes: data.amendmentNotes } const amendmentId = data.id; @@ -145,13 +158,17 @@ const DomandaBeneficiario = () => { detail: data.message }); } - const newFormDataInitial = data.data.applicationFormFields.reduce((acc, cur) => { + let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => { if (cur.fieldValue) { acc[cur.fieldId] = cur.fieldValue; } return acc; - }, formInitialData); - setFormInitialData(newFormDataInitial); + }, {}); + formDataInitial = { + ...formDataInitial, + amendmentDocuments: data.data.amendmentDocuments + } + setFormInitialData(formDataInitial); } storeSet.main.unsetAsyncRequest(); } @@ -168,6 +185,31 @@ const DomandaBeneficiario = () => { storeSet.main.unsetAsyncRequest(); } + const updateNewAmendmentData = (value, path) => { + const newData = wrap(data).set(path, value).value(); + setData(newData); + } + + const renderHeader = () => { + return ( + + + + + + + + + + + + + + ); + }; + + const header = renderHeader(); + useEffect(() => { if (formInitialData) { //reset(); @@ -182,7 +224,7 @@ const DomandaBeneficiario = () => { {data.id ?

{sprintf(__('Soccorso Istruttorio: richiesta integrazione documenti per domanda #%s', 'gepafin'), id)} -

: null} + : null} {dataAppl.id ?

{sprintf(__('Dettagli: domanda #%s', 'gepafin'), dataAppl.id)} @@ -239,7 +281,7 @@ const DomandaBeneficiario = () => { {dataAppl.id ?

- {__('ID domanda', 'gepafin')} + {__('ID domanda', 'gepafin')} {dataAppl.id}

@@ -274,6 +316,12 @@ const DomandaBeneficiario = () => {

: null} + {data.id + ?
+

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

+ +
: null} + {data.id ?

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

@@ -294,42 +342,80 @@ const DomandaBeneficiario = () => { defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []} accept={[]} source="AMENDMENT" - sourceId={data.applicationId} + sourceId={data.id} multiple={true} /> }) : null} - {/*
    - {data.formFields - ? data.formFields.map((o, i) =>
  1. - {o.label} -
  2. ) : null} -
*/} +
    + {data.formFields + ? data.formFields.map((o, i) =>
  1. + {o.label} +
  2. ) : null} +
: null} {data.id ?
-

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

- -
: null} +

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

+
+

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

+
+ updateNewAmendmentData( + e.htmlValue, + 'amendmentNotes' + )} + style={{ height: 80 * 3, width: '100%' }} + /> +
+ +
+ : null} {data.id ?
- - {__('Attenzione', 'gepafin')} - {__('Inviare la documentazione richiesta completa delle integrazioni esclusivamente via PEC. In caso contarrio l’integrazione non può essere ritenuta valida.', 'gepafin')} -
: null} + + {__('Attenzione', 'gepafin')} + {__('Inviare la documentazione richiesta completa delle integrazioni esclusivamente via PEC. In caso contarrio l’integrazione non può essere ritenuta valida.', 'gepafin')} + : null}
{data.id ?
+
+ + +
+
+ ) : null} + +