diff --git a/.env b/.env index ef5dcea..871e4c5 100644 --- a/.env +++ b/.env @@ -1,8 +1,9 @@ REACT_APP_TAB_TITLE=Gepafin REACT_APP_API_EXECUTION_ADDRESS=https://api-dev-gepafin.memento.credit/v1 REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit +REACT_APP_API_ADDRESS_WS=https://api-dev-gepafin.memento.credit/wss 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 -REACT_APP_LOCAL_DEVELOPMENT=1 \ No newline at end of file +REACT_APP_LOCAL_DEVELOPMENT=1 diff --git a/README.md b/README.md index 86475cf..6e5298b 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,7 @@ Gepafin Front End `npm run start` - start development server `npm run build:dev` - make build based on 'dev' env variables `npm run build:prod` - make build based on 'prod' env variables + +# HUB IDs +`p4lk3bcx1RStqTaIVVbXs` - gepafin +`t7jh5wfg9QXylNaTZkPoE` - sviluppumbria diff --git a/environments/dev/dev.env b/environments/dev/dev.env index 9ef0c84..ae149fd 100644 --- a/environments/dev/dev.env +++ b/environments/dev/dev.env @@ -1,7 +1,9 @@ REACT_APP_TAB_TITLE=Gepafin REACT_APP_API_EXECUTION_ADDRESS=https://api-dev-gepafin.memento.credit/v1 REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit +REACT_APP_API_ADDRESS_WS=https://api-dev-gepafin.memento.credit/wss 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/package.json b/package.json index 3331909..4061fa5 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "@emailjs/browser": "4.4.1", "@emotion/styled": "11.13.5", "@number-flow/react": "0.4.2", - "@sentry/browser": "^8.41.0", + "@sentry/browser": "^8.42.0", + "@stomp/stompjs": "^7.0.0", "@tanstack/react-table": "^8.20.5", "@wordpress/i18n": "5.13.0", "@wordpress/react-i18n": "4.13.0", @@ -36,6 +37,7 @@ "react-hook-form": "7.53.2", "react-router-dom": "7.0.1", "react-scripts": "5.0.1", + "sockjs-client": "^1.6.1", "validate.js": "0.13.1", "zustand": "4.5.4", "zustand-x": "3.0.4" diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index da0721a..4ed00a3 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; @@ -43,6 +43,10 @@ margin-left: 10px; text-transform: uppercase; } + + span.companyName { + margin: 0; + } } .appPage__spacer { @@ -85,6 +89,7 @@ } .appPageSection { + position: relative; display: flex; flex-direction: column; align-items: flex-start; @@ -95,7 +100,7 @@ gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); width: 100%; - + /*> div { max-width: 50%; }*/ @@ -126,7 +131,7 @@ padding: 5px 0; width: 100%; } - + .col { display: flex; flex-direction: column; @@ -184,7 +189,7 @@ ul, ol { padding-left: 1rem; - + li { color: var(--global-textColor); } @@ -213,7 +218,8 @@ .appPageSection__pMeta { margin-bottom: 1em; - + break-inside: avoid; + span:nth-of-type(1) { max-width: 30%; } @@ -258,8 +264,8 @@ .appPageSection__checklist { display: flex; flex-direction: column; - gap: 1rem; - + gap: 1.2rem; + div { display: flex; gap: 0.5rem; @@ -290,11 +296,11 @@ color: var(--message-info-color); border-color: var(--message-info-color); } - + .summary { font-weight: bold; } - + a { color: inherit; } @@ -397,7 +403,7 @@ gap: 10px; align-items: center; flex-wrap: wrap; - + &.lessGap { gap: 12px; } @@ -414,7 +420,7 @@ background-color: transparent; color: var(--global-textColor); padding: 0; - + &:hover { cursor: pointer; color: var(--message-info-color); @@ -430,10 +436,19 @@ } } +.appPageSection__emailTemplate { + > div { + max-width: 100%!important; + > div { + max-width: 100%!important; + } + } +} + @media (max-width: 700px) { .appPageSection { &.columns { grid-template-columns: 1fr; } } -} \ No newline at end of file +} 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/components/notificationsSidebar.scss b/src/assets/scss/components/notificationsSidebar.scss new file mode 100644 index 0000000..2bc2eb8 --- /dev/null +++ b/src/assets/scss/components/notificationsSidebar.scss @@ -0,0 +1,55 @@ +.notificationsIcon { + &:hover { + cursor: pointer; + } +} + +.notificationsSidebar { + max-width: 360px; + width: 100%; +} + +.notificationsSidebar__loading { + padding: 30px 0; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + gap: 10px; +} + +.notificationsSidebar__list { + display: flex; + flex-direction: column; + gap: 5px; + list-style: none; + padding: 0; +} + +.notificationsSidebar__listItem { + display: flex; + justify-content: space-between; + align-items: center; + gap: 5px; + padding: 15px 0; + border-bottom: 1px solid #e7e7e7; + + &:hover { + cursor: pointer; + color: var(--primary-text); + } +} + +.notificationsSidebar__listItemContent { + display: flex; + flex-direction: column; + gap: 5px; + font-size: 14px; +} + +.notificationsSidebar__listItemChosen { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 5px; +} diff --git a/src/assets/scss/components/statsBigBadges.scss b/src/assets/scss/components/statsBigBadges.scss index 7de0232..1788b0c 100644 --- a/src/assets/scss/components/statsBigBadges.scss +++ b/src/assets/scss/components/statsBigBadges.scss @@ -5,11 +5,15 @@ display: grid; align-items: stretch; /*grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));*/ - grid-template-columns: repeat(2, minmax(220px,1fr)); + grid-template-columns: repeat(2, minmax(220px, 1fr)); gap: 1rem; width: 100%; container-name: big-badges-grid; container-type: inline-size; + + &.grid-small { + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + } } .statsBigBadges__grid .statsBigBadges__gridItem span { diff --git a/src/assets/scss/theme.scss b/src/assets/scss/theme.scss index 42d7cfb..965967b 100644 --- a/src/assets/scss/theme.scss +++ b/src/assets/scss/theme.scss @@ -44,4 +44,6 @@ @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"; +@import "./components/notificationsSidebar.scss"; 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/components/FormField/components/Table/RenderTable/index.js b/src/components/FormField/components/Table/RenderTable/index.js index cb7b31f..e30ac5e 100644 --- a/src/components/FormField/components/Table/RenderTable/index.js +++ b/src/components/FormField/components/Table/RenderTable/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { wrap } from 'object-path-immutable'; -const RenderTable = ({ data, columns, setRowsFn }) => { +const RenderTable = ({ data, columns, setRowsFn, disabled }) => { const table = useReactTable({ data, columns, @@ -16,6 +16,7 @@ const RenderTable = ({ data, columns, setRowsFn }) => { return ( table.options.meta?.updateData(index, id, e.target.value)} onBlur={onBlur} diff --git a/src/components/FormField/components/Table/index.js b/src/components/FormField/components/Table/index.js index 5d80b09..d08e21e 100644 --- a/src/components/FormField/components/Table/index.js +++ b/src/components/FormField/components/Table/index.js @@ -17,6 +17,7 @@ const Table = ({ label, register, errors, + disabled = false, config = {}, defaultValue = [], tableColumns = [] @@ -29,6 +30,9 @@ const Table = ({ const [rowIndexToDelete, rowRowIndexToDelete] = useState(null); const addNewRow = () => { + if (disabled) { + return; + } const obj = columnsCfg .reduce((acc, cur) => { acc[cur.name] = '' @@ -94,6 +98,7 @@ const Table = ({ header: () => '', footer: (props) => props.column.id, cell: ({row: { index }}) => : null} {!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && data.confidi + && (data.id !== 6 || (data.id === 6 && REACT_APP_HUB_ID !== 'p4lk3bcx1RStqTaIVVbXs')) ? : null} @@ -229,4 +233,4 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => { ) } -export default AllBandiAccordion; \ No newline at end of file +export default AllBandiAccordion; 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 1fc5493..15a7de3 100644 --- a/src/pages/BandoApplicationPreview/index.js +++ b/src/pages/BandoApplicationPreview/index.js @@ -86,8 +86,8 @@ const BandoApplicationPreview = () => { ApplicationService.validateApplication(applId, {}, validateApplicationCallback, errValidateApplicationCallback); }; - const onSubmit = () => { - }; + /*const onSubmit = () => { + };*/ const validateApplicationCallback = (data) => { if (data.status === 'SUCCESS') { @@ -155,31 +155,6 @@ const BandoApplicationPreview = () => { user: {} }; - /*if (company) { - dynamicData = Object.keys(company).reduce((acc, cur) => { - if ([ - 'companyName', 'vatNumber', 'codiceFiscale', 'address', 'phoneNumber', - 'city', 'province', 'cap', 'country', 'pec', 'email', 'contactName', 'contactEmail' - ].includes(cur)) { - acc.company[cur] = company[cur]; - } - return acc; - }, dynamicData); - } - - const userData = storeGet.main.userData(); - Object.keys(userData).reduce((acc, cur) => { - if ([ - 'email', 'firstName', 'lastName', 'phoneNumber', 'codiceFiscale' - ].includes(cur)) { - acc.user[cur] = userData[cur]; - } - if (['dateOfBirth'].includes(cur)) { - acc.user[cur] = new Date(userData[cur]); - } - return acc; - }, dynamicData);*/ - if (data.data.applicationFormResponse.content) { // eslint-disable-next-line array-callback-return data.data.applicationFormResponse.content.map((o) => { @@ -252,33 +227,25 @@ const BandoApplicationPreview = () => { {activeStep > 1 && activeStep <= totalSteps ?
:
- +
diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js index 6e2dcfc..1da64fa 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js @@ -10,6 +10,7 @@ import { Editor } from 'primereact/editor'; import { mimeTypes } from '../../../../../../configData'; import ElementSettingTableColumns from '../ElementSettingTableColumns'; +import { InputSwitch } from 'primereact/inputswitch'; const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => { @@ -17,6 +18,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => { label: __('Label', 'gepafin'), placeholder: __('Segnaposto', 'gepafin'), step: __('Numero Decimali', 'gepafin'), + isRequestedAmount: __('Importo richiesto', 'gepafin'), options: __('Opzioni', 'gepafin'), mime: __('Tipo di file', 'gepafin'), text: __('Testo formattato', 'gepafin'), @@ -78,6 +80,10 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => { name={setting.name} bandoStatus={bandoStatus} setDataFn={updateDataFn}/> + } else if (setting.name === 'isRequestedAmount') { + return changeFn(e.value, setting.name)}/> } else { return { const [stateFieldData, setStateFieldData] = useState([]); const [rowsData, setRowsData] = useState([]); @@ -28,18 +29,19 @@ const ElementSettingTableColumns = ({ setStateFieldData([...stateFieldData, { name: uniqid('o'), label: '', predefined: false }]); } - const addNewRow = (index) => { - const newStateFieldData = wrap(stateFieldData) - .insert([index, 'rows'], { label: '' }, stateFieldData[index].rows.length) - .value(); - setStateFieldData(newStateFieldData); + const addNewRow = () => { + const obj = stateFieldData + .filter(o => o.predefined) + .reduce((acc, cur) => { + acc[cur.name] = '' + return acc; + }, {}); + setRowsData([...rowsData, obj]); } - const removeRow = (index, indexK) => { - const newStateFieldData = wrap(stateFieldData) - .del([index, 'rows', indexK]) - .value(); - setStateFieldData(newStateFieldData); + const removeRow = (index) => { + const newRowsData = wrap(rowsData).del([index]).value(); + setRowsData(newRowsData); } const onInputChange = (e, index) => { @@ -53,24 +55,31 @@ const ElementSettingTableColumns = ({ setStateFieldData(newData); } - const onSubInputChange = (e, index, indexK) => { + const onSubInputChange = (e, name, index) => { const { value } = e.target; - const newStateFieldData = wrap(stateFieldData) - .set([index, 'rows', indexK, 'label'], value) - .value(); - setStateFieldData(newStateFieldData); + const newRowsData = wrap(rowsData).set([index, name], value).value(); + setRowsData(newRowsData); } const setChecked = (value, index) => { + let name = ''; const newData = stateFieldData.map((o, i) => { if (i === index) { o.predefined = value; - if (value === false) { - o.rows = []; - } + name = o.name; } return o; - }) + }); + + let newRowsData = []; + + if (value === false) { + newRowsData = rowsData.map(o => wrap(o).set([name], '').value()); + } else { + newRowsData = rowsData.map(o => wrap(o).set([name], '').value()); + } + + setRowsData(newRowsData); setStateFieldData(newData); } @@ -79,23 +88,31 @@ const ElementSettingTableColumns = ({ onInputChange(e, i)}/>
{__('Predefinito?', 'gepafin')} - setChecked(e.value, i)}/> + setChecked(e.value, i)}/>
} - const properSubField = (item, i, k) => { - return onSubInputChange(e, i, k)}/> + const properSubField = (item, i, name) => { + return onSubInputChange(e, name, i)}/> } useEffect(() => { - const storeFieldData = value ?? []; - setStateFieldData(storeFieldData); + const stateFieldData = pathOr([], ['stateFieldData'], value); + setStateFieldData(stateFieldData); + const rowsData = pathOr([], ['rowsData'], value); + setRowsData(rowsData); }, []); useEffect(() => { - setDataFn(name, [...stateFieldData]); - }, [stateFieldData]); + setDataFn(name, { + stateFieldData, + rowsData + }); + }, [stateFieldData, rowsData]); stateFieldData.filter(o => o.predefined) @@ -105,10 +122,10 @@ const ElementSettingTableColumns = ({ {stateFieldData.map((o, i) =>
{properField(o, i)} -
)} -
{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/BandoFormsEdit/components/BuilderElementSettings/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js index abfe57b..3e4f66a 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/index.js @@ -5,7 +5,7 @@ import { klona } from 'klona'; import { wrap } from 'object-path-immutable'; // store -import { storeSet, useStore } from '../../../../store'; +import { storeGet, storeSet, useStore } from '../../../../store'; // components import { InputText } from 'primereact/inputtext'; @@ -128,10 +128,20 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => { useEffect(() => { const chosen = head(elements.filter(o => o.id === activeElement)); + const elementItems = storeGet.main.elementItems(); + const chosenElementItemCfg = head(elementItems.filter(o => o.name === chosen.name)); + let settings = []; + + if (chosenElementItemCfg) { + settings = chosenElementItemCfg.settings.map((o) => { + const setting = head(chosen.settings.filter(s => s.name === o.name)); + return setting ? klona(setting) : klona(o) + }); + } if (chosen) { setActiveElementData(klona(chosen)); - setSettings(klona(chosen.settings)); + setSettings(settings); setValidators(klona(chosen.validators)); setDynamicData(chosen.dynamicData ? chosen.dynamicData : ''); setCriteria(chosen.criteria ? chosen.criteria : []); diff --git a/src/pages/BandoViewBeneficiario/index.js b/src/pages/BandoViewBeneficiario/index.js index bcb7bc0..66209f8 100644 --- a/src/pages/BandoViewBeneficiario/index.js +++ b/src/pages/BandoViewBeneficiario/index.js @@ -30,6 +30,8 @@ import { Editor } from 'primereact/editor'; import { Dialog } from 'primereact/dialog'; import PreferredBandoService from '../../service/preferred-bando-service'; +const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID; + const BandoViewBeneficiario = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); const chosenCompanyId = useStore().main.chosenCompanyId(); @@ -89,30 +91,52 @@ const BandoViewBeneficiario = () => { } const submitBtnLabel = () => { - if (applicationObj && applicationObj.id) { - return __('Vai alla domanda', 'gepafin'); - } else { + if (REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE') { return __('Presenta domanda', 'gepafin'); + } else { + if (applicationObj && applicationObj.id) { + return __('Vai alla domanda', 'gepafin'); + } else { + return __('Presenta domanda', 'gepafin'); + } } } const submitBtnIcon = () => { - if (applicationObj && applicationObj.id) { - return 'pi pi-arrow-right'; - } else { + if (REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE') { return 'pi pi-save'; + } else { + if (applicationObj && applicationObj.id) { + return 'pi pi-arrow-right'; + } else { + return 'pi pi-save'; + } } } const submitApplication = () => { if (data.confidi) { - displayConfidiPopup(); - } else { - if (applicationObj && applicationObj.id) { - navigate(`/imieibandi/${applicationObj.id}`); + if (data.id === 6 && REACT_APP_HUB_ID === 'p4lk3bcx1RStqTaIVVbXs') { + if (applicationObj && applicationObj.id) { + navigate(`/imieibandi/${applicationObj.id}`); + } else { + const bandoId = getBandoId(); + ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]); + } } else { + displayConfidiPopup(); + } + } else { + if (REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE') { const bandoId = getBandoId(); ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]); + } else { + if (applicationObj && applicationObj.id) { + navigate(`/imieibandi/${applicationObj.id}`); + } else { + const bandoId = getBandoId(); + ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]); + } } } } @@ -195,6 +219,7 @@ const BandoViewBeneficiario = () => { if (data.status === 'SUCCESS') { setData(getFormattedBandiData(data.data)); } + storeSet.main.unsetAsyncRequest(); } const errGetBandoCallback = (data) => { @@ -206,6 +231,7 @@ const BandoViewBeneficiario = () => { }); } set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); } const getFormattedBandiData = (data) => { @@ -291,10 +317,13 @@ const BandoViewBeneficiario = () => { BandoService.getBando(bandoId, getBandoCallback, errGetBandoCallback, [ ['companyId', chosenCompanyId] ]); - ApplicationService.getApplications(getApplCallback, errGetApplCallback, [ - ['callId', bandoId], - ['companyId', chosenCompanyId] - ]); + if (REACT_APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE') { + storeSet.main.setAsyncRequest(); + ApplicationService.getApplications(getApplCallback, errGetApplCallback, [ + ['callId', bandoId], + ['companyId', chosenCompanyId] + ]); + } } }, [id, chosenCompanyId]); @@ -521,4 +550,4 @@ const BandoViewBeneficiario = () => { } -export default BandoViewBeneficiario; \ No newline at end of file +export default BandoViewBeneficiario; diff --git a/src/pages/Dashboard/components/DraftApplicationsTable/index.js b/src/pages/Dashboard/components/DraftApplicationsTable/index.js index acaec4b..c41abb0 100644 --- a/src/pages/Dashboard/components/DraftApplicationsTable/index.js +++ b/src/pages/Dashboard/components/DraftApplicationsTable/index.js @@ -42,7 +42,7 @@ const DraftApplicationsTable = () => { if (data.status === 'SUCCESS') { if (is(Array, data.data)) { setItems(getFormattedBandiData(data.data)); - setStatuses(uniq(items.map(o => o.status))) + setStatuses(uniq(data.data.map(o => o.status))) initFilters(); } } diff --git a/src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js b/src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js index dbffcc9..f8885ce 100644 --- a/src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js +++ b/src/pages/DashboardBeneficiario/components/MyLatestSubmissionsTable/index.js @@ -57,6 +57,23 @@ const MyLatestSubmissionsTable = () => { setLocalAsyncRequest(false); } + const handleDeleteApplication = (id) => { + setLocalAsyncRequest(true); + ApplicationService.deleteApplication(id, (resp) => delApplCallback(resp, id), errDelApplCallback) + } + + const delApplCallback = (resp, id) => { + if (resp.status === 'SUCCESS') { + const newItems = items.filter(o => o.id !== id); + setItems(newItems); + } + setLocalAsyncRequest(false); + } + + const errDelApplCallback = (data) => { + setLocalAsyncRequest(false); + } + const getFormattedBandiData = (data) => { return [...(data || [])].map((d) => { d.callEndDate = new Date(d.callEndDate); @@ -130,7 +147,8 @@ const MyLatestSubmissionsTable = () => { const statusFilterTemplate = (options) => { return options.filterCallback(e.value, options.index)} - itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter" + itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} + className="p-column-filter" showClear/>; }; @@ -143,13 +161,24 @@ const MyLatestSubmissionsTable = () => { }; const actionsBodyTemplate = (rowData) => { - return - {'DRAFT' === rowData.status - ?
+ : + + + + + + + + + + + + + ); + }; + + 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/components/ArchiveDocument/index.js b/src/pages/DomandaEditPreInstructor/components/ArchiveDocument/index.js index 936e2bc..0660dba 100644 --- a/src/pages/DomandaEditPreInstructor/components/ArchiveDocument/index.js +++ b/src/pages/DomandaEditPreInstructor/components/ArchiveDocument/index.js @@ -1,8 +1,14 @@ import React, { useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; -import { isEmpty } from 'ramda'; +import { isEmpty, pathOr, isNil } from 'ramda'; import { wrap } from 'object-path-immutable'; +// store +import AppointmentService from '../../../../service/appointment-service'; + +// tools +import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse'; + // components import { Button } from 'primereact/button'; import { Dialog } from 'primereact/dialog'; @@ -11,14 +17,11 @@ import { Dropdown } from 'primereact/dropdown'; import { classNames } from 'primereact/utils'; import { InputSwitch } from 'primereact/inputswitch'; import { InputText } from 'primereact/inputtext'; - -import { classificationType, protocolType } from '../../../../configData'; -import AppointmentService from '../../../../service/appointment-service'; -import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse'; -import { storeSet } from '../../../../store'; import { Toast } from 'primereact/toast'; -const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => { +import { classificationType, protocolType } from '../../../../configData'; + +const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0, docAttachmentId = null, updateFn = () => {} }) => { const [loading, setLoading] = useState(false); const [isVisibleDialog, setIsVisibleDialog] = useState(false); const [modalData, setModalData] = useState({}); @@ -87,19 +90,29 @@ const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => { const submitCallback = (data) => { if (data.status === 'SUCCESS') { - console.log(data.data); + if (toast.current && data.message) { + toast.current.show({ + severity: 'success', + summary: '', + detail: data.message + }); + } + const documentAttachmentId = pathOr('fake_id', ['documentAttachmentId'], data.data); + updateFn(documentAttachmentId); } + setIsVisibleDialog(false); setLoading(false); } const errSubmitCallback = (data) => { if (toast.current && data.message) { toast.current.show({ - severity: 'error', + severity: data.status === 'SUCCESS' ? 'info' : 'error', summary: '', detail: data.message }); } + setIsVisibleDialog(false); set404FromErrorResponse(data); setLoading(false); } @@ -119,7 +132,7 @@ const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => { setTypes(protocolType.map(o => ({ value: o.id, label: o.name }))); }, []); - return (!isEmpty(ndg) + return (!isEmpty(ndg) && !isNil(ndg) && !docAttachmentId ? <> + + + + + + + + + + + + ); + }; + + const header = renderHeader(); + useEffect(() => { if (formInitialData) { //reset(); @@ -182,7 +241,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)} @@ -216,11 +275,11 @@ const DomandaBeneficiario = () => { {data.callName}

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

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

@@ -239,7 +298,7 @@ const DomandaBeneficiario = () => { {dataAppl.id ?

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

@@ -247,7 +306,7 @@ const DomandaBeneficiario = () => { {dataAppl.callTitle}

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

@@ -268,10 +327,13 @@ const DomandaBeneficiario = () => { ?

{__('Dettagli Richiesta', 'gepafin')}

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

-
- {renderHtmlContent(data.note)} -
+
{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}
+
: null} + + {data.id + ?
+

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

+
: null} {data.id @@ -282,7 +344,7 @@ const DomandaBeneficiario = () => { ? data.formFields.map((o, i) => { return { 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 ?
{if (!isVisibleEmailDialog) return; setIsVisibleEmailDialog(false); }}> + onHide={() => { + if (!isVisibleEmailDialog) return; + setIsVisibleEmailDialog(false); + }}>

{data.callEmail}

@@ -355,4 +459,4 @@ const DomandaBeneficiario = () => { } -export default DomandaBeneficiario; \ No newline at end of file +export default SoccorsoEditBeneficiario; diff --git a/src/pages/SoccorsoEditPreInstructor/index.js b/src/pages/SoccorsoEditPreInstructor/index.js index 7ca9299..ff42e8c 100644 --- a/src/pages/SoccorsoEditPreInstructor/index.js +++ b/src/pages/SoccorsoEditPreInstructor/index.js @@ -16,7 +16,7 @@ import AmendmentsService from '../../service/amendments-service'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import getBandoLabel from '../../helpers/getBandoLabel'; import getDateFromISOstring from '../../helpers/getDateFromISOstring'; -import renderHtmlContent from '../../helpers/renderHtmlContent'; +import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags'; // components import { Button } from 'primereact/button'; @@ -35,10 +35,12 @@ const SoccorsoEditPreInstructor = () => { const { id, amendmentId } = useParams(); const navigate = useNavigate(); const [data, setData] = useState({}); + const [isVisibleCloseAmendDialog, setIsVisibleCloseAmendDialog] = useState(false); const [isVisibleExtendTimeDialog, setIsVisibleExtendTimeDialog] = useState(false); const [extendedTime, setExtendedTime] = useState(3); const [isLoadingExtendingTime, setIsLoadingExtendingTime] = useState(false); const [isLoadingReminding, setIsLoadingReminding] = useState(false); + const [internalNote, setInternalNote] = useState(''); const toast = useRef(null); const [formInitialData, setFormInitialData] = useState({}); const { @@ -62,12 +64,16 @@ const SoccorsoEditPreInstructor = () => { const getCallback = (data) => { if (data.status === 'SUCCESS') { setData(getFormattedData(data.data)); - const formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => { + let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => { if (cur.fieldValue) { acc[cur.fieldId] = cur.fieldValue; } return acc; }, {}); + formDataInitial = { + ...formDataInitial, + amendmentDocuments: data.data.amendmentDocuments + } setFormInitialData(formDataInitial); } storeSet.main.unsetAsyncRequest(); @@ -112,17 +118,18 @@ const SoccorsoEditPreInstructor = () => { const header = renderHeader(); const updateNewAmendmentData = (value, path) => { - const newData = wrap(data).set(path.split('.'), value).value(); + const newData = wrap(data).set(path, value).value(); setData(newData); } const onSubmit = () => { }; - const doUpdateAmendment = () => { + const doUpdateAmendment = (doClose = false) => { trigger(); let formValues = klona(getValues()); const newFormValues = Object.keys(formValues) + .filter(v => v !== 'amendmentDocuments') .reduce((acc, cur) => { let fieldVal = formValues[cur]; @@ -135,30 +142,55 @@ const SoccorsoEditPreInstructor = () => { }); return acc; }, []); + const newAmendDocs = formValues.amendmentDocuments + ? formValues.amendmentDocuments.map(o => o.id).join(',') + : ''; const submitData = { - applicationFormFields: newFormValues + applicationFormFields: newFormValues, + amendmentDocuments: newAmendDocs, + amendmentNotes: data.amendmentNotes } + storeSet.main.setAsyncRequest(); - AmendmentsService.updateSoccorso(amendmentId, submitData, updateAmendmentCallback, errUpdateAmendmentCallback); + AmendmentsService.updateSoccorso( + amendmentId, + submitData, + (resp) => updateAmendmentCallback(resp, doClose), + errUpdateAmendmentCallback + ); } - const updateAmendmentCallback = (data) => { + const updateAmendmentCallback = (data, doClose = false) => { if (data.status === 'SUCCESS') { - if (toast.current) { - toast.current.show({ - severity: 'success', - summary: '', - detail: data.message - }); - } - const newFormDataInitial = data.data.applicationFormFields.reduce((acc, cur) => { - if (cur.fieldValue) { - acc[cur.fieldId] = cur.fieldValue; + setData(getFormattedData(data.data)); + console.log('internalNote', internalNote) + if (doClose) { + const submitData = { + internalNote } - return acc; - }, formInitialData); - setFormInitialData(newFormDataInitial); + storeSet.main.setAsyncRequest(); + AmendmentsService.closeSoccorso(amendmentId, submitData, closeAmendmentCallback, errCloseAmendmentCallback); + } else { + if (toast.current) { + toast.current.show({ + severity: 'success', + summary: '', + detail: data.message + }); + } + let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => { + if (cur.fieldValue) { + acc[cur.fieldId] = cur.fieldValue; + } + return acc; + }, formInitialData); + formDataInitial = { + ...formDataInitial, + amendmentDocuments: data.data.amendmentDocuments + } + setFormInitialData(formDataInitial); + } } storeSet.main.unsetAsyncRequest(); } @@ -175,12 +207,30 @@ const SoccorsoEditPreInstructor = () => { storeSet.main.unsetAsyncRequest(); } + const openCloseAmendmentDialog = () => { + setIsVisibleCloseAmendDialog(true); + } + + const headerCloseAmendDialog = () => { + return {__('Chiudi Soccorso Istruttorio', 'gepafin')} + } + + const hideCloseAmendDialog = () => { + setIsVisibleCloseAmendDialog(false); + } + + const footerCloseAmendDialog = () => { + return
+
+ } + const doCloseAmendment = () => { - const submitData = { - internalNote: data.internalNote - } - storeSet.main.setAsyncRequest(); - AmendmentsService.closeSoccorso(amendmentId, submitData, closeAmendmentCallback, errCloseAmendmentCallback); + doUpdateAmendment(true); } const closeAmendmentCallback = (data) => { @@ -193,7 +243,8 @@ const SoccorsoEditPreInstructor = () => { }); } if (data.data.status) { - updateNewAmendmentData(data.data.status, 'status') + updateNewAmendmentData(data.data.status, ['status']); + setIsVisibleCloseAmendDialog(false); } } storeSet.main.unsetAsyncRequest(); @@ -297,7 +348,6 @@ const SoccorsoEditPreInstructor = () => { useEffect(() => { if (formInitialData) { - //reset(); Object.keys(formInitialData).map(k => setValue(k, formInitialData[k])); trigger(); } @@ -342,7 +392,7 @@ const SoccorsoEditPreInstructor = () => { {data.callName}

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

@@ -361,26 +411,19 @@ const SoccorsoEditPreInstructor = () => {

{__('Dettagli Richiesta', 'gepafin')}

-
-
-

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

-
    - {data.formFields - ? data.formFields.map((o, i) =>
  1. - {o.label} -
  2. ) : null} -
-
-
-

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

-
- {renderHtmlContent(data.note)} -
-
- -
+

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

+
{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}
+
+
+

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

+
    + {data.formFields + ? data.formFields.map((o, i) =>
  1. + {o.label} +
  2. ) : null} +
@@ -388,15 +431,15 @@ const SoccorsoEditPreInstructor = () => {
-
-

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

+ {data.formFields && !isEmpty(data.formFields) + ?
+

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

-
- {data.formFields - ? data.formFields.map((o, i) => { + + {data.formFields.map((o, i) => { return { defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []} accept={[]} source="AMENDMENT" - sourceId={data.applicationId} + sourceId={amendmentId} multiple={true} /> - }) : null} - -
+ })} + +
: null} -
- -
- - updateNewAmendmentData( - e.htmlValue, - 'internalNote' - )} - style={{ height: 80 * 3, width: '100%' }} +
+

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

+
+

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

+
+ + updateNewAmendmentData( + e.htmlValue, + 'amendmentNotes' + )} + style={{ height: 80 * 3, width: '100%' }} + /> +
+
@@ -444,7 +506,7 @@ const SoccorsoEditPreInstructor = () => {
@@ -488,15 +550,38 @@ const SoccorsoEditPreInstructor = () => { setExtendedTime(e.value)}/>
+ + +
+ +
+ + setInternalNote(e.htmlValue)} + style={{ height: 80 * 3, width: '100%' }} + /> +
+
+
) } -export default SoccorsoEditPreInstructor; \ No newline at end of file +export default SoccorsoEditPreInstructor; diff --git a/src/pages/SoccorsoIstruttorioPreInstructor/components/PreInstructorSoccorsiTable/index.js b/src/pages/SoccorsoIstruttorioPreInstructor/components/PreInstructorSoccorsiTable/index.js index e509e43..87cba6b 100644 --- a/src/pages/SoccorsoIstruttorioPreInstructor/components/PreInstructorSoccorsiTable/index.js +++ b/src/pages/SoccorsoIstruttorioPreInstructor/components/PreInstructorSoccorsiTable/index.js @@ -78,7 +78,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] }, - beneficiaryName: { + companyName: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] }, @@ -149,7 +149,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => { - { ) } -export default PreInstructorSoccorsiTable; \ No newline at end of file +export default PreInstructorSoccorsiTable; diff --git a/src/pages/UserActivity/index.js b/src/pages/UserActivity/index.js new file mode 100644 index 0000000..8e93f5e --- /dev/null +++ b/src/pages/UserActivity/index.js @@ -0,0 +1,192 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { __ } from '@wordpress/i18n'; +import { isEmpty, pathOr } from 'ramda'; +import { useNavigate, useParams } from 'react-router-dom'; +import NumberFlow from '@number-flow/react'; + +// service +import UserService from '../../service/user-service'; + +// tools +import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; +import getDateFromISOstring from '../../helpers/getDateFromISOstring'; + +// components +import { Button } from 'primereact/button'; +import { Toast } from 'primereact/toast'; +import { Dropdown } from 'primereact/dropdown'; + + +const UserActivity = () => { + const [loading, setLoading] = useState(false); + const toast = useRef(null); + const navigate = useNavigate(); + const { id } = useParams(); + const [user, setUser] = useState({}); + const [roles, setRoles] = useState([]); + const [chosenRole, setChosenRole] = useState(0); + + const goBack = () => { + navigate(`/utenti`); + } + + const getUserCallback = (resp) => { + if (resp.status === 'SUCCESS') { + setUser(resp.data) + setChosenRole(resp.data.role?.id); + } + setLoading(false); + } + + const errGetUserCallback = (resp) => { + set404FromErrorResponse(resp); + setLoading(false); + } + + const getRolesCallback = (resp) => { + if (resp.status === 'SUCCESS') { + setRoles(resp.data) + } + setLoading(false); + } + + const errGetRolesCallback = (resp) => { + set404FromErrorResponse(resp); + setLoading(false); + } + + const getStatValue = (key, fallback = 0) => { + return pathOr(fallback, [key], {}); + } + + const handleRoleUpdate = () => { + if (user.role?.id !== chosenRole) { + setLoading(true); + UserService.updateUser(user.id, {roleId: chosenRole}, updateRoleCallback, errUpdateRoleCallback) + } + } + + const updateRoleCallback = (resp) => { + if (resp.status === 'SUCCESS') { + setUser(resp.data) + } + setLoading(false); + } + + const errUpdateRoleCallback = (resp) => { + set404FromErrorResponse(resp); + setLoading(false); + } + + useEffect(() => { + if (id && !isEmpty(id)) { + setLoading(true); + UserService.getUser(id, getUserCallback, errGetUserCallback); + UserService.getRoles(getRolesCallback, errGetRolesCallback); + } + }, [id]) + + return ( +
+
+

{__('Controllo attività utenti', 'gepafin')}

+
+ +
+ + +
+
+
+
+ +
+

+ {__('Nome utente', 'gepafin')} + {`${user.firstName} ${user.lastName}`} +

+

+ {__('Email', 'gepafin')} + {user.email} +

+

+ {__('Ruolo', 'gepafin')} + {user.role?.roleName} +

+

+ {__('Data registrazione', 'gepafin')} + {getDateFromISOstring(user.createdDate)} +

+

+ {__('Ultimo accesso', 'gepafin')} + {getDateFromISOstring(user.lastLogin)} +

+

+ {__('Stato account', 'gepafin')} + {user.status} +

+
+ + {['ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(user.role?.roleType) + ? <> +
+ +
+

{__('Cambia ruolo', 'gepafin')}

+
+ setChosenRole(e.value)} + options={roles.filter(o => [3, 5].includes(o.id)).map(o => ({ label: o.roleName, value: o.id }))} + optionLabel="label" + placeholder={__('Seleziona ruolo', 'gepafin')}/> +
+
+ : null} + +
+ + {/*
+

{__('Statistiche attività', 'gepafin')}

+
+
+ {__('Login totali', 'gepafin')} + {} +
+
+ {__('Bandi gestiti', 'gepafin')} + {} +
+
+ {__('Domande processate', 'gepafin')} + {} +
+
+
*/} +
+ ) +} + +export default UserActivity; diff --git a/src/pages/Users/components/AllUsersTable/index.js b/src/pages/Users/components/AllUsersTable/index.js index 932be58..6476cb5 100644 --- a/src/pages/Users/components/AllUsersTable/index.js +++ b/src/pages/Users/components/AllUsersTable/index.js @@ -24,6 +24,7 @@ import { Calendar } from 'primereact/calendar'; import { Tag } from 'primereact/tag'; import ProperBandoLabel from '../../../../components/ProperBandoLabel'; import translationStrings from '../../../../translationStringsForComponents'; +import { Link } from 'react-router-dom'; const AllUsersTable = () => { const users = useStore().main.users(); @@ -53,7 +54,7 @@ const AllUsersTable = () => { const getFormattedData = (data) => { return data - .filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR'].includes(o.role.roleType)); + .filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.role.roleType)); }; const clearFilter = () => { @@ -125,12 +126,16 @@ const AllUsersTable = () => { return ; }; - /*const actionsBodyTemplate = (rowData) => { - /!*return -