diff --git a/src/assets/scss/components/formBuilder.scss b/src/assets/scss/components/formBuilder.scss index db9b8ad..00db384 100644 --- a/src/assets/scss/components/formBuilder.scss +++ b/src/assets/scss/components/formBuilder.scss @@ -53,6 +53,14 @@ font-weight: 400; line-height: 21px; + &:hover { + cursor: pointer; + } + + /*&.selected { + border-color: var(--menuitem-active-background); + }*/ + .meta { display: flex; flex-direction: column; @@ -116,7 +124,7 @@ border: 1px solid var(--button-secondary-borderColor); background-color: var(--button-secondary-borderColor); width: 100%; - padding: 10px; + padding: 20px 10px; opacity: 0.6; color: white; font-size: 11px; @@ -241,9 +249,13 @@ .formElementSettings__repeaterItem { display: grid; - grid-template-columns: 4.5fr 2.4fr 1fr 1.4fr 0.7fr; + grid-template-columns: 1fr; gap: 12px; + &.tableRow { + grid-template-columns: 4.5fr 2.4fr 1fr 1.4fr 0.7fr; + } + > div { display: flex; align-items: center; diff --git a/src/assets/scss/components/statsBigBadges.scss b/src/assets/scss/components/statsBigBadges.scss index 6cb3c0a..6c08cb7 100644 --- a/src/assets/scss/components/statsBigBadges.scss +++ b/src/assets/scss/components/statsBigBadges.scss @@ -43,6 +43,119 @@ } } +.statsBigBadges__gridItemDoubleStats { + display: flex; + flex-direction: column; + padding: 16px; + border-radius: 6px; + border: 1px solid #858585; + background: #cecece; + align-items: center; + gap: 32px; + + span { + color: #FFF; + font-size: 18px; + font-style: normal; + font-weight: 600; + line-height: normal; + text-align: center; + } + + > span:first-of-type { + min-height: 50px; + } + + span.number { + font-size: 22px; + } + + .auxStats { + display: flex; + gap: 7px; + align-items: flex-start; + margin-top: auto; + + span { + font-size: 15px; + font-weight: 400; + text-align: left; + } + + span.badge { + display: inline-block; + padding: 5px 10px; + background-color: var(--card-full-background-color-4); + border-radius: 4px; + margin-right: 7px; + } + } + + &:nth-of-type(1) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-2); + } + + &:nth-of-type(2) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-3); + } + + &:nth-of-type(3) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-5); + } + + &:nth-of-type(4) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-7); + } +} + +.statsBigBadges__gridItemDoubleStatsBeneficiary { + display: flex; + flex-direction: column; + padding: 16px; + border-radius: 6px; + border: 1px solid #858585; + background: #cecece; + align-items: center; + gap: 32px; + + span { + color: #FFF; + font-size: 18px; + font-style: normal; + font-weight: 600; + line-height: normal; + text-align: center; + } + + > span:first-of-type { + min-height: 50px; + } + + &:nth-of-type(1) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-2); + } + + &:nth-of-type(2) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-4); + } + + &:nth-of-type(3) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-3); + } + + &:nth-of-type(4) { + border: 1px solid var(--yellow-500); + background: var(--card-full-background-color-1); + } +} + .statsBigBadges__grid { .statsBigBadges__gridItem { &:nth-of-type(1) { @@ -109,11 +222,27 @@ } } } + + &.doubleStatsItems { + grid-template-columns: repeat(4, minmax(220px, 1fr)); + } +} + +@media (max-width: 1290px) { + .statsBigBadges__grid { + &.doubleStatsItems { + grid-template-columns: repeat(2, minmax(220px, 1fr)); + } + } } @media (max-width: 820px) { .statsBigBadges__grid { grid-template-columns: 1fr; + + &.doubleStatsItems { + grid-template-columns: minmax(220px, 1fr); + } } } diff --git a/src/components/ChartDomandePerStato/index.js b/src/components/ChartDomandePerStato/index.js new file mode 100644 index 0000000..a27c0e5 --- /dev/null +++ b/src/components/ChartDomandePerStato/index.js @@ -0,0 +1,78 @@ +import React, { useEffect, useState } from 'react'; +import { __ } from '@wordpress/i18n'; +import { Tooltip, ResponsiveContainer, Cell, Pie, PieChart, Legend } from 'recharts'; +import { isEmpty } from 'ramda'; + +// tools +import getBandoLabel from '../../helpers/getBandoLabel'; + + +const ChartDomandePerStato = ({ title, data = [] }) => { + const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042', '#8884d8', '#82ca9d']; + const [chartData, setChartData] = useState({}); + + const CustomTooltip = ({ active, payload }) => { + if (active && payload && payload.length) { + return ( +
+

{getBandoLabel(payload[0].name)}

+

+ {payload[0].name}: {payload[0].value} +

+
+ ); + } + return null; + }; + + useEffect(() => { + const grouped = data.reduce((acc, cur) => { + if (cur.status === 'APPROVED') { + acc.approved.value = cur.numberOfApplication; + } else if (cur.status === 'REJECTED') { + acc.rejected.value = cur.numberOfApplication; + } else { + acc.inProgress.value += cur.numberOfApplication; + } + return acc; + }, { + inProgress: {value: 0, label: __('In corso', 'gepafin')}, + approved: {value: 0, label: __('Approvato', 'gepafin')}, + rejected: {value: 0, label: __('Respinto', 'gepafin')} + }); + setChartData(grouped) + }, [data]); + + return (
+ {title ? {title} : null} + {chartData && !isEmpty(chartData) + ?
+ + + `${(percent * 100).toFixed(0)}%`} + outerRadius={120} + fill="#8884d8" + dataKey="value" + nameKey="label" + > + {Object.values(chartData).map((entry, index) => ( + + ))} + + } /> + + + +
: null} +
) +} + +export default ChartDomandePerStato; \ No newline at end of file diff --git a/src/components/ChartRichiesteVsApprovate/index.js b/src/components/ChartRichiesteVsApprovate/index.js new file mode 100644 index 0000000..e693b45 --- /dev/null +++ b/src/components/ChartRichiesteVsApprovate/index.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { __ } from '@wordpress/i18n'; +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; +import { isEmpty } from 'ramda'; + +// components + + +const ChartRichiesteVsApprovate = ({ title, data = [] }) => { + + // Custom tooltip + const CustomTooltip = ({ active, payload, label }) => { + if (active && payload && payload.length) { + return ( +
+

{label}

+

+ {__('In bozza', 'gepafin')}: {payload[0].value} +

+

+ {__('Inviate', 'gepafin')}: {payload[1].value} +

+
+ ); + } + return null; + }; + + return (
+ {title ? {title} : null} + {data && !isEmpty(data) + ?
+ + + + + + }/> + + + + + +
: null} +
) +} + +export default ChartRichiesteVsApprovate; \ No newline at end of file diff --git a/src/components/FormField/components/CriteriaTable/RenderTable/components/LastRowCell/index.js b/src/components/FormField/components/CriteriaTable/RenderTable/components/LastRowCell/index.js index cd0d954..73d987c 100644 --- a/src/components/FormField/components/CriteriaTable/RenderTable/components/LastRowCell/index.js +++ b/src/components/FormField/components/CriteriaTable/RenderTable/components/LastRowCell/index.js @@ -1,4 +1,4 @@ -import { head, isNil, pathOr } from 'ramda'; +import { head, is, isNil, pathOr } from 'ramda'; import getNumberFormatted from '../../../../../../../helpers/getNumberFormatted'; const LastRowCell = ({columnId, lastRowCfg, columnMeta = {}, tableValue = []}) => { @@ -9,7 +9,7 @@ const LastRowCell = ({columnId, lastRowCfg, columnMeta = {}, tableValue = []}) = cellValue = pathOr(0, ['total'], tableValue); } - return {getNumberFormatted(cellValue)}; + return {is(Number, cellValue) ? getNumberFormatted(cellValue) : cellValue}; }; export default LastRowCell; \ No newline at end of file diff --git a/src/components/FormField/components/Table/RenderTable/index.js b/src/components/FormField/components/Table/RenderTable/index.js index c925bcd..f376913 100644 --- a/src/components/FormField/components/Table/RenderTable/index.js +++ b/src/components/FormField/components/Table/RenderTable/index.js @@ -7,7 +7,7 @@ import { isEmpty } from 'ramda'; import DefaultCell from './components/DefaultCell'; import LastRowCell from './components/LastRowCell'; -const RenderTable = ({ rowsData, columnsCfg, lastRowCfg, setRowsFn, disabled }) => { +const RenderTable = ({ rowsData = [], columnsCfg, lastRowCfg, setRowsFn, disabled }) => { const table = useReactTable({ data: rowsData, columns: columnsCfg, diff --git a/src/components/FormField/components/Table/index.js b/src/components/FormField/components/Table/index.js index 02d33be..62d71de 100644 --- a/src/components/FormField/components/Table/index.js +++ b/src/components/FormField/components/Table/index.js @@ -122,13 +122,13 @@ const Table = ({ useEffect(() => { const stateFieldData = pathOr([], ['stateFieldData'], tableColumns); - const obj = stateFieldData + /*const obj = stateFieldData .reduce((acc, cur) => { acc[cur.name] = '' return acc; - }, {}); - let rowsData = pathOr([obj], ['rowsData'], tableColumns); - rowsData = isEmpty(rowsData) ? [obj] : rowsData; + }, {});*/ + let rowsData = pathOr([], ['rowsData'], tableColumns); + //rowsData = isEmpty(rowsData) ? [obj] : rowsData; setColumnsCfg(stateFieldData); setRowsCfg(rowsData); @@ -169,7 +169,8 @@ const Table = ({ {label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables) ? * : null} - {rows ? { case 'CLOSE': return __('Chiuso', 'gepafin'); + case 'REJECTED': + return __('Respinto', 'gepafin'); + default: return ''; } diff --git a/src/helpers/getBandoSeverity.js b/src/helpers/getBandoSeverity.js index d6c4dbf..03b8704 100644 --- a/src/helpers/getBandoSeverity.js +++ b/src/helpers/getBandoSeverity.js @@ -57,6 +57,9 @@ const getBandoSeverity = (status) => { case 'CLOSE': return 'closed'; + case 'REJECTED': + return 'danger'; + default: return 'info'; } diff --git a/src/helpers/isDateTimeInFuture.js b/src/helpers/isDateTimeInFuture.js new file mode 100644 index 0000000..4c24c09 --- /dev/null +++ b/src/helpers/isDateTimeInFuture.js @@ -0,0 +1,10 @@ +const isDateTimeInFuture = (dateStr, timeStr) => { + const [hours, minutes, seconds = 0] = timeStr.split(':').map(Number); + const dateTime = new Date(dateStr); + dateTime.setHours(hours, minutes, seconds); + const now = new Date(); + + return dateTime > now; +} + +export default isDateTimeInFuture; \ No newline at end of file diff --git a/src/layouts/DefaultLayout/components/AppSidebar/index.js b/src/layouts/DefaultLayout/components/AppSidebar/index.js index aa25929..c449022 100644 --- a/src/layouts/DefaultLayout/components/AppSidebar/index.js +++ b/src/layouts/DefaultLayout/components/AppSidebar/index.js @@ -132,11 +132,11 @@ const AppSidebar = () => { enable: false }, { - label: __('Report e Analisi', 'gepafin'), + label: __('Statistiche', 'gepafin'), icon: 'pi pi-chart-bar', - //href: '/stats', + href: '/stats', id: 15, - enable: false + enable: intersection(permissions, ['APPLY_CALLS']).length }, { label: __('Log di Sistema', 'gepafin'), diff --git a/src/pages/BandiBeneficiario/components/AllBandiAccordion/index.js b/src/pages/BandiBeneficiario/components/AllBandiAccordion/index.js index 057deea..8218845 100644 --- a/src/pages/BandiBeneficiario/components/AllBandiAccordion/index.js +++ b/src/pages/BandiBeneficiario/components/AllBandiAccordion/index.js @@ -1,5 +1,5 @@ import React, { useState, useEffect} from 'react'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { is, uniq, isNil, isEmpty } from 'ramda'; import { wrap } from 'object-path-immutable'; import { useNavigate } from 'react-router-dom'; @@ -30,6 +30,8 @@ import { Button } from 'primereact/button'; // i18n import translationStrings from '../../../../translationStringsForComponents'; import isDateTimeInPast from '../../../../helpers/isDateTimeInPast'; +import isDateTimeInFuture from '../../../../helpers/isDateTimeInFuture'; +import { Badge } from 'primereact/badge'; const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID; @@ -182,18 +184,22 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => { const rowExpansionTemplate = (data) => { const isCallExpired = isDateTimeInPast(data.dates[1], data.endTime); + const isCallScheduled = isDateTimeInFuture(data.dates[0], data.startTime); + return (
{renderHtmlContent(data.descriptionShort)}

{__('Scadenza', 'gepafin')}: {getDateFromISOstring(data.dates[1])}

- {!isCallExpired && !isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && (!data.confidi + {!isCallExpired && !isCallScheduled && !isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && (!data.confidi || (data.confidi && data.id === 6 && REACT_APP_HUB_ID === 'p4lk3bcx1RStqTaIVVbXs')) ? : null} {isCallExpired - ?

{__('È scaduto', 'gepafin')}

: null} - {isCallExpired || (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && data.confidi + ?

: null} + {isCallScheduled + ?

: null} + {isCallExpired || isCallScheduled || (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && data.confidi && (data.id !== 6 || (data.id === 6 && REACT_APP_HUB_ID !== 'p4lk3bcx1RStqTaIVVbXs'))) ?
+
+ + + {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' + ? : null} +
+ { @@ -221,7 +225,8 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g return (
- isEmpty(o.value) || isEmpty(o.score)).length === 0 || __('Non lasciare il valore vuoto', 'gepafin') } - }}/> + }}/> : null} - isEmpty(o.value)).length === 0 || __('Non lasciare il valore vuoto', 'gepafin') } }} - /> + /> : null}
diff --git a/src/pages/BandoEdit/components/BandoEditFormStep3/index.js b/src/pages/BandoEdit/components/BandoEditFormStep3/index.js new file mode 100644 index 0000000..b67b93f --- /dev/null +++ b/src/pages/BandoEdit/components/BandoEditFormStep3/index.js @@ -0,0 +1,149 @@ +import React, { forwardRef, useEffect, useRef, useState } from 'react'; +import { __ } from '@wordpress/i18n'; +import { useNavigate, useParams } from 'react-router-dom'; +import { klona } from 'klona'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; + +// api +import EvaluationFormsService from '../../../../service/evaluation-forms-service'; +import FormsService from '../../../../service/forms-service'; + +// store +import { storeGet, storeSet } from '../../../../store'; + +// tools +import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse'; + +// components +import BandoEditFormActions from '../BandoEditFormActions'; +import { Toast } from 'primereact/toast'; +import FormBuilder from '../../../BandoFormsEdit/components/FormBuilder'; +//import { elementItems } from '../../../../tempData'; + + +const BandoEditFormStep3 = forwardRef(function () { + const navigate = useNavigate(); + const { id } = useParams(); + const [formName, setFormName] = useState(''); + const [bandoStatus, setBandoStatus] = useState(''); + const toast = useRef(null); + + const getBandoId = () => { + const parsed = parseInt(id) + return !isNaN(parsed) ? parsed : 0; + } + + const onSaveDraft = () => { + const content = storeGet.main.formElements(); + const formId = storeGet.main.formId(); + const formData = { + label: formName, + content + } + + storeSet.main.setAsyncRequest(); + EvaluationFormsService.updateForm(formId, formData, updateFormCallback, errUpdateFormCallback) + } + + const updateFormCallback = (resp) => { + if (resp.status === 'SUCCESS') { + setBandoStatus(resp.data.callStatus); + if (toast.current) { + toast.current.show({ + severity: 'success', + summary: '', + detail: __('Il bando è stato aggiornato correttamente!', 'gepafin') + }); + } + } + storeSet.main.unsetAsyncRequest(); + } + + const errUpdateFormCallback = (resp) => { + set404FromErrorResponse(resp); + storeSet.main.unsetAsyncRequest(); + } + + const openPreview = () => { + const bandoId = getBandoId(); + navigate(`/bandi/${bandoId}/preview`); + } + + const openPreviewEvaluation = () => { + const bandoId = getBandoId(); + navigate(`/bandi/${bandoId}/preview-evaluation`); + } + + const getElementItemsCallback = (data) => { + if (data.status === 'SUCCESS') { + //storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder)); + storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder)); + } + storeSet.main.unsetAsyncRequest(); + } + + const errGetElementItemsCallbacks = (data) => { + storeSet.main.unsetAsyncRequest(); + } + + const getFormCallback = (resp) => { + if (resp.status === 'SUCCESS') { + storeSet.main.formId(resp.data.id); + storeSet.main.formLabel(resp.data.label); + setFormName(resp.data.label); + setBandoStatus(resp.data.callStatus); + const elements = klona(resp.data.content); + storeSet.main.formElements(elements); + } + storeSet.main.unsetAsyncRequest(); + } + + const errGetFormCallback = (resp) => { + set404FromErrorResponse(resp); + storeSet.main.unsetAsyncRequest(); + } + + useEffect(() => { + storeSet.main.setAsyncRequest(); + EvaluationFormsService.getFormForCall(id, getFormCallback, errGetFormCallback) + }, [id]); + + useEffect(() => { + storeSet.main.setAsyncRequest(); + FormsService.getElementItems(getElementItemsCallback, errGetElementItemsCallbacks); + + return () => { + storeSet.main.formId(0); + storeSet.main.formElements([]); + storeSet.main.activeElement(''); + storeSet.main.selectedElement(''); + } + }, []); + + return ( +
+
+ + + +
+ +
+ +
+ {__('Azioni', 'gepafin')} +
+ + + +
+ ) +}) + +export default BandoEditFormStep3; \ No newline at end of file diff --git a/src/pages/BandoEdit/index.js b/src/pages/BandoEdit/index.js index f9b0951..275fd61 100644 --- a/src/pages/BandoEdit/index.js +++ b/src/pages/BandoEdit/index.js @@ -23,6 +23,7 @@ import { Messages } from 'primereact/messages'; import FormsService from '../../service/forms-service'; import BlockingOverlay from '../../components/BlockingOverlay'; import { Toast } from 'primereact/toast'; +import BandoEditFormStep3 from './components/BandoEditFormStep3'; const BandoEdit = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); @@ -35,28 +36,45 @@ const BandoEdit = () => { const bandoMsgs = useRef(null); const toast = useRef(null); - const stepItems = [ - { - label: __('Testi', 'gepafin'), - command: () => { - if (activeStep === 0) { - return false + const stepItems = (evalProcessVer) => { + let steps = [ + { + label: __('Testi', 'gepafin'), + command: () => { + if (activeStep === 0) { + return false + } + bandoMsgs.current.clear(); + goToStep(0); } - bandoMsgs.current.clear(); - goToStep(0); - } - }, - { - label: __('Gestione', 'gepafin'), - command: () => { - if (activeStep === 1) { - return false + }, + { + label: __('Gestione', 'gepafin'), + command: () => { + if (activeStep === 1) { + return false + } + bandoMsgs.current.clear(); + goToStep(1); } - bandoMsgs.current.clear(); - goToStep(1); } + ]; + + if (evalProcessVer === 'V2') { + steps.push({ + label: __('Valutazione', 'gepafin'), + command: () => { + if (activeStep === 2) { + return false + } + bandoMsgs.current.clear(); + goToStep(2); + } + }) } - ]; + + return steps; + } const goToStep = (step) => { setActiveStep(step); @@ -238,7 +256,8 @@ const BandoEdit = () => { if (bandoId === 0) { setData({ - status: null + status: null, + evaluationVersion: 'V2' }); storeSet.main.unsetAsyncRequest(); @@ -274,7 +293,7 @@ const BandoEdit = () => { {!isEmpty(data) ? : null} @@ -293,6 +312,9 @@ const BandoEdit = () => { {activeStep === 1 ? : null} + {activeStep === 2 && data.evaluationVersion === 'V2' + ? + : null}

{__('Crea o modifica il Form compilabile dal Beneficiario', 'gepafin')}

diff --git a/src/pages/BandoFormsEdit/components/BuilderElement/index.js b/src/pages/BandoFormsEdit/components/BuilderElement/index.js index 83d22af..d0acc67 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElement/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElement/index.js @@ -1,12 +1,16 @@ -import React, { useEffect, useRef, useState } from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' import { useDrag, useDrop } from 'react-dnd' import { ItemTypes } from '../ItemTypes'; import { __ } from '@wordpress/i18n'; import { head, isEmpty } from 'ramda'; +import { klona } from 'klona'; // store import { storeSet, useStore } from '../../../../store'; +// tools +import uniqid from '../../../../helpers/uniqid'; + // components import { Button } from 'primereact/button'; import { Tag } from 'primereact/tag'; @@ -14,11 +18,14 @@ import BuilderElementProperLabel from '../BuilderElementProperLabel'; const BuilderElement = ({ id, name, label, index, bandoStatus }) => { const draggingElementId = useStore().main.draggingElementId(); + const selectedElement = useStore().main.selectedElement(); const ref = useRef(null); const elements = useStore().main.formElements(); const element = head(elements.filter(o => o.id === id)); const [isVariable, setIsVariable] = useState('secondary'); const [isFormula, setIsFormula] = useState('secondary'); + const [variableName, setVariableName] = useState('secondary'); + const [formulaName, setFormulaName] = useState('secondary'); const [isRequestedAmount, setIsRequestedAmount] = useState(false); const [isDelegation, setIsDelegation] = useState(false); @@ -93,11 +100,33 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => { storeSet.main.moveElement(dragIndex, hoverIndex, item); } - const openSettings = (id) => { + const openSettings = () => { storeSet.main.activeElement(id); } - const remove = (id) => { + const selectElement = () => { + storeSet.main.selectedElement(id); + } + + const duplicateElement = useCallback(() => { + const duplicatedElement = head(elements.filter(o => o.id === id)); + + if (duplicatedElement) { + const copyElement = klona(duplicatedElement); + copyElement.settings = copyElement.settings.map((o) => { + if (o.name === 'label') { + o.value = `Copy - ${o.value}` + } + return o; + }) + copyElement.id = uniqid(); + const originalIndex = elements.map(o => o.id).indexOf(id); + const newElements = [...elements].toSpliced(originalIndex + 1, 0, copyElement); + storeSet.main.formElements(newElements); + } + }, [elements]); + + const remove = () => { storeSet.main.removeElement(id); } @@ -112,10 +141,12 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => { if (variable && !isEmpty(variable.value)) { setIsVariable('warning'); + setVariableName(variable.value) } if (formula && !isEmpty(formula.value)) { setIsFormula('warning'); + setFormulaName(formula.value) } if (isRequestedAmount && !isEmpty(isRequestedAmount.value) && isRequestedAmount.value) { @@ -132,14 +163,18 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => { ?
{__('lascia qui', 'gepafin')}
- :
+ :
{['numberinput', 'criteria_table'].includes(name) - ? : null} + ? : null} {name === 'numberinput' - ? : null} + ? : null} {isRequestedAmount ? : null} {isDelegation @@ -148,8 +183,9 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
-
) diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js index 33cd57c..0795c5a 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js @@ -36,7 +36,8 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => { table_columns: '', criteria_table_columns: '', variable: __('Variabile (lettere, cifre e "_"; il primo carattere deve essere una lettera!)', 'gepafin'), - formula: __('Formula di calcolo automatico', 'gepafin') + formula: __('Formula di calcolo automatico', 'gepafin'), + isChecklistItem: __('Fa parte di "checklist"?', 'gepafin'), } const settingDescription = { @@ -104,7 +105,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => { name={setting.name} bandoStatus={bandoStatus} setDataFn={updateDataFn}/> - } else if (['isRequestedAmount', 'isDelegation'].includes(setting.name)) { + } else if (['isRequestedAmount', 'isDelegation', 'isChecklistItem'].includes(setting.name)) { return changeFn(e.value, setting.name)}/> diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingCriteriaTableColumns/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingCriteriaTableColumns/index.js index cd1a251..333d8b9 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingCriteriaTableColumns/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingCriteriaTableColumns/index.js @@ -277,14 +277,14 @@ const ElementSettingCriteriaTableColumns = ({ <>
{stateFieldData.length > 0 - ?
+ ?
{__('Colonne', 'gepafin')}
{__('Tipo', 'gepafin')}
{__('Calcola', 'gepafin')}
{__('Predefinito?', 'gepafin')}
: null} - {stateFieldData.map((o, i) =>
+ {stateFieldData.map((o, i) =>
{properFields(o, i)}
)}
) : null} : null} - + {context === 'application' + ?
{ display="chip" placeholder={__('Scegli', 'gepafin')}/>
-
+
: null} {settings && settings .filter(o => ['variable', 'formula'].includes(o.name)).length > 0 @@ -244,7 +249,7 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => { .map((o) => ) : null} diff --git a/src/pages/BandoFormsEdit/components/FormBuilder/index.js b/src/pages/BandoFormsEdit/components/FormBuilder/index.js index 076afdc..3a02f75 100644 --- a/src/pages/BandoFormsEdit/components/FormBuilder/index.js +++ b/src/pages/BandoFormsEdit/components/FormBuilder/index.js @@ -13,7 +13,7 @@ import BuilderElementSettings from '../BuilderElementSettings'; import BuilderDropzone from '../BuilderDropzone'; import BlockingOverlay from '../../../../components/BlockingOverlay'; -const FormBuilder = ({ bandoStatus }) => { +const FormBuilder = ({ callStatus, context }) => { const elements = useStore().main.formElements(); const elementItems = useStore().main.elementItems(); const activeElement = useStore().main.activeElement(); @@ -27,10 +27,10 @@ const FormBuilder = ({ bandoStatus }) => { id={field.id} label={field.label} name={field.name} - bandoStatus={bandoStatus} + callStatus={callStatus} /> ) - }, [bandoStatus]); + }, [callStatus]); const renderItem = useCallback((item) => { return ( @@ -58,7 +58,9 @@ const FormBuilder = ({ bandoStatus }) => { <>

{__('Impostazioni del campo modulo', 'gepafin')}

- {!isEmpty(activeElement) ? : null} + {!isEmpty(activeElement) + ? + : null}
diff --git a/src/pages/BandoFormsEdit/index.js b/src/pages/BandoFormsEdit/index.js index e26a69a..e739c89 100644 --- a/src/pages/BandoFormsEdit/index.js +++ b/src/pages/BandoFormsEdit/index.js @@ -24,7 +24,7 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import BandoService from '../../service/bando-service'; // TODO temp data -import { elementItems } from '../../tempData'; +//import { elementItems } from '../../tempData'; const BandoFormsEdit = () => { const { id, formId } = useParams(); @@ -110,7 +110,6 @@ const BandoFormsEdit = () => { const formCreateCallback = (data, shouldRedirect) => { if (data.status === 'SUCCESS') { - storeSet.main.unsetAsyncRequest(); const bandoId = getBandoId(); if (shouldRedirect) { navigate(`/bandi/${bandoId}/forms/${data.data.id}/preview`); @@ -127,6 +126,7 @@ const BandoFormsEdit = () => { }); } } + storeSet.main.unsetAsyncRequest(); } const errFormCreateCallback = (data) => { @@ -215,13 +215,15 @@ const BandoFormsEdit = () => { const getElementItemsCallback = (data) => { if (data.status === 'SUCCESS') { - storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder)); - //storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder)); + //storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder)); + storeSet.main.elementItems(data.data + .filter(o => o.id !== 22) + .sort((a, b) => a.sortOrder - b.sortOrder)); } storeSet.main.unsetAsyncRequest(); } - const errGetElementItemsCallbacks = (data) => { + const errGetElementItemsCallback = () => { storeSet.main.unsetAsyncRequest(); } @@ -261,7 +263,7 @@ const BandoFormsEdit = () => { const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0; storeSet.main.setAsyncRequest(); - FormsService.getElementItems(getElementItemsCallback, errGetElementItemsCallbacks); + FormsService.getElementItems(getElementItemsCallback, errGetElementItemsCallback); if (bandoFormId) { storeSet.main.setAsyncRequest(); @@ -276,6 +278,8 @@ const BandoFormsEdit = () => { storeSet.main.formLabel(''); storeSet.main.formElements([]); storeSet.main.bandoCriteria([]); + storeSet.main.activeElement(''); + storeSet.main.selectedElement(''); } }, [id, formId]); @@ -317,7 +321,7 @@ const BandoFormsEdit = () => {
- +
diff --git a/src/pages/BandoViewBeneficiario/index.js b/src/pages/BandoViewBeneficiario/index.js index ad984cf..ab99cb8 100644 --- a/src/pages/BandoViewBeneficiario/index.js +++ b/src/pages/BandoViewBeneficiario/index.js @@ -12,11 +12,13 @@ import getNumberWithCurrency from '../../helpers/getNumberWithCurrency'; import getDateFromISOstring from '../../helpers/getDateFromISOstring'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import renderHtmlContent from '../../helpers/renderHtmlContent'; +import isDateTimeInPast from '../../helpers/isDateTimeInPast'; // api import BandoService from '../../service/bando-service'; import FaqItemService from '../../service/faq-item-service'; import ApplicationService from '../../service/application-service'; +import PreferredBandoService from '../../service/preferred-bando-service'; // components import { Skeleton } from 'primereact/skeleton'; @@ -28,8 +30,6 @@ import { Message } from 'primereact/message'; import { Toast } from 'primereact/toast'; import { Editor } from 'primereact/editor'; import { Dialog } from 'primereact/dialog'; -import PreferredBandoService from '../../service/preferred-bando-service'; -import isDateTimeInPast from '../../helpers/isDateTimeInPast'; const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID; diff --git a/src/pages/Dashboard/index.js b/src/pages/Dashboard/index.js index 4bb003e..0126e31 100644 --- a/src/pages/Dashboard/index.js +++ b/src/pages/Dashboard/index.js @@ -112,7 +112,7 @@ const Dashboard = () => { currency: 'EUR', currencyDisplay: 'symbol' }} - locales="en-US"/> + locales="it-IT"/>
diff --git a/src/pages/DashboardPreInstructor/index.js b/src/pages/DashboardPreInstructor/index.js index cbd94a5..ed54aeb 100644 --- a/src/pages/DashboardPreInstructor/index.js +++ b/src/pages/DashboardPreInstructor/index.js @@ -31,12 +31,14 @@ const DashboardPreInstructor = () => { const errGetStats = () => {} - const getStatValue = (key, fallback = '') => { - return pathOr(fallback, [key], mainStats); + const getStatValue = (keys = [], fallback = '') => { + return pathOr(fallback, keys, mainStats); } useEffect(() => { - DashboardService.getEvaluationsStats(getStats, errGetStats); + DashboardService.getInstructorAmendmentsStats(getStats, errGetStats, [ + ['userId', userData.id] + ]); }, []); return( @@ -49,49 +51,57 @@ const DashboardPreInstructor = () => {

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

-
-
- {__('Totale domande', 'gepafin')} - +
+ {__('Domande da valutare', 'gepafin')} + + {/*
+ + {getStatValue(['assignedApplication', 'additionalApplicationPercentage'], 0)}% + {__('da ieri', 'gepafin')} +
*/}
-
- {__('In soccorso', 'gepafin')} - + {__('Domande valutate', 'gepafin')} + + {/*
+ + {getStatValue(['evaluatedApplication', 'dailyAverage'], 0)} + {__('media giornaliera', 'gepafin')} +
*/}
-
- {__('In valutazione', 'gepafin')} - -
-
- {__('Completate', 'gepafin')} - -
-
- {__('Tempo medio di valutazione', 'gepafin')} - + {__('Tempo medio valutazione', 'gepafin')} + + {/*
+ + {getStatValue(['averageEvaluationDays', 'timeDifferenceFromAverage'], 0)} + {__('rispetto alla media', 'gepafin')} +
*/}
-
- {__('Domande in scadenza (48h)', 'gepafin')} - + {__('Soccorsi istruttori in corso', 'gepafin')} + + locales="it-IT"/> + {/*
+ + {getStatValue(['amendmentInProgress', 'expiringToday'], 0)} + {__('in scadenza oggi', 'gepafin')} +
*/}
diff --git a/src/pages/DomandaEditInstructorManager/index.js b/src/pages/DomandaEditInstructorManager/index.js index c273bf2..a85efde 100644 --- a/src/pages/DomandaEditInstructorManager/index.js +++ b/src/pages/DomandaEditInstructorManager/index.js @@ -1,9 +1,12 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { __, sprintf } from '@wordpress/i18n'; import { useNavigate, useParams } from 'react-router-dom'; -import { is, isEmpty, isNil, sum, pathOr, head } from 'ramda'; +import { is, isEmpty, isNil, sum, pathOr, head, pluck } from 'ramda'; import { klona } from 'klona'; import { wrap } from 'object-path-immutable'; +import { evaluate } from 'mathjs'; +import equal from 'fast-deep-equal'; +import { useForm } from 'react-hook-form'; // store import { storeGet, storeSet, useStore } from '../../store'; @@ -15,8 +18,21 @@ import AppointmentService from '../../service/appointment-service'; // tools import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; -import getBandoLabel from '../../helpers/getBandoLabel'; -import getDateFromISOstring from '../../helpers/getDateFromISOstring'; +import { + isCAP, + isCodiceFiscale, + isEmail, + isEmailPEC, + isIBAN, + isMarcaDaBollo, + isPIVA, + isUrl, maxChecks, minChecks, nonEmptyTables +} from '../../helpers/validators'; +import formatDateString from '../../helpers/formatDateString'; +import getTokens from '../../helpers/getTokens'; +import parseCommaDecimal from '../../helpers/parseCommaDecimal'; +import renderWithDataVars from '../../helpers/renderWithDataVars'; +import renderHtmlContent from '../../helpers/renderHtmlContent'; // components import { Skeleton } from 'primereact/skeleton'; @@ -31,12 +47,11 @@ import HelpIcon from '../../icons/HelpIcon'; 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'; -import getDateTimeFromISOstring from '../../helpers/getDateTimeFromISOstring'; +import ApplicationInfo from '../DomandaEditPreInstructor/components/ApplicationInfo'; +import ApplicationDownloadFiles from '../DomandaEditPreInstructor/components/ApplicationDownloadFiles'; +import FormField from '../../components/FormField'; const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID; const APP_HUB_ID = process.env.REACT_APP_HUB_ID; @@ -66,12 +81,46 @@ const DomandaEditInstructorManager = () => { duration: 0, amount: 0 }); + const [formData, setFormData] = useState([]); + const [formId, setFormId] = useState(0); + const [formInitialData, setFormInitialData] = useState(null); + const { + control, + handleSubmit, + formState: { errors }, + setValue, + trigger, + register, + getValues, + watch, + reset + } = useForm({ + defaultValues: useMemo(() => { + return formInitialData ? formInitialData : {} + }, [formInitialData]), + mode: 'onChange' + }); + const validationFns = { + isPIVA, + isCodiceFiscale, + isCAP, + isIBAN, + isEmail, + isEmailPEC, + isUrl, + isMarcaDaBollo, + minChecks, + maxChecks, + nonEmptyTables + } + const values = getValues(); + const formValues = watch(); const goToEvaluationsPage = () => { navigate('/mie-domande'); } - const updateFlagsForSoccorso = (data) => { + const updateFlagsForSoccorso = useCallback((data) => { let nonRatedFilesLength = 0; if (data.files) { @@ -90,14 +139,28 @@ const DomandaEditInstructorManager = () => { 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) + if (data.evaluationVersion === 'V1') { + if (data.checklist) { + const checkedChecklistItems = data.checklist + .map(el => el.valid) + .filter(v => v); + setAtLeastOneChecked(checkedChecklistItems.length > 0); + setAllChecksChecked(checkedChecklistItems.length === data.checklist.length) + } + } else if (data.evaluationVersion === 'V2') { + const minChecks = data.numberOfCheck; + const formFieldsChecklist = formData + .filter(o => head(o.settings.filter(s => s.name === 'isChecklistItem' && s.value))) + .map(o => o.id); + + if (formFieldsChecklist.length >= minChecks) { + const valuesTotal = formFieldsChecklist.map(v => formValues[v]); + const valuesFirst = valuesTotal.toSpliced(minChecks); + setAtLeastOneChecked(valuesTotal.filter(v => v === true).length === valuesTotal.length); + setAllChecksChecked(valuesFirst.filter(v => v === true).length === valuesFirst.length) + } } - } + }, [formValues]); const doNewSoccorso = () => { if (connectedSoccorsoId !== 0) { @@ -107,24 +170,75 @@ const DomandaEditInstructorManager = () => { } } - const getCallback = (data) => { - if (data.status === 'SUCCESS') { - setData(getFormattedData(data.data)); - setMotivation(data.data.motivation); - updateFlagsForSoccorso(data.data); + const getVersion = (resp) => { + if (resp.status === 'SUCCESS') { + if (resp.data.evaluationVersion === 'V1') { + storeSet.main.setAsyncRequest(); + ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [ + ['applicationId', resp.data.applicationId] + ]); + } else if (resp.data.evaluationVersion === 'V2') { + storeSet.main.setAsyncRequest(); + ApplicationEvaluationService.getEvaluationV2ByApplId(getCallback, errGetCallback, [ + ['applicationId', resp.data.applicationId] + ]); + } } storeSet.main.unsetAsyncRequest(); } - const errGetCallback = (data) => { + const errGetVersion = (resp) => { if (toast.current && data.message) { toast.current.show({ severity: 'error', summary: '', - detail: data.message + detail: resp.message }); } - set404FromErrorResponse(data); + set404FromErrorResponse(resp); + storeSet.main.unsetAsyncRequest(); + } + + const getCallback = (resp) => { + if (resp.status === 'SUCCESS') { + setData(getFormattedData(resp.data)); + setMotivation(resp.data.motivation); + updateFlagsForSoccorso(resp.data); + + if (resp.data.evaluationVersion === 'V2') { + setFormData(resp.data.applicationEvaluationFormResponse.content); + setFormId(resp.data.applicationEvaluationFormResponse.id); + let formDataInitial = {}; + + if (resp.data.applicationEvaluationFormResponse.formFields) { + const submitData = resp.data.applicationEvaluationFormResponse.formFields.map((o) => ({ + fieldId: o.fieldId, + fieldValue: o.fieldValue + })); + formDataInitial = submitData.reduce((acc, cur) => { + if (cur.fieldValue) { + acc[cur.fieldId] = cur.fieldValue; + } + return acc; + }, formDataInitial); + } + + reset(); + setFormInitialData(formDataInitial); + } + } + storeSet.main.unsetAsyncRequest(); + } + + const errGetCallback = (resp) => { + if (toast.current && resp.message) { + toast.current.show({ + severity: 'error', + summary: '', + detail: resp.message + }); + } + set404FromErrorResponse(resp); storeSet.main.unsetAsyncRequest(); } @@ -166,26 +280,74 @@ const DomandaEditInstructorManager = () => { 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 - } + const getTransformedSubmitData = () => { + const formValues = getValues(); + const usedFieldsIds = pluck('id', formData); + return Object.keys(formValues) + .filter(v => usedFieldsIds.includes(v)) + .reduce((acc, cur) => { + const formField = head(formData.filter(o => o.id === cur)); + let fieldVal = formValues[cur]; - ApplicationEvaluationService.updateEvaluation( - data.assignedApplicationId, - formData, - (data) => updateCallback(data, doRedirect), - errUpdateCallback - ); + if (formValues[cur] && formValues[cur].toISOString) { + fieldVal = formatDateString(formValues[cur]); + } + + fieldVal = isEmpty(fieldVal) ? null : fieldVal; + if (formField && formField.name === 'fileupload') { + fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : null; + } + acc.push({ + 'fieldId': cur, + 'fieldValue': fieldVal + }); + return acc; + }, []); + } + + const doSaveDraft = useCallback((doRedirect = '') => { + if (data.evaluationVersion === 'V1') { + const submitData = { + 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, + submitData, + (data) => updateCallback(data, doRedirect), + errUpdateCallback + ); + } else if (data.evaluationVersion === 'V2') { + const newFormValues = getTransformedSubmitData(); + const submitData = { + formFields: newFormValues, + 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.updateEvaluationV2( + data.assignedApplicationId, + formId, + submitData, + (data) => updateCallback(data, doRedirect), + errUpdateCallback + ); + } }, [data]); const updateCallback = (data, doRedirect = '') => { @@ -218,33 +380,95 @@ const DomandaEditInstructorManager = () => { } const doApprove = () => { - const formData = { - applicationStatus: 'APPROVED', - criteria: klona(data.criteria), - checklist: klona(data.checklist), - files: klona(data.files), - note: data.note, - motivation - } + if (data.evaluationVersion === 'V1') { + const submitData = { + applicationStatus: 'APPROVED', + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + note: data.note, + motivation + } - setLoading(true); - setIsVisibleCompleteDialog(false); - ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback); + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluation( + data.assignedApplicationId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } else if (data.evaluationVersion === 'V2') { + const newFormValues = getTransformedSubmitData(); + const submitData = { + formFields: newFormValues, + 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, + motivation + } + + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluationV2( + data.assignedApplicationId, + formId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } } const doReject = () => { - const formData = { - applicationStatus: 'REJECTED', - criteria: klona(data.criteria), - checklist: klona(data.checklist), - files: klona(data.files), - note: data.note, - motivation - } + if (data.evaluationVersion === 'V1') { + const submitData = { + applicationStatus: 'REJECTED', + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + note: data.note, + motivation + } - setLoading(true); - setIsVisibleCompleteDialog(false); - ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback); + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluation( + data.assignedApplicationId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } else if (data.evaluationVersion === 'V2') { + const newFormValues = getTransformedSubmitData(); + const submitData = { + formFields: newFormValues, + 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, + motivation + } + + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluationV2( + data.assignedApplicationId, + formId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } } const updateStatusCallback = (data) => { @@ -431,7 +655,7 @@ const DomandaEditInstructorManager = () => { setIsVisibleAppointmentDialog(true); } - const setValue = (name, value) => { + const setFieldValue = (name, value) => { const newData = wrap(appointmentData).set(name, value).value(); setAppointmentData(newData); } @@ -505,11 +729,153 @@ const DomandaEditInstructorManager = () => { // TODO } - const evaluationShouldBeBlocked = (data = {}) => { + const evaluationBlockedForUser = (data = {}) => { const userData = storeGet.main.userData(); return isAsyncRequest || userData.id !== data.assignedUserId; } + const shouldDisableNewSoccorso = () => { + if (data.evaluationVersion === 'V1') { + return !allFilesRated || !atLeastOneChecked; + } else if (data.evaluationVersion === 'V2') { + return !allFilesRated || !atLeastOneChecked; + } else { + return true; + } + } + + const actionBtns = () => { + return
+ {['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus) + ?
+ } + + useEffect(() => { + let updatedFormValues = klona(formValues); + let context = {}; + + // eslint-disable-next-line array-callback-return + formData.map((o) => { + const variable = head(o.settings.filter(o => o.name === 'variable')); + const formula = head(o.settings.filter(o => o.name === 'formula')); + + if (formula && !isEmpty(formula.value)) { + context = getTokens(formula.value) + .filter(v => !['false', 'null', 'true'].includes(v)) + .reduce((acc, cur) => { + acc[cur] = isNil(context[cur]) ? 0 : parseCommaDecimal(context[cur]); + return acc; + }, context); + + const mathFormula = renderWithDataVars(formula.value, context); + try { + updatedFormValues[o.id] = evaluate(mathFormula); + } catch (e) { + console.log('Error in math formula: "', mathFormula, '"', e.message); + updatedFormValues[o.id] = 0; + } + } + + if (variable && !isEmpty(variable.value)) { + context[variable.value[0]] = 'criteria_table' === o.name + ? pathOr(0, [o.id, 'total'], updatedFormValues) + : pathOr(0, [o.id], updatedFormValues); + } + }); + + if (!isEmpty(updatedFormValues) && !equal(updatedFormValues, formValues)) { + reset(updatedFormValues); + } + + updateFlagsForSoccorso(data); + }, [formValues]); + + useEffect(() => { + if (formInitialData) { + //reset(); + Object.keys(formInitialData).map(k => setValue(k, formInitialData[k])); + trigger(); + } + }, [formInitialData]); + useEffect(() => { const maxScore = pathOr(0, ['minScore'], data); const criteria = pathOr([], ['criteria'], data); @@ -523,9 +889,7 @@ const DomandaEditInstructorManager = () => { const entityId = !isNaN(parsed) ? parsed : 0; storeSet.main.setAsyncRequest(); - ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [ - ['applicationId', entityId] - ]); + ApplicationEvaluationService.getEvaluationVersionByApplId(entityId, getVersion, errGetVersion); AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [ ['statuses', 'AWAITING'] ]); @@ -553,68 +917,18 @@ const DomandaEditInstructorManager = () => { {!isAsyncRequest && !isEmpty(data) ?
-
-

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

-

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

- {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' - ?

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

: null} - {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' - ?

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

: null} -

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

-

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

-

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

-

- {__('Data ricezione', 'gepafin')} - {getDateTimeFromISOstring(data.submissionDate)} -

-

- {__('Data assegnazione', 'gepafin')} - {getDateTimeFromISOstring(data.assignedAt)} -

-

- {__('Aassegnato a', 'gepafin')} - {data.assignedUserName} -

-

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

-

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

+ + +
+ {__('Azioni rapide', 'gepafin')}
-

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

-
- - - -
+ {actionBtns()}
+ +

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

{ data, ['evaluationDocument'] )} - shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)} + shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationBlockedForUser(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}> - -
)} + {data.evaluationVersion === 'V2' + ?
+

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

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

{__('Nessun documento allegato', 'gepafin')}

} +
+ : null} + + {data.evaluationVersion === 'V2' + ? { + })}> + {formData.map(o => { + const label = head(o.settings.filter(o => o.name === 'label')); + const text = head(o.settings.filter(o => o.name === 'text')); + const placeholder = head(o.settings.filter(o => o.name === 'placeholder')); + const options = head(o.settings.filter(o => o.name === 'options')); + let tableColumns = head(o.settings.filter(o => o.name === 'table_columns')); + if (!tableColumns) { + tableColumns = head(o.settings.filter(o => o.name === 'criteria_table_columns')); + } + const step = head(o.settings.filter(o => o.name === 'step')); + const mime = head(o.settings.filter(o => o.name === 'mime')); + const formula = head(o.settings.filter(o => o.name === 'formula')); + let mimeValue = ''; + + if (mime) { + mimeValue = mime.value.map(o => o.code ? o.code : o.ext); + } + + const validations = Object.keys(o.validators).reduce((acc, cur) => { + if (o.validators[cur]) { + if (['min', 'max', 'minLength', 'maxLength', 'maxSize'].includes(cur)) { + acc[cur] = parseInt(o.validators[cur]); + } else if ('pattern' === cur) { + acc[cur] = new RegExp(o.validators[cur]); + } else if ('isRequired' === cur) { + //acc[cur] = o.validators[cur]; + acc['required'] = true; + } else if ('custom' === cur && validationFns[o.validators[cur]]) { + if (!acc.validate) { + acc.validate = {}; + } + acc.validate[o.validators[cur]] = validationFns[o.validators[cur]]; + } + } + + return acc; + }, {}); + + /*if (o.name === 'table') { + console.log('value:', values[o.id] ? values[o.id] : '') + }*/ + + return ['paragraph'].includes(o.name) && text + ?
+
+ {renderHtmlContent(text.value)} +
+
+ : + })} + + : null} + + {data.evaluationVersion === 'V1' + ?
+

{__('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%' }} + />
- -

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

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

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

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

{__('Nessun documento allegato', 'gepafin')}

}
-
-

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

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

{__('Nessun documento allegato', 'gepafin')}

} -
-
+ : null} {!isEmpty(data.amendmentDetails) ?
@@ -685,90 +1092,92 @@ const DomandaEditInstructorManager = () => { shouldDisableField(name) || evaluationShouldBeBlocked(data)} + shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(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 - )}/> - + {data.evaluationVersion === 'V1' + ?
+

{__('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} -
+
+
+
+ {!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} +
+ : null}
@@ -777,85 +1186,7 @@ const DomandaEditInstructorManager = () => {
-
- {['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus) - ?
+ {actionBtns()}
{ value={appointmentData.amount} keyfilter="int" invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0} - onChange={(e) => setValue('amount', e.value)}/> + onChange={(e) => setFieldValue('amount', e.value)}/>
diff --git a/src/pages/DomandaEditPreInstructor/components/ApplicationDownloadFiles/index.js b/src/pages/DomandaEditPreInstructor/components/ApplicationDownloadFiles/index.js new file mode 100644 index 0000000..64be84e --- /dev/null +++ b/src/pages/DomandaEditPreInstructor/components/ApplicationDownloadFiles/index.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { __ } from '@wordpress/i18n'; +import { isNil } from 'ramda'; + +// components +import DownloadApplicationArchive from '../DownloadApplicationArchive'; +import DownloadSignedApplication from '../DownloadSignedApplication'; +import DownloadCompanyDelegation from '../DownloadCompanyDelegation'; + +const ApplicationDownloadFiles = ({ id }) => { + return ( + !isNil(id) + ?
+

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

+
+ + + +
+
: null + ) +} + +export default ApplicationDownloadFiles; \ No newline at end of file diff --git a/src/pages/DomandaEditPreInstructor/components/ApplicationInfo/index.js b/src/pages/DomandaEditPreInstructor/components/ApplicationInfo/index.js new file mode 100644 index 0000000..d3d0a4f --- /dev/null +++ b/src/pages/DomandaEditPreInstructor/components/ApplicationInfo/index.js @@ -0,0 +1,70 @@ +import React from 'react'; +import { __ } from '@wordpress/i18n'; +import { isNil } from 'ramda'; + +// tools +import getDateTimeFromISOstring from '../../../../helpers/getDateTimeFromISOstring'; +import getDateFromISOstring from '../../../../helpers/getDateFromISOstring'; +import getBandoLabel from '../../../../helpers/getBandoLabel'; + +const APP_HUB_ID = process.env.REACT_APP_HUB_ID; + +const ApplicationInfo = ({ data }) => { + return ( + !isNil(data) + ?
+

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

+

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

+ {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' + ?

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

: null} + {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' + ?

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

: null} +

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

+

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

+

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

+

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

+

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

+

+ {__('Aassegnato a', 'gepafin')} + {data.assignedUserName} +

+

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

+

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

+
: null + ) +} + +export default ApplicationInfo; \ No newline at end of file diff --git a/src/pages/DomandaEditPreInstructor/index.js b/src/pages/DomandaEditPreInstructor/index.js index 684adf2..64b4546 100644 --- a/src/pages/DomandaEditPreInstructor/index.js +++ b/src/pages/DomandaEditPreInstructor/index.js @@ -1,9 +1,12 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { __, sprintf } from '@wordpress/i18n'; import { useNavigate, useParams } from 'react-router-dom'; -import { is, isEmpty, isNil, sum, pathOr, head } from 'ramda'; +import { is, isEmpty, isNil, sum, pathOr, head, pluck } from 'ramda'; import { klona } from 'klona'; import { wrap } from 'object-path-immutable'; +import { useForm } from 'react-hook-form'; +import { evaluate } from 'mathjs'; +import equal from 'fast-deep-equal'; // store import { storeGet, storeSet, useStore } from '../../store'; @@ -15,8 +18,21 @@ import AppointmentService from '../../service/appointment-service'; // tools import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; -import getBandoLabel from '../../helpers/getBandoLabel'; -import getDateFromISOstring from '../../helpers/getDateFromISOstring'; +import { + isCAP, + isCodiceFiscale, + isEmail, + isEmailPEC, + isIBAN, + isMarcaDaBollo, + isPIVA, + isUrl, maxChecks, minChecks, nonEmptyTables +} from '../../helpers/validators'; +import getTokens from '../../helpers/getTokens'; +import parseCommaDecimal from '../../helpers/parseCommaDecimal'; +import renderWithDataVars from '../../helpers/renderWithDataVars'; +import renderHtmlContent from '../../helpers/renderHtmlContent'; +import formatDateString from '../../helpers/formatDateString'; // components import { Skeleton } from 'primereact/skeleton'; @@ -32,12 +48,11 @@ import BlockingOverlay from '../../components/BlockingOverlay'; import { classNames } from 'primereact/utils'; import { InputTextarea } from 'primereact/inputtextarea'; import { InputText } from 'primereact/inputtext'; -import DownloadApplicationArchive from './components/DownloadApplicationArchive'; -import DownloadCompanyDelegation from './components/DownloadCompanyDelegation'; -import DownloadSignedApplication from './components/DownloadSignedApplication'; import ListOfFiles from './components/ListOfFiles'; import RepeaterFields from './components/RepeaterFields'; -import getDateTimeFromISOstring from '../../helpers/getDateTimeFromISOstring'; +import ApplicationInfo from './components/ApplicationInfo'; +import ApplicationDownloadFiles from './components/ApplicationDownloadFiles'; +import FormField from '../../components/FormField'; const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID; const APP_HUB_ID = process.env.REACT_APP_HUB_ID; @@ -67,12 +82,46 @@ const DomandaEditPreInstructor = () => { duration: 0, amount: 0 }); + const [formData, setFormData] = useState([]); + const [formId, setFormId] = useState(0); + const [formInitialData, setFormInitialData] = useState(null); + const { + control, + handleSubmit, + formState: { errors }, + setValue, + trigger, + register, + getValues, + watch, + reset + } = useForm({ + defaultValues: useMemo(() => { + return formInitialData ? formInitialData : {} + }, [formInitialData]), + mode: 'onChange' + }); + const validationFns = { + isPIVA, + isCodiceFiscale, + isCAP, + isIBAN, + isEmail, + isEmailPEC, + isUrl, + isMarcaDaBollo, + minChecks, + maxChecks, + nonEmptyTables + } + const values = getValues(); + const formValues = watch(); const goToEvaluationsPage = () => { navigate('/domande'); } - const updateFlagsForSoccorso = (data) => { + const updateFlagsForSoccorso = useCallback((data) => { let nonRatedFilesLength = 0; if (data.files) { @@ -91,14 +140,28 @@ const DomandaEditPreInstructor = () => { 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) + if (data.evaluationVersion === 'V1') { + if (data.checklist) { + const checkedChecklistItems = data.checklist + .map(el => el.valid) + .filter(v => v); + setAtLeastOneChecked(checkedChecklistItems.length > 0); + setAllChecksChecked(checkedChecklistItems.length === data.checklist.length) + } + } else if (data.evaluationVersion === 'V2') { + const minChecks = data.numberOfCheck; + const formFieldsChecklist = formData + .filter(o => head(o.settings.filter(s => s.name === 'isChecklistItem' && s.value))) + .map(o => o.id); + + if (formFieldsChecklist.length >= minChecks) { + const valuesTotal = formFieldsChecklist.map(v => formValues[v]); + const valuesFirst = valuesTotal.toSpliced(minChecks); + setAtLeastOneChecked(valuesTotal.filter(v => v === true).length === valuesTotal.length); + setAllChecksChecked(valuesFirst.filter(v => v === true).length === valuesFirst.length) + } } - } + }, [formValues]); const doNewSoccorso = () => { if (connectedSoccorsoId !== 0) { @@ -108,24 +171,75 @@ const DomandaEditPreInstructor = () => { } } - const getCallback = (data) => { - if (data.status === 'SUCCESS') { - setData(getFormattedData(data.data)); - setMotivation(data.data.motivation); - updateFlagsForSoccorso(data.data); + const getVersion = (resp) => { + if (resp.status === 'SUCCESS') { + if (resp.data.evaluationVersion === 'V1') { + storeSet.main.setAsyncRequest(); + ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [ + ['applicationId', resp.data.applicationId] + ]); + } else if (resp.data.evaluationVersion === 'V2') { + storeSet.main.setAsyncRequest(); + ApplicationEvaluationService.getEvaluationV2ByApplId(getCallback, errGetCallback, [ + ['applicationId', resp.data.applicationId] + ]); + } } storeSet.main.unsetAsyncRequest(); } - const errGetCallback = (data) => { + const errGetVersion = (resp) => { if (toast.current && data.message) { toast.current.show({ severity: 'error', summary: '', - detail: data.message + detail: resp.message }); } - set404FromErrorResponse(data); + set404FromErrorResponse(resp); + storeSet.main.unsetAsyncRequest(); + } + + const getCallback = (resp) => { + if (resp.status === 'SUCCESS') { + setData(getFormattedData(resp.data)); + setMotivation(resp.data.motivation); + updateFlagsForSoccorso(resp.data); + + if (resp.data.evaluationVersion === 'V2') { + setFormData(resp.data.applicationEvaluationFormResponse.content); + setFormId(resp.data.applicationEvaluationFormResponse.id); + let formDataInitial = {}; + + if (resp.data.applicationEvaluationFormResponse.formFields) { + const submitData = resp.data.applicationEvaluationFormResponse.formFields.map((o) => ({ + fieldId: o.fieldId, + fieldValue: o.fieldValue + })); + formDataInitial = submitData.reduce((acc, cur) => { + if (cur.fieldValue) { + acc[cur.fieldId] = cur.fieldValue; + } + return acc; + }, formDataInitial); + } + + reset(); + setFormInitialData(formDataInitial); + } + } + storeSet.main.unsetAsyncRequest(); + } + + const errGetCallback = (resp) => { + if (toast.current && resp.message) { + toast.current.show({ + severity: 'error', + summary: '', + detail: resp.message + }); + } + set404FromErrorResponse(resp); storeSet.main.unsetAsyncRequest(); } @@ -167,26 +281,74 @@ const DomandaEditPreInstructor = () => { 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 - } + const getTransformedSubmitData = () => { + const formValues = getValues(); + const usedFieldsIds = pluck('id', formData); + return Object.keys(formValues) + .filter(v => usedFieldsIds.includes(v)) + .reduce((acc, cur) => { + const formField = head(formData.filter(o => o.id === cur)); + let fieldVal = formValues[cur]; - ApplicationEvaluationService.updateEvaluation( - data.assignedApplicationId, - formData, - (data) => updateCallback(data, doRedirect), - errUpdateCallback - ); + if (formValues[cur] && formValues[cur].toISOString) { + fieldVal = formatDateString(formValues[cur]); + } + + fieldVal = isEmpty(fieldVal) ? null : fieldVal; + if (formField && formField.name === 'fileupload') { + fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : null; + } + acc.push({ + 'fieldId': cur, + 'fieldValue': fieldVal + }); + return acc; + }, []); + } + + const doSaveDraft = useCallback((doRedirect = '') => { + if (data.evaluationVersion === 'V1') { + const submitData = { + 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, + submitData, + (data) => updateCallback(data, doRedirect), + errUpdateCallback + ); + } else if (data.evaluationVersion === 'V2') { + const newFormValues = getTransformedSubmitData(); + const submitData = { + formFields: newFormValues, + 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.updateEvaluationV2( + data.assignedApplicationId, + formId, + submitData, + (data) => updateCallback(data, doRedirect), + errUpdateCallback + ); + } }, [data]); const updateCallback = (data, doRedirect = '') => { @@ -219,33 +381,95 @@ const DomandaEditPreInstructor = () => { } const doApprove = () => { - const formData = { - applicationStatus: 'APPROVED', - criteria: klona(data.criteria), - checklist: klona(data.checklist), - files: klona(data.files), - note: data.note, - motivation - } + if (data.evaluationVersion === 'V1') { + const submitData = { + applicationStatus: 'APPROVED', + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + note: data.note, + motivation + } - setLoading(true); - setIsVisibleCompleteDialog(false); - ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback); + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluation( + data.assignedApplicationId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } else if (data.evaluationVersion === 'V2') { + const newFormValues = getTransformedSubmitData(); + const submitData = { + formFields: newFormValues, + 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, + motivation + } + + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluationV2( + data.assignedApplicationId, + formId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } } const doReject = () => { - const formData = { - applicationStatus: 'REJECTED', - criteria: klona(data.criteria), - checklist: klona(data.checklist), - files: klona(data.files), - note: data.note, - motivation - } + if (data.evaluationVersion === 'V1') { + const submitData = { + applicationStatus: 'REJECTED', + criteria: klona(data.criteria), + checklist: klona(data.checklist), + files: klona(data.files), + note: data.note, + motivation + } - setLoading(true); - setIsVisibleCompleteDialog(false); - ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback); + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluation( + data.assignedApplicationId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } else if (data.evaluationVersion === 'V2') { + const newFormValues = getTransformedSubmitData(); + const submitData = { + formFields: newFormValues, + 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, + motivation + } + + setLoading(true); + setIsVisibleCompleteDialog(false); + ApplicationEvaluationService.updateEvaluationV2( + data.assignedApplicationId, + formId, + submitData, + updateStatusCallback, + errUpdateStatusCallback + ); + } } const updateStatusCallback = (data) => { @@ -432,7 +656,7 @@ const DomandaEditPreInstructor = () => { setIsVisibleAppointmentDialog(true); } - const setValue = (name, value) => { + const setFieldValue = (name, value) => { const newData = wrap(appointmentData).set(name, value).value(); setAppointmentData(newData); } @@ -506,10 +730,152 @@ const DomandaEditPreInstructor = () => { // TODO } - const evaluationShouldBeBlocked = (data = {}) => { + const evaluationBlockedForUser = (data = {}) => { const userData = storeGet.main.userData() return isAsyncRequest || userData.id !== data.assignedUserId; } + + const shouldDisableNewSoccorso = () => { + if (data.evaluationVersion === 'V1') { + return !allFilesRated || !atLeastOneChecked; + } else if (data.evaluationVersion === 'V2') { + return !allFilesRated || !atLeastOneChecked; + } else { + return true; + } + } + + const actionBtns = () => { + return
+ {['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus) + ?
+ } + + useEffect(() => { + let updatedFormValues = klona(formValues); + let context = {}; + + // eslint-disable-next-line array-callback-return + formData.map((o) => { + const variable = head(o.settings.filter(o => o.name === 'variable')); + const formula = head(o.settings.filter(o => o.name === 'formula')); + + if (formula && !isEmpty(formula.value)) { + context = getTokens(formula.value) + .filter(v => !['false', 'null', 'true'].includes(v)) + .reduce((acc, cur) => { + acc[cur] = isNil(context[cur]) ? 0 : parseCommaDecimal(context[cur]); + return acc; + }, context); + + const mathFormula = renderWithDataVars(formula.value, context); + try { + updatedFormValues[o.id] = evaluate(mathFormula); + } catch (e) { + console.log('Error in math formula: "', mathFormula, '"', e.message); + updatedFormValues[o.id] = 0; + } + } + + if (variable && !isEmpty(variable.value)) { + context[variable.value[0]] = 'criteria_table' === o.name + ? pathOr(0, [o.id, 'total'], updatedFormValues) + : pathOr(0, [o.id], updatedFormValues); + } + }); + + if (!isEmpty(updatedFormValues) && !equal(updatedFormValues, formValues)) { + reset(updatedFormValues); + } + + updateFlagsForSoccorso(data); + }, [formValues]); + + useEffect(() => { + if (formInitialData) { + //reset(); + Object.keys(formInitialData).map(k => setValue(k, formInitialData[k])); + trigger(); + } + }, [formInitialData]); useEffect(() => { const maxScore = pathOr(0, ['minScore'], data); @@ -524,9 +890,7 @@ const DomandaEditPreInstructor = () => { const entityId = !isNaN(parsed) ? parsed : 0; storeSet.main.setAsyncRequest(); - ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [ - ['applicationId', entityId] - ]); + ApplicationEvaluationService.getEvaluationVersionByApplId(entityId, getVersion, errGetVersion); AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [ ['statuses', 'AWAITING'] ]); @@ -555,68 +919,18 @@ const DomandaEditPreInstructor = () => { {!isAsyncRequest && !isEmpty(data) ?
-
-

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

-

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

- {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' - ?

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

: null} - {APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE' - ?

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

: null} -

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

-

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

-

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

-

- {__('Data ricezione', 'gepafin')} - {getDateTimeFromISOstring(data.submissionDate)} -

-

- {__('Data assegnazione', 'gepafin')} - {getDateTimeFromISOstring(data.assignedAt)} -

-

- {__('Aassegnato a', 'gepafin')} - {data.assignedUserName} -

-

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

-

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

+ + +
+ {__('Azioni rapide', 'gepafin')}
-

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

-
- - - -
+ {actionBtns()}
+ +

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

{ data, ['evaluationDocument'] )} - shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)} + shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationBlockedForUser(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}> - -
)} + {data.evaluationVersion === 'V2' + ?
+

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

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

{__('Nessun documento allegato', 'gepafin')}

} +
+ : null} + + {data.evaluationVersion === 'V2' + ?
{ + })}> + {formData.map(o => { + const label = head(o.settings.filter(o => o.name === 'label')); + const text = head(o.settings.filter(o => o.name === 'text')); + const placeholder = head(o.settings.filter(o => o.name === 'placeholder')); + const options = head(o.settings.filter(o => o.name === 'options')); + let tableColumns = head(o.settings.filter(o => o.name === 'table_columns')); + if (!tableColumns) { + tableColumns = head(o.settings.filter(o => o.name === 'criteria_table_columns')); + } + const step = head(o.settings.filter(o => o.name === 'step')); + const mime = head(o.settings.filter(o => o.name === 'mime')); + const formula = head(o.settings.filter(o => o.name === 'formula')); + let mimeValue = ''; + + if (mime) { + mimeValue = mime.value.map(o => o.code ? o.code : o.ext); + } + + const validations = Object.keys(o.validators).reduce((acc, cur) => { + if (o.validators[cur]) { + if (['min', 'max', 'minLength', 'maxLength', 'maxSize'].includes(cur)) { + acc[cur] = parseInt(o.validators[cur]); + } else if ('pattern' === cur) { + acc[cur] = new RegExp(o.validators[cur]); + } else if ('isRequired' === cur) { + //acc[cur] = o.validators[cur]; + acc['required'] = true; + } else if ('custom' === cur && validationFns[o.validators[cur]]) { + if (!acc.validate) { + acc.validate = {}; + } + acc.validate[o.validators[cur]] = validationFns[o.validators[cur]]; + } + } + + return acc; + }, {}); + + /*if (o.name === 'table') { + console.log('value:', values[o.id] ? values[o.id] : '') + }*/ + + return ['paragraph'].includes(o.name) && text + ?
+
+ {renderHtmlContent(text.value)} +
+
+ : + })} + + : null} + + {data.evaluationVersion === 'V1' + ?
+

{__('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%' }} + />
- -

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

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

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

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

{__('Nessun documento allegato', 'gepafin')}

}
-
-

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

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

{__('Nessun documento allegato', 'gepafin')}

} -
-
+ : null} {!isEmpty(data.amendmentDetails) ?
@@ -687,90 +1094,92 @@ const DomandaEditPreInstructor = () => { shouldDisableField(name) || evaluationShouldBeBlocked(data)} + shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(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 - )}/> - + {data.evaluationVersion === 'V1' + ?
+

{__('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} -
+
+
+
+ {!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} +
+ : null}
@@ -779,85 +1188,7 @@ const DomandaEditPreInstructor = () => {
-
- {['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus) - ?
+ {actionBtns()}
{ value={appointmentData.amount} keyfilter="int" invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0} - onChange={(e) => setValue('amount', e.value)}/> + onChange={(e) => setFieldValue('amount', e.value)}/>
diff --git a/src/pages/DomandeInstructorManager/index.js b/src/pages/DomandeInstructorManager/index.js index 35957b5..31ee817 100644 --- a/src/pages/DomandeInstructorManager/index.js +++ b/src/pages/DomandeInstructorManager/index.js @@ -1,6 +1,6 @@ import React, { useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; -import { isEmpty, pathOr } from 'ramda'; +import { isEmpty } from 'ramda'; // store import { storeSet } from '../../store'; diff --git a/src/pages/Profile/index.js b/src/pages/Profile/index.js index d7b3474..3b2d5b7 100644 --- a/src/pages/Profile/index.js +++ b/src/pages/Profile/index.js @@ -36,7 +36,7 @@ const Profile = () => { const onSubmit = (formData) => { storeSet.main.setAsyncRequest(); - UserService.updateUser(userData.id, formData, updateCallback, updateError); + UserService.updateUserSelf(userData.id, formData, updateCallback, updateError); }; const updateCallback = (data) => { @@ -109,6 +109,7 @@ const Profile = () => { { const onSubmit = (formData) => { storeSet.main.setAsyncRequest(); - UserService.updateUser(userData.id, formData, updateCallback, updateError); + UserService.updateUserSelf(userData.id, formData, updateCallback, updateError); }; const updateCallback = (data) => { diff --git a/src/pages/SoccorsoIstruttorioPreInstructor/index.js b/src/pages/SoccorsoIstruttorioPreInstructor/index.js index fd1cc4d..b0959b7 100644 --- a/src/pages/SoccorsoIstruttorioPreInstructor/index.js +++ b/src/pages/SoccorsoIstruttorioPreInstructor/index.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { __ } from '@wordpress/i18n'; import { pathOr } from 'ramda'; import NumberFlow from '@number-flow/react'; @@ -22,9 +22,9 @@ const SoccorsoIstruttorioPreInstructor = () => { const errGetStats = () => {} - const getStatValue = (key, fallback = '') => { + const getStatValue = useCallback((key, fallback = '') => { return pathOr(fallback, [key], mainStats); - } + }, [mainStats]); useEffect(() => { DashboardService.getAmendmentsStats(getStats, errGetStats); diff --git a/src/pages/StatsBeneficiary/components/BeneficiarioUltimeDomandeTable/index.js b/src/pages/StatsBeneficiary/components/BeneficiarioUltimeDomandeTable/index.js new file mode 100644 index 0000000..31c7ec9 --- /dev/null +++ b/src/pages/StatsBeneficiary/components/BeneficiarioUltimeDomandeTable/index.js @@ -0,0 +1,146 @@ +import React, { useState, useEffect } from 'react'; +import { __ } from '@wordpress/i18n'; +import { is, isEmpty, uniq } from 'ramda'; + +// store +import { useStore } from '../../../../store'; + +// api +import ApplicationService from '../../../../service/application-service'; + +// tools +import getNumberWithCurrency from '../../../../helpers/getNumberWithCurrency'; + +// components +import { FilterMatchMode, FilterOperator } from 'primereact/api'; +import { DataTable } from 'primereact/datatable'; +import { Column } from 'primereact/column'; +import ProperBandoLabel from '../../../../components/ProperBandoLabel'; +import translationStrings from '../../../../translationStringsForComponents'; + + +const BeneficiarioUltimeDomandeTable = () => { + const chosenCompanyId = useStore().main.chosenCompanyId(); + const [items, setItems] = useState(null); + // eslint-disable-next-line + const [filters, setFilters] = useState(null); + const [localAsyncRequest, setLocalAsyncRequest] = useState(false); + // eslint-disable-next-line + const [statuses, setStatuses] = useState([]); + const perPage = 5; + + const getPaginationQuery = (status = 'DRAFT', curPage = 1) => { + return { + "globalFilters": { + //"year": 0, + "page": curPage, + //"search": "", + "limit": perPage, + }, + //"daysRange": 0, + "status": status + } + } + + useEffect(() => { + if (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && !localAsyncRequest) { + const bodyParams = getPaginationQuery( + ['SOCCORSO', 'APPROVED', 'REJECTED', 'EVALUATION', 'SUBMIT'], + 1 + ); + + setLocalAsyncRequest(true); + ApplicationService.getApplicationsPaginated(bodyParams, getApplCallback, errGetApplCallback, [ + ['companyId', chosenCompanyId], + ['statuses', ['SOCCORSO', 'APPROVED', 'REJECTED', 'EVALUATION', 'SUBMIT']] // 'NDG', 'ADMISSIBLE', 'APPOINTMENT' + ]); + } + }, [chosenCompanyId]); + + const getApplCallback = (resp) => { + if (resp.status === 'SUCCESS') { + if (resp.data && is(Array, resp.data.body)) { + setItems(getFormattedBandiData(resp.data.body)); + setStatuses(uniq(items.map(o => o.status))) + initFilters(); + } + } + setLocalAsyncRequest(false); + } + + const errGetApplCallback = () => { + setLocalAsyncRequest(false); + } + + const getFormattedBandiData = (data) => { + return [...(data || [])].map((d) => { + d.callEndDate = new Date(d.callEndDate); + d.modifiedDate = new Date(d.modifiedDate); + d.submissionDate = new Date(d.submissionDate); + + return d; + }); + }; + + const formatDate = (value) => { + return value.toLocaleDateString('it-IT', { + year: 'numeric' + }); + }; + + const initFilters = () => { + setFilters({ + global: { value: null, matchMode: FilterMatchMode.CONTAINS }, + callTitle: { + operator: FilterOperator.AND, + constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] + }, + companyName: { + operator: FilterOperator.AND, + constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] + }, + modifiedDate: { + operator: FilterOperator.AND, + constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] + }, + callEndDate: { + operator: FilterOperator.AND, + constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] + } + }); + }; + + const dateSubmissionBodyTemplate = (rowData) => { + return formatDate(rowData.submissionDate); + }; + + const importoBodyTemplate = (rowData) => { + return getNumberWithCurrency(rowData.amountRequested); + }; + + const statusBodyTemplate = (rowData) => { + return ; + }; + + return ( +
+ + + + + + +
+ ) +} + +export default BeneficiarioUltimeDomandeTable; diff --git a/src/pages/StatsBeneficiary/index.js b/src/pages/StatsBeneficiary/index.js new file mode 100644 index 0000000..503393d --- /dev/null +++ b/src/pages/StatsBeneficiary/index.js @@ -0,0 +1,112 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { __ } from '@wordpress/i18n'; +import { isEmpty, pathOr } from 'ramda'; +import NumberFlow from '@number-flow/react'; + +// store +import { useStore } from '../../store'; + +// components +import DashboardService from '../../service/dashboard-service'; +import ChartDomandePerStato from '../../components/ChartDomandePerStato'; +import ChartRichiesteVsApprovate from '../../components/ChartRichiesteVsApprovate'; +import BeneficiarioUltimeDomandeTable from './components/BeneficiarioUltimeDomandeTable'; + +const StatsBeneficiary = () => { + const [mainStats, setMainStats] = useState({}); + const [chartStats, setChartStats] = useState({}); + const chosenCompanyId = useStore().main.chosenCompanyId(); + + const getStats = (resp) => { + if (resp.status === 'SUCCESS') { + setMainStats(resp.data.applicationWidget); + setChartStats(resp.data.applicationWidgetBars); + } + } + + const errGetStats = () => {} + + const getStatValue = useCallback((key, fallback = '') => { + return pathOr(fallback, [key], mainStats); + }, [mainStats]); + + useEffect(() => { + DashboardService.getBeneficiaryStatsPage(chosenCompanyId, getStats, errGetStats); + }, [chosenCompanyId]); + + return( +
+
+

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

+
+ +
+ +
+

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

+
+
+ {__('Domande presentate', 'gepafin')} + +
+
+ {__('Tasso di successo', 'gepafin')} + +
+
+ {__('Domande approvate', 'gepafin')} + +
+
+ {__('Importo totale finanziato', 'gepafin')} + +
+
+
+ +
+ + {chartStats && !isEmpty(chartStats) + ?
+

{__('Statistiche di sistema', 'gepafin')}

+
+ + +
+
: null} + +
+ +
+

{__('Ultime richieste di finanziamento', 'gepafin')}

+ +
+
+ ) +} + +export default StatsBeneficiary; \ No newline at end of file diff --git a/src/routes.js b/src/routes.js index df80af3..f5555e3 100644 --- a/src/routes.js +++ b/src/routes.js @@ -50,6 +50,7 @@ import SoccorsoAddInstructorManager from './pages/SoccorsoAddInstructorManager'; import SoccorsoEditInstructorManager from './pages/SoccorsoEditInstructorManager'; import SoccorsoIstruttorioInstructorManager from './pages/SoccorsoIstruttorioInstructorManager'; import SoccorsoIstruttorioMioInstructorManager from './pages/SoccorsoIstruttorioMioInstructorManager'; +import StatsBeneficiary from './pages/StatsBeneficiary'; const routes = ({ role, chosenCompanyId }) => { @@ -236,6 +237,12 @@ const routes = ({ role, chosenCompanyId }) => { {'ROLE_PRE_INSTRUCTOR' === role ? : null} {'ROLE_INSTRUCTOR_MANAGER' === role ? : null} }/> + + {'ROLE_SUPER_ADMIN' === role ? : null} + {'ROLE_BENEFICIARY' === role ? : null} + {'ROLE_PRE_INSTRUCTOR' === role ? : null} + {'ROLE_INSTRUCTOR_MANAGER' === role ? : null} + }/> }/> }/> diff --git a/src/service/application-evaluation-service.js b/src/service/application-evaluation-service.js index 048cb46..cc20ea6 100644 --- a/src/service/application-evaluation-service.js +++ b/src/service/application-evaluation-service.js @@ -8,7 +8,21 @@ export default class ApplicationEvaluationService { NetworkService.get(`${API_BASE_URL}/applicationEvaluation/application`, callback, errCallback, queryParams); }; + static getEvaluationV2ByApplId = (callback, errCallback, queryParams) => { + NetworkService.get(`${API_BASE_URL}/applicationEvaluation/v2`, callback, errCallback, queryParams); + }; + + static getEvaluationVersionByApplId = (id, callback, errCallback, queryParams) => { + NetworkService.get(`${API_BASE_URL}/applicationEvaluation/application/${id}/version`, callback, errCallback, queryParams); + }; + static updateEvaluation = (assignedApplicationId, body, callback, errCallback, queryParams) => { NetworkService.put(`${API_BASE_URL}/applicationEvaluation/${assignedApplicationId}`, body, callback, errCallback, queryParams); }; + + static updateEvaluationV2 = (assignedApplicationId, formId, body, callback, errCallback, queryParams = []) => { + NetworkService.put(`${API_BASE_URL}/applicationEvaluation/v2/assignedApplication/${assignedApplicationId}`, body, callback, errCallback, [ + ['evaluationFormId', formId] + ]); + }; } diff --git a/src/service/application-service.js b/src/service/application-service.js index ae59a84..961ee34 100644 --- a/src/service/application-service.js +++ b/src/service/application-service.js @@ -8,6 +8,10 @@ export default class ApplicationService { NetworkService.get(`${API_BASE_URL}/application`, callback, errCallback, queryParams); }; + static getApplicationsPaginated = (body, callback, errCallback, queryParams) => { + NetworkService.post(`${API_BASE_URL}/application/pagination`, body, callback, errCallback, queryParams); + }; + static getApplication = (id, callback, errCallback) => { NetworkService.get(`${API_BASE_URL}/application/${id}`, callback, errCallback); }; diff --git a/src/service/bando-service.js b/src/service/bando-service.js index 5f616fb..3a38a80 100644 --- a/src/service/bando-service.js +++ b/src/service/bando-service.js @@ -32,6 +32,10 @@ export default class BandoService { NetworkService.put(`${API_BASE_URL}/call/step2/${id}`, body, callback, errCallback); }; + static updateBandoStep2V2 = (id, body, callback, errCallback) => { + NetworkService.put(`${API_BASE_URL}/call/step2-v2/${id}`, body, callback, errCallback); + }; + static updateBandoStatus = (id, callback, errCallback, queryParams) => { NetworkService.put(`${API_BASE_URL}/call/${id}/status`, {}, callback, errCallback, queryParams); }; diff --git a/src/service/dashboard-service.js b/src/service/dashboard-service.js index 093db59..6453d4f 100644 --- a/src/service/dashboard-service.js +++ b/src/service/dashboard-service.js @@ -23,4 +23,11 @@ export default class DashboardService { static getBeneficiaryStatsForCompany = (id, callback, errCallback) => { NetworkService.get(`${API_BASE_URL}/dashboard/beneficiary/company/${id}`, callback, errCallback); }; + static getBeneficiaryStatsPage = (id, callback, errCallback) => { + NetworkService.get(`${API_BASE_URL}/dashboard/beneficiary/statistic/company/${id}`, callback, errCallback); + }; + + static getInstructorAmendmentsStats = (callback, errCallback, queryParams) => { + NetworkService.get(`${API_BASE_URL}/dashboard/instructor/amendment`, callback, errCallback, queryParams); + }; } diff --git a/src/service/evaluation-forms-service.js b/src/service/evaluation-forms-service.js new file mode 100644 index 0000000..dc5d048 --- /dev/null +++ b/src/service/evaluation-forms-service.js @@ -0,0 +1,26 @@ +import { NetworkService } from './network-service'; + +const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS; + +export default class EvaluationFormsService { + + static getFormForCall = (id, callback, errCallback) => { + NetworkService.get(`${API_BASE_URL}/evaluationForm/call/${id}`, callback, errCallback); + }; + + static createFormForCall = (id, body, callback, errCallback) => { + NetworkService.post(`${API_BASE_URL}/evaluationForm/call/${id}`, body, callback, errCallback); + }; + + static updateForm = (id, body, callback, errCallback, queryParams) => { + NetworkService.put(`${API_BASE_URL}/evaluationForm/${id}`, body, callback, errCallback, queryParams); + }; + + static getFormById = (id, callback, errCallback) => { + NetworkService.get(`${API_BASE_URL}/evaluationForm/${id}`, callback, errCallback); + }; + + static deleteForm = (id, callback, errCallback) => { + NetworkService.delete(`${API_BASE_URL}/evaluationForm/${id}`, {}, callback, errCallback); + }; +} diff --git a/src/service/user-service.js b/src/service/user-service.js index e98fd89..1906903 100644 --- a/src/service/user-service.js +++ b/src/service/user-service.js @@ -16,6 +16,10 @@ export default class UserService { NetworkService.put(`${API_BASE_URL}/user/${id}`, body, callback, errCallback); }; + static updateUserSelf = (id, body, callback, errCallback) => { + NetworkService.put(`${API_BASE_URL}/user/${id}/update-details`, body, callback, errCallback); + }; + static createUser = (body, callback, errCallback) => { NetworkService.post(`${API_BASE_URL}/user`, body, callback, errCallback); }; diff --git a/src/store/initial.js b/src/store/initial.js index 14223f5..ea1fda5 100644 --- a/src/store/initial.js +++ b/src/store/initial.js @@ -17,6 +17,7 @@ const initialStore = { formElements: [], elementItems: [], activeElement: '', + selectedElement: '', draggingElementId: 0, bandoCriteria: [], // flow diff --git a/src/tempData.js b/src/tempData.js index bc8df5f..431f555 100644 --- a/src/tempData.js +++ b/src/tempData.js @@ -185,6 +185,10 @@ export const elementItems = [ { name: "label", value: "Casella di Spunta" + }, + { + name: "isChecklistItem", + value: false } ], validators: { @@ -459,5 +463,25 @@ export const elementItems = [ validators: { custom: 'nonEmptyTables' } + }, + { + id: 22, + sortOrder: 22, + name: 'switch', + label: 'Casella di spunta "Checklist"', + description: 'Per selezioni binarie, accettazioni, conferme', + settings: [ + { + name: "label", + value: "Casella di Spunta" + }, + { + name: "isChecklistItem", + value: true + } + ], + validators: { + isRequired: false + } } ]