Merge pull request #35 from Kitzanos/master-sync/fields-calc-feature
Master sync/fields calc feature
This commit is contained in:
39
package.json
39
package.json
@@ -4,38 +4,41 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
|
||||||
"@babel/preset-react": "7.25.9",
|
"@babel/preset-react": "7.26.3",
|
||||||
"@date-fns/tz": "1.2.0",
|
"@date-fns/tz": "1.2.0",
|
||||||
"@emailjs/browser": "4.4.1",
|
"@emailjs/browser": "4.4.1",
|
||||||
"@emotion/styled": "11.13.5",
|
"@emotion/styled": "11.14.0",
|
||||||
"@number-flow/react": "0.4.2",
|
"@number-flow/react": "0.5.5",
|
||||||
"@sentry/browser": "8.42.0",
|
"@sentry/browser": "8.51.0",
|
||||||
"@stomp/stompjs": "7.0.0",
|
"@stomp/stompjs": "7.0.0",
|
||||||
"@tanstack/react-table": "8.20.5",
|
"@tanstack/react-table": "8.20.6",
|
||||||
"@wordpress/i18n": "5.13.0",
|
"@wordpress/i18n": "5.16.0",
|
||||||
"@wordpress/react-i18n": "4.13.0",
|
"@wordpress/react-i18n": "4.16.0",
|
||||||
"codice-fiscale-js": "2.3.22",
|
"codice-fiscale-js": "2.3.22",
|
||||||
"copy-to-clipboard": "3.3.3",
|
"copy-to-clipboard": "3.3.3",
|
||||||
"deep-object-diff": "1.1.9",
|
"deep-object-diff": "1.1.9",
|
||||||
"dompurify": "3.2.2",
|
"dompurify": "3.2.3",
|
||||||
|
"expression-language": "^1.2.0",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
"hotkeys-js": "3.13.7",
|
"hotkeys-js": "3.13.9",
|
||||||
"html-react-parser": "5.1.18",
|
"html-react-parser": "5.2.2",
|
||||||
"jwt-decode": "4.0.0",
|
"jwt-decode": "4.0.0",
|
||||||
"klona": "2.0.6",
|
"klona": "2.0.6",
|
||||||
"leader-line-new": "1.1.9",
|
"leader-line-new": "1.1.9",
|
||||||
"luxon": "3.5.0",
|
"luxon": "3.5.0",
|
||||||
|
"mathjs": "^14.0.1",
|
||||||
|
"mustache": "^4.2.0",
|
||||||
"object-path-immutable": "4.1.2",
|
"object-path-immutable": "4.1.2",
|
||||||
"primeicons": "7.0.0",
|
"primeicons": "7.0.0",
|
||||||
"primereact": "10.8.5",
|
"primereact": "10.9.2",
|
||||||
"quill": "2.0.3",
|
"quill": "2.0.3",
|
||||||
"ramda": "0.30.1",
|
"ramda": "0.30.1",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-dnd": "16.0.1",
|
"react-dnd": "16.0.1",
|
||||||
"react-dnd-html5-backend": "16.0.1",
|
"react-dnd-html5-backend": "16.0.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-hook-form": "7.53.2",
|
"react-hook-form": "7.54.2",
|
||||||
"react-router-dom": "7.0.1",
|
"react-router-dom": "7.1.3",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"recharts": "2.15.0",
|
"recharts": "2.15.0",
|
||||||
"sockjs-client": "^1.6.1",
|
"sockjs-client": "^1.6.1",
|
||||||
@@ -44,14 +47,14 @@
|
|||||||
"zustand-x": "3.0.4"
|
"zustand-x": "3.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.25.9",
|
"@babel/cli": "7.26.4",
|
||||||
"@babel/core": "7.26.0",
|
"@babel/core": "7.26.7",
|
||||||
"@babel/plugin-syntax-jsx": "7.25.9",
|
"@babel/plugin-syntax-jsx": "7.25.9",
|
||||||
"@wordpress/babel-plugin-makepot": "6.13.0",
|
"@wordpress/babel-plugin-makepot": "6.16.0",
|
||||||
"babel-plugin-macros": "3.1.0",
|
"babel-plugin-macros": "3.1.0",
|
||||||
"node-wp-i18n": "1.2.7",
|
"node-wp-i18n": "1.2.7",
|
||||||
"sass": "1.81.0",
|
"sass": "1.83.4",
|
||||||
"sass-loader": "16.0.3"
|
"sass-loader": "16.0.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "GENERATE_SOURCEMAP=false react-scripts start",
|
"start": "GENERATE_SOURCEMAP=false react-scripts start",
|
||||||
|
|||||||
@@ -57,13 +57,10 @@
|
|||||||
background-color: #e3e3e3;
|
background-color: #e3e3e3;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.table {
|
&.table, &.criteria_table {
|
||||||
div.addNewTableRow {
|
div.addNewTableRow {
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 5px 0;
|
justify-content: center;
|
||||||
background: var(--table-border-color);
|
|
||||||
color: var(--primary-text);
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -88,7 +85,6 @@
|
|||||||
color: var(--global-textColor);
|
color: var(--global-textColor);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
text-align: start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
@@ -97,16 +93,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
|
min-width: 120px;
|
||||||
input {
|
input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 3px 5px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tfoot td,
|
tfoot td {
|
||||||
tfoot th {
|
border-top: 1px solid var(--table-border-color);
|
||||||
border-top: 1px solid var(--table-border-color);
|
border-top: 1px solid var(--table-border-color);
|
||||||
border-bottom: 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table.striped tbody tr:nth-child(odd) td,
|
table.striped tbody tr:nth-child(odd) td,
|
||||||
|
|||||||
@@ -53,11 +53,24 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*&.selected {
|
||||||
|
border-color: var(--menuitem-active-background);
|
||||||
|
}*/
|
||||||
|
|
||||||
.meta {
|
.meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.tagHeader {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
@@ -111,7 +124,7 @@
|
|||||||
border: 1px solid var(--button-secondary-borderColor);
|
border: 1px solid var(--button-secondary-borderColor);
|
||||||
background-color: var(--button-secondary-borderColor);
|
background-color: var(--button-secondary-borderColor);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 20px 10px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
@@ -176,6 +189,44 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.formElementSettings__fieldDescription, .formElementSettings__fieldVarsList {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #ffe0c5;
|
||||||
|
border: 1px solid #e6a973;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
color: #c68e5e;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
border: 1px solid #e1b48b;
|
||||||
|
background-color: #fbeadb;
|
||||||
|
border-radius: 3px;
|
||||||
|
user-select: all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.formElementSettings__fieldVarsList {
|
||||||
|
background-color: #e7fddd;
|
||||||
|
border: 1px solid #9de673;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #5eae30;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
border: 1px solid #9de673;
|
||||||
|
background-color: #effaea;
|
||||||
|
margin-right: 4px;
|
||||||
|
user-select: all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.formElementSettings__tabs {
|
.formElementSettings__tabs {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@@ -198,9 +249,13 @@
|
|||||||
|
|
||||||
.formElementSettings__repeaterItem {
|
.formElementSettings__repeaterItem {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 4.5fr 2.4fr 1fr 1.4fr 0.7fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
|
||||||
|
&.tableRow {
|
||||||
|
grid-template-columns: 4.5fr 2.4fr 1fr 1.4fr 0.7fr;
|
||||||
|
}
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -116,6 +116,20 @@ img {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
li div.nonLink {
|
||||||
|
display: flex;
|
||||||
|
padding: 10.5px 17.5px;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 100%;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid var(--menu-borderColor);
|
||||||
|
background-color: var(--button-secondary-borderColor);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.p-tag {
|
.p-tag {
|
||||||
|
&.p-tag-secondary {
|
||||||
|
background-color: var(--table-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.p-tag-tertiary {
|
||||||
|
background-color: var(--card-full-background-color-6);
|
||||||
|
}
|
||||||
|
|
||||||
.p-tag-value {
|
.p-tag-value {
|
||||||
color: var(--menuitem-active-color);
|
color: var(--menuitem-active-color);
|
||||||
}
|
}
|
||||||
@@ -147,6 +155,10 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-dropdown, .p-chips, .p-chips-multiple-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.p-password.p-inputwrapper {
|
.p-password.p-inputwrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@@ -155,6 +167,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-inputnumber-input[readonly] {
|
||||||
|
background-color: #e1e1e1;
|
||||||
|
}
|
||||||
|
|
||||||
.p-inputgroup.flex-1 {
|
.p-inputgroup.flex-1 {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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__grid {
|
||||||
.statsBigBadges__gridItem {
|
.statsBigBadges__gridItem {
|
||||||
&:nth-of-type(1) {
|
&: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) {
|
@media (max-width: 820px) {
|
||||||
.statsBigBadges__grid {
|
.statsBigBadges__grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
&.doubleStatsItems {
|
||||||
|
grid-template-columns: minmax(220px, 1fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ const ChartDomandePerBando = ({ title, data = [] }) => {
|
|||||||
<div className="chartCard__tooltip">
|
<div className="chartCard__tooltip">
|
||||||
<p className="chartCard__tooltipTitle">{label}</p>
|
<p className="chartCard__tooltipTitle">{label}</p>
|
||||||
<p className="chartCard__tooltipText">
|
<p className="chartCard__tooltipText">
|
||||||
{__('Domande', 'gepafin')}: {payload[0].value}
|
{__('In bozza', 'gepafin')}: {payload[0].value}
|
||||||
|
</p>
|
||||||
|
<p className="chartCard__tooltipText">
|
||||||
|
{__('Inviate', 'gepafin')}: {payload[1].value}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -50,7 +53,8 @@ const ChartDomandePerBando = ({ title, data = [] }) => {
|
|||||||
<YAxis/>
|
<YAxis/>
|
||||||
<Tooltip content={<CustomTooltip/>}/>
|
<Tooltip content={<CustomTooltip/>}/>
|
||||||
<Legend/>
|
<Legend/>
|
||||||
<Bar dataKey="numberOfApplications" fill="#EEC137" name={__('Quantità delle domande', 'gepafin')}/>
|
<Bar dataKey="numberOfDraftApplications" fill="#8884d8" name={__('Domande in bozza', 'gepafin')}/>
|
||||||
|
<Bar dataKey="numberOfSubmitedApplications" fill="#EEC137" name={__('Domande inviate', 'gepafin')}/>
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|||||||
78
src/components/ChartDomandePerStato/index.js
Normal file
78
src/components/ChartDomandePerStato/index.js
Normal file
@@ -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 (
|
||||||
|
<div className="chartCard__tooltip">
|
||||||
|
<p className="chartCard__tooltipTitle">{getBandoLabel(payload[0].name)}</p>
|
||||||
|
<p className="chartCard__tooltipText">
|
||||||
|
{payload[0].name}: {payload[0].value}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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 (<div className="chartCard">
|
||||||
|
{title ? <span className="chartCard__title">{title}</span> : null}
|
||||||
|
{chartData && !isEmpty(chartData)
|
||||||
|
? <div className="chartCard__chart">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<PieChart>
|
||||||
|
<Pie
|
||||||
|
data={Object.values(chartData)}
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
labelLine={false}
|
||||||
|
label={({ percent }) => `${(percent * 100).toFixed(0)}%`}
|
||||||
|
outerRadius={120}
|
||||||
|
fill="#8884d8"
|
||||||
|
dataKey="value"
|
||||||
|
nameKey="label"
|
||||||
|
>
|
||||||
|
{Object.values(chartData).map((entry, index) => (
|
||||||
|
<Cell
|
||||||
|
key={`cell-${index}`}
|
||||||
|
fill={COLORS[index % COLORS.length]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Pie>
|
||||||
|
<Tooltip content={<CustomTooltip />} />
|
||||||
|
<Legend verticalAlign="top" height={36}/>
|
||||||
|
</PieChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div> : null}
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChartDomandePerStato;
|
||||||
56
src/components/ChartRichiesteVsApprovate/index.js
Normal file
56
src/components/ChartRichiesteVsApprovate/index.js
Normal file
@@ -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 (
|
||||||
|
<div className="chartCard__tooltip">
|
||||||
|
<p className="chartCard__tooltipTitle">{label}</p>
|
||||||
|
<p className="chartCard__tooltipText">
|
||||||
|
{__('In bozza', 'gepafin')}: {payload[0].value}
|
||||||
|
</p>
|
||||||
|
<p className="chartCard__tooltipText">
|
||||||
|
{__('Inviate', 'gepafin')}: {payload[1].value}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (<div className="chartCard">
|
||||||
|
{title ? <span className="chartCard__title">{title}</span> : null}
|
||||||
|
{data && !isEmpty(data)
|
||||||
|
? <div className="chartCard__chart">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<BarChart
|
||||||
|
data={data}
|
||||||
|
margin={{
|
||||||
|
top: 20,
|
||||||
|
right: 30,
|
||||||
|
left: 20,
|
||||||
|
bottom: 60,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3"/>
|
||||||
|
<XAxis dataKey="month"/>
|
||||||
|
<YAxis/>
|
||||||
|
<Tooltip content={<CustomTooltip/>}/>
|
||||||
|
<Legend/>
|
||||||
|
<Bar dataKey="totalRequested" fill="#8884d8" stackId="a" name={__('Richiesti', 'gepafin')}/>
|
||||||
|
<Bar dataKey="totalApproved" fill="#EEC137" stackId="a" name={__('Approvati', 'gepafin')}/>
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div> : null}
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChartRichiesteVsApprovate;
|
||||||
@@ -38,7 +38,7 @@ const ChartStatoDomande = ({ title, data = [] }) => {
|
|||||||
label={({ percent }) => `${(percent * 100).toFixed(0)}%`}
|
label={({ percent }) => `${(percent * 100).toFixed(0)}%`}
|
||||||
outerRadius={120}
|
outerRadius={120}
|
||||||
fill="#8884d8"
|
fill="#8884d8"
|
||||||
dataKey="numberOfApplications"
|
dataKey="numberOfSubmitedApplications"
|
||||||
nameKey="status"
|
nameKey="status"
|
||||||
>
|
>
|
||||||
{data.map((entry, index) => (
|
{data.map((entry, index) => (
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
|
||||||
|
const DefaultCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
||||||
|
const initialValue = getValue();
|
||||||
|
const disabled = table.options.meta?.disabled;
|
||||||
|
|
||||||
|
const onFocus = (e) => {
|
||||||
|
e.target.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InputText
|
||||||
|
value={initialValue ?? ''}
|
||||||
|
disabled={disabled}
|
||||||
|
onFocus={onFocus}
|
||||||
|
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DefaultCell;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { head, is, isNil, pathOr } from 'ramda';
|
||||||
|
import getNumberFormatted from '../../../../../../../helpers/getNumberFormatted';
|
||||||
|
|
||||||
|
const LastRowCell = ({columnId, lastRowCfg, columnMeta = {}, tableValue = []}) => {
|
||||||
|
const cellData = head(lastRowCfg.filter(o => !isNil(o[columnId])));
|
||||||
|
let cellValue = cellData[columnId];
|
||||||
|
|
||||||
|
if (columnMeta.enableFormula) {
|
||||||
|
cellValue = pathOr(0, ['total'], tableValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <td>{is(Number, cellValue) ? getNumberFormatted(cellValue) : cellValue}</td>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LastRowCell;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { InputNumber } from 'primereact/inputnumber';
|
||||||
|
|
||||||
|
const NumericFormulaCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
||||||
|
const initialValue = getValue();
|
||||||
|
const disabled = table.options.meta?.disabled;
|
||||||
|
|
||||||
|
const onFocus = (e) => {
|
||||||
|
e.target.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange = (value) => {
|
||||||
|
table.options.meta?.updateData(index, id, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InputNumber
|
||||||
|
disabled={disabled}
|
||||||
|
value={initialValue ?? 0}
|
||||||
|
onValueChange={(e) => onChange(e.value)}
|
||||||
|
onFocus={onFocus}
|
||||||
|
minFractionDigits={0}
|
||||||
|
maxFractionDigits={2}
|
||||||
|
locale='it-IT'
|
||||||
|
useGrouping={false}
|
||||||
|
showButtons
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NumericFormulaCell;
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { head, isEmpty, isNil, pathOr, sum } from 'ramda';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import DefaultCell from './components/DefaultCell';
|
||||||
|
import LastRowCell from './components/LastRowCell';
|
||||||
|
|
||||||
|
const RenderTable = ({ tableValue = {}, columnsCfg, lastRowCfg, setTableValueFn, disabled }) => {
|
||||||
|
const rows = pathOr([], ['rows'], tableValue)
|
||||||
|
const table = useReactTable({
|
||||||
|
data: rows,
|
||||||
|
columns: columnsCfg,
|
||||||
|
defaultColumn: {
|
||||||
|
cell: DefaultCell
|
||||||
|
},
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
meta: {
|
||||||
|
disabled,
|
||||||
|
updateData: (rowIndex, columnId, value) => {
|
||||||
|
const columnCfgData = head(columnsCfg.filter(o => o.accessorKey === columnId));
|
||||||
|
const cellData = head(lastRowCfg.filter(o => !isNil(o[columnId])));
|
||||||
|
const cellValue = cellData[columnId];
|
||||||
|
let newRowsData = wrap(tableValue).set(['rows', rowIndex, columnId], value).value();
|
||||||
|
let total = pathOr(0, ['total'], tableValue);
|
||||||
|
|
||||||
|
if (columnCfgData.meta.enableFormula) {
|
||||||
|
const getAllRowsValues = newRowsData.rows
|
||||||
|
.map(row => row[columnId])
|
||||||
|
.map(v => isEmpty(v) || isNil(v) ? 0 : v);
|
||||||
|
|
||||||
|
if (cellValue === 'sum') {
|
||||||
|
total = sum(getAllRowsValues);
|
||||||
|
} else {
|
||||||
|
total = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newRowsData = wrap(newRowsData).set(['total'], total).value();
|
||||||
|
setTableValueFn(newRowsData);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<tr key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
return (
|
||||||
|
<th key={header.id} colSpan={header.colSpan}>
|
||||||
|
{header.isPlaceholder ? null : (
|
||||||
|
<>
|
||||||
|
{flexRender(
|
||||||
|
header.column.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{table.getRowModel().rows.map((row) => {
|
||||||
|
return (
|
||||||
|
<tr key={row.id}>
|
||||||
|
{row.getVisibleCells().map((cell) => {
|
||||||
|
return (
|
||||||
|
<td key={cell.id}>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
{!isEmpty(lastRowCfg)
|
||||||
|
? <tfoot><tr>
|
||||||
|
{columnsCfg.map((o) => <LastRowCell
|
||||||
|
key={o.accessorKey}
|
||||||
|
columnId={o.accessorKey}
|
||||||
|
columnMeta={o.meta}
|
||||||
|
lastRowCfg={lastRowCfg}
|
||||||
|
tableValue={tableValue}/>)}
|
||||||
|
</tr></tfoot>
|
||||||
|
: null}
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RenderTable
|
||||||
132
src/components/FormField/components/CriteriaTable/index.js
Normal file
132
src/components/FormField/components/CriteriaTable/index.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import React, { useEffect, useState, useCallback } from 'react';
|
||||||
|
import { classNames } from 'primereact/utils';
|
||||||
|
import { pathOr, isEmpty } from 'ramda';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import { nonEmptyTables } from '../../../../helpers/validators';
|
||||||
|
|
||||||
|
//components
|
||||||
|
import RenderTable from './RenderTable';
|
||||||
|
import NumericFormulaCell from './RenderTable/components/NumericFormulaCell';
|
||||||
|
|
||||||
|
const Table = ({
|
||||||
|
fieldName,
|
||||||
|
setDataFn,
|
||||||
|
label,
|
||||||
|
register,
|
||||||
|
errors,
|
||||||
|
disabled = false,
|
||||||
|
config = {},
|
||||||
|
defaultValue = [],
|
||||||
|
tableColumns = []
|
||||||
|
}) => {
|
||||||
|
const [columnsCfg, setColumnsCfg] = useState([]);
|
||||||
|
const [rowsCfg, setRowsCfg] = useState([]);
|
||||||
|
const [columns, setColumns] = useState([]);
|
||||||
|
const [lastRow, setLastRow] = useState([]);
|
||||||
|
const [tableValue, setTableValue] = useState(null);
|
||||||
|
|
||||||
|
const updateValue = useCallback((data) => {
|
||||||
|
setTableValue(data);
|
||||||
|
setDataFn(fieldName, data, { shouldValidate: true });
|
||||||
|
}, [tableValue, defaultValue]);
|
||||||
|
|
||||||
|
const properConfig = (config) => {
|
||||||
|
let newConfig = klona(config);
|
||||||
|
if (config.validate && config.validate.nonEmptyTables) {
|
||||||
|
newConfig = wrap(newConfig)
|
||||||
|
.set(['validate', 'nonEmptyTables'], (v) => nonEmptyTables(v, tableColumns))
|
||||||
|
.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let newColumns = columnsCfg.map((o) => {
|
||||||
|
const item = {
|
||||||
|
accessorKey: o.name,
|
||||||
|
header: () => o.label,
|
||||||
|
footer: (props) => props.column.id,
|
||||||
|
meta: {
|
||||||
|
predefined: o.predefined,
|
||||||
|
enableFormula: o.enableFormula,
|
||||||
|
fieldtype: o.fieldtype
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o.enableFormula || o.fieldtype === 'numeric') {
|
||||||
|
item.cell = NumericFormulaCell;
|
||||||
|
} else {
|
||||||
|
item.cell = (info) => info.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
|
setColumns(newColumns);
|
||||||
|
}, [columnsCfg, disabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTableValue(rowsCfg);
|
||||||
|
}, [rowsCfg]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const stateFieldData = pathOr([], ['stateFieldData'], tableColumns);
|
||||||
|
const obj = stateFieldData
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
acc[cur.name] = ''
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
let rowsData = pathOr([obj], ['rowsData'], tableColumns);
|
||||||
|
rowsData = isEmpty(rowsData) ? [obj] : rowsData;
|
||||||
|
setColumnsCfg(stateFieldData);
|
||||||
|
setRowsCfg({ rows: rowsData, total: 0 });
|
||||||
|
|
||||||
|
let lastRowData = stateFieldData.reduce((acc, cur) => {
|
||||||
|
const value = cur.enableFormula ? cur.lastRowFormula : (cur.lastRowText ? cur.lastRowText : '');
|
||||||
|
acc.push({ [cur.name]: value });
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const lastRowValues = lastRowData
|
||||||
|
.map(o => {
|
||||||
|
const values = Object.values(o);
|
||||||
|
return values[0];
|
||||||
|
})
|
||||||
|
.filter(v => !isEmpty(v));
|
||||||
|
|
||||||
|
setLastRow(!isEmpty(lastRowValues) ? lastRowData : []);
|
||||||
|
}, [tableColumns]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!equal(tableValue, defaultValue)) {
|
||||||
|
setTableValue(defaultValue);
|
||||||
|
}
|
||||||
|
}, [defaultValue]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTableValue(defaultValue);
|
||||||
|
register(fieldName, properConfig(config));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
|
||||||
|
{label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
|
||||||
|
? <span className="appForm__field--required">*</span> : null}
|
||||||
|
</label>
|
||||||
|
{tableValue
|
||||||
|
? <RenderTable
|
||||||
|
columnsCfg={columns}
|
||||||
|
tableValue={tableValue}
|
||||||
|
lastRowCfg={lastRow}
|
||||||
|
setTableValueFn={updateValue}
|
||||||
|
disabled={disabled}/> : null}
|
||||||
|
</>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Table;
|
||||||
@@ -21,6 +21,7 @@ const NumberInput = ({
|
|||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
readOnly = false,
|
||||||
useGrouping = true
|
useGrouping = true
|
||||||
}) => {
|
}) => {
|
||||||
const minAttr = config.min ? config.min : min;
|
const minAttr = config.min ? config.min : min;
|
||||||
@@ -33,11 +34,13 @@ const NumberInput = ({
|
|||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
<InputNumber inputId={field.name}
|
<InputNumber inputId={field.name}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
readOnly={readOnly}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={(e) => field.onChange(e.value)}
|
onValueChange={(e) => field.onChange(e.value)}
|
||||||
min={minAttr}
|
min={minAttr}
|
||||||
max={maxAttr}
|
max={maxAttr}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
showButtons
|
||||||
useGrouping={useGrouping}
|
useGrouping={useGrouping}
|
||||||
maxFractionDigits={!isNaN(parseInt(maxFractionDigits)) ? parseInt(maxFractionDigits) : 0}
|
maxFractionDigits={!isNaN(parseInt(maxFractionDigits)) ? parseInt(maxFractionDigits) : 0}
|
||||||
minFractionDigits={!isNaN(parseInt(minFractionDigits)) ? parseInt(minFractionDigits) : 0}
|
minFractionDigits={!isNaN(parseInt(minFractionDigits)) ? parseInt(minFractionDigits) : 0}
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
|
||||||
const DefaultCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
const DefaultCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
||||||
const initialValue = getValue();
|
const initialValue = getValue();
|
||||||
const disabled = table.options.meta?.disabled;
|
const disabled = table.options.meta?.disabled;
|
||||||
|
|
||||||
const onBlur = (e) => {
|
|
||||||
table.options.meta?.updateData(index, id, e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onFocus = (e) => {
|
const onFocus = (e) => {
|
||||||
e.target.select();
|
e.target.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<InputText
|
||||||
disabled={disabled}
|
|
||||||
value={initialValue ?? ''}
|
value={initialValue ?? ''}
|
||||||
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)}
|
disabled={disabled}
|
||||||
onBlur={onBlur}
|
|
||||||
onFocus={onFocus}
|
onFocus={onFocus}
|
||||||
className="w-full px-2 py-1 border rounded"
|
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)} />
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { head, isEmpty, isNil, sum } from 'ramda';
|
import { head, isEmpty, isNil, sum } from 'ramda';
|
||||||
|
import getNumberFormatted from '../../../../../../../helpers/getNumberFormatted';
|
||||||
|
|
||||||
const LastRowCell = ({columnId, lastRows, columnMeta = {}, getColumnDataFn}) => {
|
const LastRowCell = ({columnId, lastRowCfg, columnMeta = {}, getColumnDataFn}) => {
|
||||||
const cellData = head(lastRows.filter(o => !isNil(o[columnId])));
|
const cellData = head(lastRowCfg.filter(o => !isNil(o[columnId])));
|
||||||
let cellValue = cellData[columnId];
|
let cellValue = cellData[columnId];
|
||||||
|
|
||||||
if (columnMeta.enableFormula) {
|
if (columnMeta.enableFormula) {
|
||||||
@@ -9,7 +10,7 @@ const LastRowCell = ({columnId, lastRows, columnMeta = {}, getColumnDataFn}) =>
|
|||||||
.map(v => isEmpty(v) || isNil(v) ? 0 : v);
|
.map(v => isEmpty(v) || isNil(v) ? 0 : v);
|
||||||
|
|
||||||
if (cellValue === 'sum') {
|
if (cellValue === 'sum') {
|
||||||
cellValue = sum(getAllRowsValues);
|
cellValue = getNumberFormatted(sum(getAllRowsValues));
|
||||||
} else {
|
} else {
|
||||||
cellValue = 0;
|
cellValue = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,28 @@
|
|||||||
|
import { InputNumber } from 'primereact/inputnumber';
|
||||||
|
|
||||||
const NumericFormulaCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
const NumericFormulaCell = ({ getValue, row: { index }, column: { id }, table }) => {
|
||||||
const initialValue = getValue();
|
const initialValue = getValue();
|
||||||
const disabled = table.options.meta?.disabled;
|
const disabled = table.options.meta?.disabled;
|
||||||
|
|
||||||
const onBlur = (e) => {
|
|
||||||
const numValue = e.target.value === 0 ? null : Number(e.target.value);
|
|
||||||
table.options.meta?.updateData(index, id, numValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onFocus = (e) => {
|
const onFocus = (e) => {
|
||||||
e.target.select();
|
e.target.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
const onChange = (e) => {
|
const onChange = (value) => {
|
||||||
if (e.target.value === 0 || !isNaN(e.target.value)) {
|
table.options.meta?.updateData(index, id, value);
|
||||||
table.options.meta?.updateData(index, id, e.target.value);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<InputNumber
|
||||||
type="number"
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={initialValue ?? 0}
|
value={initialValue ?? 0}
|
||||||
onChange={onChange}
|
onValueChange={(e) => onChange(e.value)}
|
||||||
onFocus={onFocus}
|
onFocus={onFocus}
|
||||||
onBlur={onBlur}
|
minFractionDigits={0}
|
||||||
step="any"
|
maxFractionDigits={2}
|
||||||
className="w-full px-2 py-1 border rounded"
|
locale='it-IT'
|
||||||
|
useGrouping={false}
|
||||||
|
showButtons
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import { isEmpty } from 'ramda';
|
|||||||
import DefaultCell from './components/DefaultCell';
|
import DefaultCell from './components/DefaultCell';
|
||||||
import LastRowCell from './components/LastRowCell';
|
import LastRowCell from './components/LastRowCell';
|
||||||
|
|
||||||
const RenderTable = ({ data, columns, lastRow, setRowsFn, disabled }) => {
|
const RenderTable = ({ rowsData = [], columnsCfg, lastRowCfg, setRowsFn, disabled }) => {
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data: rowsData,
|
||||||
columns,
|
columns: columnsCfg,
|
||||||
defaultColumn: {
|
defaultColumn: {
|
||||||
cell: DefaultCell
|
cell: DefaultCell
|
||||||
},
|
},
|
||||||
@@ -18,7 +18,7 @@ const RenderTable = ({ data, columns, lastRow, setRowsFn, disabled }) => {
|
|||||||
meta: {
|
meta: {
|
||||||
disabled,
|
disabled,
|
||||||
updateData: (rowIndex, columnId, value) => {
|
updateData: (rowIndex, columnId, value) => {
|
||||||
const newRowsData = wrap(data).set([rowIndex, columnId], value).value();
|
const newRowsData = wrap(rowsData).set([rowIndex, columnId], value).value();
|
||||||
setRowsFn(newRowsData);
|
setRowsFn(newRowsData);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -68,17 +68,17 @@ const RenderTable = ({ data, columns, lastRow, setRowsFn, disabled }) => {
|
|||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{!isEmpty(lastRow)
|
</tbody>
|
||||||
? <tr>
|
{!isEmpty(lastRowCfg)
|
||||||
{columns.map((o) => <LastRowCell
|
? <tfoot><tr>
|
||||||
|
{columnsCfg.map((o) => <LastRowCell
|
||||||
key={o.accessorKey}
|
key={o.accessorKey}
|
||||||
columnId={o.accessorKey}
|
columnId={o.accessorKey}
|
||||||
columnMeta={o.meta}
|
columnMeta={o.meta}
|
||||||
lastRows={lastRow}
|
lastRowCfg={lastRowCfg}
|
||||||
getColumnDataFn={getColumnData}/>)}
|
getColumnDataFn={getColumnData}/>)}
|
||||||
</tr>
|
</tr></tfoot>
|
||||||
: null}
|
: null}
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,13 +122,13 @@ const Table = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const stateFieldData = pathOr([], ['stateFieldData'], tableColumns);
|
const stateFieldData = pathOr([], ['stateFieldData'], tableColumns);
|
||||||
const obj = stateFieldData
|
/*const obj = stateFieldData
|
||||||
.reduce((acc, cur) => {
|
.reduce((acc, cur) => {
|
||||||
acc[cur.name] = ''
|
acc[cur.name] = ''
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});*/
|
||||||
let rowsData = pathOr([obj], ['rowsData'], tableColumns);
|
let rowsData = pathOr([], ['rowsData'], tableColumns);
|
||||||
rowsData = isEmpty(rowsData) ? [obj] : rowsData;
|
//rowsData = isEmpty(rowsData) ? [obj] : rowsData;
|
||||||
setColumnsCfg(stateFieldData);
|
setColumnsCfg(stateFieldData);
|
||||||
setRowsCfg(rowsData);
|
setRowsCfg(rowsData);
|
||||||
|
|
||||||
@@ -169,14 +169,15 @@ const Table = ({
|
|||||||
{label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
|
{label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
|
||||||
? <span className="appForm__field--required">*</span> : null}
|
? <span className="appForm__field--required">*</span> : null}
|
||||||
</label>
|
</label>
|
||||||
{rows ? <RenderTable
|
{rows
|
||||||
columns={columns}
|
? <RenderTable
|
||||||
data={rows}
|
columnsCfg={columns}
|
||||||
lastRow={lastRow}
|
rowsData={rows}
|
||||||
|
lastRowCfg={lastRow}
|
||||||
setRowsFn={updateRows}
|
setRowsFn={updateRows}
|
||||||
disabled={disabled}/> : null}
|
disabled={disabled}/> : null}
|
||||||
{!isEmpty(columns) && !shouldDisableNewRows
|
{!isEmpty(columns) && !shouldDisableNewRows
|
||||||
? <div className="addNewTableRow" onClick={addNewRow}>
|
? <div className="addNewTableRow p-button p-component" onClick={addNewRow}>
|
||||||
{__('Aggiungi una riga', 'gepafin')}
|
{__('Aggiungi una riga', 'gepafin')}
|
||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import Checkboxes from './components/Checkboxes';
|
|||||||
import Fileupload from './components/Fileupload';
|
import Fileupload from './components/Fileupload';
|
||||||
import Table from './components/Table';
|
import Table from './components/Table';
|
||||||
import PasswordField from './components/PasswordField';
|
import PasswordField from './components/PasswordField';
|
||||||
|
import CriteriaTable from './components/CriteriaTable';
|
||||||
|
|
||||||
const FormField = (props) => {
|
const FormField = (props) => {
|
||||||
const fields = {
|
const fields = {
|
||||||
@@ -33,6 +34,7 @@ const FormField = (props) => {
|
|||||||
wysiwyg: Wysiwyg,
|
wysiwyg: Wysiwyg,
|
||||||
checkboxes: Checkboxes,
|
checkboxes: Checkboxes,
|
||||||
table: Table,
|
table: Table,
|
||||||
|
criteria_table: CriteriaTable,
|
||||||
password: PasswordField
|
password: PasswordField
|
||||||
}
|
}
|
||||||
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;
|
const Comp = !isNil(fields[props.type]) ? fields[props.type] : null;
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ const NotificationItemChosen = ({ item, closeFn, markReadFn }) => {
|
|||||||
<span>{getDateFromISOstring(item.createdDate)}</span>
|
<span>{getDateFromISOstring(item.createdDate)}</span>
|
||||||
{item.message}
|
{item.message}
|
||||||
|
|
||||||
<Button
|
{item.status === 'UNREAD'
|
||||||
|
? <Button
|
||||||
style={{marginTop: '20px'}}
|
style={{marginTop: '20px'}}
|
||||||
type="button"
|
type="button"
|
||||||
outlined
|
outlined
|
||||||
onClick={() => markReadFn(item.id)}
|
onClick={() => markReadFn(item.id)}
|
||||||
label={__('Letto', 'gepafin')}/>
|
label={__('Letto', 'gepafin')}/> : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { head, isEmpty, pathOr } from 'ramda';
|
import { head, isEmpty, pathOr } from 'ramda';
|
||||||
import SockJS from 'sockjs-client';
|
import SockJS from 'sockjs-client';
|
||||||
@@ -19,6 +19,7 @@ import { Sidebar } from 'primereact/sidebar';
|
|||||||
import { TabPanel, TabView } from 'primereact/tabview';
|
import { TabPanel, TabView } from 'primereact/tabview';
|
||||||
import NotificationItem from './components/NotificationItem';
|
import NotificationItem from './components/NotificationItem';
|
||||||
import NotificationItemChosen from './components/NotificationItemChosen';
|
import NotificationItemChosen from './components/NotificationItemChosen';
|
||||||
|
import PaginatorBasic from '../PaginatorBasic';
|
||||||
|
|
||||||
const socketUrl = process.env.REACT_APP_API_ADDRESS_WS;
|
const socketUrl = process.env.REACT_APP_API_ADDRESS_WS;
|
||||||
|
|
||||||
@@ -35,22 +36,22 @@ const NotificationsSidebar = () => {
|
|||||||
const stomp = useRef(null);
|
const stomp = useRef(null);
|
||||||
const [currentSubscription, setCurrentSubscription] = useState(null);
|
const [currentSubscription, setCurrentSubscription] = useState(null);
|
||||||
const [isConnected, setIsConnected] = useState(false);
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [totalRecordsNum, setTotalRecordsNum] = useState(0);
|
||||||
|
const [totalPagesNum, setTotalPagesNum] = useState(0);
|
||||||
|
const perPage = 10;
|
||||||
|
|
||||||
// Handle tab change
|
// Handle tab change
|
||||||
const handleTabChange = (e) => {
|
const handleTabChange = (e) => {
|
||||||
setActiveIndex(e.index);
|
if (e.index === activeIndex) {
|
||||||
fetchTabData(e.index);
|
return
|
||||||
};
|
}
|
||||||
|
setTotalRecordsNum(0);
|
||||||
const fetchTabData = (index) => {
|
setTotalPagesNum(0);
|
||||||
setChosenMsg({});
|
setChosenMsg({});
|
||||||
|
setActiveIndex(e.index);
|
||||||
if (0 === index) {
|
setCurrentPage(1);
|
||||||
fetchMessages();
|
};
|
||||||
} else {
|
|
||||||
fetchMessages('READ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const chooseNotification = (id) => {
|
const chooseNotification = (id) => {
|
||||||
const properItems = activeIndex === 0 ? notifications : notificationsRead;
|
const properItems = activeIndex === 0 ? notifications : notificationsRead;
|
||||||
@@ -64,10 +65,27 @@ const NotificationsSidebar = () => {
|
|||||||
setChosenMsg({});
|
setChosenMsg({});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchMessages = (status = 'UNREAD') => {
|
const getPaginationQuery = (status = 'UNREAD', curPage = 1) => {
|
||||||
|
return {
|
||||||
|
'globalFilters': {
|
||||||
|
'page': curPage,
|
||||||
|
'limit': perPage,
|
||||||
|
'sortBy': {
|
||||||
|
'columnName': 'id',
|
||||||
|
'sortDesc': true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'status': [
|
||||||
|
status
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchMessages = useCallback((status = 'UNREAD') => {
|
||||||
const chosenCompanyId = storeGet.main.chosenCompanyId();
|
const chosenCompanyId = storeGet.main.chosenCompanyId();
|
||||||
const userData = storeGet.main.userData();
|
const userData = storeGet.main.userData();
|
||||||
const role = pathOr('', ['role', 'roleType'], userData);
|
const role = pathOr('', ['role', 'roleType'], userData);
|
||||||
|
const bodyParams = getPaginationQuery(status, currentPage);
|
||||||
|
|
||||||
if (currentSubscription) {
|
if (currentSubscription) {
|
||||||
//console.log('UNsubscribed')
|
//console.log('UNsubscribed')
|
||||||
@@ -77,37 +95,72 @@ const NotificationsSidebar = () => {
|
|||||||
|
|
||||||
if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') {
|
if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
NotificationService.getNotifications(
|
NotificationService.getNotificationsByCompanyId(
|
||||||
userData.id,
|
|
||||||
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
|
||||||
errGetNotifications,
|
|
||||||
[
|
|
||||||
['status', status],
|
|
||||||
['companyId', chosenCompanyId]
|
|
||||||
]
|
|
||||||
);
|
|
||||||
if (isConnected && socket.current) {
|
|
||||||
subscribeTo(`/topic/notifications_user_${userData.id}_company_${chosenCompanyId}`)
|
|
||||||
}
|
|
||||||
} else if (userData.id && role !== 'ROLE_BENEFICIARY') {
|
|
||||||
setLoading(true);
|
|
||||||
NotificationService.getNotifications(
|
|
||||||
userData.id,
|
userData.id,
|
||||||
|
chosenCompanyId,
|
||||||
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
||||||
errGetNotifications,
|
errGetNotifications,
|
||||||
[
|
[
|
||||||
['status', status]
|
['status', status]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
if (isConnected && socket.current) {
|
||||||
|
subscribeTo(`/topic/notifications_user_${userData.id}_company_${chosenCompanyId}`)
|
||||||
|
}
|
||||||
|
} else if (userData.id && role !== 'ROLE_BENEFICIARY') {
|
||||||
|
setLoading(true);
|
||||||
|
/*NotificationService.getNotifications(
|
||||||
|
userData.id,
|
||||||
|
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
||||||
|
errGetNotifications,
|
||||||
|
[
|
||||||
|
['status', status]
|
||||||
|
]
|
||||||
|
);*/
|
||||||
|
NotificationService.getNotificationsPagination(
|
||||||
|
userData.id,
|
||||||
|
bodyParams,
|
||||||
|
status === 'UNREAD' ? getNotificationsPagi : getNotificationsReadPagi,
|
||||||
|
errGetNotifications
|
||||||
|
);
|
||||||
if (isConnected && socket.current) {
|
if (isConnected && socket.current) {
|
||||||
subscribeTo(`/topic/notifications_user_${userData.id}`)
|
subscribeTo(`/topic/notifications_user_${userData.id}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, [currentPage]);
|
||||||
|
|
||||||
|
const getNotificationsPagi = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
const { body, totalRecords, currentPage, totalPages } = resp.data;
|
||||||
|
setNotifications(body);
|
||||||
|
setTotalRecordsNum(totalRecords);
|
||||||
|
setTotalPagesNum(totalPages);
|
||||||
|
if (currentPage > totalPages) {
|
||||||
|
setCurrentPage(totalPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNotificationsReadPagi = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
const { body, totalRecords, currentPage, totalPages } = resp.data;
|
||||||
|
setNotificationsRead(body);
|
||||||
|
setTotalRecordsNum(totalRecords);
|
||||||
|
setTotalPagesNum(totalPages);
|
||||||
|
if (currentPage > totalPages) {
|
||||||
|
setCurrentPage(totalPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getNotifications = (resp) => {
|
const getNotifications = (resp) => {
|
||||||
if (resp.status === 'SUCCESS') {
|
if (resp.status === 'SUCCESS') {
|
||||||
setNotifications(resp.data);
|
setNotifications(resp.data);
|
||||||
|
setTotalRecordsNum(resp.data.length);
|
||||||
}
|
}
|
||||||
set404FromErrorResponse(resp);
|
set404FromErrorResponse(resp);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -116,6 +169,7 @@ const NotificationsSidebar = () => {
|
|||||||
const getNotificationsRead = (resp) => {
|
const getNotificationsRead = (resp) => {
|
||||||
if (resp.status === 'SUCCESS') {
|
if (resp.status === 'SUCCESS') {
|
||||||
setNotificationsRead(resp.data);
|
setNotificationsRead(resp.data);
|
||||||
|
setTotalRecordsNum(resp.data.length);
|
||||||
}
|
}
|
||||||
set404FromErrorResponse(resp);
|
set404FromErrorResponse(resp);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -139,6 +193,7 @@ const NotificationsSidebar = () => {
|
|||||||
const msgs = notificationsRead.map(o => o.id === resp.data.id ? resp.data : o);
|
const msgs = notificationsRead.map(o => o.id === resp.data.id ? resp.data : o);
|
||||||
setNotificationsRead(msgs);
|
setNotificationsRead(msgs);
|
||||||
}
|
}
|
||||||
|
setTotalRecordsNum(totalRecordsNum - 1);
|
||||||
}
|
}
|
||||||
set404FromErrorResponse(resp);
|
set404FromErrorResponse(resp);
|
||||||
}
|
}
|
||||||
@@ -152,7 +207,7 @@ const NotificationsSidebar = () => {
|
|||||||
stomp.current = Stomp.over(socket.current);
|
stomp.current = Stomp.over(socket.current);
|
||||||
|
|
||||||
stomp.current.configure({
|
stomp.current.configure({
|
||||||
debug: function(str) {
|
debug: function (str) {
|
||||||
//console.log(str);
|
//console.log(str);
|
||||||
},
|
},
|
||||||
reconnectDelay: 5000,
|
reconnectDelay: 5000,
|
||||||
@@ -190,10 +245,22 @@ const NotificationsSidebar = () => {
|
|||||||
setCurrentSubscription(subscription);
|
setCurrentSubscription(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onPageChange = (num) => {
|
||||||
|
setCurrentPage(num);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchMessages();
|
fetchMessages();
|
||||||
}, [chosenCompanyId, userData.id, isConnected]);
|
}, [chosenCompanyId, userData.id, isConnected]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (0 === activeIndex) {
|
||||||
|
fetchMessages();
|
||||||
|
} else {
|
||||||
|
fetchMessages('READ');
|
||||||
|
}
|
||||||
|
}, [currentPage, activeIndex]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
connectWebSocket();
|
connectWebSocket();
|
||||||
|
|
||||||
@@ -215,7 +282,7 @@ const NotificationsSidebar = () => {
|
|||||||
<>
|
<>
|
||||||
<i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon"
|
<i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon"
|
||||||
onClick={() => setNotificationsVisible(true)}>
|
onClick={() => setNotificationsVisible(true)}>
|
||||||
<Badge value={notifications.filter(o => o.status === 'UNREAD').length}></Badge>
|
<Badge value={totalRecordsNum}></Badge>
|
||||||
</i>
|
</i>
|
||||||
<Sidebar
|
<Sidebar
|
||||||
className="notificationsSidebar"
|
className="notificationsSidebar"
|
||||||
@@ -234,12 +301,19 @@ const NotificationsSidebar = () => {
|
|||||||
closeFn={closeChosenMsg}
|
closeFn={closeChosenMsg}
|
||||||
markReadFn={makeNotificationRead}/>
|
markReadFn={makeNotificationRead}/>
|
||||||
: (notifications.length > 0
|
: (notifications.length > 0
|
||||||
? <ul className="notificationsSidebar__list">
|
? <>
|
||||||
|
<ul className="notificationsSidebar__list">
|
||||||
{notifications.map(o => <NotificationItem
|
{notifications.map(o => <NotificationItem
|
||||||
key={o.id}
|
key={o.id}
|
||||||
item={o}
|
item={o}
|
||||||
clickFn={chooseNotification}/>)}
|
clickFn={chooseNotification}/>)}
|
||||||
</ul>
|
</ul>
|
||||||
|
<PaginatorBasic
|
||||||
|
totalPages={totalPagesNum}
|
||||||
|
currentPage={currentPage}
|
||||||
|
clickFn={onPageChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
: <div className="notificationsSidebar__loading">
|
: <div className="notificationsSidebar__loading">
|
||||||
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
|
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
|
||||||
{__('Vuoto', 'gepafin')}
|
{__('Vuoto', 'gepafin')}
|
||||||
@@ -256,12 +330,19 @@ const NotificationsSidebar = () => {
|
|||||||
closeFn={closeChosenMsg}
|
closeFn={closeChosenMsg}
|
||||||
markReadFn={makeNotificationRead}/>
|
markReadFn={makeNotificationRead}/>
|
||||||
: (notificationsRead.length > 0
|
: (notificationsRead.length > 0
|
||||||
? <ul className="notificationsSidebar__list">
|
? <>
|
||||||
|
<ul className="notificationsSidebar__list">
|
||||||
{notificationsRead.map(o => <NotificationItem
|
{notificationsRead.map(o => <NotificationItem
|
||||||
key={o.id}
|
key={o.id}
|
||||||
item={o}
|
item={o}
|
||||||
clickFn={chooseNotification}/>)}
|
clickFn={chooseNotification}/>)}
|
||||||
</ul>
|
</ul>
|
||||||
|
<PaginatorBasic
|
||||||
|
totalPages={totalPagesNum}
|
||||||
|
currentPage={currentPage}
|
||||||
|
clickFn={onPageChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
:
|
:
|
||||||
<div className="notificationsSidebar__loading">
|
<div className="notificationsSidebar__loading">
|
||||||
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
|
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
|
||||||
|
|||||||
59
src/components/PaginatorBasic/index.js
Normal file
59
src/components/PaginatorBasic/index.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
const PaginatorBasic = ({
|
||||||
|
currentPage = 0,
|
||||||
|
totalPages = 0,
|
||||||
|
clickFn = () => {
|
||||||
|
}
|
||||||
|
}) => {
|
||||||
|
const handleClick = (num) => {
|
||||||
|
const newNum = num < 0
|
||||||
|
? 0
|
||||||
|
: num > totalPages ? totalPages : num;
|
||||||
|
clickFn(newNum);
|
||||||
|
}
|
||||||
|
const prevDisabled = currentPage <= 1;
|
||||||
|
const nextDisabled = currentPage >= totalPages
|
||||||
|
|
||||||
|
return (
|
||||||
|
totalPages !== 0
|
||||||
|
? <div className="p-paginator p-component" data-pc-name="paginator" data-pc-section="root">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`p-paginator-prev p-paginator-element p-link${prevDisabled ? ' p-disabled' : ''}`}
|
||||||
|
disabled={prevDisabled}
|
||||||
|
onClick={prevDisabled ? () => {
|
||||||
|
} : () => handleClick(currentPage - 1)}
|
||||||
|
aria-label={__('Pagina precedente', 'gepafin')}
|
||||||
|
data-pc-section="prevpagebutton">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="p-icon p-paginator-icon" aria-hidden="true" data-pc-section="prevpageicon">
|
||||||
|
<path
|
||||||
|
d="M8.75 11.185C8.65146 11.1854 8.55381 11.1662 8.4628 11.1284C8.37179 11.0906 8.28924 11.0351 8.22 10.965L4.72 7.46496C4.57955 7.32433 4.50066 7.13371 4.50066 6.93496C4.50066 6.73621 4.57955 6.54558 4.72 6.40496L8.22 2.93496C8.36095 2.84357 8.52851 2.80215 8.69582 2.81733C8.86312 2.83252 9.02048 2.90344 9.14268 3.01872C9.26487 3.134 9.34483 3.28696 9.36973 3.4531C9.39463 3.61924 9.36303 3.78892 9.28 3.93496L6.28 6.93496L9.28 9.93496C9.42045 10.0756 9.49934 10.2662 9.49934 10.465C9.49934 10.6637 9.42045 10.8543 9.28 10.995C9.13526 11.1257 8.9448 11.1939 8.75 11.185Z"
|
||||||
|
fill="currentColor"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<span aria-live="polite" className="p-paginator-current" data-pc-section="current">
|
||||||
|
({currentPage} {__('di', 'gepafin')} {totalPages})
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={nextDisabled}
|
||||||
|
onClick={nextDisabled ? () => {
|
||||||
|
} : () => handleClick(currentPage + 1)}
|
||||||
|
className={`p-paginator-next p-paginator-element p-link${nextDisabled ? ' p-disabled' : ''}`}
|
||||||
|
aria-label={__('Pagina successiva', 'gepafin')}
|
||||||
|
data-pc-section="nextpagebutton">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="p-icon p-paginator-icon" aria-hidden="true" data-pc-section="nextpageicon">
|
||||||
|
<path
|
||||||
|
d="M5.25 11.1728C5.14929 11.1694 5.05033 11.1455 4.9592 11.1025C4.86806 11.0595 4.78666 10.9984 4.72 10.9228C4.57955 10.7822 4.50066 10.5916 4.50066 10.3928C4.50066 10.1941 4.57955 10.0035 4.72 9.86283L7.72 6.86283L4.72 3.86283C4.66067 3.71882 4.64765 3.55991 4.68275 3.40816C4.71785 3.25642 4.79932 3.11936 4.91585 3.01602C5.03238 2.91268 5.17819 2.84819 5.33305 2.83149C5.4879 2.81479 5.64411 2.84671 5.78 2.92283L9.28 6.42283C9.42045 6.56346 9.49934 6.75408 9.49934 6.95283C9.49934 7.15158 9.42045 7.34221 9.28 7.48283L5.78 10.9228C5.71333 10.9984 5.63193 11.0595 5.5408 11.1025C5.44966 11.1455 5.35071 11.1694 5.25 11.1728Z"
|
||||||
|
fill="currentColor"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div> : null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PaginatorBasic;
|
||||||
@@ -59,6 +59,9 @@ const getBandoLabel = (status) => {
|
|||||||
case 'CLOSE':
|
case 'CLOSE':
|
||||||
return __('Chiuso', 'gepafin');
|
return __('Chiuso', 'gepafin');
|
||||||
|
|
||||||
|
case 'REJECTED':
|
||||||
|
return __('Respinto', 'gepafin');
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ const getBandoSeverity = (status) => {
|
|||||||
case 'CLOSE':
|
case 'CLOSE':
|
||||||
return 'closed';
|
return 'closed';
|
||||||
|
|
||||||
|
case 'REJECTED':
|
||||||
|
return 'danger';
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 'info';
|
return 'info';
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/helpers/getTokens.js
Normal file
11
src/helpers/getTokens.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { tokenize } from 'expression-language';
|
||||||
|
|
||||||
|
const getTokens = expr => tokenize(expr).tokens
|
||||||
|
.filter((o, i, arr) => o.type === 'name'
|
||||||
|
&& (typeof arr[i+1] === 'undefined'
|
||||||
|
|| (typeof arr[i+1] !== 'undefined' && arr[i+1].value !== '('))
|
||||||
|
)
|
||||||
|
.map(o => o.value)
|
||||||
|
.filter((v, i, arr) => arr.indexOf(v) === i);
|
||||||
|
|
||||||
|
export default getTokens;
|
||||||
10
src/helpers/isDateTimeInFuture.js
Normal file
10
src/helpers/isDateTimeInFuture.js
Normal file
@@ -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;
|
||||||
3
src/helpers/keepKeys.js
Normal file
3
src/helpers/keepKeys.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const keepKeys = (arr, keys) => arr.map(obj => Object.fromEntries(keys.map(k => [k, obj[k]])));
|
||||||
|
|
||||||
|
export default keepKeys;
|
||||||
3
src/helpers/parseCommaDecimal.js
Normal file
3
src/helpers/parseCommaDecimal.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const parseCommaDecimal = (value = '') => parseFloat(String(value).replace(',', '.'));
|
||||||
|
|
||||||
|
export default parseCommaDecimal;
|
||||||
3
src/helpers/removeKey.js
Normal file
3
src/helpers/removeKey.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const removeKey = (arr, key) => arr.map(({[key]: _, ...rest}) => rest);
|
||||||
|
|
||||||
|
export default removeKey;
|
||||||
23
src/helpers/renderWithDataVars.js
Normal file
23
src/helpers/renderWithDataVars.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import mustache from 'mustache';
|
||||||
|
import { replace } from 'ramda';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use mustachejs to parse content and replace variables with their values
|
||||||
|
* Each variable (everything in brackets) is expression for EE
|
||||||
|
*
|
||||||
|
* @param {string} content
|
||||||
|
* @param {object} context
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
const renderWithDataVars = (content = '', context = {}) => {
|
||||||
|
try {
|
||||||
|
let newContent = replace(/{/g, '{{&', content);
|
||||||
|
newContent = replace(/}/g, '}}', newContent);
|
||||||
|
return mustache.render(newContent, context);
|
||||||
|
} catch {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default renderWithDataVars;
|
||||||
@@ -45,77 +45,105 @@ const AppSidebar = () => {
|
|||||||
label: __('Bandi osservati', 'gepafin'),
|
label: __('Bandi osservati', 'gepafin'),
|
||||||
icon: 'pi pi-star',
|
icon: 'pi pi-star',
|
||||||
href: '/bandi-osservati',
|
href: '/bandi-osservati',
|
||||||
id: 13,
|
id: 5,
|
||||||
enable: intersection(permissions, ['VIEW_CALLS']).length
|
enable: intersection(permissions, ['VIEW_CALLS']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Gestione domande', 'gepafin'),
|
label: __('Gestione domande', 'gepafin'),
|
||||||
icon: 'pi pi-file',
|
icon: 'pi pi-file',
|
||||||
href: '/domande',
|
href: '/domande',
|
||||||
id: 5,
|
id: 6,
|
||||||
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS', 'ASSIGED_APPLICATION']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Domande da valutare', 'gepafin'),
|
label: __('Domande da valutare', 'gepafin'),
|
||||||
icon: 'pi pi-calendar-clock',
|
icon: 'pi pi-calendar-clock',
|
||||||
href: '/domande',
|
href: '/domande',
|
||||||
id: 6,
|
id: 7,
|
||||||
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length && !intersection(permissions, ['ASSIGED_APPLICATION']).length
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Bandi attivi', 'gepafin'),
|
||||||
|
icon: 'pi pi-file',
|
||||||
|
href: '/bandi',
|
||||||
|
id: 8,
|
||||||
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Soccorso', 'gepafin'),
|
||||||
|
icon: <HelpIcon/>,
|
||||||
|
href: '/soccorso-istruttorio',
|
||||||
|
id: 9,
|
||||||
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Archivio domande', 'gepafin'),
|
label: __('Archivio domande', 'gepafin'),
|
||||||
icon: 'pi pi-briefcase',
|
icon: 'pi pi-briefcase',
|
||||||
href: '/domande',
|
href: '/domande',
|
||||||
id: 7,
|
id: 10,
|
||||||
enable: intersection(permissions, ['APPLY_CALLS']).length
|
enable: intersection(permissions, ['APPLY_CALLS']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Archivio domande', 'gepafin'),
|
label: __('Archivio domande', 'gepafin'),
|
||||||
icon: 'pi pi-briefcase',
|
icon: 'pi pi-briefcase',
|
||||||
href: '/domande-archivio',
|
href: '/domande-archivio',
|
||||||
id: 5,
|
id: 11,
|
||||||
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Archivio domande', 'gepafin'),
|
label: __('Archivio domande', 'gepafin'),
|
||||||
icon: 'pi pi-briefcase',
|
icon: 'pi pi-briefcase',
|
||||||
href: '/domande-archivio',
|
href: '/domande-archivio',
|
||||||
id: 6,
|
id: 12,
|
||||||
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: __('Area personale', 'gepafin'),
|
||||||
|
icon: 'pi pi-calendar-clock',
|
||||||
|
id: 17,
|
||||||
|
enable: intersection(permissions, ['ASSIGED_APPLICATION']).length
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __('Domande da valutare', 'gepafin'),
|
||||||
|
icon: 'pi pi-calendar-clock',
|
||||||
|
href: '/mie-domande',
|
||||||
|
id: 18,
|
||||||
|
enable: intersection(permissions, ['ASSIGED_APPLICATION']).length
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: __('Soccorso istruttorio', 'gepafin'),
|
label: __('Soccorso istruttorio', 'gepafin'),
|
||||||
icon: <HelpIcon/>,
|
icon: <HelpIcon/>,
|
||||||
href: '/soccorso-istruttorio',
|
href: '/mio-soccorso-istruttorio',
|
||||||
id: 8,
|
id: 19,
|
||||||
enable: intersection(permissions, ['EVALUATE_APPLICATIONS']).length
|
enable: intersection(permissions, ['ASSIGED_APPLICATION']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Gestione utenti', 'gepafin'),
|
label: __('Gestione utenti', 'gepafin'),
|
||||||
icon: 'pi pi-users',
|
icon: 'pi pi-users',
|
||||||
href: '/utenti',
|
href: '/utenti',
|
||||||
id: 9,
|
id: 13,
|
||||||
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
enable: intersection(permissions, ['VIEW_USERS', 'MANAGE_USERS']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Configurazione', 'gepafin'),
|
label: __('Configurazione', 'gepafin'),
|
||||||
icon: 'pi pi-cog',
|
icon: 'pi pi-cog',
|
||||||
//href: '/configurazione',
|
//href: '/configurazione',
|
||||||
id: 10,
|
id: 14,
|
||||||
enable: false
|
enable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Report e Analisi', 'gepafin'),
|
label: __('Statistiche', 'gepafin'),
|
||||||
icon: 'pi pi-chart-bar',
|
icon: 'pi pi-chart-bar',
|
||||||
//href: '/stats',
|
href: '/stats',
|
||||||
id: 11,
|
id: 15,
|
||||||
enable: false
|
enable: intersection(permissions, ['APPLY_CALLS']).length
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('Log di Sistema', 'gepafin'),
|
label: __('Log di Sistema', 'gepafin'),
|
||||||
icon: 'pi pi-receipt',
|
icon: 'pi pi-receipt',
|
||||||
clickFn: () => {},
|
clickFn: () => {
|
||||||
id: 12,
|
},
|
||||||
|
id: 16,
|
||||||
enable: false
|
enable: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -132,12 +160,17 @@ const AppSidebar = () => {
|
|||||||
: o.icon}
|
: o.icon}
|
||||||
<span>{o.label}</span>
|
<span>{o.label}</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
: <button onClick={() => {}}>
|
: (o.clickFn ?
|
||||||
|
<button onClick={() => {
|
||||||
|
}}>
|
||||||
{is(String, o.icon)
|
{is(String, o.icon)
|
||||||
? <i className={o.icon}></i>
|
? <i className={o.icon}></i>
|
||||||
: o.icon}
|
: o.icon}
|
||||||
<span>{o.label}</span>
|
<span>{o.label}</span>
|
||||||
</button>}
|
</button>
|
||||||
|
: <div className="nonLink">
|
||||||
|
<span>{o.label}</span>
|
||||||
|
</div>)}
|
||||||
</li>)}
|
</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ const AllBandiTable = () => {
|
|||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect} from 'react';
|
import React, { useState, useEffect} from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { is, uniq, isNil, isEmpty } from 'ramda';
|
import { is, uniq, isNil, isEmpty } from 'ramda';
|
||||||
import { wrap } from 'object-path-immutable';
|
import { wrap } from 'object-path-immutable';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@@ -30,6 +30,8 @@ import { Button } from 'primereact/button';
|
|||||||
// i18n
|
// i18n
|
||||||
import translationStrings from '../../../../translationStringsForComponents';
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
import isDateTimeInPast from '../../../../helpers/isDateTimeInPast';
|
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;
|
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
@@ -182,18 +184,22 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
|
|||||||
|
|
||||||
const rowExpansionTemplate = (data) => {
|
const rowExpansionTemplate = (data) => {
|
||||||
const isCallExpired = isDateTimeInPast(data.dates[1], data.endTime);
|
const isCallExpired = isDateTimeInPast(data.dates[1], data.endTime);
|
||||||
|
const isCallScheduled = isDateTimeInFuture(data.dates[0], data.startTime);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-3">
|
<div className="p-3">
|
||||||
{renderHtmlContent(data.descriptionShort)}
|
{renderHtmlContent(data.descriptionShort)}
|
||||||
<p>{__('Scadenza', 'gepafin')}: {getDateFromISOstring(data.dates[1])}</p>
|
<p>{__('Scadenza', 'gepafin')}: {getDateFromISOstring(data.dates[1])}</p>
|
||||||
{!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'))
|
|| (data.confidi && data.id === 6 && REACT_APP_HUB_ID === 'p4lk3bcx1RStqTaIVVbXs'))
|
||||||
? <Button onClick={() => goToBandoPage(data.id)} severity="info">
|
? <Button onClick={() => goToBandoPage(data.id)} severity="info">
|
||||||
{__('Partecipa', 'gepafin')}
|
{__('Partecipa', 'gepafin')}
|
||||||
</Button> : null}
|
</Button> : null}
|
||||||
{isCallExpired
|
{isCallExpired
|
||||||
? <p>{__('È scaduto', 'gepafin')}</p> : null}
|
? <p><Badge value={__('È scaduto', 'gepafin')} severity="danger"></Badge></p> : null}
|
||||||
{isCallExpired || (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && data.confidi
|
{isCallScheduled
|
||||||
|
? <p><Badge value={sprintf(__('È programmato. Inizia: %s %s', 'gepafin'), getDateFromISOstring(data.dates[0]), data.startTime)}></Badge></p> : null}
|
||||||
|
{isCallExpired || isCallScheduled || (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && data.confidi
|
||||||
&& (data.id !== 6 || (data.id === 6 && REACT_APP_HUB_ID !== 'p4lk3bcx1RStqTaIVVbXs')))
|
&& (data.id !== 6 || (data.id === 6 && REACT_APP_HUB_ID !== 'p4lk3bcx1RStqTaIVVbXs')))
|
||||||
? <Button onClick={() => goToBandoPage(data.id)} severity="info">
|
? <Button onClick={() => goToBandoPage(data.id)} severity="info">
|
||||||
{__('Mostra', 'gepafin')}
|
{__('Mostra', 'gepafin')}
|
||||||
@@ -210,7 +216,7 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
|
|||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items}
|
<DataTable value={items}
|
||||||
paginator
|
paginator
|
||||||
rows={10}
|
rows={5}
|
||||||
loading={isAsyncRequest}
|
loading={isAsyncRequest}
|
||||||
dataKey="id"
|
dataKey="id"
|
||||||
filters={filters}
|
filters={filters}
|
||||||
|
|||||||
149
src/pages/BandiPreInstructor/components/AllBandiTable/index.js
Normal file
149
src/pages/BandiPreInstructor/components/AllBandiTable/index.js
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import React, { useState, useEffect} from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { is, uniq } from 'ramda';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
|
||||||
|
import getBandoLabel from '../../../../helpers/getBandoLabel';
|
||||||
|
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
|
||||||
|
|
||||||
|
// api
|
||||||
|
import BandoService from '../../../../service/bando-service';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { FilterMatchMode, FilterOperator } from 'primereact/api';
|
||||||
|
import { DataTable } from 'primereact/datatable';
|
||||||
|
import { Column } from 'primereact/column';
|
||||||
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import { Calendar } from 'primereact/calendar';
|
||||||
|
import { Tag } from 'primereact/tag';
|
||||||
|
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
|
|
||||||
|
|
||||||
|
const AllBandiTable = () => {
|
||||||
|
const [items, setItems] = useState(null);
|
||||||
|
const [filters, setFilters] = useState(null);
|
||||||
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
|
const [statuses, setStatuses] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalAsyncRequest(true);
|
||||||
|
BandoService.getBandi(getCallback, errGetCallbacks);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setItems(getFormattedBandiData(data.data));
|
||||||
|
setStatuses(uniq(data.data.map(o => o.status)))
|
||||||
|
initFilters();
|
||||||
|
}
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetCallbacks = (data) => {
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormattedBandiData = (data) => {
|
||||||
|
return data.map((d) => {
|
||||||
|
d.dates = d.dates.map(v => is(String, v) ? new Date(v) : (v ? v : ''));
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
initFilters();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initFilters = () => {
|
||||||
|
setFilters({
|
||||||
|
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
|
||||||
|
name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
|
||||||
|
start_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
|
||||||
|
end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
|
||||||
|
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
return (
|
||||||
|
<div className="appTableHeader">
|
||||||
|
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*const nameBodyTemplate = (rowData) => {
|
||||||
|
return <span>{rowData.name}</span>
|
||||||
|
}*/
|
||||||
|
|
||||||
|
const dateStartBodyTemplate = (rowData) => {
|
||||||
|
return getDateFromISOstring(rowData.dates[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateEndBodyTemplate = (rowData) => {
|
||||||
|
return getDateFromISOstring(rowData.dates[1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateFilterTemplate = (options) => {
|
||||||
|
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusBodyTemplate = (rowData) => {
|
||||||
|
return <ProperBandoLabel status={rowData.status}/>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusFilterTemplate = (options) => {
|
||||||
|
return <Dropdown
|
||||||
|
value={options.value}
|
||||||
|
options={statuses}
|
||||||
|
onChange={(e) => options.filterCallback(e.value, options.index)}
|
||||||
|
itemTemplate={statusItemTemplate}
|
||||||
|
placeholder={translationStrings.selectOneLabel}
|
||||||
|
className="p-column-filter"
|
||||||
|
showClear />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusItemTemplate = (option) => {
|
||||||
|
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const actionsBodyTemplate = (rowData) => {
|
||||||
|
return <Link to={`/bandi/${rowData.id}`}>
|
||||||
|
<Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small" iconPos="right" />
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = renderHeader();
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="appPageSection__table">
|
||||||
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
|
filters={filters} stripedRows removableSort
|
||||||
|
header={header}
|
||||||
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
onFilter={(e) => setFilters(e.filters)}>
|
||||||
|
<Column field="name" header={__('Nome Bando', 'gepafin')}
|
||||||
|
filter sortable
|
||||||
|
filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column header={__('Data Pubblicazione', 'gepafin')} filterField="start_date" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateStartBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||||
|
<Column header={__('Data Scadenza', 'gepafin')} filterField="end_date" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||||
|
<Column field="status" header={__('Stato', 'gepafin')} filterMenuStyle={{ width: '14rem' }}
|
||||||
|
style={{ minWidth: '7rem' }} body={statusBodyTemplate} filter
|
||||||
|
filterElement={statusFilterTemplate}/>
|
||||||
|
<Column header={__('Azioni', 'gepafin')}
|
||||||
|
body={actionsBodyTemplate}/>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AllBandiTable;
|
||||||
23
src/pages/BandiPreInstructor/index.js
Normal file
23
src/pages/BandiPreInstructor/index.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import AllBandiTable from './components/AllBandiTable';
|
||||||
|
|
||||||
|
const BandiPreInstructor = () => {
|
||||||
|
return(
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Bandi attivi', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<AllBandiTable/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BandiPreInstructor;
|
||||||
@@ -186,7 +186,7 @@ const AllBandiPreferredAccordion = () => {
|
|||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items}
|
<DataTable value={items}
|
||||||
paginator
|
paginator
|
||||||
rows={10}
|
rows={5}
|
||||||
loading={isAsyncRequest}
|
loading={isAsyncRequest}
|
||||||
dataKey="id"
|
dataKey="id"
|
||||||
filters={filters}
|
filters={filters}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { head, is, pluck, isEmpty, pathOr } from 'ramda';
|
import { head, is, pluck, isEmpty, pathOr, isNil } from 'ramda';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import 'quill/dist/quill.core.css';
|
import 'quill/dist/quill.core.css';
|
||||||
import { wrap } from 'object-path-immutable';
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeSet, storeGet, useStore } from '../../store';
|
import { storeSet, storeGet, useStore } from '../../store';
|
||||||
@@ -26,6 +29,10 @@ import {
|
|||||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
|
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
|
||||||
|
import renderWithDataVars from '../../helpers/renderWithDataVars';
|
||||||
|
import getTokens from '../../helpers/getTokens';
|
||||||
|
import formatDateString from '../../helpers/formatDateString';
|
||||||
|
import isDateTimeInPast from '../../helpers/isDateTimeInPast';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { Skeleton } from 'primereact/skeleton';
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
@@ -39,8 +46,7 @@ import { Dialog } from 'primereact/dialog';
|
|||||||
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
|
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
|
||||||
|
|
||||||
import { defaultMaxFileSize } from '../../configData';
|
import { defaultMaxFileSize } from '../../configData';
|
||||||
import formatDateString from '../../helpers/formatDateString';
|
import parseCommaDecimal from '../../helpers/parseCommaDecimal';
|
||||||
import isDateTimeInPast from '../../helpers/isDateTimeInPast';
|
|
||||||
|
|
||||||
const BandoApplication = () => {
|
const BandoApplication = () => {
|
||||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||||
@@ -67,6 +73,7 @@ const BandoApplication = () => {
|
|||||||
trigger,
|
trigger,
|
||||||
register,
|
register,
|
||||||
getValues,
|
getValues,
|
||||||
|
watch,
|
||||||
reset
|
reset
|
||||||
} = useForm({
|
} = useForm({
|
||||||
defaultValues: useMemo(() => {
|
defaultValues: useMemo(() => {
|
||||||
@@ -89,6 +96,7 @@ const BandoApplication = () => {
|
|||||||
}
|
}
|
||||||
const activeStepIndex = activeStep - 1;
|
const activeStepIndex = activeStep - 1;
|
||||||
const values = getValues();
|
const values = getValues();
|
||||||
|
const formValues = watch();
|
||||||
|
|
||||||
const onValidate = () => {
|
const onValidate = () => {
|
||||||
const applId = getApplicationId();
|
const applId = getApplicationId();
|
||||||
@@ -165,13 +173,25 @@ const BandoApplication = () => {
|
|||||||
const validateApplicationCallback = (data) => {
|
const validateApplicationCallback = (data) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
if (data.data.status) {
|
if (data.data.status) {
|
||||||
setApplicationStatus(data.data.status); // ask why not 'applicationStatus'?
|
setApplicationStatus(data.data.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
const errValidateApplicationCallback = (data) => {
|
const errValidateApplicationCallback = (data) => {
|
||||||
|
if (data.status === 'VALIDATION_ERROR') {
|
||||||
|
if (formMsgs.current) {
|
||||||
|
formMsgs.current.show([
|
||||||
|
{
|
||||||
|
id: '99',
|
||||||
|
sticky: true, severity: 'error', summary: '',
|
||||||
|
detail: data.data.join(' '),
|
||||||
|
closable: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (toast.current) {
|
if (toast.current) {
|
||||||
toast.current.show({
|
toast.current.show({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
@@ -179,6 +199,7 @@ const BandoApplication = () => {
|
|||||||
detail: data.message
|
detail: data.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +281,7 @@ const BandoApplication = () => {
|
|||||||
{
|
{
|
||||||
id: '99',
|
id: '99',
|
||||||
sticky: true, severity: 'error', summary: '',
|
sticky: true, severity: 'error', summary: '',
|
||||||
detail: data.data.join(', '),
|
detail: data.data.join(' '),
|
||||||
closable: true
|
closable: true
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -301,9 +322,6 @@ const BandoApplication = () => {
|
|||||||
setActiveStep(data.data.currentStep);
|
setActiveStep(data.data.currentStep);
|
||||||
const isCallExpired = isDateTimeInPast(data.data.callEndDate, data.data.callEndTime);
|
const isCallExpired = isDateTimeInPast(data.data.callEndDate, data.data.callEndTime);
|
||||||
setIsExpired(isCallExpired);
|
setIsExpired(isCallExpired);
|
||||||
if (data.data.callId === 13) {
|
|
||||||
setIsExpired(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const chosenCompanyId = data.data.companyId;
|
const chosenCompanyId = data.data.companyId;
|
||||||
const companies = storeGet.main.companies();
|
const companies = storeGet.main.companies();
|
||||||
@@ -352,7 +370,7 @@ const BandoApplication = () => {
|
|||||||
if (o.dynamicData && !isEmpty(o.dynamicData)) {
|
if (o.dynamicData && !isEmpty(o.dynamicData)) {
|
||||||
formDataInitial[o.id] = pathOr('', o.dynamicData.split('.'), dynamicData);
|
formDataInitial[o.id] = pathOr('', o.dynamicData.split('.'), dynamicData);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.data.applicationFormResponse.formFields) {
|
if (data.data.applicationFormResponse.formFields) {
|
||||||
@@ -423,7 +441,9 @@ const BandoApplication = () => {
|
|||||||
icon="pi pi-arrow-right"
|
icon="pi pi-arrow-right"
|
||||||
iconPos="right"/> : null}
|
iconPos="right"/> : null}
|
||||||
<Button
|
<Button
|
||||||
|
type="button"
|
||||||
disabled={'SUBMIT' === applicationStatus || isExpired}
|
disabled={'SUBMIT' === applicationStatus || isExpired}
|
||||||
|
onClick={onValidate}
|
||||||
label={__('Convalidare', 'gepafin')}
|
label={__('Convalidare', 'gepafin')}
|
||||||
icon="pi pi-check"
|
icon="pi pi-check"
|
||||||
iconPos="right"/>
|
iconPos="right"/>
|
||||||
@@ -504,10 +524,48 @@ const BandoApplication = () => {
|
|||||||
// TODO hardcoded for now
|
// TODO hardcoded for now
|
||||||
const signedDocMime = bandoId === 10
|
const signedDocMime = bandoId === 10
|
||||||
? ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime', '.pdf,application/pdf']
|
? ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime', '.pdf,application/pdf']
|
||||||
: ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime']
|
: ['.p7m,application/pkcs7-mime,application/x-pkcs7-mime'];
|
||||||
const signedDocValidationString = bandoId === 10
|
const signedDocValidationString = bandoId === 10
|
||||||
? ['.p7m', '.pdf']
|
? ['.p7m', '.pdf']
|
||||||
: ['.p7m']
|
: ['.p7m'];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}, [formValues]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ('SUBMIT' === applicationStatus) {
|
if ('SUBMIT' === applicationStatus) {
|
||||||
@@ -595,9 +653,13 @@ const BandoApplication = () => {
|
|||||||
const text = head(o.settings.filter(o => o.name === 'text'));
|
const text = head(o.settings.filter(o => o.name === 'text'));
|
||||||
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
||||||
const options = head(o.settings.filter(o => o.name === 'options'));
|
const options = head(o.settings.filter(o => o.name === 'options'));
|
||||||
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
|
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 step = head(o.settings.filter(o => o.name === 'step'));
|
||||||
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
||||||
|
const formula = head(o.settings.filter(o => o.name === 'formula'));
|
||||||
let mimeValue = '';
|
let mimeValue = '';
|
||||||
|
|
||||||
if (mime) {
|
if (mime) {
|
||||||
@@ -623,7 +685,10 @@ const BandoApplication = () => {
|
|||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
//console.log('validations', validations, o.name)
|
|
||||||
|
/*if (o.name === 'table') {
|
||||||
|
console.log('value:', values[o.id] ? values[o.id] : '')
|
||||||
|
}*/
|
||||||
|
|
||||||
return ['paragraph'].includes(o.name) && text
|
return ['paragraph'].includes(o.name) && text
|
||||||
? <div key={o.id}>
|
? <div key={o.id}>
|
||||||
@@ -633,6 +698,8 @@ const BandoApplication = () => {
|
|||||||
</div>
|
</div>
|
||||||
: <FormField
|
: <FormField
|
||||||
key={o.id}
|
key={o.id}
|
||||||
|
disabled={isExpired}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
type={o.name}
|
type={o.name}
|
||||||
fieldName={o.id}
|
fieldName={o.id}
|
||||||
label={label ? label.value : ''}
|
label={label ? label.value : ''}
|
||||||
@@ -681,7 +748,7 @@ const BandoApplication = () => {
|
|||||||
iconPos="right"/>
|
iconPos="right"/>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|
||||||
{'DRAFT' !== applicationStatus
|
{'AWAITING' === applicationStatus
|
||||||
? <div className="appPageSection">
|
? <div className="appPageSection">
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label htmlFor="signedPdfFile">
|
<label htmlFor="signedPdfFile">
|
||||||
@@ -704,7 +771,7 @@ const BandoApplication = () => {
|
|||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
|
|
||||||
{'DRAFT' !== applicationStatus
|
{['AWAITING', 'READY'].includes(applicationStatus)
|
||||||
? <div className="appPageSection">
|
? <div className="appPageSection">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { head, isEmpty, pathOr } from 'ramda';
|
import { head, isEmpty, isNil, pathOr } from 'ramda';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import 'quill/dist/quill.core.css';
|
import 'quill/dist/quill.core.css';
|
||||||
|
|
||||||
@@ -33,6 +33,12 @@ import { Toast } from 'primereact/toast';
|
|||||||
import { Messages } from 'primereact/messages';
|
import { Messages } from 'primereact/messages';
|
||||||
import ApplicationSteps from '../BandoApplication/ApplicationSteps';
|
import ApplicationSteps from '../BandoApplication/ApplicationSteps';
|
||||||
import BlockingOverlay from '../../components/BlockingOverlay';
|
import BlockingOverlay from '../../components/BlockingOverlay';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
import getTokens from '../../helpers/getTokens';
|
||||||
|
import renderWithDataVars from '../../helpers/renderWithDataVars';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
import parseCommaDecimal from '../../helpers/parseCommaDecimal';
|
||||||
|
|
||||||
const BandoApplicationPreview = () => {
|
const BandoApplicationPreview = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -55,7 +61,8 @@ const BandoApplicationPreview = () => {
|
|||||||
trigger,
|
trigger,
|
||||||
register,
|
register,
|
||||||
getValues,
|
getValues,
|
||||||
reset
|
reset,
|
||||||
|
watch
|
||||||
} = useForm({
|
} = useForm({
|
||||||
defaultValues: useMemo(() => {
|
defaultValues: useMemo(() => {
|
||||||
return formInitialData ? formInitialData : {}
|
return formInitialData ? formInitialData : {}
|
||||||
@@ -77,6 +84,7 @@ const BandoApplicationPreview = () => {
|
|||||||
}
|
}
|
||||||
const activeStepIndex = activeStep - 1;
|
const activeStepIndex = activeStep - 1;
|
||||||
const values = getValues();
|
const values = getValues();
|
||||||
|
const formValues = watch();
|
||||||
|
|
||||||
const onValidate = () => {
|
const onValidate = () => {
|
||||||
const applId = getApplicationId();
|
const applId = getApplicationId();
|
||||||
@@ -252,6 +260,43 @@ const BandoApplicationPreview = () => {
|
|||||||
iconPos="right"/>
|
iconPos="right"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}, [formValues]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (formInitialData) {
|
if (formInitialData) {
|
||||||
//reset();
|
//reset();
|
||||||
@@ -301,9 +346,13 @@ const BandoApplicationPreview = () => {
|
|||||||
const text = head(o.settings.filter(o => o.name === 'text'));
|
const text = head(o.settings.filter(o => o.name === 'text'));
|
||||||
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
||||||
const options = head(o.settings.filter(o => o.name === 'options'));
|
const options = head(o.settings.filter(o => o.name === 'options'));
|
||||||
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
|
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 step = head(o.settings.filter(o => o.name === 'step'));
|
||||||
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
||||||
|
const formula = head(o.settings.filter(o => o.name === 'formula'));
|
||||||
let mimeValue = '';
|
let mimeValue = '';
|
||||||
|
|
||||||
if (mime) {
|
if (mime) {
|
||||||
@@ -339,6 +388,7 @@ const BandoApplicationPreview = () => {
|
|||||||
</div>
|
</div>
|
||||||
: <FormField
|
: <FormField
|
||||||
key={o.id}
|
key={o.id}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
type={o.name}
|
type={o.name}
|
||||||
disabled={o.name === 'fileupload' || 'DRAFT' !== applicationStatus}
|
disabled={o.name === 'fileupload' || 'DRAFT' !== applicationStatus}
|
||||||
fieldName={o.id}
|
fieldName={o.id}
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ import { storeSet } from '../../../../store';
|
|||||||
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
|
||||||
import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString';
|
import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString';
|
||||||
import formatDateString from '../../../../helpers/formatDateString';
|
import formatDateString from '../../../../helpers/formatDateString';
|
||||||
|
import EvaluationFormsService from '../../../../service/evaluation-forms-service';
|
||||||
|
|
||||||
|
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, getFormErrors, status }, ref) {
|
const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, getFormErrors, status }, ref) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -50,7 +53,8 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
const values = getValues();
|
const values = getValues();
|
||||||
const toast = useRef(null);
|
const toast = useRef(null);
|
||||||
|
|
||||||
const onSubmit = () => {};
|
const onSubmit = () => {
|
||||||
|
};
|
||||||
|
|
||||||
const onSaveDraft = () => {
|
const onSaveDraft = () => {
|
||||||
trigger();
|
trigger();
|
||||||
@@ -115,7 +119,12 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
}
|
}
|
||||||
const values = getValues();
|
const values = getValues();
|
||||||
if (!values.id && data.data.id) {
|
if (!values.id && data.data.id) {
|
||||||
navigate(`/bandi/${data.data.id}`);
|
storeSet.main.setAsyncRequest();
|
||||||
|
const sampleFormData = {
|
||||||
|
label: `Evaluation form for call #${data.data.id}`,
|
||||||
|
content: []
|
||||||
|
}
|
||||||
|
EvaluationFormsService.createFormForCall(data.data.id, sampleFormData, createFormCallback, errCreateFormCallback)
|
||||||
} else {
|
} else {
|
||||||
setFormInitialData(data.data);
|
setFormInitialData(data.data);
|
||||||
setInitialData(data.data);
|
setInitialData(data.data);
|
||||||
@@ -135,6 +144,18 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createFormCallback = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
navigate(`/bandi/${resp.data.callId}`);
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errCreateFormCallback = (resp) => {
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
const openPreview = () => {
|
const openPreview = () => {
|
||||||
navigate(`/bandi/${values.id}/preview`);
|
navigate(`/bandi/${values.id}/preview`);
|
||||||
}
|
}
|
||||||
@@ -180,7 +201,7 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
![
|
![
|
||||||
'descriptionShort', 'descriptionLong', 'documentationRequested', 'threshold',
|
'descriptionShort', 'descriptionLong', 'documentationRequested', 'threshold',
|
||||||
'aimedTo', 'criteria', 'docs', 'checklist', 'faq', 'amount', 'amountMin', 'amountMax',
|
'aimedTo', 'criteria', 'docs', 'checklist', 'faq', 'amount', 'amountMin', 'amountMax',
|
||||||
'email', 'phoneNumber', 'checkList', 'images'
|
'email', 'phoneNumber', 'checkList', 'images', 'numberOfCheck', 'productId'
|
||||||
].includes(fieldName)
|
].includes(fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +480,35 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="appForm__cols">
|
||||||
|
<FormField
|
||||||
|
type="numberinput"
|
||||||
|
disabled={shouldDisableField('numberOfCheck')}
|
||||||
|
fieldName="numberOfCheck"
|
||||||
|
label={__('Quantità dei checklist per creare un soccorso', 'gepafin')}
|
||||||
|
control={control}
|
||||||
|
errors={errors}
|
||||||
|
defaultValue={values['numberOfCheck']}
|
||||||
|
config={{
|
||||||
|
required: __('È obbligatorio', 'gepafin'),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <FormField
|
||||||
|
type="numberinput"
|
||||||
|
disabled={shouldDisableField('productId')}
|
||||||
|
fieldName="productId"
|
||||||
|
label={__('Prodotto ID dentro Odessa', 'gepafin')}
|
||||||
|
control={control}
|
||||||
|
errors={errors}
|
||||||
|
defaultValue={values['productId']}
|
||||||
|
config={{
|
||||||
|
required: __('È obbligatorio', 'gepafin'),
|
||||||
|
}}
|
||||||
|
/> : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
<FormFieldRepeaterFaq
|
<FormFieldRepeaterFaq
|
||||||
data={values['faq']}
|
data={values['faq']}
|
||||||
disabled={shouldDisableField('faq')}
|
disabled={shouldDisableField('faq')}
|
||||||
|
|||||||
@@ -94,7 +94,11 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
delete formData.endDate;
|
delete formData.endDate;
|
||||||
|
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
|
if (values.evaluationVersion === 'V1') {
|
||||||
BandoService.updateBandoStep2(formData.id, formData, createCallback, errCreateCallback);
|
BandoService.updateBandoStep2(formData.id, formData, createCallback, errCreateCallback);
|
||||||
|
} else if (values.evaluationVersion === 'V2') {
|
||||||
|
BandoService.updateBandoStep2V2(formData.id, formData, createCallback, errCreateCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const createCallback = (data) => {
|
const createCallback = (data) => {
|
||||||
@@ -221,7 +225,8 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
return (
|
return (
|
||||||
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
|
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<UnsavedChangesDetector getValuesFn={getValues}/>
|
<UnsavedChangesDetector getValuesFn={getValues}/>
|
||||||
<FormFieldRepeaterCriteria
|
{values.evaluationVersion === 'V1'
|
||||||
|
? <FormFieldRepeaterCriteria
|
||||||
data={values}
|
data={values}
|
||||||
disabled={shouldDisableField('criteria')}
|
disabled={shouldDisableField('criteria')}
|
||||||
setDataFn={setValue}
|
setDataFn={setValue}
|
||||||
@@ -238,7 +243,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
.filter(o => isEmpty(o.value) || isEmpty(o.score)).length === 0
|
.filter(o => isEmpty(o.value) || isEmpty(o.score)).length === 0
|
||||||
|| __('Non lasciare il valore vuoto', 'gepafin')
|
|| __('Non lasciare il valore vuoto', 'gepafin')
|
||||||
}
|
}
|
||||||
}}/>
|
}}/> : null}
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
type="fileuploadasync"
|
type="fileuploadasync"
|
||||||
@@ -275,7 +280,8 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
multiple={false}
|
multiple={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormFieldRepeater
|
{values.evaluationVersion === 'V1'
|
||||||
|
? <FormFieldRepeater
|
||||||
data={values['checkList']}
|
data={values['checkList']}
|
||||||
disabled={shouldDisableField('checkList')}
|
disabled={shouldDisableField('checkList')}
|
||||||
setDataFn={setValue}
|
setDataFn={setValue}
|
||||||
@@ -292,7 +298,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g
|
|||||||
.filter(o => isEmpty(o.value)).length === 0 || __('Non lasciare il valore vuoto', 'gepafin')
|
.filter(o => isEmpty(o.value)).length === 0 || __('Non lasciare il valore vuoto', 'gepafin')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/> : null}
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
|||||||
149
src/pages/BandoEdit/components/BandoEditFormStep3/index.js
Normal file
149
src/pages/BandoEdit/components/BandoEditFormStep3/index.js
Normal file
@@ -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 (
|
||||||
|
<div className="appForm">
|
||||||
|
<div className="appPageSection">
|
||||||
|
<DndProvider backend={HTML5Backend}>
|
||||||
|
<FormBuilder callStatus={bandoStatus} context="call"/>
|
||||||
|
</DndProvider>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection__hr">
|
||||||
|
<span>{__('Azioni', 'gepafin')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Toast ref={toast} />
|
||||||
|
<BandoEditFormActions
|
||||||
|
id={id}
|
||||||
|
status={bandoStatus}
|
||||||
|
submitFn={onSaveDraft}
|
||||||
|
openPreview={openPreview}
|
||||||
|
openPreviewEvaluation={openPreviewEvaluation}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default BandoEditFormStep3;
|
||||||
@@ -23,6 +23,7 @@ import { Messages } from 'primereact/messages';
|
|||||||
import FormsService from '../../service/forms-service';
|
import FormsService from '../../service/forms-service';
|
||||||
import BlockingOverlay from '../../components/BlockingOverlay';
|
import BlockingOverlay from '../../components/BlockingOverlay';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
|
import BandoEditFormStep3 from './components/BandoEditFormStep3';
|
||||||
|
|
||||||
const BandoEdit = () => {
|
const BandoEdit = () => {
|
||||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
@@ -35,7 +36,8 @@ const BandoEdit = () => {
|
|||||||
const bandoMsgs = useRef(null);
|
const bandoMsgs = useRef(null);
|
||||||
const toast = useRef(null);
|
const toast = useRef(null);
|
||||||
|
|
||||||
const stepItems = [
|
const stepItems = (evalProcessVer) => {
|
||||||
|
let steps = [
|
||||||
{
|
{
|
||||||
label: __('Testi', 'gepafin'),
|
label: __('Testi', 'gepafin'),
|
||||||
command: () => {
|
command: () => {
|
||||||
@@ -58,6 +60,22 @@ const BandoEdit = () => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (evalProcessVer === 'V2') {
|
||||||
|
steps.push({
|
||||||
|
label: __('Valutazione', 'gepafin'),
|
||||||
|
command: () => {
|
||||||
|
if (activeStep === 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
bandoMsgs.current.clear();
|
||||||
|
goToStep(2);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
const goToStep = (step) => {
|
const goToStep = (step) => {
|
||||||
setActiveStep(step);
|
setActiveStep(step);
|
||||||
}
|
}
|
||||||
@@ -238,7 +256,8 @@ const BandoEdit = () => {
|
|||||||
|
|
||||||
if (bandoId === 0) {
|
if (bandoId === 0) {
|
||||||
setData({
|
setData({
|
||||||
status: null
|
status: null,
|
||||||
|
evaluationVersion: 'V2'
|
||||||
});
|
});
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
|
||||||
@@ -274,7 +293,7 @@ const BandoEdit = () => {
|
|||||||
|
|
||||||
{!isEmpty(data)
|
{!isEmpty(data)
|
||||||
? <Steps
|
? <Steps
|
||||||
model={stepItems}
|
model={stepItems(data.evaluationVersion)}
|
||||||
activeIndex={activeStep}
|
activeIndex={activeStep}
|
||||||
readOnly={isNil(data.status)}/>
|
readOnly={isNil(data.status)}/>
|
||||||
: null}
|
: null}
|
||||||
@@ -293,6 +312,9 @@ const BandoEdit = () => {
|
|||||||
{activeStep === 1
|
{activeStep === 1
|
||||||
? <BandoEditFormStep2 initialData={data} setInitialData={setData} ref={formRef} status={data.status}/>
|
? <BandoEditFormStep2 initialData={data} setInitialData={setData} ref={formRef} status={data.status}/>
|
||||||
: null}
|
: null}
|
||||||
|
{activeStep === 2 && data.evaluationVersion === 'V2'
|
||||||
|
? <BandoEditFormStep3/>
|
||||||
|
: null}
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Crea o modifica il Form compilabile dal Beneficiario', 'gepafin')}</h2>
|
<h2>{__('Crea o modifica il Form compilabile dal Beneficiario', 'gepafin')}</h2>
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ const BandoFlowEdit = () => {
|
|||||||
const [forms, setForms] = useState([]);
|
const [forms, setForms] = useState([]);
|
||||||
const [formOptions, setFormOptions] = useState([]);
|
const [formOptions, setFormOptions] = useState([]);
|
||||||
const [chosenMainFieldOptions, setChosenMainFieldOptions] = useState([]);
|
const [chosenMainFieldOptions, setChosenMainFieldOptions] = useState([]);
|
||||||
//const [chosenMainField, setChosenMainField] = useState('');
|
|
||||||
const [mainFieldSuboptions, setMainFieldSubOptions] = useState([]);
|
const [mainFieldSuboptions, setMainFieldSubOptions] = useState([]);
|
||||||
const [bandoStatus, setBandoStatus] = useState('');
|
const [bandoStatus, setBandoStatus] = useState('');
|
||||||
const [isFlowAllowed, setIsFlowAllowed] = useState(true);
|
const [isFlowAllowed, setIsFlowAllowed] = useState(true);
|
||||||
@@ -162,18 +161,18 @@ const BandoFlowEdit = () => {
|
|||||||
const shoudDisableSaving = useCallback(() => {
|
const shoudDisableSaving = useCallback(() => {
|
||||||
const nonEmptyFlowItems = flowStructure.flowData.filter(o => isEmpty(o.chosenField)).filter(o => !isEmpty(o.chosenValue));
|
const nonEmptyFlowItems = flowStructure.flowData.filter(o => isEmpty(o.chosenField)).filter(o => !isEmpty(o.chosenValue));
|
||||||
|
|
||||||
/*if (flowForms.length > 2) {
|
/*if (forms.length > 2) {
|
||||||
console.log('disable BTN:', nonEmptyFlowItems.length !== flowForms.length - 2, isEmpty(flowEdges), 'PUBLISH' === bandoStatus,
|
console.log('disable BTN:', nonEmptyFlowItems.length !== forms.length - 2, isEmpty(flowStructure.flowEdges), 'PUBLISH' === bandoStatus,
|
||||||
isEmpty(initialForm), isEmpty(finalForm));
|
isEmpty(flowStructure.initialForm), isEmpty(flowStructure.finalForm));
|
||||||
} else {
|
} else {
|
||||||
console.log('disable BTN:', nonEmptyFlowItems.length !== 1, isEmpty(flowEdges), 'PUBLISH' === bandoStatus,
|
console.log('disable BTN (2 forms):', isEmpty(flowStructure.flowEdges), 'PUBLISH' === bandoStatus,
|
||||||
isEmpty(initialForm), isEmpty(finalForm));
|
isEmpty(flowStructure.initialForm), isEmpty(flowStructure.finalForm));
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
return forms.length > 2
|
return forms.length > 2
|
||||||
? nonEmptyFlowItems.length !== forms.length - 2 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|
? nonEmptyFlowItems.length !== forms.length - 2 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|
||||||
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm)
|
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm)
|
||||||
: nonEmptyFlowItems.length !== 1 || isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|
: isEmpty(flowStructure.flowEdges) || 'PUBLISH' === bandoStatus
|
||||||
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm);
|
|| isEmpty(flowStructure.initialForm) || isEmpty(flowStructure.finalForm);
|
||||||
}, [flowStructure, forms]);
|
}, [flowStructure, forms]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import React, { useRef } from 'react'
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useDrag, useDrop } from 'react-dnd'
|
import { useDrag, useDrop } from 'react-dnd'
|
||||||
import { ItemTypes } from '../ItemTypes';
|
import { ItemTypes } from '../ItemTypes';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { head, isEmpty } from 'ramda';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeSet, useStore } from '../../../../store';
|
import { storeSet, useStore } from '../../../../store';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import uniqid from '../../../../helpers/uniqid';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
import { Tag } from 'primereact/tag';
|
import { Tag } from 'primereact/tag';
|
||||||
@@ -13,7 +18,16 @@ import BuilderElementProperLabel from '../BuilderElementProperLabel';
|
|||||||
|
|
||||||
const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||||
const draggingElementId = useStore().main.draggingElementId();
|
const draggingElementId = useStore().main.draggingElementId();
|
||||||
|
const selectedElement = useStore().main.selectedElement();
|
||||||
const ref = useRef(null);
|
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);
|
||||||
|
|
||||||
const [{ handlerId }, drop] = useDrop({
|
const [{ handlerId }, drop] = useDrop({
|
||||||
accept: ItemTypes.FIELD,
|
accept: ItemTypes.FIELD,
|
||||||
@@ -86,30 +100,92 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
|||||||
storeSet.main.moveElement(dragIndex, hoverIndex, item);
|
storeSet.main.moveElement(dragIndex, hoverIndex, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
const openSettings = (id) => {
|
const openSettings = () => {
|
||||||
storeSet.main.activeElement(id);
|
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);
|
storeSet.main.removeElement(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const opacity = isDragging ? 0 : 1;
|
const opacity = isDragging ? 0 : 1;
|
||||||
drag(drop(ref));
|
drag(drop(ref));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const variable = head(element.settings.filter(o => o.name === 'variable'));
|
||||||
|
const formula = head(element.settings.filter(o => o.name === 'formula'));
|
||||||
|
const isRequestedAmount = head(element.settings.filter(o => o.name === 'isRequestedAmount'));
|
||||||
|
const isDelegation = head(element.settings.filter(o => o.name === 'isDelegation'));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
setIsRequestedAmount('tertiary');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDelegation && !isEmpty(isDelegation.value) && isDelegation.value) {
|
||||||
|
setIsDelegation('tertiary');
|
||||||
|
}
|
||||||
|
}, [elements]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
draggingElementId === id
|
draggingElementId === id
|
||||||
? <div ref={ref} className="formBuilder__elementNew">
|
? <div ref={ref} className="formBuilder__elementNew">
|
||||||
{__('lascia qui', 'gepafin')}
|
{__('lascia qui', 'gepafin')}
|
||||||
</div>
|
</div>
|
||||||
: <div ref={ref} className="formBuilder__element" style={{ opacity }} data-handler-id={handlerId}>
|
: <div ref={ref}
|
||||||
|
className={`formBuilder__element${selectedElement === id ? ' selected' : ''}`}
|
||||||
|
style={{ opacity }}
|
||||||
|
onClick={selectElement}
|
||||||
|
data-handler-id={handlerId}>
|
||||||
<div className="meta">
|
<div className="meta">
|
||||||
|
<div className="tagHeader">
|
||||||
<Tag value={label} severity="info"/>
|
<Tag value={label} severity="info"/>
|
||||||
|
{['numberinput', 'criteria_table'].includes(name)
|
||||||
|
? <Tag value="var" severity={isVariable} title={variableName}/> : null}
|
||||||
|
{name === 'numberinput'
|
||||||
|
? <Tag value="f(x)" severity={isFormula} title={formulaName}/> : null}
|
||||||
|
{isRequestedAmount
|
||||||
|
? <Tag value="importo" severity={isRequestedAmount}/> : null}
|
||||||
|
{isDelegation
|
||||||
|
? <Tag value="delega" severity={isDelegation}/> : null}
|
||||||
|
</div>
|
||||||
<BuilderElementProperLabel id={id} defaultLabel={label}/>
|
<BuilderElementProperLabel id={id} defaultLabel={label}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<Button icon="pi pi-cog" onClick={() => openSettings(id)} outlined severity="info"/>
|
<Button icon="pi pi-clone" onClick={duplicateElement} outlined severity="success"/>
|
||||||
<Button icon="pi pi-trash" disabled={bandoStatus === 'PUBLISH'} onClick={() => remove(id)} outlined severity="danger"/>
|
<Button icon="pi pi-cog" onClick={openSettings} outlined severity="info"/>
|
||||||
|
<Button icon="pi pi-trash" disabled={bandoStatus === 'PUBLISH'} onClick={remove} outlined severity="danger"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,18 +1,28 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { is } from 'ramda';
|
import { head, is, isEmpty, isNil, uniq } from 'ramda';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { storeGet } from '../../../../../../store';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import renderHtmlContent from '../../../../../../helpers/renderHtmlContent';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import ElementSettingRepeater from '../ElementSettingRepeater';
|
import ElementSettingRepeater from '../ElementSettingRepeater';
|
||||||
import { InputText } from 'primereact/inputtext';
|
import { InputText } from 'primereact/inputtext';
|
||||||
import { MultiSelect } from 'primereact/multiselect';
|
import { MultiSelect } from 'primereact/multiselect';
|
||||||
import { Editor } from 'primereact/editor';
|
import { Editor } from 'primereact/editor';
|
||||||
|
|
||||||
import { mimeTypes } from '../../../../../../configData';
|
|
||||||
import ElementSettingTableColumns from '../ElementSettingTableColumns';
|
import ElementSettingTableColumns from '../ElementSettingTableColumns';
|
||||||
import { InputSwitch } from 'primereact/inputswitch';
|
import { InputSwitch } from 'primereact/inputswitch';
|
||||||
|
import ElementSettingChips from '../ElementSettingChips';
|
||||||
|
import ElementSettingCriteriaTableColumns from '../ElementSettingCriteriaTableColumns';
|
||||||
|
|
||||||
|
import { mimeTypes } from '../../../../../../configData';
|
||||||
|
|
||||||
|
|
||||||
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||||
|
const [existingVars, setExistingVars] = useState([]);
|
||||||
|
|
||||||
const settingLabels = {
|
const settingLabels = {
|
||||||
label: __('Label', 'gepafin'),
|
label: __('Label', 'gepafin'),
|
||||||
@@ -24,6 +34,14 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
mime: __('Tipo di file', 'gepafin'),
|
mime: __('Tipo di file', 'gepafin'),
|
||||||
text: __('Testo formattato', 'gepafin'),
|
text: __('Testo formattato', 'gepafin'),
|
||||||
table_columns: '',
|
table_columns: '',
|
||||||
|
criteria_table_columns: '',
|
||||||
|
variable: __('Variabile (lettere, cifre e "_"; il primo carattere deve essere una lettera!)', 'gepafin'),
|
||||||
|
formula: __('Formula di calcolo automatico', 'gepafin'),
|
||||||
|
isChecklistItem: __('Fa parte di "checklist"?', 'gepafin'),
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingDescription = {
|
||||||
|
formula: __('Crea una formula usando variabili dichiarate in precedenza. Utilizza questi operatori matematici: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>. Esempio: <code>{entrate}+{assicurazione}</code>.', 'gepafin')
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderHeader = () => {
|
const renderHeader = () => {
|
||||||
@@ -60,7 +78,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
options={mimeTypes}
|
options={mimeTypes}
|
||||||
optionLabel="name"
|
optionLabel="name"
|
||||||
display="chip"
|
display="chip"
|
||||||
placeholder={__('Scegli', 'gepafin')} />
|
placeholder={__('Scegli', 'gepafin')}/>
|
||||||
} else if (setting.name === 'text') {
|
} else if (setting.name === 'text') {
|
||||||
return <Editor
|
return <Editor
|
||||||
value={setting.value}
|
value={setting.value}
|
||||||
@@ -81,10 +99,21 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
name={setting.name}
|
name={setting.name}
|
||||||
bandoStatus={bandoStatus}
|
bandoStatus={bandoStatus}
|
||||||
setDataFn={updateDataFn}/>
|
setDataFn={updateDataFn}/>
|
||||||
} else if (['isRequestedAmount', 'isDelegation'].includes(setting.name)) {
|
} else if (setting.name === 'criteria_table_columns') {
|
||||||
|
return <ElementSettingCriteriaTableColumns
|
||||||
|
value={is(Object, setting.value) ? setting.value : {}}
|
||||||
|
name={setting.name}
|
||||||
|
bandoStatus={bandoStatus}
|
||||||
|
setDataFn={updateDataFn}/>
|
||||||
|
} else if (['isRequestedAmount', 'isDelegation', 'isChecklistItem'].includes(setting.name)) {
|
||||||
return <InputSwitch
|
return <InputSwitch
|
||||||
checked={setting.value}
|
checked={setting.value}
|
||||||
onChange={(e) => changeFn(e.value, setting.name)}/>
|
onChange={(e) => changeFn(e.value, setting.name)}/>
|
||||||
|
} else if (['variable'].includes(setting.name)) {
|
||||||
|
return <ElementSettingChips
|
||||||
|
restrictedValues={[]}
|
||||||
|
changeFn={(value) => changeFn(value, setting.name)}
|
||||||
|
value={setting.value}/>
|
||||||
} else {
|
} else {
|
||||||
return <InputText id={setting.name} aria-describedby={`${setting.name}-help`}
|
return <InputText id={setting.name} aria-describedby={`${setting.name}-help`}
|
||||||
value={setting.value}
|
value={setting.value}
|
||||||
@@ -92,9 +121,34 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const elements = storeGet.main.formElements();
|
||||||
|
const activeElement = storeGet.main.activeElement();
|
||||||
|
const vars = elements
|
||||||
|
.filter(o => o.id !== activeElement)
|
||||||
|
// eslint-disable-next-line
|
||||||
|
.map((o) => {
|
||||||
|
const variableSetting = head(o.settings.filter(s => s.name === 'variable'));
|
||||||
|
if (variableSetting) {
|
||||||
|
return variableSetting.value[0];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(v => !isNil(v));
|
||||||
|
|
||||||
|
setExistingVars(uniq(vars));
|
||||||
|
}, []);
|
||||||
|
|
||||||
return <div className="formElementSettings__field" key={setting.name}>
|
return <div className="formElementSettings__field" key={setting.name}>
|
||||||
<label htmlFor={setting.name}>{settingLabels[setting.name]}</label>
|
<label htmlFor={setting.name}>{settingLabels[setting.name]}</label>
|
||||||
{getProperField(setting)}
|
{getProperField(setting)}
|
||||||
|
{setting.name === 'formula' && !isEmpty(existingVars)
|
||||||
|
? <div className="formElementSettings__fieldVarsList">
|
||||||
|
<p>Existing variables: {existingVars.map(v => <code key={v}>{`{${v}}`}</code>)}</p>
|
||||||
|
</div> : null}
|
||||||
|
{settingDescription[setting.name]
|
||||||
|
? <div className="formElementSettings__fieldDescription">
|
||||||
|
<p>{renderHtmlContent(settingDescription[setting.name])}</p>
|
||||||
|
</div> : null}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { Chips } from 'primereact/chips';
|
||||||
|
import { isEmpty } from 'ramda';
|
||||||
|
|
||||||
|
const ElementSettingChips = ({ restrictedValues = [], changeFn, value = [] }) => {
|
||||||
|
const [lastTyped, setLastTyped] = useState([])
|
||||||
|
|
||||||
|
const isValidValue = (newVal) => {
|
||||||
|
const validationRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
||||||
|
return validationRegex.test(newVal);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAdd = (e) => {
|
||||||
|
const newValue = isEmpty(e.value) ? '' : e.value[e.value.length - 1];
|
||||||
|
|
||||||
|
if (restrictedValues.includes(newValue)) {
|
||||||
|
changeFn([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValidValue(newValue)) {
|
||||||
|
changeFn(lastTyped);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLastTyped(e.value)
|
||||||
|
changeFn(e.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Chips
|
||||||
|
value={value}
|
||||||
|
addOnBlur={true}
|
||||||
|
onChange={handleAdd}
|
||||||
|
max={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ElementSettingChips;
|
||||||
@@ -0,0 +1,329 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { isEmpty, last, pathOr } from 'ramda';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { InputText } from 'primereact/inputtext';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import { InputSwitch } from 'primereact/inputswitch';
|
||||||
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
|
import { Accordion, AccordionTab } from 'primereact/accordion';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import uniqid from '../../../../../../helpers/uniqid';
|
||||||
|
import removeKey from '../../../../../../helpers/removeKey';
|
||||||
|
|
||||||
|
const ElementSettingCriteriaTableColumns = ({
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
setDataFn,
|
||||||
|
bandoStatus
|
||||||
|
}) => {
|
||||||
|
const [stateFieldData, setStateFieldData] = useState([]);
|
||||||
|
const [rowsData, setRowsData] = useState([]);
|
||||||
|
|
||||||
|
const removeItem = (index) => {
|
||||||
|
let newData = stateFieldData
|
||||||
|
.toSpliced(index, 1);
|
||||||
|
newData = newData.map((o, i) => {
|
||||||
|
return i === newData.length - 1
|
||||||
|
? {...o, fieldtype: 'numeric', predefined: false, enableFormula: true}
|
||||||
|
: {...o, fieldtype: 'text', predefined: true, enableFormula: false}
|
||||||
|
});
|
||||||
|
setStateFieldData(newData);
|
||||||
|
const newRowsData = removeKey(rowsData, last(newData.map(o => o.name)));
|
||||||
|
setRowsData(newRowsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const addNewItem = () => {
|
||||||
|
setStateFieldData([
|
||||||
|
...stateFieldData.map(o => ({...o, fieldtype: 'text', predefined: true, enableFormula: false})),
|
||||||
|
{ name: uniqid('o'), label: '', fieldtype: 'numeric', predefined: false, enableFormula: true }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const addNewRow = () => {
|
||||||
|
const obj = stateFieldData
|
||||||
|
.filter(o => o.predefined)
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
acc[cur.name] = ''
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
setRowsData([...rowsData, obj]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeRow = (index) => {
|
||||||
|
const newRowsData = wrap(rowsData).del([index]).value();
|
||||||
|
setRowsData(newRowsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onInputChange = (e, index) => {
|
||||||
|
const { value } = e.target;
|
||||||
|
const newData = stateFieldData.map((o, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
o.label = value;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
})
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onLastRowInputChange = (e, index) => {
|
||||||
|
const { value } = e.target;
|
||||||
|
const newData = stateFieldData.map((o, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
o.lastRowText = value;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
})
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onTypeChange = (value, index) => {
|
||||||
|
const newData = stateFieldData.map((o, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
o.fieldtype = value;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
})
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onLastRowFormulaChange = (value, index) => {
|
||||||
|
const newData = stateFieldData.map((o, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
o.lastRowFormula = value;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
})
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubInputChange = (e, name, index) => {
|
||||||
|
const { value } = e.target;
|
||||||
|
const newRowsData = wrap(rowsData).set([index, name], value).value();
|
||||||
|
setRowsData(newRowsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const setChecked = (value, index) => {
|
||||||
|
let name = '';
|
||||||
|
const newData = stateFieldData.map((o, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
o.predefined = value;
|
||||||
|
name = o.name;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
});
|
||||||
|
|
||||||
|
let newRowsData = [];
|
||||||
|
|
||||||
|
if (value === false) {
|
||||||
|
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
|
||||||
|
} else {
|
||||||
|
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
|
||||||
|
}
|
||||||
|
|
||||||
|
setRowsData(newRowsData);
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const setColFormulaChecked = (index) => {
|
||||||
|
const newData = stateFieldData.map((o, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
const newVal = o.enableFormula !== true;
|
||||||
|
o.enableFormula = newVal;
|
||||||
|
if (newVal) {
|
||||||
|
o.lastRowFormula = 'sum';
|
||||||
|
o.fieldtype = 'numeric';
|
||||||
|
delete o.lastRowText;
|
||||||
|
} else {
|
||||||
|
delete o.lastRowFormula;
|
||||||
|
delete o.fieldtype;
|
||||||
|
o.lastRowText = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
});
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClearLastRowData = useCallback(() => {
|
||||||
|
const newData = stateFieldData.map((o) => {
|
||||||
|
delete o.lastRowFormula;
|
||||||
|
o.lastRowText = '';
|
||||||
|
delete o.enableFormula;
|
||||||
|
|
||||||
|
return o;
|
||||||
|
});
|
||||||
|
|
||||||
|
setStateFieldData(newData);
|
||||||
|
}, [stateFieldData]);
|
||||||
|
|
||||||
|
const properFields = (item, i) => {
|
||||||
|
return <>
|
||||||
|
<div>
|
||||||
|
<InputText
|
||||||
|
value={item.label}
|
||||||
|
placeholder={sprintf(__('Colonna %d', 'gepafin'), i + 1)}
|
||||||
|
onInput={(e) => onInputChange(e, i)}/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Dropdown
|
||||||
|
disabled={true}
|
||||||
|
value={item.fieldtype ? item.fieldtype : 'text'}
|
||||||
|
onChange={(e) => onTypeChange(e.value, i)}
|
||||||
|
options={[
|
||||||
|
{ value: 'text', label: __('Testo', 'gepafin') },
|
||||||
|
{ value: 'numeric', label: __('Numerico', 'gepafin') }
|
||||||
|
]}/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
disabled={true}
|
||||||
|
className="formElementSettings__repeaterItemIconBtn"
|
||||||
|
onClick={() => setColFormulaChecked(i)}
|
||||||
|
data-active={item.enableFormula ? item.enableFormula : false}
|
||||||
|
type="button">
|
||||||
|
<i className="pi pi-calculator"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<InputSwitch
|
||||||
|
checked={item.predefined}
|
||||||
|
disabled={true}
|
||||||
|
onChange={(e) => setChecked(e.value, i)}/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button icon="pi pi-times"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
className="p-button-danger"
|
||||||
|
onClick={() => removeItem(i)}/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
const properSubField = (item, i, name) => {
|
||||||
|
return <>
|
||||||
|
<div>
|
||||||
|
<InputText
|
||||||
|
value={item[name]}
|
||||||
|
onInput={(e) => onSubInputChange(e, name, i)}/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button icon="pi pi-times"
|
||||||
|
className="p-button-danger"
|
||||||
|
onClick={() => removeRow(i)}/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
const properFieldsLastRow = useCallback((item, i) => {
|
||||||
|
return <>
|
||||||
|
<div>
|
||||||
|
<span>{sprintf(__('Colonna %d'), i + 1)}</span>
|
||||||
|
</div>
|
||||||
|
{item.enableFormula
|
||||||
|
? <div>
|
||||||
|
<Dropdown
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
value={item.lastRowFormula}
|
||||||
|
onChange={(e) => onLastRowFormulaChange(e.value, i)}
|
||||||
|
options={[
|
||||||
|
{ value: 'sum', label: __('Somma automatica', 'gepafin') }
|
||||||
|
]}/>
|
||||||
|
</div>
|
||||||
|
: <div>
|
||||||
|
<InputText
|
||||||
|
value={item.lastRowText ? item.lastRowText : ''}
|
||||||
|
onInput={(e) => onLastRowInputChange(e, i)}/>
|
||||||
|
</div>}
|
||||||
|
</>
|
||||||
|
}, [stateFieldData]);
|
||||||
|
|
||||||
|
const lastRow = <div className="formElementSettings__repeater">
|
||||||
|
<div className="formElementSettings__lastRowHeader">
|
||||||
|
<div className="formElementSettings__lastRowHeaderTitle">
|
||||||
|
{__('Definisci ultima righa', 'gepafin')}
|
||||||
|
</div>
|
||||||
|
<Button type="button"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
outlined
|
||||||
|
label={__('Pulisci', 'gepafin')}
|
||||||
|
iconPos="right"
|
||||||
|
icon="pi pi-refresh"
|
||||||
|
onClick={handleClearLastRowData}/>
|
||||||
|
</div>
|
||||||
|
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__lastRowItem">
|
||||||
|
{properFieldsLastRow(o, i)}
|
||||||
|
</div>)}
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const stateFieldData = pathOr([], ['stateFieldData'], value);
|
||||||
|
setStateFieldData(stateFieldData);
|
||||||
|
const rowsData = pathOr([], ['rowsData'], value);
|
||||||
|
setRowsData(rowsData);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setDataFn(name, {
|
||||||
|
stateFieldData,
|
||||||
|
rowsData
|
||||||
|
});
|
||||||
|
}, [stateFieldData, rowsData]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="formElementSettings__repeater">
|
||||||
|
{stateFieldData.length > 0
|
||||||
|
? <div className="formElementSettings__repeaterItem tableRow">
|
||||||
|
<div>{__('Colonne', 'gepafin')}</div>
|
||||||
|
<div>{__('Tipo', 'gepafin')}</div>
|
||||||
|
<div>{__('Calcola', 'gepafin')}</div>
|
||||||
|
<div>{__('Predefinito?', 'gepafin')}</div>
|
||||||
|
<div></div>
|
||||||
|
</div> : null}
|
||||||
|
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem tableRow">
|
||||||
|
{properFields(o, i)}
|
||||||
|
</div>)}
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
outlined
|
||||||
|
label={__('Aggiungi colonna', 'gepafin')}
|
||||||
|
onClick={addNewItem}/>
|
||||||
|
</div>
|
||||||
|
{stateFieldData
|
||||||
|
.filter(o => o.predefined).length > 0
|
||||||
|
? <div className="formElementSettings__subRepeaterWrapper">
|
||||||
|
<Accordion activeIndex={0}>
|
||||||
|
{stateFieldData
|
||||||
|
//.filter(o => o.predefined)
|
||||||
|
.map((o, i) =>
|
||||||
|
o.predefined
|
||||||
|
? <AccordionTab
|
||||||
|
key={i}
|
||||||
|
header={sprintf(__('Righe per colonna: %s'), !isEmpty(o.label) ? o.label : i + 1)}>
|
||||||
|
<div className="formElementSettings__subRepeaterWrapper">
|
||||||
|
{rowsData.map((c, k) => {
|
||||||
|
return <div key={k} className="formElementSettings__subRepeaterItem">
|
||||||
|
{properSubField(c, k, o.name)}
|
||||||
|
</div>
|
||||||
|
})}
|
||||||
|
<Button type="button"
|
||||||
|
outlined
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
label={__('Aggiungi una riga', 'gepafin')}
|
||||||
|
onClick={addNewRow}/>
|
||||||
|
</div>
|
||||||
|
</AccordionTab> : null)}
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
{lastRow}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ElementSettingCriteriaTableColumns;
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import { wrap } from 'object-path-immutable';
|
|
||||||
import { pathOr } from 'ramda';
|
|
||||||
|
|
||||||
// components
|
|
||||||
import { InputText } from 'primereact/inputtext';
|
|
||||||
import { Button } from 'primereact/button';
|
|
||||||
import { InputSwitch } from 'primereact/inputswitch';
|
|
||||||
|
|
||||||
// tools
|
|
||||||
import uniqid from '../../../../../../helpers/uniqid';
|
|
||||||
|
|
||||||
const ElementSettingTableColumns = ({
|
|
||||||
value,
|
|
||||||
name,
|
|
||||||
setDataFn,
|
|
||||||
bandoStatus
|
|
||||||
}) => {
|
|
||||||
const [stateFieldData, setStateFieldData] = useState([]);
|
|
||||||
const [rowsData, setRowsData] = useState([]);
|
|
||||||
|
|
||||||
const removeItem = (index) => {
|
|
||||||
const newData = stateFieldData.toSpliced(index, 1);
|
|
||||||
setStateFieldData(newData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const addNewItem = () => {
|
|
||||||
setStateFieldData([...stateFieldData, { name: uniqid('o'), label: '', predefined: false }]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const addNewRow = () => {
|
|
||||||
const obj = stateFieldData
|
|
||||||
.filter(o => o.predefined)
|
|
||||||
.reduce((acc, cur) => {
|
|
||||||
acc[cur.name] = ''
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
setRowsData([...rowsData, obj]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeRow = (index) => {
|
|
||||||
const newRowsData = wrap(rowsData).del([index]).value();
|
|
||||||
setRowsData(newRowsData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onInputChange = (e, index) => {
|
|
||||||
const { value } = e.target;
|
|
||||||
const newData = stateFieldData.map((o, i) => {
|
|
||||||
if (i === index) {
|
|
||||||
o.label = value;
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
})
|
|
||||||
setStateFieldData(newData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSubInputChange = (e, name, index) => {
|
|
||||||
const { value } = e.target;
|
|
||||||
const newRowsData = wrap(rowsData).set([index, name], value).value();
|
|
||||||
setRowsData(newRowsData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const setChecked = (value, index) => {
|
|
||||||
let name = '';
|
|
||||||
const newData = stateFieldData.map((o, i) => {
|
|
||||||
if (i === index) {
|
|
||||||
o.predefined = value;
|
|
||||||
name = o.name;
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
});
|
|
||||||
|
|
||||||
let newRowsData = [];
|
|
||||||
|
|
||||||
if (value === false) {
|
|
||||||
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
|
|
||||||
} else {
|
|
||||||
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
|
|
||||||
}
|
|
||||||
|
|
||||||
setRowsData(newRowsData);
|
|
||||||
setStateFieldData(newData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const properField = (item, i) => {
|
|
||||||
return <>
|
|
||||||
<InputText value={item.label} onInput={(e) => onInputChange(e, i)}/>
|
|
||||||
<div className="flex-1">
|
|
||||||
<span>{__('Predefinito?', 'gepafin')}</span>
|
|
||||||
<InputSwitch
|
|
||||||
checked={item.predefined}
|
|
||||||
disabled={bandoStatus === 'PUBLISH'}
|
|
||||||
onChange={(e) => setChecked(e.value, i)}/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
|
|
||||||
const properSubField = (item, i, name) => {
|
|
||||||
return <InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/>
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const stateFieldData = pathOr([], ['stateFieldData'], value);
|
|
||||||
setStateFieldData(stateFieldData);
|
|
||||||
const rowsData = pathOr([], ['rowsData'], value);
|
|
||||||
setRowsData(rowsData);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setDataFn(name, {
|
|
||||||
stateFieldData,
|
|
||||||
rowsData
|
|
||||||
});
|
|
||||||
}, [stateFieldData, rowsData]);
|
|
||||||
|
|
||||||
stateFieldData.filter(o => o.predefined)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="formElementSettings__repeater">
|
|
||||||
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
|
|
||||||
<div className="p-inputgroup flex-1">
|
|
||||||
{properField(o, i)}
|
|
||||||
<Button icon="pi pi-times" disabled={bandoStatus === 'PUBLISH'} className="p-button-danger" onClick={() => removeItem(i)}/>
|
|
||||||
</div>
|
|
||||||
</div>)}
|
|
||||||
<Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined label={__('Aggiungi', 'gepafin')} onClick={addNewItem}/>
|
|
||||||
</div>
|
|
||||||
{stateFieldData
|
|
||||||
.filter(o => o.predefined)
|
|
||||||
.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
|
|
||||||
<div className="formElementSettings__repeater formElementSettings__subRepeater">
|
|
||||||
<label>{__('Righe per colonna:', 'gepafin')} <strong>{o.label}</strong></label>
|
|
||||||
<div className="formElementSettings__repeater">
|
|
||||||
{rowsData.map((c, k) => {
|
|
||||||
return <div key={k} className="formElementSettings__repeaterItem">
|
|
||||||
<div className="p-inputgroup flex-1">
|
|
||||||
{properSubField(c, k, o.name)}
|
|
||||||
<Button icon="pi pi-times"
|
|
||||||
disabled={bandoStatus === 'PUBLISH'}
|
|
||||||
className="p-button-danger"
|
|
||||||
onClick={() => removeRow(k)}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
})}
|
|
||||||
<Button type="button"
|
|
||||||
outlined
|
|
||||||
disabled={bandoStatus === 'PUBLISH'}
|
|
||||||
label={__('Aggiungi una riga', 'gepafin')}
|
|
||||||
onClick={addNewRow}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ElementSettingTableColumns;
|
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { wrap } from 'object-path-immutable';
|
import { wrap } from 'object-path-immutable';
|
||||||
import { isEmpty, pathOr } from 'ramda';
|
import { isEmpty, last, pathOr } from 'ramda';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { InputText } from 'primereact/inputtext';
|
import { InputText } from 'primereact/inputtext';
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
import { InputSwitch } from 'primereact/inputswitch';
|
import { InputSwitch } from 'primereact/inputswitch';
|
||||||
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
|
import { Accordion, AccordionTab } from 'primereact/accordion';
|
||||||
|
|
||||||
// tools
|
// tools
|
||||||
import uniqid from '../../../../../../helpers/uniqid';
|
import uniqid from '../../../../../../helpers/uniqid';
|
||||||
import { Dropdown } from 'primereact/dropdown';
|
import removeKey from '../../../../../../helpers/removeKey';
|
||||||
import { Accordion, AccordionTab } from 'primereact/accordion';
|
|
||||||
|
|
||||||
const ElementSettingTableColumns = ({
|
const ElementSettingTableColumns = ({
|
||||||
value,
|
value,
|
||||||
@@ -25,6 +26,8 @@ const ElementSettingTableColumns = ({
|
|||||||
const removeItem = (index) => {
|
const removeItem = (index) => {
|
||||||
const newData = stateFieldData.toSpliced(index, 1);
|
const newData = stateFieldData.toSpliced(index, 1);
|
||||||
setStateFieldData(newData);
|
setStateFieldData(newData);
|
||||||
|
const newRowsData = removeKey(rowsData, last(newData.map(o => o.name)));
|
||||||
|
setRowsData(newRowsData);
|
||||||
}
|
}
|
||||||
|
|
||||||
const addNewItem = () => {
|
const addNewItem = () => {
|
||||||
@@ -158,7 +161,7 @@ const ElementSettingTableColumns = ({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
disabled={item.enableFormula}
|
disabled={item.enableFormula || bandoStatus === 'PUBLISH'}
|
||||||
value={item.fieldtype ? item.fieldtype : 'text'}
|
value={item.fieldtype ? item.fieldtype : 'text'}
|
||||||
onChange={(e) => onTypeChange(e.value, i)}
|
onChange={(e) => onTypeChange(e.value, i)}
|
||||||
options={[
|
options={[
|
||||||
@@ -168,6 +171,7 @@ const ElementSettingTableColumns = ({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
className="formElementSettings__repeaterItemIconBtn"
|
className="formElementSettings__repeaterItemIconBtn"
|
||||||
onClick={() => setColFormulaChecked(i)}
|
onClick={() => setColFormulaChecked(i)}
|
||||||
data-active={item.enableFormula ? item.enableFormula : false}
|
data-active={item.enableFormula ? item.enableFormula : false}
|
||||||
@@ -193,11 +197,12 @@ const ElementSettingTableColumns = ({
|
|||||||
const properSubField = (item, i, name) => {
|
const properSubField = (item, i, name) => {
|
||||||
return <>
|
return <>
|
||||||
<div>
|
<div>
|
||||||
<InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/>
|
<InputText
|
||||||
|
value={item[name]}
|
||||||
|
onInput={(e) => onSubInputChange(e, name, i)}/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button icon="pi pi-times"
|
<Button icon="pi pi-times"
|
||||||
disabled={bandoStatus === 'PUBLISH'}
|
|
||||||
className="p-button-danger"
|
className="p-button-danger"
|
||||||
onClick={() => removeRow(i)}/>
|
onClick={() => removeRow(i)}/>
|
||||||
</div>
|
</div>
|
||||||
@@ -212,6 +217,7 @@ const ElementSettingTableColumns = ({
|
|||||||
{item.enableFormula
|
{item.enableFormula
|
||||||
? <div>
|
? <div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
value={item.lastRowFormula}
|
value={item.lastRowFormula}
|
||||||
onChange={(e) => onLastRowFormulaChange(e.value, i)}
|
onChange={(e) => onLastRowFormulaChange(e.value, i)}
|
||||||
options={[
|
options={[
|
||||||
@@ -232,6 +238,7 @@ const ElementSettingTableColumns = ({
|
|||||||
{__('Definisci ultima righa', 'gepafin')}
|
{__('Definisci ultima righa', 'gepafin')}
|
||||||
</div>
|
</div>
|
||||||
<Button type="button"
|
<Button type="button"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
outlined
|
outlined
|
||||||
label={__('Pulisci', 'gepafin')}
|
label={__('Pulisci', 'gepafin')}
|
||||||
iconPos="right"
|
iconPos="right"
|
||||||
@@ -261,18 +268,22 @@ const ElementSettingTableColumns = ({
|
|||||||
<>
|
<>
|
||||||
<div className="formElementSettings__repeater">
|
<div className="formElementSettings__repeater">
|
||||||
{stateFieldData.length > 0
|
{stateFieldData.length > 0
|
||||||
? <div className="formElementSettings__repeaterItem">
|
? <div className="formElementSettings__repeaterItem tableRow">
|
||||||
<div>{__('Colonne', 'gepafin')}</div>
|
<div>{__('Colonne', 'gepafin')}</div>
|
||||||
<div>{__('Tipo', 'gepafin')}</div>
|
<div>{__('Tipo', 'gepafin')}</div>
|
||||||
<div>{__('Calcola', 'gepafin')}</div>
|
<div>{__('Calcola', 'gepafin')}</div>
|
||||||
<div>{__('Predefinito?', 'gepafin')}</div>
|
<div>{__('Predefinito?', 'gepafin')}</div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
|
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem tableRow">
|
||||||
{properFields(o, i)}
|
{properFields(o, i)}
|
||||||
</div>)}
|
</div>)}
|
||||||
<Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined
|
<Button
|
||||||
label={__('Aggiungi colonna', 'gepafin')} onClick={addNewItem}/>
|
type="button"
|
||||||
|
disabled={bandoStatus === 'PUBLISH'}
|
||||||
|
outlined
|
||||||
|
label={__('Aggiungi colonna', 'gepafin')}
|
||||||
|
onClick={addNewItem}/>
|
||||||
</div>
|
</div>
|
||||||
{stateFieldData
|
{stateFieldData
|
||||||
.filter(o => o.predefined).length > 0
|
.filter(o => o.predefined).length > 0
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { MultiSelect } from 'primereact/multiselect';
|
|||||||
|
|
||||||
import { dynamicDataOptions } from '../../../../configData';
|
import { dynamicDataOptions } from '../../../../configData';
|
||||||
|
|
||||||
const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
const BuilderElementSettings = ({ closeSettingsFn, callStatus, context }) => {
|
||||||
const elements = useStore().main.formElements();
|
const elements = useStore().main.formElements();
|
||||||
const activeElement = useStore().main.activeElement();
|
const activeElement = useStore().main.activeElement();
|
||||||
const criteriaOptions = useStore().main.bandoCriteria();
|
const criteriaOptions = useStore().main.bandoCriteria();
|
||||||
@@ -110,22 +110,6 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
return dynamicDataOptions[type] ?? [];
|
return dynamicDataOptions[type] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*const searchDynamicTags = (event) => {
|
|
||||||
const type = activeElementData.name;
|
|
||||||
const available = dynamicDataOptions[type];
|
|
||||||
let filtered;
|
|
||||||
|
|
||||||
if (!event.query.trim().length) {
|
|
||||||
filtered = [...available];
|
|
||||||
} else {
|
|
||||||
filtered = available.filter((tag) => {
|
|
||||||
return tag.label.toLowerCase().startsWith(event.query.toLowerCase());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilteredDynamicDataOptions(filtered);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const chosen = head(elements.filter(o => o.id === activeElement));
|
const chosen = head(elements.filter(o => o.id === activeElement));
|
||||||
const elementItems = storeGet.main.elementItems();
|
const elementItems = storeGet.main.elementItems();
|
||||||
@@ -139,6 +123,10 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings = settings.filter(o => context === 'call'
|
||||||
|
? !['isRequestedAmount', 'isDelegation', ''].includes(o.name)
|
||||||
|
: !['isChecklistItem'].includes(o.name));
|
||||||
|
|
||||||
if (chosen) {
|
if (chosen) {
|
||||||
setActiveElementData(klona(chosen));
|
setActiveElementData(klona(chosen));
|
||||||
setSettings(settings);
|
setSettings(settings);
|
||||||
@@ -160,14 +148,16 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
<TabView className="formElementSettings__tabs">
|
<TabView className="formElementSettings__tabs">
|
||||||
<TabPanel header={__('Presentation', 'gepafin')}>
|
<TabPanel header={__('Presentation', 'gepafin')}>
|
||||||
{settings
|
{settings
|
||||||
? settings.map((o) => <ElementSetting
|
? settings
|
||||||
|
.filter(o => !['variable', 'formula'].includes(o.name))
|
||||||
|
.map((o) => <ElementSetting
|
||||||
key={o.name}
|
key={o.name}
|
||||||
setting={o}
|
setting={o}
|
||||||
bandoStatus={bandoStatus}
|
callStatus={callStatus}
|
||||||
changeFn={onChange}
|
changeFn={onChange}
|
||||||
updateDataFn={onUpdateOptions}/>)
|
updateDataFn={onUpdateOptions}/>)
|
||||||
: null}
|
: null}
|
||||||
{!isNil(dynamicDataOptions[activeElementData.name])
|
{!isNil(dynamicDataOptions[activeElementData.name]) && context === 'application'
|
||||||
? <div className="formElementSettings__field">
|
? <div className="formElementSettings__field">
|
||||||
<label htmlFor="dynamicData">{__('Dati dinamici', 'gepafin')}</label>
|
<label htmlFor="dynamicData">{__('Dati dinamici', 'gepafin')}</label>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@@ -234,7 +224,8 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
</div> : null}
|
</div> : null}
|
||||||
</div>) : null}
|
</div>) : null}
|
||||||
</TabPanel> : null}
|
</TabPanel> : null}
|
||||||
<TabPanel header={__('Criteri', 'gepafin')}>
|
{context === 'application'
|
||||||
|
? <TabPanel header={__('Criteri', 'gepafin')}>
|
||||||
<div className="formElementSettings__field">
|
<div className="formElementSettings__field">
|
||||||
<label htmlFor="criteria">{__('Criteri di valutazione', 'gepafin')}</label>
|
<label htmlFor="criteria">{__('Criteri di valutazione', 'gepafin')}</label>
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
@@ -247,11 +238,29 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
|||||||
display="chip"
|
display="chip"
|
||||||
placeholder={__('Scegli', 'gepafin')}/>
|
placeholder={__('Scegli', 'gepafin')}/>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel> : null}
|
||||||
|
{settings
|
||||||
|
&& settings
|
||||||
|
.filter(o => ['variable', 'formula'].includes(o.name)).length > 0
|
||||||
|
? <TabPanel header={__('Calcolo', 'gepafin')}>
|
||||||
|
{settings
|
||||||
|
? settings
|
||||||
|
.filter(o => ['variable', 'formula'].includes(o.name))
|
||||||
|
.map((o) => <ElementSetting
|
||||||
|
key={o.name}
|
||||||
|
setting={o}
|
||||||
|
callStatus={callStatus}
|
||||||
|
changeFn={onChange}
|
||||||
|
updateDataFn={onUpdateOptions}/>)
|
||||||
|
: null}
|
||||||
|
</TabPanel> : null}
|
||||||
</TabView>
|
</TabView>
|
||||||
|
|
||||||
|
<div style={{display: 'flex', gap: '0.5rem'}}>
|
||||||
|
<Button label={__('Annulla', 'gepafin')} onClick={closeSettingsFn} severity="danger"/>
|
||||||
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
|
<Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
: null
|
: null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import BuilderElementSettings from '../BuilderElementSettings';
|
|||||||
import BuilderDropzone from '../BuilderDropzone';
|
import BuilderDropzone from '../BuilderDropzone';
|
||||||
import BlockingOverlay from '../../../../components/BlockingOverlay';
|
import BlockingOverlay from '../../../../components/BlockingOverlay';
|
||||||
|
|
||||||
const FormBuilder = ({ bandoStatus }) => {
|
const FormBuilder = ({ callStatus, context }) => {
|
||||||
const elements = useStore().main.formElements();
|
const elements = useStore().main.formElements();
|
||||||
const elementItems = useStore().main.elementItems();
|
const elementItems = useStore().main.elementItems();
|
||||||
const activeElement = useStore().main.activeElement();
|
const activeElement = useStore().main.activeElement();
|
||||||
@@ -27,10 +27,10 @@ const FormBuilder = ({ bandoStatus }) => {
|
|||||||
id={field.id}
|
id={field.id}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
name={field.name}
|
name={field.name}
|
||||||
bandoStatus={bandoStatus}
|
callStatus={callStatus}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}, [bandoStatus]);
|
}, [callStatus]);
|
||||||
|
|
||||||
const renderItem = useCallback((item) => {
|
const renderItem = useCallback((item) => {
|
||||||
return (
|
return (
|
||||||
@@ -56,9 +56,11 @@ const FormBuilder = ({ bandoStatus }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Sidebar visible={!isEmpty(activeElement)} onHide={closeSettings} className="formBuilder__elementSettings">
|
<Sidebar visible={!isEmpty(activeElement)} onHide={closeSettings} dismissable={false} className="formBuilder__elementSettings">
|
||||||
<h2>{__('Impostazioni del campo modulo', 'gepafin')}</h2>
|
<h2>{__('Impostazioni del campo modulo', 'gepafin')}</h2>
|
||||||
{!isEmpty(activeElement) ? <BuilderElementSettings closeSettingsFn={closeSettings} bandoStatus={bandoStatus}/> : null}
|
{!isEmpty(activeElement)
|
||||||
|
? <BuilderElementSettings closeSettingsFn={closeSettings} callStatus={callStatus} context={context}/>
|
||||||
|
: null}
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
<div className="formBuilder">
|
<div className="formBuilder">
|
||||||
<div className="formBuilder__main">
|
<div className="formBuilder__main">
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ const BandoFormsEdit = () => {
|
|||||||
|
|
||||||
const formCreateCallback = (data, shouldRedirect) => {
|
const formCreateCallback = (data, shouldRedirect) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
storeSet.main.unsetAsyncRequest();
|
|
||||||
const bandoId = getBandoId();
|
const bandoId = getBandoId();
|
||||||
if (shouldRedirect) {
|
if (shouldRedirect) {
|
||||||
navigate(`/bandi/${bandoId}/forms/${data.data.id}/preview`);
|
navigate(`/bandi/${bandoId}/forms/${data.data.id}/preview`);
|
||||||
@@ -127,6 +126,7 @@ const BandoFormsEdit = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
const errFormCreateCallback = (data) => {
|
const errFormCreateCallback = (data) => {
|
||||||
@@ -216,12 +216,14 @@ const BandoFormsEdit = () => {
|
|||||||
const getElementItemsCallback = (data) => {
|
const getElementItemsCallback = (data) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
//storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
|
//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(data.data
|
||||||
|
.filter(o => o.id !== 22)
|
||||||
|
.sort((a, b) => a.sortOrder - b.sortOrder));
|
||||||
}
|
}
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
const errGetElementItemsCallbacks = (data) => {
|
const errGetElementItemsCallback = () => {
|
||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +263,7 @@ const BandoFormsEdit = () => {
|
|||||||
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
|
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
|
||||||
|
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
FormsService.getElementItems(getElementItemsCallback, errGetElementItemsCallbacks);
|
FormsService.getElementItems(getElementItemsCallback, errGetElementItemsCallback);
|
||||||
|
|
||||||
if (bandoFormId) {
|
if (bandoFormId) {
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
@@ -276,6 +278,8 @@ const BandoFormsEdit = () => {
|
|||||||
storeSet.main.formLabel('');
|
storeSet.main.formLabel('');
|
||||||
storeSet.main.formElements([]);
|
storeSet.main.formElements([]);
|
||||||
storeSet.main.bandoCriteria([]);
|
storeSet.main.bandoCriteria([]);
|
||||||
|
storeSet.main.activeElement('');
|
||||||
|
storeSet.main.selectedElement('');
|
||||||
}
|
}
|
||||||
}, [id, formId]);
|
}, [id, formId]);
|
||||||
|
|
||||||
@@ -317,7 +321,7 @@ const BandoFormsEdit = () => {
|
|||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<FormBuilder bandoStatus={bandoStatus}/>
|
<FormBuilder callStatus={bandoStatus} context="application"/>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { klona } from 'klona';
|
import { klona } from 'klona';
|
||||||
import { head, isNil } from 'ramda';
|
import { head, isNil, isEmpty, pathOr } from 'ramda';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import 'quill/dist/quill.core.css';
|
import 'quill/dist/quill.core.css';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeSet, useStore } from '../../store';
|
import { storeSet, useStore } from '../../store';
|
||||||
@@ -30,6 +32,9 @@ import {
|
|||||||
isUrl, minChecks, maxChecks, nonEmptyTables
|
isUrl, minChecks, maxChecks, nonEmptyTables
|
||||||
} from '../../helpers/validators';
|
} from '../../helpers/validators';
|
||||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||||
|
import renderWithDataVars from '../../helpers/renderWithDataVars';
|
||||||
|
import getTokens from '../../helpers/getTokens';
|
||||||
|
import parseCommaDecimal from '../../helpers/parseCommaDecimal';
|
||||||
|
|
||||||
const BandoFormsPreview = () => {
|
const BandoFormsPreview = () => {
|
||||||
const { id, formId } = useParams();
|
const { id, formId } = useParams();
|
||||||
@@ -43,9 +48,12 @@ const BandoFormsPreview = () => {
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
getValues,
|
getValues,
|
||||||
register,
|
register,
|
||||||
setValue
|
setValue,
|
||||||
|
watch,
|
||||||
|
reset
|
||||||
} = useForm({ defaultValues: {}, mode: 'onChange' });
|
} = useForm({ defaultValues: {}, mode: 'onChange' });
|
||||||
const values = getValues();
|
const values = getValues();
|
||||||
|
const formValues = watch();
|
||||||
const validationFns = {
|
const validationFns = {
|
||||||
isPIVA,
|
isPIVA,
|
||||||
isCodiceFiscale,
|
isCodiceFiscale,
|
||||||
@@ -85,6 +93,43 @@ const BandoFormsPreview = () => {
|
|||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}, [formValues]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const parsedFormId = parseInt(formId)
|
const parsedFormId = parseInt(formId)
|
||||||
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
|
const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
|
||||||
@@ -126,9 +171,13 @@ const BandoFormsPreview = () => {
|
|||||||
const text = head(o.settings.filter(o => o.name === 'text'));
|
const text = head(o.settings.filter(o => o.name === 'text'));
|
||||||
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
|
||||||
const options = head(o.settings.filter(o => o.name === 'options'));
|
const options = head(o.settings.filter(o => o.name === 'options'));
|
||||||
const tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
|
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 step = head(o.settings.filter(o => o.name === 'step'));
|
||||||
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
const mime = head(o.settings.filter(o => o.name === 'mime'));
|
||||||
|
const formula = head(o.settings.filter(o => o.name === 'formula'));
|
||||||
let mimeValue = '';
|
let mimeValue = '';
|
||||||
|
|
||||||
if (mime) {
|
if (mime) {
|
||||||
@@ -162,6 +211,7 @@ const BandoFormsPreview = () => {
|
|||||||
</div>
|
</div>
|
||||||
: <FormField
|
: <FormField
|
||||||
key={o.id}
|
key={o.id}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
type={o.name}
|
type={o.name}
|
||||||
fieldName={o.id}
|
fieldName={o.id}
|
||||||
label={label ? label.value : ''}
|
label={label ? label.value : ''}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ import getNumberWithCurrency from '../../helpers/getNumberWithCurrency';
|
|||||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||||
|
import isDateTimeInPast from '../../helpers/isDateTimeInPast';
|
||||||
|
|
||||||
// api
|
// api
|
||||||
import BandoService from '../../service/bando-service';
|
import BandoService from '../../service/bando-service';
|
||||||
import FaqItemService from '../../service/faq-item-service';
|
import FaqItemService from '../../service/faq-item-service';
|
||||||
import ApplicationService from '../../service/application-service';
|
import ApplicationService from '../../service/application-service';
|
||||||
|
import PreferredBandoService from '../../service/preferred-bando-service';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { Skeleton } from 'primereact/skeleton';
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
@@ -28,8 +30,6 @@ import { Message } from 'primereact/message';
|
|||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import { Editor } from 'primereact/editor';
|
import { Editor } from 'primereact/editor';
|
||||||
import { Dialog } from 'primereact/dialog';
|
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;
|
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
|
|||||||
269
src/pages/BandoViewPreInstructor/index.js
Normal file
269
src/pages/BandoViewPreInstructor/index.js
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { is, isEmpty, isNil } from 'ramda';
|
||||||
|
import 'quill/dist/quill.core.css';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { storeSet, useStore } from '../../store';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import getNumberWithCurrency from '../../helpers/getNumberWithCurrency';
|
||||||
|
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
|
import { Accordion } from 'primereact/accordion';
|
||||||
|
import { AccordionTab } from 'primereact/accordion';
|
||||||
|
import { InputTextarea } from 'primereact/inputtextarea';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import BandoService from '../../service/bando-service';
|
||||||
|
import { Messages } from 'primereact/messages';
|
||||||
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
|
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||||
|
|
||||||
|
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
|
const BandoViewPreInstructor = () => {
|
||||||
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
|
const { id } = useParams();
|
||||||
|
const [data, setData] = useState({});
|
||||||
|
const [newQuestion, setNewQuestion] = useState('');
|
||||||
|
const bandoMsgs = useRef(null);
|
||||||
|
|
||||||
|
const getCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setData(getFormattedBandiData(data.data));
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetCallback = (data) => {
|
||||||
|
if (bandoMsgs.current && data.message) {
|
||||||
|
bandoMsgs.current.show([
|
||||||
|
{
|
||||||
|
sticky: true, severity: 'error', summary: '',
|
||||||
|
detail: data.message,
|
||||||
|
closable: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormattedBandiData = (data) => {
|
||||||
|
data.dates = data.dates.map(v => is(String, v) ? new Date(v) : (v ? v : ''));
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const parsed = parseInt(id)
|
||||||
|
const bandoId = !isNaN(parsed) ? parsed : 0;
|
||||||
|
|
||||||
|
BandoService.getBando(bandoId, getCallback, errGetCallback);
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="appPage">
|
||||||
|
{!isAsyncRequest && !isEmpty(data)
|
||||||
|
? <div className="appPage__pageHeader">
|
||||||
|
<h1>{data.name}</h1>
|
||||||
|
<p>
|
||||||
|
{__('Data:', 'gepafin')}
|
||||||
|
<span>{getDateFromISOstring(data.createdDate)}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
: <>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
|
||||||
|
</>}
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
<Messages ref={bandoMsgs}/>
|
||||||
|
|
||||||
|
{!isAsyncRequest && !isEmpty(data)
|
||||||
|
? <div className="appPage__content">
|
||||||
|
{!isEmpty(data.images)
|
||||||
|
? <picture className="appPageSection__hero">
|
||||||
|
<source srcSet={data.images[0] ? data.images[0].filePath : ''}/>
|
||||||
|
<img src={data.images[0] ? data.images[0].filePath : ''} alt={data.name}/>
|
||||||
|
</picture> : null}
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Descrizione breve', 'gepafin')}</h2>
|
||||||
|
<div className="ql-editor">
|
||||||
|
{renderHtmlContent(data.descriptionShort)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__row">
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Importo totale', 'gepafin')}</span>
|
||||||
|
<span>{getNumberWithCurrency(data.amount)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Importo minimo per progetto', 'gepafin')}</span>
|
||||||
|
<span>{getNumberWithCurrency(data.amountMin)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Importo massimo per progetto', 'gepafin')}</span>
|
||||||
|
<span>{getNumberWithCurrency(data.amountMax)}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Data apertura', 'gepafin')}</span>
|
||||||
|
<span>{getDateFromISOstring(data.dates[0])} {data.startTime}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Data chiusura', 'gepafin')}</span>
|
||||||
|
<span>{getDateFromISOstring(data.dates[1])} {data.endTime}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Descrizione dettagliata', 'gepafin')}</h2>
|
||||||
|
<div className="ql-editor">
|
||||||
|
{renderHtmlContent(data.descriptionLong)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Requisiti di Partecipazione', 'gepafin')}</h2>
|
||||||
|
<div className="row rowContent">
|
||||||
|
<ul>
|
||||||
|
{data.aimedTo.map((o, i) => <li key={i}>
|
||||||
|
{o.value}
|
||||||
|
</li>)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Documentazione richiesta', 'gepafin')}</h2>
|
||||||
|
<div className="ql-editor">
|
||||||
|
{renderHtmlContent(data.documentationRequested)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/*<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Criteri di Valutazione', 'gepafin')}</h2>
|
||||||
|
<div className="row rowContent">
|
||||||
|
<ul>
|
||||||
|
{data.criteria.map((o, i) => <li key={i}>
|
||||||
|
{o.value} {o.score > 0 ? sprintf(__(' (%d punti)'), o.score) : null}
|
||||||
|
</li>)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>*/}
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Allegati', 'gepafin')}</h2>
|
||||||
|
<div className="row rowContent">
|
||||||
|
<ul>
|
||||||
|
{data.docs
|
||||||
|
.filter(o => o.source === 'CALL' && o.type === 'DOCUMENT')
|
||||||
|
.map((o, i) => <li key={i}>
|
||||||
|
<a href={o.filePath} target="_blank" rel="noreferrer">{o.name}</a>
|
||||||
|
</li>)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('FAQ', 'gepafin')}</h2>
|
||||||
|
<Accordion>
|
||||||
|
{data.faq
|
||||||
|
.filter(o => o.isVisible)
|
||||||
|
.map((o, i) => <AccordionTab key={i} header={renderHtmlContent(o.value)}>
|
||||||
|
<div className="ql-editor">
|
||||||
|
{renderHtmlContent(o.response)}
|
||||||
|
</div>
|
||||||
|
</AccordionTab>)}
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? null
|
||||||
|
: <div className="appPageSection">
|
||||||
|
<h2>{__('Non hai trovato la risposta che cercavi?', 'gepafin')}</h2>
|
||||||
|
<div className="appForm__field">
|
||||||
|
<label htmlFor="newQuestion">{__('Fai una domanda', 'gepafin')}</label>
|
||||||
|
<InputTextarea
|
||||||
|
id="newQuestion"
|
||||||
|
disabled
|
||||||
|
rows={7}
|
||||||
|
value={newQuestion}
|
||||||
|
placeholder={__('Digita qui la tua domanda', 'gepafin')}
|
||||||
|
onChange={(e) => setNewQuestion(e.target.value)}
|
||||||
|
aria-describedby="newQuestion-help"/>
|
||||||
|
<small id="newQuestion-help">
|
||||||
|
{__('Riceverai una notifica quando ti risponderemo', 'gepafin')}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Download Documenti', 'gepafin')}</h2>
|
||||||
|
<div className="appPageSection__actions">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
onClick={() => {
|
||||||
|
}}
|
||||||
|
label={__('Scarica Bando Completo', 'gepafin')}
|
||||||
|
icon="pi pi-download" iconPos="right"/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
onClick={() => {
|
||||||
|
}}
|
||||||
|
label={__('Scarica Modulistica', 'gepafin')}
|
||||||
|
icon="pi pi-download" iconPos="right"/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={true}
|
||||||
|
onClick={() => {
|
||||||
|
}}
|
||||||
|
label={__('Presenta Domanda', 'gepafin')}
|
||||||
|
icon="pi pi-save" iconPos="right"/>
|
||||||
|
{/*<Button
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
disabled={true}
|
||||||
|
onClick={() => {}}
|
||||||
|
label={__('Aggiungi a preferiti', 'gepafin')}
|
||||||
|
icon="pi pi-heart" iconPos="left"/>*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__withBorder">
|
||||||
|
<h2>{__('Contatti per Assistenza', 'gepafin')}</h2>
|
||||||
|
<div className="row rowContent">
|
||||||
|
<p>Email: {data.email}</p>
|
||||||
|
{!isNil(data.phoneNumber) ?
|
||||||
|
<p>{__('Telefono', 'gepafin')}: +39 {data.phoneNumber}</p> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: <>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="4rem" className="mb-8"></Skeleton>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="4rem"></Skeleton>
|
||||||
|
</>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BandoViewPreInstructor;
|
||||||
@@ -136,7 +136,7 @@ const DraftApplicationsTable = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -21,17 +21,43 @@ const LatestBandiTable = () => {
|
|||||||
const [filters, setFilters] = useState(null);
|
const [filters, setFilters] = useState(null);
|
||||||
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
const [, setStatuses] = useState([]);
|
const [, setStatuses] = useState([]);
|
||||||
|
/*const [totalRecordsNum, setTotalRecordsNum] = useState(0);
|
||||||
|
const [perPageNum, setPerPageNum] = useState(0);
|
||||||
|
const getPaginationQuery = () => {
|
||||||
|
return {
|
||||||
|
"globalFilters": {
|
||||||
|
"page": 1,
|
||||||
|
"limit": 5,
|
||||||
|
"sortBy": {
|
||||||
|
"columnName": "ID",
|
||||||
|
"sortDesc": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPageChange = (e) => {
|
||||||
|
console.log('onPageChange', e)
|
||||||
|
}*/
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocalAsyncRequest(true);
|
setLocalAsyncRequest(true);
|
||||||
BandoService.getBandi(getCallback, errGetCallbacks);
|
BandoService.getBandi(getCallback, errGetCallbacks);
|
||||||
|
//const paginationQuery = getPaginationQuery();
|
||||||
|
//BandoService.getBandiPaginated(paginationQuery, getCallback, errGetCallbacks);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getCallback = (data) => {
|
const getCallback = (data) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
|
/*const { body, totalRecords, currentPage, totalPages, pageSize } = data.data;
|
||||||
|
setTotalRecordsNum(totalRecords);
|
||||||
|
setPerPageNum(pageSize);
|
||||||
|
const newItems = body.filter(o => o.status === 'PUBLISH');
|
||||||
|
setItems(getFormattedBandiData(newItems));
|
||||||
|
setStatuses(uniq(body.map(o => o.status)));*/
|
||||||
const newItems = data.data.filter(o => o.status === 'PUBLISH');
|
const newItems = data.data.filter(o => o.status === 'PUBLISH');
|
||||||
setItems(getFormattedBandiData(newItems));
|
setItems(getFormattedBandiData(newItems));
|
||||||
setStatuses(uniq(data.data.map(o => o.status)))
|
setStatuses(uniq(data.data.map(o => o.status)));
|
||||||
initFilters();
|
initFilters();
|
||||||
}
|
}
|
||||||
setLocalAsyncRequest(false);
|
setLocalAsyncRequest(false);
|
||||||
@@ -106,7 +132,10 @@ const LatestBandiTable = () => {
|
|||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items}
|
||||||
|
paginator showGridlines
|
||||||
|
/*lazy totalRecords={totalRecordsNum} onPage={onPageChange}*/
|
||||||
|
rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ const LatestUsersActivityTable = () => {
|
|||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={loading} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={loading} dataKey="id"
|
||||||
filters={filters}
|
filters={filters}
|
||||||
globalFilterFields={['name', 'status']}
|
globalFilterFields={['name', 'status']}
|
||||||
header={header}
|
header={header}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ const Dashboard = () => {
|
|||||||
currency: 'EUR',
|
currency: 'EUR',
|
||||||
currencyDisplay: 'symbol'
|
currencyDisplay: 'symbol'
|
||||||
}}
|
}}
|
||||||
locales="en-US"/></span>
|
locales="it-IT"/></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ const LatestBandiTable = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={loading} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={loading} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ const MyLatestSubmissionsTable = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -0,0 +1,228 @@
|
|||||||
|
import React, { useState, useEffect} from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { is, uniq, isNil, head } from 'ramda';
|
||||||
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
// api
|
||||||
|
import AssignedApplicationService from '../../../../service/assigned-application-service';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import getBandoLabel from '../../../../helpers/getBandoLabel';
|
||||||
|
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { FilterMatchMode, FilterOperator } from 'primereact/api';
|
||||||
|
import { DataTable } from 'primereact/datatable';
|
||||||
|
import { Column } from 'primereact/column';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import { Calendar } from 'primereact/calendar';
|
||||||
|
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
||||||
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
|
import { Tag } from 'primereact/tag';
|
||||||
|
|
||||||
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
|
import { useStore } from '../../../../store';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
|
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
|
const InstructorManagerMieDomandeTable = ({ userId = null, statuses = [] }) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [items, setItems] = useState(null);
|
||||||
|
const [filters, setFilters] = useState(null);
|
||||||
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
|
const [statusesForFilter, setStatusesForFilter] = useState([]);
|
||||||
|
const userData = useStore().main.userData();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isNil(userId)) {
|
||||||
|
setLocalAsyncRequest(true);
|
||||||
|
|
||||||
|
if (userId === 0) {
|
||||||
|
AssignedApplicationService.getAssignedApplications(getCallback, errGetCallbacks, [
|
||||||
|
['statuses', statuses]
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
AssignedApplicationService.getAssignedApplications(getCallback, errGetCallbacks, [
|
||||||
|
['userId', userId],
|
||||||
|
['statuses', statuses]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [userId]);
|
||||||
|
|
||||||
|
const getCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setItems(getFormattedData(data.data));
|
||||||
|
setStatusesForFilter(uniq(data.data.map(o => o.status)))
|
||||||
|
initFilters();
|
||||||
|
}
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetCallbacks = (data) => {
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormattedData = (data) => {
|
||||||
|
return data.map((d) => {
|
||||||
|
d.evaluationEndDate = is(String, d.evaluationEndDate) ? new Date(d.evaluationEndDate) : (d.evaluationEndDate ? d.evaluationEndDate : '');
|
||||||
|
d.submissionDate = is(String, d.submissionDate) ? new Date(d.submissionDate) : (d.submissionDate ? d.submissionDate : '');
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (value) => {
|
||||||
|
return value.toLocaleDateString('it-IT', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
initFilters();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initFilters = () => {
|
||||||
|
setFilters({
|
||||||
|
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
|
||||||
|
callName: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||||
|
},
|
||||||
|
companyName: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||||
|
},
|
||||||
|
submissionDate: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
||||||
|
},
|
||||||
|
evaluationEndDate: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
return (
|
||||||
|
<div className="appTableHeader">
|
||||||
|
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateAppliedBodyTemplate = (rowData) => {
|
||||||
|
return formatDate(rowData.submissionDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateEndBodyTemplate = (rowData) => {
|
||||||
|
return formatDate(rowData.evaluationEndDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateFilterTemplate = (options) => {
|
||||||
|
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusBodyTemplate = (rowData) => {
|
||||||
|
return <ProperBandoLabel status={rowData.status}/>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusFilterTemplate = (options) => {
|
||||||
|
return <Dropdown value={options.value} options={statusesForFilter} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter" showClear />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusItemTemplate = (option) => {
|
||||||
|
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInitiateEvaluation = (id) => {
|
||||||
|
setLocalAsyncRequest(true);
|
||||||
|
AssignedApplicationService.updateStatusAssignedApplication(id, getInitEvalCallback, errInitEvalCallbacks, [
|
||||||
|
['status', 'OPEN']
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInitEvalCallback = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
const evaluation = klona(head(getFormattedData([resp.data])));
|
||||||
|
const newItems = items.map(o => o.id === evaluation.id ? evaluation : o);
|
||||||
|
setItems(newItems);
|
||||||
|
navigate(`/mie-domande/${evaluation.applicationId}`);
|
||||||
|
}
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errInitEvalCallbacks = (resp) => {
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionsBodyTemplate = (rowData) => {
|
||||||
|
if (rowData.status === 'AWAITING') {
|
||||||
|
return <Button
|
||||||
|
severity="info"
|
||||||
|
onClick={() => handleInitiateEvaluation(rowData.id)}
|
||||||
|
label={__('Valuta', 'gepafin')}
|
||||||
|
icon="pi pi-eye"
|
||||||
|
size="small"
|
||||||
|
iconPos="right"/>
|
||||||
|
} else {
|
||||||
|
const label = ['OPEN', 'SOCCORSO'].includes(rowData.status) && userData.id === rowData.userId
|
||||||
|
? __('Valuta', 'gepafin')
|
||||||
|
: __('Mostra', 'gepafin');
|
||||||
|
return <Link to={`/mie-domande/${rowData.applicationId}`}>
|
||||||
|
<Button severity="info" label={label} icon="pi pi-eye" size="small" iconPos="right"/>
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = renderHeader();
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="appPageSection__table">
|
||||||
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
|
filters={filters} stripedRows removableSort
|
||||||
|
header={header}
|
||||||
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
onFilter={(e) => setFilters(e.filters)}>
|
||||||
|
<Column field="applicationId" header={__('ID domanda', 'gepafin')}
|
||||||
|
sortable filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '6rem' }}/>
|
||||||
|
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
|
||||||
|
sortable filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '6rem' }}/>
|
||||||
|
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <Column field="ndg" header={__('NDG', 'gepafin')}
|
||||||
|
sortable filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '6rem' }}/> : null}
|
||||||
|
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <Column field="appointmentId" header={__('ID appuntamento', 'gepafin')}
|
||||||
|
sortable filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '6rem' }}/> : null}
|
||||||
|
<Column field="callName" header={__('Bando', 'gepafin')}
|
||||||
|
filter sortable
|
||||||
|
filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column field="companyName" header={__('Azienda', 'gepafin')}
|
||||||
|
filter sortable
|
||||||
|
filterPlaceholder={__('Cerca il nome', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column header={__('Data ricezione', 'gepafin')} filterField="submissionDate" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||||
|
<Column header={__('Scadenza', 'gepafin')} filterField="evaluationEndDate" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||||
|
<Column field="status" header={__('Stato', 'gepafin')}
|
||||||
|
style={{ minWidth: '7rem' }} body={statusBodyTemplate} filter
|
||||||
|
filterElement={statusFilterTemplate} />
|
||||||
|
<Column header={__('Azioni', 'gepafin')}
|
||||||
|
body={actionsBodyTemplate}/>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InstructorManagerMieDomandeTable;
|
||||||
119
src/pages/DashboardInstructorManager/index.js
Normal file
119
src/pages/DashboardInstructorManager/index.js
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import NumberFlow from '@number-flow/react';
|
||||||
|
import { pathOr } from 'ramda';
|
||||||
|
|
||||||
|
// service
|
||||||
|
import DashboardService from '../../service/dashboard-service';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import PreInstructorDomandeTable from '../DashboardPreInstructor/components/PreInstructorDomandeTable';
|
||||||
|
|
||||||
|
const DashboardInstructorManager = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [mainStats, setMainStats] = useState({});
|
||||||
|
|
||||||
|
const goToAllEvaluations = () => {
|
||||||
|
navigate('/domande');
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStats = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setMainStats(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetStats = () => {}
|
||||||
|
|
||||||
|
const getStatValue = (key, fallback = '') => {
|
||||||
|
return pathOr(fallback, [key], mainStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
DashboardService.getEvaluationsStats(getStats, errGetStats);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Dashboard', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection statsBigBadges">
|
||||||
|
<h2>{__('Riepilogo', 'gepafin')}</h2>
|
||||||
|
<div className="statsBigBadges__grid applStats">
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Totale domande', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfAssignedApplication', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('In soccorso', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationInAmendmentState', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('In valutazione', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationInOpenState', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Completate', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationInCloseState', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Tempo medio di valutazione', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('averageEvaluationDays', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
suffix={` ${__('giorni', 'gepafin')}`}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Domande in scadenza (48h)', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationExpiringIn48Hours', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="en-US"/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Panoramica delle domande da valutare', 'gepafin')}</h2>
|
||||||
|
<PreInstructorDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={0}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection__hr">
|
||||||
|
<span>{__('Azioni rapide', 'gepafin')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<div className="appPageSection__actions">
|
||||||
|
<Button
|
||||||
|
onClick={goToAllEvaluations}
|
||||||
|
label={__('Tutte le domande', 'gepafin')} icon="pi pi-arrow-right" iconPos="right"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DashboardInstructorManager;
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
import React, { useState, useEffect} from 'react';
|
import React, { useState, useEffect} from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { is, uniq } from 'ramda';
|
import { is, uniq, isNil, head } from 'ramda';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
// store
|
|
||||||
import { useStore } from '../../../../store';
|
|
||||||
|
|
||||||
// api
|
// api
|
||||||
import AssignedApplicationService from '../../../../service/assigned-application-service';
|
import AssignedApplicationService from '../../../../service/assigned-application-service';
|
||||||
@@ -24,27 +21,40 @@ import { Dropdown } from 'primereact/dropdown';
|
|||||||
import { Tag } from 'primereact/tag';
|
import { Tag } from 'primereact/tag';
|
||||||
|
|
||||||
import translationStrings from '../../../../translationStringsForComponents';
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
|
import { useStore } from '../../../../store';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
|
||||||
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
const PreInstructorDomandeTable = () => {
|
const PreInstructorDomandeTable = ({ userId = null, statuses = [] }) => {
|
||||||
const userData = useStore().main.userData();
|
const navigate = useNavigate();
|
||||||
const [items, setItems] = useState(null);
|
const [items, setItems] = useState(null);
|
||||||
const [filters, setFilters] = useState(null);
|
const [filters, setFilters] = useState(null);
|
||||||
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
const [statuses, setStatuses] = useState([]);
|
const [statusesForFilter, setStatusesForFilter] = useState([]);
|
||||||
|
const userData = useStore().main.userData();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!isNil(userId)) {
|
||||||
setLocalAsyncRequest(true);
|
setLocalAsyncRequest(true);
|
||||||
|
|
||||||
|
if (userId === 0) {
|
||||||
AssignedApplicationService.getAssignedApplications(getCallback, errGetCallbacks, [
|
AssignedApplicationService.getAssignedApplications(getCallback, errGetCallbacks, [
|
||||||
['userId', userData.id]
|
['statuses', statuses]
|
||||||
]);
|
]);
|
||||||
}, []);
|
} else {
|
||||||
|
AssignedApplicationService.getAssignedApplications(getCallback, errGetCallbacks, [
|
||||||
|
['userId', userId],
|
||||||
|
['statuses', statuses]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [userId]);
|
||||||
|
|
||||||
const getCallback = (data) => {
|
const getCallback = (data) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
setItems(getFormattedData(data.data));
|
setItems(getFormattedData(data.data));
|
||||||
setStatuses(uniq(data.data.map(o => o.status)))
|
setStatusesForFilter(uniq(data.data.map(o => o.status)))
|
||||||
initFilters();
|
initFilters();
|
||||||
}
|
}
|
||||||
setLocalAsyncRequest(false);
|
setLocalAsyncRequest(false);
|
||||||
@@ -121,24 +131,58 @@ const PreInstructorDomandeTable = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const statusFilterTemplate = (options) => {
|
const statusFilterTemplate = (options) => {
|
||||||
return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter" showClear />;
|
return <Dropdown value={options.value} options={statusesForFilter} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter" showClear />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusItemTemplate = (option) => {
|
const statusItemTemplate = (option) => {
|
||||||
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
|
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleInitiateEvaluation = (id) => {
|
||||||
|
setLocalAsyncRequest(true);
|
||||||
|
AssignedApplicationService.updateStatusAssignedApplication(id, getInitEvalCallback, errInitEvalCallbacks, [
|
||||||
|
['status', 'OPEN']
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInitEvalCallback = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
const evaluation = klona(head(getFormattedData([resp.data])));
|
||||||
|
const newItems = items.map(o => o.id === evaluation.id ? evaluation : o);
|
||||||
|
setItems(newItems);
|
||||||
|
navigate(`/domande/${evaluation.applicationId}`);
|
||||||
|
}
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errInitEvalCallbacks = (resp) => {
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
const actionsBodyTemplate = (rowData) => {
|
const actionsBodyTemplate = (rowData) => {
|
||||||
|
if (rowData.status === 'AWAITING') {
|
||||||
|
return <Button
|
||||||
|
severity="info"
|
||||||
|
onClick={() => handleInitiateEvaluation(rowData.id)}
|
||||||
|
label={__('Valuta', 'gepafin')}
|
||||||
|
icon="pi pi-eye"
|
||||||
|
size="small"
|
||||||
|
iconPos="right"/>
|
||||||
|
} else {
|
||||||
|
const label = ['OPEN', 'SOCCORSO'].includes(rowData.status) && userData.id === rowData.userId
|
||||||
|
? __('Valuta', 'gepafin')
|
||||||
|
: __('Mostra', 'gepafin');
|
||||||
return <Link to={`/domande/${rowData.applicationId}`}>
|
return <Link to={`/domande/${rowData.applicationId}`}>
|
||||||
<Button severity="info" label={__('Valuta', 'gepafin')} icon="pi pi-eye" size="small" iconPos="right"/>
|
<Button severity="info" label={label} icon="pi pi-eye" size="small" iconPos="right"/>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const header = renderHeader();
|
const header = renderHeader();
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -1,58 +1,116 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import NumberFlow from '@number-flow/react';
|
||||||
|
import { pathOr } from 'ramda';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
//import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
|
|
||||||
// api
|
// service
|
||||||
//import DashboardService from '../../service/dashboard-service';
|
import DashboardService from '../../service/dashboard-service';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
//import LatestBandiTable from './components/LatestBandiTable';
|
|
||||||
//import MyLatestSubmissionsTable from './components/MyLatestSubmissionsTable';
|
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
import PreInstructorDomandeTable from './components/PreInstructorDomandeTable';
|
import PreInstructorDomandeTable from './components/PreInstructorDomandeTable';
|
||||||
|
|
||||||
const DashboardPreInstructor = () => {
|
const DashboardPreInstructor = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
//const [mainStats, setMainStats] = useState({});
|
const [mainStats, setMainStats] = useState({});
|
||||||
|
const userData = useStore().main.userData();
|
||||||
|
|
||||||
const goToAllEvaluations = () => {
|
const goToAllEvaluations = () => {
|
||||||
navigate('/domande');
|
navigate('/domande');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getStats = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setMainStats(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetStats = () => {}
|
||||||
|
|
||||||
|
const getStatValue = (keys = [], fallback = '') => {
|
||||||
|
return pathOr(fallback, keys, mainStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
DashboardService.getInstructorAmendmentsStats(getStats, errGetStats, [
|
||||||
|
['userId', userData.id]
|
||||||
|
]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPage">
|
<div className="appPage">
|
||||||
<div className="appPage__pageHeader">
|
<div className="appPage__pageHeader">
|
||||||
<h1>{__('Dashboard', 'gepafin')}</h1>
|
<h1>{__('Dashboard', 'gepafin')}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/*<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
<div className="appPageSection statsBigBadges">
|
<div className="appPageSection statsBigBadges">
|
||||||
<h2>{__('Panoramica di Sistema', 'gepafin')}</h2>
|
<h2>{__('Riepilogo', 'gepafin')}</h2>
|
||||||
<div className="statsBigBadges__grid">
|
<div className="statsBigBadges__grid doubleStatsItems">
|
||||||
<div className="statsBigBadges__gridItem">
|
<div className="statsBigBadges__gridItemDoubleStats">
|
||||||
<span>{__('Domande attive', 'gepafin')}</span>
|
<span>{__('Domande da valutare', 'gepafin')}</span>
|
||||||
<span>{getStatValue('numberOfApplications', 0)}</span>
|
<span className="number"><NumberFlow
|
||||||
</div>
|
value={getStatValue(['assignedApplication', 'totalAssignedApplication'], 0)}
|
||||||
<div className="statsBigBadges__gridItem">
|
format={{ notation: 'compact' }}
|
||||||
<span>{__('Bandi osservati', 'gepafin')}</span>
|
locales="it-IT"/></span>
|
||||||
<span>{getStatValue('numberOfCalls', 0)}</span>
|
{/*<div className="auxStats">
|
||||||
</div>
|
<span>
|
||||||
<div className="statsBigBadges__gridItem">
|
<span
|
||||||
<span>{__('Documenti da integrare', 'gepafin')}</span>
|
className="badge">{getStatValue(['assignedApplication', 'additionalApplicationPercentage'], 0)}%</span>
|
||||||
<span>{getStatValue('numberOfIntegratedDocuments', 0)}</span>
|
{__('da ieri', 'gepafin')}</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>*/}
|
</div>*/}
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStats">
|
||||||
|
<span>{__('Domande valutate', 'gepafin')}</span>
|
||||||
|
<span className="number"><NumberFlow
|
||||||
|
value={getStatValue(['evaluatedApplication', 'evaluatedApplication'], 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
{/*<div className="auxStats">
|
||||||
|
<span>
|
||||||
|
<span
|
||||||
|
className="badge">{getStatValue(['evaluatedApplication', 'dailyAverage'], 0)}</span>
|
||||||
|
{__('media giornaliera', 'gepafin')}</span>
|
||||||
|
</div>*/}
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStats">
|
||||||
|
<span>{__('Tempo medio valutazione', 'gepafin')}</span>
|
||||||
|
<span className="number"><NumberFlow
|
||||||
|
value={getStatValue(['averageEvaluationDays', 'averageEvlauationDaysRating'], 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
suffix={` ${__('giorni', 'gepafin')}`}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
{/*<div className="auxStats">
|
||||||
|
<span>
|
||||||
|
<span className="badge">{getStatValue(['averageEvaluationDays', 'timeDifferenceFromAverage'], 0)}</span>
|
||||||
|
{__('rispetto alla media', 'gepafin')}</span>
|
||||||
|
</div>*/}
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStats">
|
||||||
|
<span>{__('Soccorsi istruttori in corso', 'gepafin')}</span>
|
||||||
|
<span className="number"><NumberFlow
|
||||||
|
value={getStatValue(['amendmentInProgress', 'totalAmendmentInProgress'], 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
{/*<div className="auxStats">
|
||||||
|
<span>
|
||||||
|
<span className="badge">{getStatValue(['amendmentInProgress', 'expiringToday'], 0)}</span>
|
||||||
|
{__('in scadenza oggi', 'gepafin')}</span>
|
||||||
|
</div>*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Coda di lavoro', 'gepafin')}</h2>
|
<h2>{__('Coda di lavoro', 'gepafin')}</h2>
|
||||||
<PreInstructorDomandeTable/>
|
<PreInstructorDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|||||||
@@ -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 { __, sprintf } from '@wordpress/i18n';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
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 { klona } from 'klona';
|
||||||
import { wrap } from 'object-path-immutable';
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeGet, storeSet, useStore } from '../../store';
|
import { storeGet, storeSet, useStore } from '../../store';
|
||||||
@@ -15,8 +18,21 @@ import AppointmentService from '../../service/appointment-service';
|
|||||||
|
|
||||||
// tools
|
// tools
|
||||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
import getBandoLabel from '../../helpers/getBandoLabel';
|
import {
|
||||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
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
|
// components
|
||||||
import { Skeleton } from 'primereact/skeleton';
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
@@ -31,17 +47,16 @@ import HelpIcon from '../../icons/HelpIcon';
|
|||||||
import { classNames } from 'primereact/utils';
|
import { classNames } from 'primereact/utils';
|
||||||
import { InputTextarea } from 'primereact/inputtextarea';
|
import { InputTextarea } from 'primereact/inputtextarea';
|
||||||
import { InputText } from 'primereact/inputtext';
|
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 ListOfFiles from '../DomandaEditPreInstructor/components/ListOfFiles';
|
||||||
import RepeaterFields from '../DomandaEditPreInstructor/components/RepeaterFields';
|
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_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
|
||||||
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
|
|
||||||
const DomandaEditPreInstructor = () => {
|
const DomandaEditInstructorManager = () => {
|
||||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -66,12 +81,46 @@ const DomandaEditPreInstructor = () => {
|
|||||||
duration: 0,
|
duration: 0,
|
||||||
amount: 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 = () => {
|
const goToEvaluationsPage = () => {
|
||||||
navigate('/domande');
|
navigate('/mie-domande');
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFlagsForSoccorso = (data) => {
|
const updateFlagsForSoccorso = useCallback((data) => {
|
||||||
let nonRatedFilesLength = 0;
|
let nonRatedFilesLength = 0;
|
||||||
|
|
||||||
if (data.files) {
|
if (data.files) {
|
||||||
@@ -90,6 +139,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
setAllFilesRated(nonRatedFilesLength === 0);
|
setAllFilesRated(nonRatedFilesLength === 0);
|
||||||
|
|
||||||
|
if (data.evaluationVersion === 'V1') {
|
||||||
if (data.checklist) {
|
if (data.checklist) {
|
||||||
const checkedChecklistItems = data.checklist
|
const checkedChecklistItems = data.checklist
|
||||||
.map(el => el.valid)
|
.map(el => el.valid)
|
||||||
@@ -97,34 +147,98 @@ const DomandaEditPreInstructor = () => {
|
|||||||
setAtLeastOneChecked(checkedChecklistItems.length > 0);
|
setAtLeastOneChecked(checkedChecklistItems.length > 0);
|
||||||
setAllChecksChecked(checkedChecklistItems.length === data.checklist.length)
|
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 = () => {
|
const doNewSoccorso = () => {
|
||||||
if (connectedSoccorsoId !== 0) {
|
if (connectedSoccorsoId !== 0) {
|
||||||
navigate(`/domande/${id}/soccorso/${connectedSoccorsoId}`);
|
navigate(`/mie-domande/${id}/soccorso/${connectedSoccorsoId}`);
|
||||||
} else {
|
} else {
|
||||||
doSaveDraft(`/domande/${id}/aggiungi-soccorso/`)
|
doSaveDraft(`/mie-domande/${id}/aggiungi-soccorso/`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCallback = (data) => {
|
const getVersion = (resp) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (resp.status === 'SUCCESS') {
|
||||||
setData(getFormattedData(data.data));
|
if (resp.data.evaluationVersion === 'V1') {
|
||||||
setMotivation(data.data.motivation);
|
storeSet.main.setAsyncRequest();
|
||||||
updateFlagsForSoccorso(data.data);
|
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();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
const errGetCallback = (data) => {
|
const errGetVersion = (resp) => {
|
||||||
if (toast.current && data.message) {
|
if (toast.current && data.message) {
|
||||||
toast.current.show({
|
toast.current.show({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
summary: '',
|
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();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,8 +280,34 @@ const DomandaEditPreInstructor = () => {
|
|||||||
updateFlagsForSoccorso(newData);
|
updateFlagsForSoccorso(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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 = '') => {
|
const doSaveDraft = useCallback((doRedirect = '') => {
|
||||||
const formData = {
|
if (data.evaluationVersion === 'V1') {
|
||||||
|
const submitData = {
|
||||||
criteria: klona(data.criteria),
|
criteria: klona(data.criteria),
|
||||||
checklist: klona(data.checklist),
|
checklist: klona(data.checklist),
|
||||||
files: klona(data.files),
|
files: klona(data.files),
|
||||||
@@ -178,14 +318,36 @@ const DomandaEditPreInstructor = () => {
|
|||||||
)),
|
)),
|
||||||
amendmentDetails: klona(data.amendmentDetails),
|
amendmentDetails: klona(data.amendmentDetails),
|
||||||
note: data.note
|
note: data.note
|
||||||
}
|
};
|
||||||
|
|
||||||
ApplicationEvaluationService.updateEvaluation(
|
ApplicationEvaluationService.updateEvaluation(
|
||||||
data.assignedApplicationId,
|
data.assignedApplicationId,
|
||||||
formData,
|
submitData,
|
||||||
(data) => updateCallback(data, doRedirect),
|
(data) => updateCallback(data, doRedirect),
|
||||||
errUpdateCallback
|
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]);
|
}, [data]);
|
||||||
|
|
||||||
const updateCallback = (data, doRedirect = '') => {
|
const updateCallback = (data, doRedirect = '') => {
|
||||||
@@ -218,7 +380,8 @@ const DomandaEditPreInstructor = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const doApprove = () => {
|
const doApprove = () => {
|
||||||
const formData = {
|
if (data.evaluationVersion === 'V1') {
|
||||||
|
const submitData = {
|
||||||
applicationStatus: 'APPROVED',
|
applicationStatus: 'APPROVED',
|
||||||
criteria: klona(data.criteria),
|
criteria: klona(data.criteria),
|
||||||
checklist: klona(data.checklist),
|
checklist: klona(data.checklist),
|
||||||
@@ -229,11 +392,42 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setIsVisibleCompleteDialog(false);
|
setIsVisibleCompleteDialog(false);
|
||||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
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 doReject = () => {
|
||||||
const formData = {
|
if (data.evaluationVersion === 'V1') {
|
||||||
|
const submitData = {
|
||||||
applicationStatus: 'REJECTED',
|
applicationStatus: 'REJECTED',
|
||||||
criteria: klona(data.criteria),
|
criteria: klona(data.criteria),
|
||||||
checklist: klona(data.checklist),
|
checklist: klona(data.checklist),
|
||||||
@@ -244,7 +438,37 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setIsVisibleCompleteDialog(false);
|
setIsVisibleCompleteDialog(false);
|
||||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
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) => {
|
const updateStatusCallback = (data) => {
|
||||||
@@ -431,7 +655,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
setIsVisibleAppointmentDialog(true);
|
setIsVisibleAppointmentDialog(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const setValue = (name, value) => {
|
const setFieldValue = (name, value) => {
|
||||||
const newData = wrap(appointmentData).set(name, value).value();
|
const newData = wrap(appointmentData).set(name, value).value();
|
||||||
setAppointmentData(newData);
|
setAppointmentData(newData);
|
||||||
}
|
}
|
||||||
@@ -505,11 +729,153 @@ const DomandaEditPreInstructor = () => {
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
const evaluationShouldBeBlocked = (data = {}) => {
|
const evaluationBlockedForUser = (data = {}) => {
|
||||||
const userData = storeGet.main.userData()
|
const userData = storeGet.main.userData();
|
||||||
return isAsyncRequest || userData.id !== data.assignedUserId;
|
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 <div className="appPageSection__actions">
|
||||||
|
{['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus)
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || data.status === 'CLOSE'
|
||||||
|
|| (data.applicationStatus === 'EVALUATION' && shouldDisableNewSoccorso())
|
||||||
|
|| evaluationBlockedForUser(data)}
|
||||||
|
onClick={doNewSoccorso}
|
||||||
|
outlined
|
||||||
|
label={<>
|
||||||
|
{data.applicationStatus === 'EVALUATION'
|
||||||
|
? __('Richiedi soccorso istruttorio', 'gepafin')
|
||||||
|
: __('Apri soccorso istruttorio', 'gepafin')}
|
||||||
|
<i style={{ marginLeft: 7 }}>
|
||||||
|
<HelpIcon/>
|
||||||
|
</i>
|
||||||
|
</>}
|
||||||
|
/> : null}
|
||||||
|
{data.id
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={data.status === 'CLOSE' || evaluationBlockedForUser(data)}
|
||||||
|
onClick={() => doSaveDraft()}
|
||||||
|
outlined
|
||||||
|
label={__('Salva bozza valutazione', 'gepafin')}
|
||||||
|
icon="pi pi-save" iconPos="right"/>
|
||||||
|
: <Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => doSaveDraft()}
|
||||||
|
label={__('Crea valutazione', 'gepafin')}
|
||||||
|
icon="pi pi-save" iconPos="right"/>}
|
||||||
|
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
|
||||||
|
&& APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || !allFilesRated || !allChecksChecked
|
||||||
|
|| !['EVALUATION'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
|
||||||
|
onClick={doCheckNDG}
|
||||||
|
label={__('Controlla NDG', 'gepafin')}
|
||||||
|
/> : null}
|
||||||
|
{APP_EVALUATION_FLOW_ID === '1' && APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || !['NDG'].includes(data.applicationStatus) || !data.ndg || evaluationBlockedForUser(data)}
|
||||||
|
onClick={doCreateAppointment}
|
||||||
|
label={__('Crea l\'appuntamento', 'gepafin')}
|
||||||
|
/> : null}
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || !['APPOINTMENT'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
|
||||||
|
onClick={doMakeAdmisible}
|
||||||
|
label={__('Ammissibile formalmente', 'gepafin')}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={true}
|
||||||
|
onClick={() => {
|
||||||
|
}}
|
||||||
|
label={__('Valutazione tecnico-finanziaria positiva', 'gepafin')}
|
||||||
|
/>
|
||||||
|
{data.id
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!isAdmissible
|
||||||
|
|| ['APPROVED'].includes(data.applicationStatus)
|
||||||
|
|| evaluationBlockedForUser(data)
|
||||||
|
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE'].includes(data.applicationStatus))
|
||||||
|
}
|
||||||
|
onClick={initiateApproving}
|
||||||
|
label={__('Domanda deliberata', 'gepafin')}
|
||||||
|
icon="pi pi-check" iconPos="right"/> : null}
|
||||||
|
{data.id
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={APP_EVALUATION_FLOW_ID === '1'
|
||||||
|
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)
|
||||||
|
|| evaluationBlockedForUser(data))}
|
||||||
|
onClick={initiateRejecting}
|
||||||
|
label={__('Respingi domanda', 'gepafin')}
|
||||||
|
icon="pi pi-times" iconPos="right"/> : null}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
const maxScore = pathOr(0, ['minScore'], data);
|
const maxScore = pathOr(0, ['minScore'], data);
|
||||||
const criteria = pathOr([], ['criteria'], data);
|
const criteria = pathOr([], ['criteria'], data);
|
||||||
@@ -523,9 +889,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
const entityId = !isNaN(parsed) ? parsed : 0;
|
const entityId = !isNaN(parsed) ? parsed : 0;
|
||||||
|
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [
|
ApplicationEvaluationService.getEvaluationVersionByApplId(entityId, getVersion, errGetVersion);
|
||||||
['applicationId', entityId]
|
|
||||||
]);
|
|
||||||
AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [
|
AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [
|
||||||
['statuses', 'AWAITING']
|
['statuses', 'AWAITING']
|
||||||
]);
|
]);
|
||||||
@@ -553,64 +917,18 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
{!isAsyncRequest && !isEmpty(data)
|
{!isAsyncRequest && !isEmpty(data)
|
||||||
? <div className="appPage__content">
|
? <div className="appPage__content">
|
||||||
<div className="appPageSection__withBorder columns">
|
<ApplicationInfo data={data}/>
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('ID domanda', 'gepafin')}</span>
|
<div className="appPageSection__hr">
|
||||||
<span>{data.applicationId}</span>
|
<span>{__('Azioni rapide', 'gepafin')}</span>
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Protocollo', 'gepafin')}</span>
|
|
||||||
<span>{data.protocolNumber}</span>
|
|
||||||
</p>
|
|
||||||
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <p className="appPageSection__pMeta">
|
|
||||||
<span>{__('NDG', 'gepafin')}</span>
|
|
||||||
<span>{data.ndg}</span>
|
|
||||||
</p> : null}
|
|
||||||
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Appuntamento', 'gepafin')}</span>
|
|
||||||
<span>{data.appointmentId}</span>
|
|
||||||
</p> : null}
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Bando', 'gepafin')}</span>
|
|
||||||
<span>{data.callName}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
|
||||||
<span>{data.beneficiary}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
|
|
||||||
<span>{data.companyName}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Data ricezione', 'gepafin')}</span>
|
|
||||||
<span>{getDateTimeFromISOstring(data.submissionDate)}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Data assegnazione', 'gepafin')}</span>
|
|
||||||
<span>{getDateTimeFromISOstring(data.assignedAt)}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Scadenza Valutazione', 'gepafin')}</span>
|
|
||||||
<span>{getDateFromISOstring(data.evaluationEndDate)}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Stato', 'gepafin')}</span>
|
|
||||||
<span>{getBandoLabel(data.applicationStatus)}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Scarica documenti della domanda', 'gepafin')}</h2>
|
{actionBtns()}
|
||||||
<div className="appPageSection__row autoFlow">
|
|
||||||
<DownloadApplicationArchive applicationId={id}/>
|
|
||||||
<DownloadSignedApplication applicationId={id}/>
|
|
||||||
<DownloadCompanyDelegation applicationId={id}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ApplicationDownloadFiles id={id}/>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
||||||
<RepeaterFields
|
<RepeaterFields
|
||||||
@@ -619,12 +937,104 @@ const DomandaEditPreInstructor = () => {
|
|||||||
data,
|
data,
|
||||||
['evaluationDocument']
|
['evaluationDocument']
|
||||||
)}
|
)}
|
||||||
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
|
||||||
sourceId={data.assignedApplicationId}
|
sourceId={data.assignedApplicationId}
|
||||||
sourceName="evaluation"/>
|
sourceName="evaluation"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
{data.evaluationVersion === 'V2'
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Documenti allegati', 'gepafin')}</h2>
|
||||||
|
{!isEmpty(data.files)
|
||||||
|
? <ListOfFiles
|
||||||
|
files={data.files}
|
||||||
|
updateFn={updateEvaluationValue}
|
||||||
|
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(data)}
|
||||||
|
name="files"
|
||||||
|
ndg={data.ndg}
|
||||||
|
applicationId={id}/>
|
||||||
|
: <p>{__('Nessun documento allegato', 'gepafin')}</p>}
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{data.evaluationVersion === 'V2'
|
||||||
|
? <form className="appForm" onSubmit={handleSubmit(() => {
|
||||||
|
})}>
|
||||||
|
{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
|
||||||
|
? <div key={o.id}>
|
||||||
|
<div className="ql-editor">
|
||||||
|
{renderHtmlContent(text.value)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: <FormField
|
||||||
|
key={o.id}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
|
type={o.name}
|
||||||
|
fieldName={o.id}
|
||||||
|
label={label ? label.value : ''}
|
||||||
|
placeholder={placeholder ? placeholder.value : ''}
|
||||||
|
control={control}
|
||||||
|
register={register}
|
||||||
|
errors={errors}
|
||||||
|
defaultValue={values[o.id] ? values[o.id] : ''}
|
||||||
|
maxFractionDigits={step ? step.value : 0}
|
||||||
|
accept={mimeValue}
|
||||||
|
config={validations}
|
||||||
|
options={options ? options.value : []}
|
||||||
|
setDataFn={setValue}
|
||||||
|
saveFormCallback={doSaveDraft}
|
||||||
|
sourceId={id}
|
||||||
|
useGrouping={false}
|
||||||
|
tableColumns={tableColumns ? tableColumns.value : {}}
|
||||||
|
/>
|
||||||
|
})}
|
||||||
|
</form>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{data.evaluationVersion === 'V1'
|
||||||
|
? <div className="appPageSection">
|
||||||
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
|
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
|
||||||
<div className="appPageSection columns">
|
<div className="appPageSection columns">
|
||||||
<div>
|
<div>
|
||||||
@@ -633,7 +1043,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<div className="appPageSection__checklist">
|
<div className="appPageSection__checklist">
|
||||||
{data.checklist.map((o, i) => <div key={o.id}>
|
{data.checklist.map((o, i) => <div key={o.id}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
disabled={shouldDisableField('checklist') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('checklist') || evaluationBlockedForUser(data)}
|
||||||
inputId={`checklist_${o.id}`}
|
inputId={`checklist_${o.id}`}
|
||||||
onChange={(e) => updateEvaluationValue(
|
onChange={(e) => updateEvaluationValue(
|
||||||
e.checked,
|
e.checked,
|
||||||
@@ -649,7 +1059,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Editor
|
<Editor
|
||||||
value={data.note}
|
value={data.note}
|
||||||
readOnly={shouldDisableField('note') || evaluationShouldBeBlocked(data)}
|
readOnly={shouldDisableField('note') || evaluationBlockedForUser(data)}
|
||||||
placeholder={__('Digita qui il messagio', 'gepafin')}
|
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||||
headerTemplate={header}
|
headerTemplate={header}
|
||||||
onTextChange={(e) => updateEvaluationValue(
|
onTextChange={(e) => updateEvaluationValue(
|
||||||
@@ -662,16 +1072,19 @@ const DomandaEditPreInstructor = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3>{__('Documenti allegati', 'gepafin')}</h3>
|
<h3>{__('Documenti allegati', 'gepafin')}</h3>
|
||||||
<ListOfFiles
|
{!isEmpty(data.files)
|
||||||
|
? <ListOfFiles
|
||||||
files={data.files}
|
files={data.files}
|
||||||
updateFn={updateEvaluationValue}
|
updateFn={updateEvaluationValue}
|
||||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(data)}
|
||||||
name="files"
|
name="files"
|
||||||
ndg={data.ndg}
|
ndg={data.ndg}
|
||||||
applicationId={id}/>
|
applicationId={id}/>
|
||||||
|
: <p>{__('Nessun documento allegato', 'gepafin')}</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
{!isEmpty(data.amendmentDetails)
|
{!isEmpty(data.amendmentDetails)
|
||||||
? <div className="appPageSection">
|
? <div className="appPageSection">
|
||||||
@@ -679,13 +1092,14 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<ListOfFiles
|
<ListOfFiles
|
||||||
files={data.amendmentDetails}
|
files={data.amendmentDetails}
|
||||||
updateFn={updateEvaluationValue}
|
updateFn={updateEvaluationValue}
|
||||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(data)}
|
||||||
name="amendmentDetails"
|
name="amendmentDetails"
|
||||||
ndg={data.ndg}
|
ndg={data.ndg}
|
||||||
applicationId={id}/>
|
applicationId={id}/>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|
||||||
<div className="appPageSection">
|
{data.evaluationVersion === 'V1'
|
||||||
|
? <div className="appPageSection">
|
||||||
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
|
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
|
||||||
{data.criteria
|
{data.criteria
|
||||||
? <table className="myTable">
|
? <table className="myTable">
|
||||||
@@ -702,7 +1116,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<td>
|
<td>
|
||||||
<div className="p-inputgroup">
|
<div className="p-inputgroup">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('criteria') || evaluationBlockedForUser(data)}
|
||||||
placeholder={__('Punteggio', 'gepafin')}
|
placeholder={__('Punteggio', 'gepafin')}
|
||||||
keyfilter="int"
|
keyfilter="int"
|
||||||
value={o.score}
|
value={o.score}
|
||||||
@@ -725,7 +1139,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
onClick={() => displayCriterionData(o.id)}
|
onClick={() => displayCriterionData(o.id)}
|
||||||
aria-label={__('Mostra', 'gepafin')}/> : null}
|
aria-label={__('Mostra', 'gepafin')}/> : null}
|
||||||
<Button icon="pi pi-thumbs-up" rounded outlined
|
<Button icon="pi pi-thumbs-up" rounded outlined
|
||||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('criteria') || evaluationBlockedForUser(data)}
|
||||||
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
||||||
onClick={() => updateEvaluationValue(
|
onClick={() => updateEvaluationValue(
|
||||||
true,
|
true,
|
||||||
@@ -733,7 +1147,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
)}
|
)}
|
||||||
aria-label={__('Su', 'gepafin')}/>
|
aria-label={__('Su', 'gepafin')}/>
|
||||||
<Button icon="pi pi-thumbs-down" rounded outlined
|
<Button icon="pi pi-thumbs-down" rounded outlined
|
||||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('criteria') || evaluationBlockedForUser(data)}
|
||||||
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
|
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
|
||||||
onClick={() => updateEvaluationValue(
|
onClick={() => updateEvaluationValue(
|
||||||
false,
|
false,
|
||||||
@@ -763,6 +1177,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
</tfoot>
|
</tfoot>
|
||||||
</table> : null}
|
</table> : null}
|
||||||
</div>
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
@@ -771,86 +1186,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<div className="appPageSection__actions">
|
{actionBtns()}
|
||||||
{['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus)
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || data.status === 'CLOSE' || (data.applicationStatus === 'EVALUATION'
|
|
||||||
&& (!allFilesRated || !atLeastOneChecked)) || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doNewSoccorso}
|
|
||||||
outlined
|
|
||||||
label={<>
|
|
||||||
{data.applicationStatus === 'EVALUATION'
|
|
||||||
? __('Richiedi soccorso istruttorio', 'gepafin')
|
|
||||||
: __('Apri soccorso istruttorio', 'gepafin')}
|
|
||||||
<i style={{ marginLeft: 7 }}>
|
|
||||||
<HelpIcon/>
|
|
||||||
</i>
|
|
||||||
</>}
|
|
||||||
/> : null}
|
|
||||||
{data.id
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={data.status === 'CLOSE' || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={() => doSaveDraft()}
|
|
||||||
outlined
|
|
||||||
label={__('Salva bozza valutazione', 'gepafin')}
|
|
||||||
icon="pi pi-save" iconPos="right"/>
|
|
||||||
: <Button
|
|
||||||
type="button"
|
|
||||||
onClick={() => doSaveDraft()}
|
|
||||||
label={__('Crea valutazione', 'gepafin')}
|
|
||||||
icon="pi pi-save" iconPos="right"/>}
|
|
||||||
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
|
|
||||||
&& APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || !allFilesRated || !allChecksChecked
|
|
||||||
|| !['EVALUATION'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doCheckNDG}
|
|
||||||
label={__('Controlla NDG', 'gepafin')}
|
|
||||||
/> : null}
|
|
||||||
{APP_EVALUATION_FLOW_ID === '1' && APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || !['NDG'].includes(data.applicationStatus) || !data.ndg || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doCreateAppointment}
|
|
||||||
label={__('Crea l\'appuntamento', 'gepafin')}
|
|
||||||
/> : null}
|
|
||||||
{APP_EVALUATION_FLOW_ID === '1'
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || !['APPOINTMENT'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doMakeAdmisible}
|
|
||||||
label={__('Ammissibile formalmente', 'gepafin')}
|
|
||||||
/> : null}
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
disabled={true}
|
|
||||||
onClick={() => {}}
|
|
||||||
label={__('Valutazione tecnico-finanziaria positiva', 'gepafin')}
|
|
||||||
/>
|
|
||||||
{data.id
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!isAdmissible
|
|
||||||
|| ['APPROVED'].includes(data.applicationStatus)
|
|
||||||
|| evaluationShouldBeBlocked(data)
|
|
||||||
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE'].includes(data.applicationStatus))
|
|
||||||
}
|
|
||||||
onClick={initiateApproving}
|
|
||||||
label={__('Domanda deliberata', 'gepafin')}
|
|
||||||
icon="pi pi-check" iconPos="right"/> : null}
|
|
||||||
{data.id
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={APP_EVALUATION_FLOW_ID === '1'
|
|
||||||
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)
|
|
||||||
|| evaluationShouldBeBlocked(data))}
|
|
||||||
onClick={initiateRejecting}
|
|
||||||
label={__('Respingi Domanda', 'gepafin')}
|
|
||||||
icon="pi pi-times" iconPos="right"/> : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
@@ -897,7 +1233,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
value={appointmentData.amount}
|
value={appointmentData.amount}
|
||||||
keyfilter="int"
|
keyfilter="int"
|
||||||
invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0}
|
invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0}
|
||||||
onChange={(e) => setValue('amount', e.value)}/>
|
onChange={(e) => setFieldValue('amount', e.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label
|
<label
|
||||||
@@ -908,7 +1244,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
value={appointmentData.duration}
|
value={appointmentData.duration}
|
||||||
keyfilter="int"
|
keyfilter="int"
|
||||||
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
|
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
|
||||||
onChange={(e) => setValue('duration', e.value)}/>
|
onChange={(e) => setFieldValue('duration', e.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label className={classNames({ 'p-error': isEmpty(appointmentData.title) })}>
|
<label className={classNames({ 'p-error': isEmpty(appointmentData.title) })}>
|
||||||
@@ -917,7 +1253,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<InputText
|
<InputText
|
||||||
value={appointmentData.title}
|
value={appointmentData.title}
|
||||||
invalid={isEmpty(appointmentData.title)}
|
invalid={isEmpty(appointmentData.title)}
|
||||||
onChange={(e) => setValue('title', e.target.value)}/>
|
onChange={(e) => setFieldValue('title', e.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label className={classNames({ 'p-error': isEmpty(appointmentData.text) })}>
|
<label className={classNames({ 'p-error': isEmpty(appointmentData.text) })}>
|
||||||
@@ -926,7 +1262,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<InputTextarea
|
<InputTextarea
|
||||||
value={appointmentData.text}
|
value={appointmentData.text}
|
||||||
invalid={isEmpty(appointmentData.text)}
|
invalid={isEmpty(appointmentData.text)}
|
||||||
onChange={(e) => setValue('text', e.target.value)}
|
onChange={(e) => setFieldValue('text', e.target.value)}
|
||||||
rows={3}
|
rows={3}
|
||||||
cols={30}/>
|
cols={30}/>
|
||||||
</div>
|
</div>
|
||||||
@@ -948,4 +1284,4 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DomandaEditPreInstructor;
|
export default DomandaEditInstructorManager;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Scarica documenti della domanda', 'gepafin')}</h2>
|
||||||
|
<div className="appPageSection__row autoFlow">
|
||||||
|
<DownloadApplicationArchive applicationId={id}/>
|
||||||
|
<DownloadSignedApplication applicationId={id}/>
|
||||||
|
<DownloadCompanyDelegation applicationId={id}/>
|
||||||
|
</div>
|
||||||
|
</div> : null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ApplicationDownloadFiles;
|
||||||
@@ -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)
|
||||||
|
? <div className="appPageSection__withBorder columns">
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('ID domanda', 'gepafin')}</span>
|
||||||
|
<span>{data.applicationId}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Protocollo', 'gepafin')}</span>
|
||||||
|
<span>{data.protocolNumber}</span>
|
||||||
|
</p>
|
||||||
|
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <p className="appPageSection__pMeta">
|
||||||
|
<span>{__('NDG', 'gepafin')}</span>
|
||||||
|
<span>{data.ndg}</span>
|
||||||
|
</p> : null}
|
||||||
|
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Appuntamento', 'gepafin')}</span>
|
||||||
|
<span>{data.appointmentId}</span>
|
||||||
|
</p> : null}
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Bando', 'gepafin')}</span>
|
||||||
|
<span>{data.callName}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||||
|
<span>{data.beneficiary}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
|
||||||
|
<span>{data.companyName}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Data ricezione', 'gepafin')}</span>
|
||||||
|
<span>{getDateTimeFromISOstring(data.submissionDate)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Data assegnazione', 'gepafin')}</span>
|
||||||
|
<span>{getDateTimeFromISOstring(data.assignedAt)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Aassegnato a', 'gepafin')}</span>
|
||||||
|
<span>{data.assignedUserName}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Scadenza Valutazione', 'gepafin')}</span>
|
||||||
|
<span>{getDateFromISOstring(data.evaluationEndDate)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Stato', 'gepafin')}</span>
|
||||||
|
<span>{getBandoLabel(data.applicationStatus)}</span>
|
||||||
|
</p>
|
||||||
|
</div> : null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ApplicationInfo;
|
||||||
@@ -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 { __, sprintf } from '@wordpress/i18n';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
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 { klona } from 'klona';
|
||||||
import { wrap } from 'object-path-immutable';
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { evaluate } from 'mathjs';
|
||||||
|
import equal from 'fast-deep-equal';
|
||||||
|
|
||||||
// store
|
// store
|
||||||
import { storeGet, storeSet, useStore } from '../../store';
|
import { storeGet, storeSet, useStore } from '../../store';
|
||||||
@@ -15,8 +18,21 @@ import AppointmentService from '../../service/appointment-service';
|
|||||||
|
|
||||||
// tools
|
// tools
|
||||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
import getBandoLabel from '../../helpers/getBandoLabel';
|
import {
|
||||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
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
|
// components
|
||||||
import { Skeleton } from 'primereact/skeleton';
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
@@ -32,12 +48,11 @@ import BlockingOverlay from '../../components/BlockingOverlay';
|
|||||||
import { classNames } from 'primereact/utils';
|
import { classNames } from 'primereact/utils';
|
||||||
import { InputTextarea } from 'primereact/inputtextarea';
|
import { InputTextarea } from 'primereact/inputtextarea';
|
||||||
import { InputText } from 'primereact/inputtext';
|
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 ListOfFiles from './components/ListOfFiles';
|
||||||
import RepeaterFields from './components/RepeaterFields';
|
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_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
|
||||||
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||||
@@ -67,12 +82,46 @@ const DomandaEditPreInstructor = () => {
|
|||||||
duration: 0,
|
duration: 0,
|
||||||
amount: 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 = () => {
|
const goToEvaluationsPage = () => {
|
||||||
navigate('/domande');
|
navigate('/domande');
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFlagsForSoccorso = (data) => {
|
const updateFlagsForSoccorso = useCallback((data) => {
|
||||||
let nonRatedFilesLength = 0;
|
let nonRatedFilesLength = 0;
|
||||||
|
|
||||||
if (data.files) {
|
if (data.files) {
|
||||||
@@ -91,6 +140,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
setAllFilesRated(nonRatedFilesLength === 0);
|
setAllFilesRated(nonRatedFilesLength === 0);
|
||||||
|
|
||||||
|
if (data.evaluationVersion === 'V1') {
|
||||||
if (data.checklist) {
|
if (data.checklist) {
|
||||||
const checkedChecklistItems = data.checklist
|
const checkedChecklistItems = data.checklist
|
||||||
.map(el => el.valid)
|
.map(el => el.valid)
|
||||||
@@ -98,7 +148,20 @@ const DomandaEditPreInstructor = () => {
|
|||||||
setAtLeastOneChecked(checkedChecklistItems.length > 0);
|
setAtLeastOneChecked(checkedChecklistItems.length > 0);
|
||||||
setAllChecksChecked(checkedChecklistItems.length === data.checklist.length)
|
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 = () => {
|
const doNewSoccorso = () => {
|
||||||
if (connectedSoccorsoId !== 0) {
|
if (connectedSoccorsoId !== 0) {
|
||||||
@@ -108,24 +171,75 @@ const DomandaEditPreInstructor = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCallback = (data) => {
|
const getVersion = (resp) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (resp.status === 'SUCCESS') {
|
||||||
setData(getFormattedData(data.data));
|
if (resp.data.evaluationVersion === 'V1') {
|
||||||
setMotivation(data.data.motivation);
|
storeSet.main.setAsyncRequest();
|
||||||
updateFlagsForSoccorso(data.data);
|
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();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
const errGetCallback = (data) => {
|
const errGetVersion = (resp) => {
|
||||||
if (toast.current && data.message) {
|
if (toast.current && data.message) {
|
||||||
toast.current.show({
|
toast.current.show({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
summary: '',
|
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();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +281,34 @@ const DomandaEditPreInstructor = () => {
|
|||||||
updateFlagsForSoccorso(newData);
|
updateFlagsForSoccorso(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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 = '') => {
|
const doSaveDraft = useCallback((doRedirect = '') => {
|
||||||
const formData = {
|
if (data.evaluationVersion === 'V1') {
|
||||||
|
const submitData = {
|
||||||
criteria: klona(data.criteria),
|
criteria: klona(data.criteria),
|
||||||
checklist: klona(data.checklist),
|
checklist: klona(data.checklist),
|
||||||
files: klona(data.files),
|
files: klona(data.files),
|
||||||
@@ -179,14 +319,36 @@ const DomandaEditPreInstructor = () => {
|
|||||||
)),
|
)),
|
||||||
amendmentDetails: klona(data.amendmentDetails),
|
amendmentDetails: klona(data.amendmentDetails),
|
||||||
note: data.note
|
note: data.note
|
||||||
}
|
};
|
||||||
|
|
||||||
ApplicationEvaluationService.updateEvaluation(
|
ApplicationEvaluationService.updateEvaluation(
|
||||||
data.assignedApplicationId,
|
data.assignedApplicationId,
|
||||||
formData,
|
submitData,
|
||||||
(data) => updateCallback(data, doRedirect),
|
(data) => updateCallback(data, doRedirect),
|
||||||
errUpdateCallback
|
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]);
|
}, [data]);
|
||||||
|
|
||||||
const updateCallback = (data, doRedirect = '') => {
|
const updateCallback = (data, doRedirect = '') => {
|
||||||
@@ -219,7 +381,8 @@ const DomandaEditPreInstructor = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const doApprove = () => {
|
const doApprove = () => {
|
||||||
const formData = {
|
if (data.evaluationVersion === 'V1') {
|
||||||
|
const submitData = {
|
||||||
applicationStatus: 'APPROVED',
|
applicationStatus: 'APPROVED',
|
||||||
criteria: klona(data.criteria),
|
criteria: klona(data.criteria),
|
||||||
checklist: klona(data.checklist),
|
checklist: klona(data.checklist),
|
||||||
@@ -230,11 +393,42 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setIsVisibleCompleteDialog(false);
|
setIsVisibleCompleteDialog(false);
|
||||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
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 doReject = () => {
|
||||||
const formData = {
|
if (data.evaluationVersion === 'V1') {
|
||||||
|
const submitData = {
|
||||||
applicationStatus: 'REJECTED',
|
applicationStatus: 'REJECTED',
|
||||||
criteria: klona(data.criteria),
|
criteria: klona(data.criteria),
|
||||||
checklist: klona(data.checklist),
|
checklist: klona(data.checklist),
|
||||||
@@ -245,7 +439,37 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setIsVisibleCompleteDialog(false);
|
setIsVisibleCompleteDialog(false);
|
||||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
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) => {
|
const updateStatusCallback = (data) => {
|
||||||
@@ -432,7 +656,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
setIsVisibleAppointmentDialog(true);
|
setIsVisibleAppointmentDialog(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const setValue = (name, value) => {
|
const setFieldValue = (name, value) => {
|
||||||
const newData = wrap(appointmentData).set(name, value).value();
|
const newData = wrap(appointmentData).set(name, value).value();
|
||||||
setAppointmentData(newData);
|
setAppointmentData(newData);
|
||||||
}
|
}
|
||||||
@@ -506,11 +730,153 @@ const DomandaEditPreInstructor = () => {
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
const evaluationShouldBeBlocked = (data = {}) => {
|
const evaluationBlockedForUser = (data = {}) => {
|
||||||
const userData = storeGet.main.userData()
|
const userData = storeGet.main.userData()
|
||||||
return isAsyncRequest || userData.id !== data.assignedUserId;
|
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 <div className="appPageSection__actions">
|
||||||
|
{['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus)
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || data.status === 'CLOSE'
|
||||||
|
|| (data.applicationStatus === 'EVALUATION' && shouldDisableNewSoccorso())
|
||||||
|
|| evaluationBlockedForUser(data)}
|
||||||
|
onClick={doNewSoccorso}
|
||||||
|
outlined
|
||||||
|
label={<>
|
||||||
|
{data.applicationStatus === 'EVALUATION'
|
||||||
|
? __('Richiedi soccorso istruttorio', 'gepafin')
|
||||||
|
: __('Apri soccorso istruttorio', 'gepafin')}
|
||||||
|
<i style={{ marginLeft: 7 }}>
|
||||||
|
<HelpIcon/>
|
||||||
|
</i>
|
||||||
|
</>}
|
||||||
|
/> : null}
|
||||||
|
{data.id
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={data.status === 'CLOSE' || evaluationBlockedForUser(data)}
|
||||||
|
onClick={() => doSaveDraft()}
|
||||||
|
outlined
|
||||||
|
label={__('Salva bozza valutazione', 'gepafin')}
|
||||||
|
icon="pi pi-save" iconPos="right"/>
|
||||||
|
: <Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => doSaveDraft()}
|
||||||
|
label={__('Crea valutazione', 'gepafin')}
|
||||||
|
icon="pi pi-save" iconPos="right"/>}
|
||||||
|
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
|
||||||
|
&& APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || !allFilesRated || !allChecksChecked
|
||||||
|
|| !['EVALUATION'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
|
||||||
|
onClick={doCheckNDG}
|
||||||
|
label={__('Controlla NDG', 'gepafin')}
|
||||||
|
/> : null}
|
||||||
|
{APP_EVALUATION_FLOW_ID === '1' && APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || !['NDG'].includes(data.applicationStatus) || !data.ndg || evaluationBlockedForUser(data)}
|
||||||
|
onClick={doCreateAppointment}
|
||||||
|
label={__('Crea l\'appuntamento', 'gepafin')}
|
||||||
|
/> : null}
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={!data.id || !['APPOINTMENT'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
|
||||||
|
onClick={doMakeAdmisible}
|
||||||
|
label={__('Ammissibile formalmente', 'gepafin')}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={true}
|
||||||
|
onClick={() => {
|
||||||
|
}}
|
||||||
|
label={__('Valutazione tecnico-finanziaria positiva', 'gepafin')}
|
||||||
|
/>
|
||||||
|
{data.id
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={!isAdmissible
|
||||||
|
|| ['APPROVED'].includes(data.applicationStatus)
|
||||||
|
|| evaluationBlockedForUser(data)
|
||||||
|
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE'].includes(data.applicationStatus))
|
||||||
|
}
|
||||||
|
onClick={initiateApproving}
|
||||||
|
label={__('Domanda deliberata', 'gepafin')}
|
||||||
|
icon="pi pi-check" iconPos="right"/> : null}
|
||||||
|
{data.id
|
||||||
|
? <Button
|
||||||
|
type="button"
|
||||||
|
disabled={APP_EVALUATION_FLOW_ID === '1'
|
||||||
|
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)
|
||||||
|
|| evaluationBlockedForUser(data))}
|
||||||
|
onClick={initiateRejecting}
|
||||||
|
label={__('Respingi domanda', 'gepafin')}
|
||||||
|
icon="pi pi-times" iconPos="right"/> : null}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
const maxScore = pathOr(0, ['minScore'], data);
|
const maxScore = pathOr(0, ['minScore'], data);
|
||||||
const criteria = pathOr([], ['criteria'], data);
|
const criteria = pathOr([], ['criteria'], data);
|
||||||
@@ -524,9 +890,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
const entityId = !isNaN(parsed) ? parsed : 0;
|
const entityId = !isNaN(parsed) ? parsed : 0;
|
||||||
|
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [
|
ApplicationEvaluationService.getEvaluationVersionByApplId(entityId, getVersion, errGetVersion);
|
||||||
['applicationId', entityId]
|
|
||||||
]);
|
|
||||||
AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [
|
AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [
|
||||||
['statuses', 'AWAITING']
|
['statuses', 'AWAITING']
|
||||||
]);
|
]);
|
||||||
@@ -555,64 +919,18 @@ const DomandaEditPreInstructor = () => {
|
|||||||
|
|
||||||
{!isAsyncRequest && !isEmpty(data)
|
{!isAsyncRequest && !isEmpty(data)
|
||||||
? <div className="appPage__content">
|
? <div className="appPage__content">
|
||||||
<div className="appPageSection__withBorder columns">
|
<ApplicationInfo data={data}/>
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('ID domanda', 'gepafin')}</span>
|
<div className="appPageSection__hr">
|
||||||
<span>{data.applicationId}</span>
|
<span>{__('Azioni rapide', 'gepafin')}</span>
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Protocollo', 'gepafin')}</span>
|
|
||||||
<span>{data.protocolNumber}</span>
|
|
||||||
</p>
|
|
||||||
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <p className="appPageSection__pMeta">
|
|
||||||
<span>{__('NDG', 'gepafin')}</span>
|
|
||||||
<span>{data.ndg}</span>
|
|
||||||
</p> : null}
|
|
||||||
{APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Appuntamento', 'gepafin')}</span>
|
|
||||||
<span>{data.appointmentId}</span>
|
|
||||||
</p> : null}
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Bando', 'gepafin')}</span>
|
|
||||||
<span>{data.callName}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
|
||||||
<span>{data.beneficiary}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
|
|
||||||
<span>{data.companyName}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Data ricezione', 'gepafin')}</span>
|
|
||||||
<span>{getDateTimeFromISOstring(data.submissionDate)}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Data assegnazione', 'gepafin')}</span>
|
|
||||||
<span>{getDateTimeFromISOstring(data.assignedAt)}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Scadenza Valutazione', 'gepafin')}</span>
|
|
||||||
<span>{getDateFromISOstring(data.evaluationEndDate)}</span>
|
|
||||||
</p>
|
|
||||||
<p className="appPageSection__pMeta">
|
|
||||||
<span>{__('Stato', 'gepafin')}</span>
|
|
||||||
<span>{getBandoLabel(data.applicationStatus)}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Scarica documenti della domanda', 'gepafin')}</h2>
|
{actionBtns()}
|
||||||
<div className="appPageSection__row autoFlow">
|
|
||||||
<DownloadApplicationArchive applicationId={id}/>
|
|
||||||
<DownloadSignedApplication applicationId={id}/>
|
|
||||||
<DownloadCompanyDelegation applicationId={id}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ApplicationDownloadFiles id={id}/>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
||||||
<RepeaterFields
|
<RepeaterFields
|
||||||
@@ -621,12 +939,104 @@ const DomandaEditPreInstructor = () => {
|
|||||||
data,
|
data,
|
||||||
['evaluationDocument']
|
['evaluationDocument']
|
||||||
)}
|
)}
|
||||||
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationBlockedForUser(data)}
|
||||||
sourceId={data.assignedApplicationId}
|
sourceId={data.assignedApplicationId}
|
||||||
sourceName="evaluation"/>
|
sourceName="evaluation"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
{data.evaluationVersion === 'V2'
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Documenti allegati', 'gepafin')}</h2>
|
||||||
|
{!isEmpty(data.files)
|
||||||
|
? <ListOfFiles
|
||||||
|
files={data.files}
|
||||||
|
updateFn={updateEvaluationValue}
|
||||||
|
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(data)}
|
||||||
|
name="files"
|
||||||
|
ndg={data.ndg}
|
||||||
|
applicationId={id}/>
|
||||||
|
: <p>{__('Nessun documento allegato', 'gepafin')}</p>}
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{data.evaluationVersion === 'V2'
|
||||||
|
? <form className="appForm" onSubmit={handleSubmit(() => {
|
||||||
|
})}>
|
||||||
|
{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
|
||||||
|
? <div key={o.id}>
|
||||||
|
<div className="ql-editor">
|
||||||
|
{renderHtmlContent(text.value)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: <FormField
|
||||||
|
key={o.id}
|
||||||
|
readOnly={formula && !isEmpty(formula.value)}
|
||||||
|
type={o.name}
|
||||||
|
fieldName={o.id}
|
||||||
|
label={label ? label.value : ''}
|
||||||
|
placeholder={placeholder ? placeholder.value : ''}
|
||||||
|
control={control}
|
||||||
|
register={register}
|
||||||
|
errors={errors}
|
||||||
|
defaultValue={values[o.id] ? values[o.id] : ''}
|
||||||
|
maxFractionDigits={step ? step.value : 0}
|
||||||
|
accept={mimeValue}
|
||||||
|
config={validations}
|
||||||
|
options={options ? options.value : []}
|
||||||
|
setDataFn={setValue}
|
||||||
|
saveFormCallback={doSaveDraft}
|
||||||
|
sourceId={id}
|
||||||
|
useGrouping={false}
|
||||||
|
tableColumns={tableColumns ? tableColumns.value : {}}
|
||||||
|
/>
|
||||||
|
})}
|
||||||
|
</form>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{data.evaluationVersion === 'V1'
|
||||||
|
? <div className="appPageSection">
|
||||||
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
|
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
|
||||||
<div className="appPageSection columns">
|
<div className="appPageSection columns">
|
||||||
<div>
|
<div>
|
||||||
@@ -635,7 +1045,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<div className="appPageSection__checklist">
|
<div className="appPageSection__checklist">
|
||||||
{data.checklist.map((o, i) => <div key={o.id}>
|
{data.checklist.map((o, i) => <div key={o.id}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
disabled={shouldDisableField('checklist') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('checklist') || evaluationBlockedForUser(data)}
|
||||||
inputId={`checklist_${o.id}`}
|
inputId={`checklist_${o.id}`}
|
||||||
onChange={(e) => updateEvaluationValue(
|
onChange={(e) => updateEvaluationValue(
|
||||||
e.checked,
|
e.checked,
|
||||||
@@ -651,7 +1061,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Editor
|
<Editor
|
||||||
value={data.note}
|
value={data.note}
|
||||||
readOnly={shouldDisableField('note') || evaluationShouldBeBlocked(data)}
|
readOnly={shouldDisableField('note') || evaluationBlockedForUser(data)}
|
||||||
placeholder={__('Digita qui il messagio', 'gepafin')}
|
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||||
headerTemplate={header}
|
headerTemplate={header}
|
||||||
onTextChange={(e) => updateEvaluationValue(
|
onTextChange={(e) => updateEvaluationValue(
|
||||||
@@ -664,16 +1074,19 @@ const DomandaEditPreInstructor = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3>{__('Documenti allegati', 'gepafin')}</h3>
|
<h3>{__('Documenti allegati', 'gepafin')}</h3>
|
||||||
<ListOfFiles
|
{!isEmpty(data.files)
|
||||||
|
? <ListOfFiles
|
||||||
files={data.files}
|
files={data.files}
|
||||||
updateFn={updateEvaluationValue}
|
updateFn={updateEvaluationValue}
|
||||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(data)}
|
||||||
name="files"
|
name="files"
|
||||||
ndg={data.ndg}
|
ndg={data.ndg}
|
||||||
applicationId={id}/>
|
applicationId={id}/>
|
||||||
|
: <p>{__('Nessun documento allegato', 'gepafin')}</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
{!isEmpty(data.amendmentDetails)
|
{!isEmpty(data.amendmentDetails)
|
||||||
? <div className="appPageSection">
|
? <div className="appPageSection">
|
||||||
@@ -681,13 +1094,14 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<ListOfFiles
|
<ListOfFiles
|
||||||
files={data.amendmentDetails}
|
files={data.amendmentDetails}
|
||||||
updateFn={updateEvaluationValue}
|
updateFn={updateEvaluationValue}
|
||||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationBlockedForUser(data)}
|
||||||
name="amendmentDetails"
|
name="amendmentDetails"
|
||||||
ndg={data.ndg}
|
ndg={data.ndg}
|
||||||
applicationId={id}/>
|
applicationId={id}/>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|
||||||
<div className="appPageSection">
|
{data.evaluationVersion === 'V1'
|
||||||
|
? <div className="appPageSection">
|
||||||
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
|
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
|
||||||
{data.criteria
|
{data.criteria
|
||||||
? <table className="myTable">
|
? <table className="myTable">
|
||||||
@@ -704,7 +1118,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<td>
|
<td>
|
||||||
<div className="p-inputgroup">
|
<div className="p-inputgroup">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('criteria') || evaluationBlockedForUser(data)}
|
||||||
placeholder={__('Punteggio', 'gepafin')}
|
placeholder={__('Punteggio', 'gepafin')}
|
||||||
keyfilter="int"
|
keyfilter="int"
|
||||||
value={o.score}
|
value={o.score}
|
||||||
@@ -727,7 +1141,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
onClick={() => displayCriterionData(o.id)}
|
onClick={() => displayCriterionData(o.id)}
|
||||||
aria-label={__('Mostra', 'gepafin')}/> : null}
|
aria-label={__('Mostra', 'gepafin')}/> : null}
|
||||||
<Button icon="pi pi-thumbs-up" rounded outlined
|
<Button icon="pi pi-thumbs-up" rounded outlined
|
||||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('criteria') || evaluationBlockedForUser(data)}
|
||||||
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
||||||
onClick={() => updateEvaluationValue(
|
onClick={() => updateEvaluationValue(
|
||||||
true,
|
true,
|
||||||
@@ -735,7 +1149,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
)}
|
)}
|
||||||
aria-label={__('Su', 'gepafin')}/>
|
aria-label={__('Su', 'gepafin')}/>
|
||||||
<Button icon="pi pi-thumbs-down" rounded outlined
|
<Button icon="pi pi-thumbs-down" rounded outlined
|
||||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
disabled={shouldDisableField('criteria') || evaluationBlockedForUser(data)}
|
||||||
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
|
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
|
||||||
onClick={() => updateEvaluationValue(
|
onClick={() => updateEvaluationValue(
|
||||||
false,
|
false,
|
||||||
@@ -765,6 +1179,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
</tfoot>
|
</tfoot>
|
||||||
</table> : null}
|
</table> : null}
|
||||||
</div>
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
@@ -773,86 +1188,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<div className="appPageSection__actions">
|
{actionBtns()}
|
||||||
{['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus)
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || data.status === 'CLOSE' || (data.applicationStatus === 'EVALUATION'
|
|
||||||
&& (!allFilesRated || !atLeastOneChecked)) || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doNewSoccorso}
|
|
||||||
outlined
|
|
||||||
label={<>
|
|
||||||
{data.applicationStatus === 'EVALUATION'
|
|
||||||
? __('Richiedi soccorso istruttorio', 'gepafin')
|
|
||||||
: __('Apri soccorso istruttorio', 'gepafin')}
|
|
||||||
<i style={{ marginLeft: 7 }}>
|
|
||||||
<HelpIcon/>
|
|
||||||
</i>
|
|
||||||
</>}
|
|
||||||
/> : null}
|
|
||||||
{data.id
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={data.status === 'CLOSE' || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={() => doSaveDraft()}
|
|
||||||
outlined
|
|
||||||
label={__('Salva bozza valutazione', 'gepafin')}
|
|
||||||
icon="pi pi-save" iconPos="right"/>
|
|
||||||
: <Button
|
|
||||||
type="button"
|
|
||||||
onClick={() => doSaveDraft()}
|
|
||||||
label={__('Crea valutazione', 'gepafin')}
|
|
||||||
icon="pi pi-save" iconPos="right"/>}
|
|
||||||
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
|
|
||||||
&& APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || !allFilesRated || !allChecksChecked
|
|
||||||
|| !['EVALUATION'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doCheckNDG}
|
|
||||||
label={__('Controlla NDG', 'gepafin')}
|
|
||||||
/> : null}
|
|
||||||
{APP_EVALUATION_FLOW_ID === '1' && APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE'
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || !['NDG'].includes(data.applicationStatus) || !data.ndg || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doCreateAppointment}
|
|
||||||
label={__('Crea l\'appuntamento', 'gepafin')}
|
|
||||||
/> : null}
|
|
||||||
{APP_EVALUATION_FLOW_ID === '1'
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!data.id || !['APPOINTMENT'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
|
||||||
onClick={doMakeAdmisible}
|
|
||||||
label={__('Ammissibile formalmente', 'gepafin')}
|
|
||||||
/> : null}
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
disabled={true}
|
|
||||||
onClick={() => {}}
|
|
||||||
label={__('Valutazione tecnico-finanziaria positiva', 'gepafin')}
|
|
||||||
/>
|
|
||||||
{data.id
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={!isAdmissible
|
|
||||||
|| ['APPROVED'].includes(data.applicationStatus)
|
|
||||||
|| evaluationShouldBeBlocked(data)
|
|
||||||
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE'].includes(data.applicationStatus))
|
|
||||||
}
|
|
||||||
onClick={initiateApproving}
|
|
||||||
label={__('Domanda deliberata', 'gepafin')}
|
|
||||||
icon="pi pi-check" iconPos="right"/> : null}
|
|
||||||
{data.id
|
|
||||||
? <Button
|
|
||||||
type="button"
|
|
||||||
disabled={APP_EVALUATION_FLOW_ID === '1'
|
|
||||||
&& (!['EVALUATION', 'ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)
|
|
||||||
|| evaluationShouldBeBlocked(data))}
|
|
||||||
onClick={initiateRejecting}
|
|
||||||
label={__('Respingi domanda', 'gepafin')}
|
|
||||||
icon="pi pi-times" iconPos="right"/> : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
@@ -899,7 +1235,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
value={appointmentData.amount}
|
value={appointmentData.amount}
|
||||||
keyfilter="int"
|
keyfilter="int"
|
||||||
invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0}
|
invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0}
|
||||||
onChange={(e) => setValue('amount', e.value)}/>
|
onChange={(e) => setFieldValue('amount', e.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label
|
<label
|
||||||
@@ -910,7 +1246,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
value={appointmentData.duration}
|
value={appointmentData.duration}
|
||||||
keyfilter="int"
|
keyfilter="int"
|
||||||
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
|
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
|
||||||
onChange={(e) => setValue('duration', e.value)}/>
|
onChange={(e) => setFieldValue('duration', e.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label className={classNames({ 'p-error': isEmpty(appointmentData.title) })}>
|
<label className={classNames({ 'p-error': isEmpty(appointmentData.title) })}>
|
||||||
@@ -919,7 +1255,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<InputText
|
<InputText
|
||||||
value={appointmentData.title}
|
value={appointmentData.title}
|
||||||
invalid={isEmpty(appointmentData.title)}
|
invalid={isEmpty(appointmentData.title)}
|
||||||
onChange={(e) => setValue('title', e.target.value)}/>
|
onChange={(e) => setFieldValue('title', e.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="appForm__field">
|
<div className="appForm__field">
|
||||||
<label className={classNames({ 'p-error': isEmpty(appointmentData.text) })}>
|
<label className={classNames({ 'p-error': isEmpty(appointmentData.text) })}>
|
||||||
@@ -928,7 +1264,7 @@ const DomandaEditPreInstructor = () => {
|
|||||||
<InputTextarea
|
<InputTextarea
|
||||||
value={appointmentData.text}
|
value={appointmentData.text}
|
||||||
invalid={isEmpty(appointmentData.text)}
|
invalid={isEmpty(appointmentData.text)}
|
||||||
onChange={(e) => setValue('text', e.target.value)}
|
onChange={(e) => setFieldValue('text', e.target.value)}
|
||||||
rows={3}
|
rows={3}
|
||||||
cols={30}/>
|
cols={30}/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ const Domande = () => {
|
|||||||
<span><NumberFlow
|
<span><NumberFlow
|
||||||
value={getStatValue('evaluationAverageTime', 0)}
|
value={getStatValue('evaluationAverageTime', 0)}
|
||||||
format={{ notation: 'compact' }}
|
format={{ notation: 'compact' }}
|
||||||
suffix={` ${__('minuti', 'gepafin')}`}
|
suffix={` ${__('giorni', 'gepafin')}`}
|
||||||
locales="it-IT"/></span>
|
locales="it-IT"/></span>
|
||||||
</div>
|
</div>
|
||||||
<div className="statsBigBadges__gridItem">
|
<div className="statsBigBadges__gridItem">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { is, uniq } from 'ramda';
|
import { is, uniq } from 'ramda';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
// api
|
// api
|
||||||
import ApplicationService from '../../../../service/application-service';
|
import ApplicationService from '../../../../service/application-service';
|
||||||
@@ -29,7 +29,6 @@ const AllDomandeArchiveTable = ({ updaterString = '' }) => {
|
|||||||
const [filters, setFilters] = useState(null);
|
const [filters, setFilters] = useState(null);
|
||||||
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
const [statuses, setStatuses] = useState([]);
|
const [statuses, setStatuses] = useState([]);
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocalAsyncRequest(true);
|
setLocalAsyncRequest(true);
|
||||||
@@ -141,7 +140,7 @@ const AllDomandeArchiveTable = ({ updaterString = '' }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import React from 'react';
|
|||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import AllDomandeArchiveTable from './components/AllDomandeArchiveTable';
|
//import AllDomandeArchiveTable from './components/AllDomandeArchiveTable';
|
||||||
|
import PreInstructorDomandeTable from '../DashboardPreInstructor/components/PreInstructorDomandeTable';
|
||||||
const Domande = () => {
|
|
||||||
|
|
||||||
|
const DomandeArchive = () => {
|
||||||
return (
|
return (
|
||||||
<div className="appPage">
|
<div className="appPage">
|
||||||
<div className="appPage__pageHeader">
|
<div className="appPage__pageHeader">
|
||||||
@@ -15,11 +15,11 @@ const Domande = () => {
|
|||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Domande pubblicate', 'gepafin')}</h2>
|
<h2>{__('Domande completate', 'gepafin')}</h2>
|
||||||
<AllDomandeArchiveTable/>
|
<PreInstructorDomandeTable statuses={['CLOSE']} userId={0}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Domande;
|
export default DomandeArchive;
|
||||||
29
src/pages/DomandeArchivePreInstructor/index.js
Normal file
29
src/pages/DomandeArchivePreInstructor/index.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { useStore } from '../../store';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import PreInstructorDomandeTable from '../DashboardPreInstructor/components/PreInstructorDomandeTable';
|
||||||
|
|
||||||
|
const DomandeArchivePreInstructor = () => {
|
||||||
|
const userData = useStore().main.userData();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Archivio domande', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Domande completate', 'gepafin')}</h2>
|
||||||
|
<PreInstructorDomandeTable statuses={['CLOSE']} userId={userData.id}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DomandeArchivePreInstructor;
|
||||||
@@ -157,7 +157,7 @@ const BeneficiarioDomandeTable = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useStore } from '../../store';
|
|||||||
// components
|
// components
|
||||||
import BeneficiarioDomandeTable from './components/BeneficiarioDomandeTable';
|
import BeneficiarioDomandeTable from './components/BeneficiarioDomandeTable';
|
||||||
|
|
||||||
const DomandePreInstructor = () => {
|
const DomandeBeneficiario = () => {
|
||||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||||
const companies = useStore().main.companies();
|
const companies = useStore().main.companies();
|
||||||
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
||||||
@@ -29,4 +29,4 @@ const DomandePreInstructor = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DomandePreInstructor;
|
export default DomandeBeneficiario;
|
||||||
@@ -20,6 +20,7 @@ import { classNames } from 'primereact/utils';
|
|||||||
import { Dropdown } from 'primereact/dropdown';
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
|
import DashboardService from '../../service/dashboard-service';
|
||||||
|
|
||||||
const DomandeInstructorManager = () => {
|
const DomandeInstructorManager = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -30,6 +31,7 @@ const DomandeInstructorManager = () => {
|
|||||||
const [chosenApplication, setChosenApplication] = useState(0);
|
const [chosenApplication, setChosenApplication] = useState(0);
|
||||||
const [updaterString, setUpdaterString] = useState('');
|
const [updaterString, setUpdaterString] = useState('');
|
||||||
const toast = useRef(null);
|
const toast = useRef(null);
|
||||||
|
const [mainStats, setMainStats] = useState({});
|
||||||
|
|
||||||
const getRolesCallback = (data) => {
|
const getRolesCallback = (data) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
@@ -123,6 +125,18 @@ const DomandeInstructorManager = () => {
|
|||||||
storeSet.main.unsetAsyncRequest();
|
storeSet.main.unsetAsyncRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getStats = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setMainStats(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetStats = () => {}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
DashboardService.getEvaluationsStats(getStats, errGetStats);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (roleIds.length > 0) {
|
if (roleIds.length > 0) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -140,22 +154,74 @@ const DomandeInstructorManager = () => {
|
|||||||
return(
|
return(
|
||||||
<div className="appPage">
|
<div className="appPage">
|
||||||
<div className="appPage__pageHeader">
|
<div className="appPage__pageHeader">
|
||||||
<h1>{__('Domande da valutare', 'gepafin')}</h1>
|
<h1>{__('Gestione domande', 'gepafin')}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<PreInstructorDomandeTable/>
|
<h2>{__('Da assegnare', 'gepafin')}</h2>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
|
||||||
|
|
||||||
<div className="appPageSection">
|
|
||||||
<h2>{__('Domande pubblicate', 'gepafin')}</h2>
|
|
||||||
<AllDomandeTable openDialogFn={openAssignDialog} updaterString={updaterString}/>
|
<AllDomandeTable openDialogFn={openAssignDialog} updaterString={updaterString}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('In lavorazione', 'gepafin')}</h2>
|
||||||
|
<PreInstructorDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={0}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/*<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection statsBigBadges">
|
||||||
|
<h2>{__('Riepilogo', 'gepafin')}</h2>
|
||||||
|
<div className="statsBigBadges__grid applStats">
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Totale domande', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfAssignedApplication', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('In soccorso', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationInAmendmentState', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('In valutazione', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationInOpenState', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Completate', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationInCloseState', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Tempo medio di valutazione', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('averageEvaluationDays', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
suffix={` ${__('giorni', 'gepafin')}`}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Domande in scadenza (48h)', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('numberOfApplicationExpiringIn48Hours', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="en-US"/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>*/}
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
visible={isVisibleEditDialog}
|
visible={isVisibleEditDialog}
|
||||||
modal
|
modal
|
||||||
|
|||||||
37
src/pages/DomandeMieInstructorManager/index.js
Normal file
37
src/pages/DomandeMieInstructorManager/index.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { useStore } from '../../store';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import InstructorManagerMieDomandeTable
|
||||||
|
from '../DashboardInstructorManager/components/InstructorManagerMieDomandeTable';
|
||||||
|
|
||||||
|
const DomandeMieInstructorManager = () => {
|
||||||
|
const userData = useStore().main.userData();
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Domande da valutare', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Nuove domande da valutare', 'gepafin')}</h2>
|
||||||
|
<InstructorManagerMieDomandeTable statuses={['AWAITING']} userId={userData.id}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Coda di lavoro', 'gepafin')}</h2>
|
||||||
|
<InstructorManagerMieDomandeTable statuses={['OPEN', 'SOCCORSO']} userId={userData.id}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DomandeMieInstructorManager;
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { useStore } from '../../store';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import PreInstructorDomandeTable from '../DashboardPreInstructor/components/PreInstructorDomandeTable';
|
import PreInstructorDomandeTable from '../DashboardPreInstructor/components/PreInstructorDomandeTable';
|
||||||
|
|
||||||
const DomandePreInstructor = () => {
|
const DomandePreInstructor = () => {
|
||||||
|
const userData = useStore().main.userData();
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPage">
|
<div className="appPage">
|
||||||
<div className="appPage__pageHeader">
|
<div className="appPage__pageHeader">
|
||||||
@@ -14,7 +19,8 @@ const DomandePreInstructor = () => {
|
|||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<PreInstructorDomandeTable/>
|
<h2>{__('Nuove domande da valutare', 'gepafin')}</h2>
|
||||||
|
<PreInstructorDomandeTable statuses={['AWAITING']} userId={userData.id}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const Profile = () => {
|
|||||||
const onSubmit = (formData) => {
|
const onSubmit = (formData) => {
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
|
|
||||||
UserService.updateUser(userData.id, formData, updateCallback, updateError);
|
UserService.updateUserSelf(userData.id, formData, updateCallback, updateError);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateCallback = (data) => {
|
const updateCallback = (data) => {
|
||||||
@@ -109,6 +109,7 @@ const Profile = () => {
|
|||||||
<FormField
|
<FormField
|
||||||
type="textinput"
|
type="textinput"
|
||||||
fieldName="email"
|
fieldName="email"
|
||||||
|
disabled={true}
|
||||||
label={__('Email', 'gepafin')}
|
label={__('Email', 'gepafin')}
|
||||||
control={control}
|
control={control}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const ProfileBeneficiario = () => {
|
|||||||
const onSubmit = (formData) => {
|
const onSubmit = (formData) => {
|
||||||
storeSet.main.setAsyncRequest();
|
storeSet.main.setAsyncRequest();
|
||||||
|
|
||||||
UserService.updateUser(userData.id, formData, updateCallback, updateError);
|
UserService.updateUserSelf(userData.id, formData, updateCallback, updateError);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateCallback = (data) => {
|
const updateCallback = (data) => {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { useRef, useState, useEffect, useMemo } from 'react';
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { classNames } from 'primereact/utils';
|
import { classNames } from 'primereact/utils';
|
||||||
import { isEmpty, isNil } from 'ramda';
|
import { isEmpty } from 'ramda';
|
||||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
// tools
|
// tools
|
||||||
|
|||||||
351
src/pages/SoccorsoAddInstructorManager/index.js
Normal file
351
src/pages/SoccorsoAddInstructorManager/index.js
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
import { isEmpty } from 'ramda';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { storeSet, useStore } from '../../store';
|
||||||
|
|
||||||
|
// api
|
||||||
|
import AmendmentsService from '../../service/amendments-service';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { Skeleton } from 'primereact/skeleton';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import { Checkbox } from 'primereact/checkbox';
|
||||||
|
import { Editor } from 'primereact/editor';
|
||||||
|
import { InputNumber } from 'primereact/inputnumber';
|
||||||
|
import BlockingOverlay from '../../components/BlockingOverlay';
|
||||||
|
import { Toast } from 'primereact/toast';
|
||||||
|
import { InputSwitch } from 'primereact/inputswitch';
|
||||||
|
import ApplicationEvaluationService from '../../service/application-evaluation-service';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
|
||||||
|
const SoccorsoAddInstructorManager = () => {
|
||||||
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
|
const { id } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [data, setData] = useState({});
|
||||||
|
const [evaluationId, setEvaluationId] = useState(0);
|
||||||
|
const [formData, setFormData] = useState({});
|
||||||
|
const [isVisibleConfirmDialog, setIsVisibleConfirmDialog] = useState(false)
|
||||||
|
const toast = useRef(null);
|
||||||
|
|
||||||
|
const goToEvaluationPage = () => {
|
||||||
|
navigate(`/mie-domande/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const parsed = parseInt(id)
|
||||||
|
const entityId = !isNaN(parsed) ? parsed : 0;
|
||||||
|
|
||||||
|
storeSet.main.setAsyncRequest();
|
||||||
|
ApplicationEvaluationService.getEvaluationByApplId(getCallbackEvaluation, errGetCallback, [
|
||||||
|
['applicationId', entityId]
|
||||||
|
]);
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
const getCallbackEvaluation = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setEvaluationId(data.data.id);
|
||||||
|
AmendmentsService.getSoccorsoByApplEvalId(data.data.id, getCallback, errGetCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setData(data.data);
|
||||||
|
setFormData(getFormattedFormData(data.data));
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormattedFormData = (data) => {
|
||||||
|
let newData = {};
|
||||||
|
newData.formFields = data.formFields;
|
||||||
|
newData.responseDays = 10;
|
||||||
|
newData.note = '';
|
||||||
|
newData.isSendNotification = true;
|
||||||
|
newData.isSendEmail = true;
|
||||||
|
return newData;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
return (
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-bold" aria-label="Bold"></button>
|
||||||
|
<button className="ql-italic" aria-label="Italic"></button>
|
||||||
|
<button className="ql-underline" aria-label="Underline"></button>
|
||||||
|
<button className="ql-link" aria-label="Link"></button>
|
||||||
|
<button className="ql-list" value="ordered"></button>
|
||||||
|
<button className="ql-header" value="2"></button>
|
||||||
|
<button className="ql-header" value="3"></button>
|
||||||
|
<button className="ql-blockquote"></button>
|
||||||
|
<button className="ql-list" value="bullet"></button>
|
||||||
|
<button className="ql-indent" value="-1"></button>
|
||||||
|
<button className="ql-indent" value="+1"></button>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = renderHeader();
|
||||||
|
|
||||||
|
const updateEvaluationValue = (value, path, maxValue) => {
|
||||||
|
let finalValue = value;
|
||||||
|
|
||||||
|
if (maxValue) {
|
||||||
|
finalValue = value > maxValue ? maxValue : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newData = wrap(formData).set(path.split('.'), finalValue).value();
|
||||||
|
|
||||||
|
setFormData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const doCreate = () => {
|
||||||
|
storeSet.main.setAsyncRequest();
|
||||||
|
|
||||||
|
AmendmentsService.createSoccorso(formData, createCallback, errCreateCallback, [
|
||||||
|
['applicationEvaluationId', evaluationId]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
if (toast.current) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'success',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate(`/mie-domande/${id}/soccorso/${data.data.id}`);
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errCreateCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCreationProcess = () => {
|
||||||
|
setIsVisibleConfirmDialog(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerConfirmDialog = () => {
|
||||||
|
return <span>{__('Richiesta di conferma', 'gepafin')}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideConfirmDialog = () => {
|
||||||
|
setIsVisibleConfirmDialog(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const footerConfirmDialog = () => {
|
||||||
|
return <div>
|
||||||
|
<Button type="button" label={__('No', 'gepafin')} onClick={goToEvaluationPage} outlined/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
label={__('Si', 'gepafin')} onClick={doConfirm}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const doConfirm = () => {
|
||||||
|
setIsVisibleConfirmDialog(false);
|
||||||
|
doCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Richiesta Integrazione Documentale', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
<Toast ref={toast}/>
|
||||||
|
<BlockingOverlay shouldDisplay={isAsyncRequest}/>
|
||||||
|
|
||||||
|
<div className="appPageSection__row">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
onClick={goToEvaluationPage}
|
||||||
|
label={__('Indietro', 'gepafin')}
|
||||||
|
icon="pi pi-arrow-left" iconPos="left"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
{!isAsyncRequest && !isEmpty(data)
|
||||||
|
? <div className="appPage__content">
|
||||||
|
<div className="appPageSection__withBorder column">
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('ID domanda', 'gepafin')}</span>
|
||||||
|
<span>{data.applicationId}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Bando', 'gepafin')}</span>
|
||||||
|
<span>{data.callName}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||||
|
<span>{data.beneficiaryName}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<div className="appPageSection columns">
|
||||||
|
<div>
|
||||||
|
<h3>{__('Pec/Email', 'gepafin')}</h3>
|
||||||
|
<div style={{marginBottom: '30px'}}>
|
||||||
|
<Editor
|
||||||
|
value={formData.note}
|
||||||
|
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||||
|
headerTemplate={header}
|
||||||
|
onTextChange={(e) => updateEvaluationValue(
|
||||||
|
e.htmlValue,
|
||||||
|
'note'
|
||||||
|
)}
|
||||||
|
style={{ height: 80 * 3, width: '100%' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{__('Tempo per la Risposta (giorni)', 'gepafin')}</h3>
|
||||||
|
<div style={{marginBottom: '30px'}}>
|
||||||
|
<InputNumber
|
||||||
|
keyfilter="int"
|
||||||
|
value={formData.responseDays}
|
||||||
|
showButtons
|
||||||
|
onChange={(e) => updateEvaluationValue(
|
||||||
|
e.value,
|
||||||
|
'responseDays',
|
||||||
|
9999
|
||||||
|
)}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{__('Notifica', 'gepafin')}</h3>
|
||||||
|
<div className="appPageSection__withBorder grey">
|
||||||
|
<div className="appForm__field row">
|
||||||
|
<InputSwitch
|
||||||
|
inputId="notify_email"
|
||||||
|
checked={formData.isSendEmail}
|
||||||
|
onChange={(e) => updateEvaluationValue(
|
||||||
|
e.value,
|
||||||
|
'isSendEmail'
|
||||||
|
)}/>
|
||||||
|
<label htmlFor="notify_email">{__('Notifiche Email', 'gepafin')}</label>
|
||||||
|
</div>
|
||||||
|
<div className="appForm__field row">
|
||||||
|
<InputSwitch
|
||||||
|
inputId="notify_push"
|
||||||
|
checked={formData.isSendNotification}
|
||||||
|
onChange={(e) => updateEvaluationValue(
|
||||||
|
e.value,
|
||||||
|
'isSendNotification'
|
||||||
|
)}/>
|
||||||
|
<label htmlFor="notify_push">{__('Notifiche Push', 'gepafin')}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{formData.formFields
|
||||||
|
? <div>
|
||||||
|
<h3>{__('Documenti da Integrare', 'gepafin')}</h3>
|
||||||
|
<div className="appPageSection__withBorder grey">
|
||||||
|
<div className="appPageSection__checklist">
|
||||||
|
{formData.formFields.map((o, i) => <div key={o.fieldId}>
|
||||||
|
<Checkbox
|
||||||
|
inputId={`checklist_${o.fieldId}`}
|
||||||
|
onChange={(e) => updateEvaluationValue(
|
||||||
|
e.checked,
|
||||||
|
`formFields.${i}.selected`
|
||||||
|
)}
|
||||||
|
checked={o.selected}></Checkbox>
|
||||||
|
<label htmlFor={`checklist_${o.fieldId}`}>{o.label}</label>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__message warning">
|
||||||
|
<i className="pi pi-exclamation-triangle"></i>
|
||||||
|
<span className="summary">{__('Attenzione', 'gepafin')}</span>
|
||||||
|
<span>{__("L'invio della richiesta di integrazione sospenderà il termine di valutazione della domanda.", 'gepafin')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection__hr">
|
||||||
|
<span>{__('Azioni', 'gepafin')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<div className="appPageSection__actions">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
onClick={goToEvaluationPage}
|
||||||
|
label={__('Anulla', 'gepafin')}
|
||||||
|
icon="pi pi-times" iconPos="right"/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={initCreationProcess}
|
||||||
|
label={__('Invia richiesta', 'gepafin')}
|
||||||
|
icon="pi pi-check" iconPos="right"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
visible={isVisibleConfirmDialog}
|
||||||
|
modal
|
||||||
|
header={headerConfirmDialog}
|
||||||
|
footer={footerConfirmDialog}
|
||||||
|
style={{ maxWidth: '600px', width: '100%' }}
|
||||||
|
onHide={hideConfirmDialog}>
|
||||||
|
<div className="appForm__field">
|
||||||
|
<p>{__('Soccorso istruttorio autorizzato dal direttore e autorizzazione caricata su portale a seguito del quale parte l\'email?', 'gepafin')}</p>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
: <>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="4rem" className="mb-8"></Skeleton>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
|
||||||
|
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
|
||||||
|
<Skeleton width="100%" height="4rem"></Skeleton>
|
||||||
|
</>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SoccorsoAddInstructorManager;
|
||||||
587
src/pages/SoccorsoEditInstructorManager/index.js
Normal file
587
src/pages/SoccorsoEditInstructorManager/index.js
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
import { is, isEmpty } from 'ramda';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { klona } from 'klona';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { storeSet, useStore } from '../../store';
|
||||||
|
|
||||||
|
// api
|
||||||
|
import AmendmentsService from '../../service/amendments-service';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
|
import getBandoLabel from '../../helpers/getBandoLabel';
|
||||||
|
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||||
|
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import BlockingOverlay from '../../components/BlockingOverlay';
|
||||||
|
import { Toast } from 'primereact/toast';
|
||||||
|
import { classNames } from 'primereact/utils';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
|
import FormField from '../../components/FormField';
|
||||||
|
import { Editor } from 'primereact/editor';
|
||||||
|
import { InputNumber } from 'primereact/inputnumber';
|
||||||
|
import SoccorsoComunications from '../SoccorsoEditPreInstructor/components/SoccorsoComunications';
|
||||||
|
|
||||||
|
|
||||||
|
const SoccorsoEditInstructorManager = () => {
|
||||||
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
|
const { id, amendmentId } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [data, setData] = useState({});
|
||||||
|
const [isVisibleCloseAmendDialog, setIsVisibleCloseAmendDialog] = useState(false);
|
||||||
|
const [isVisibleExtendTimeDialog, setIsVisibleExtendTimeDialog] = useState(false);
|
||||||
|
const [extendedTime, setExtendedTime] = useState(3);
|
||||||
|
const [isLoadingExtendingTime, setIsLoadingExtendingTime] = useState(false);
|
||||||
|
const [isLoadingReminding, setIsLoadingReminding] = useState(false);
|
||||||
|
const [internalNote, setInternalNote] = useState('');
|
||||||
|
const toast = useRef(null);
|
||||||
|
const [formInitialData, setFormInitialData] = useState({});
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
setValue,
|
||||||
|
register,
|
||||||
|
trigger,
|
||||||
|
getValues
|
||||||
|
} = useForm({
|
||||||
|
defaultValues: useMemo(() => {
|
||||||
|
return formInitialData;
|
||||||
|
}, [formInitialData]), mode: 'onChange'
|
||||||
|
});
|
||||||
|
|
||||||
|
const goToEvaluationPage = () => {
|
||||||
|
navigate(`/mie-domande/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setData(getFormattedData(data.data));
|
||||||
|
let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||||
|
if (cur.fieldValue) {
|
||||||
|
acc[cur.fieldId] = cur.fieldValue;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
formDataInitial = {
|
||||||
|
...formDataInitial,
|
||||||
|
amendmentDocuments: data.data.amendmentDocuments
|
||||||
|
}
|
||||||
|
setFormInitialData(formDataInitial);
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormattedData = (data) => {
|
||||||
|
data.startDate = is(String, data.startDate) ? new Date(data.startDate) : (data.startDate ? data.startDate : '');
|
||||||
|
data.expirationDate = is(String, data.expirationDate) ? new Date(data.expirationDate) : (data.expirationDate ? data.expirationDate : '');
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
return (
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-bold" aria-label="Bold"></button>
|
||||||
|
<button className="ql-italic" aria-label="Italic"></button>
|
||||||
|
<button className="ql-underline" aria-label="Underline"></button>
|
||||||
|
<button className="ql-link" aria-label="Link"></button>
|
||||||
|
<button className="ql-list" value="ordered"></button>
|
||||||
|
<button className="ql-header" value="2"></button>
|
||||||
|
<button className="ql-header" value="3"></button>
|
||||||
|
<button className="ql-blockquote"></button>
|
||||||
|
<button className="ql-list" value="bullet"></button>
|
||||||
|
<button className="ql-indent" value="-1"></button>
|
||||||
|
<button className="ql-indent" value="+1"></button>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = renderHeader();
|
||||||
|
|
||||||
|
const updateNewAmendmentData = (value, path) => {
|
||||||
|
const newData = wrap(data).set(path, value).value();
|
||||||
|
setData(newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
};
|
||||||
|
|
||||||
|
const doUpdateAmendment = (doClose = false) => {
|
||||||
|
trigger();
|
||||||
|
let formValues = klona(getValues());
|
||||||
|
const newFormValues = Object.keys(formValues)
|
||||||
|
.filter(v => v !== 'amendmentDocuments')
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
let fieldVal = formValues[cur];
|
||||||
|
|
||||||
|
fieldVal = isEmpty(fieldVal) ? null : fieldVal;
|
||||||
|
fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : null;
|
||||||
|
|
||||||
|
acc.push({
|
||||||
|
'fieldId': cur,
|
||||||
|
'fieldValue': fieldVal
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
const newAmendDocs = formValues.amendmentDocuments
|
||||||
|
? formValues.amendmentDocuments.map(o => o.id).join(',')
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const submitData = {
|
||||||
|
applicationFormFields: newFormValues,
|
||||||
|
amendmentDocuments: newAmendDocs,
|
||||||
|
amendmentNotes: data.amendmentNotes
|
||||||
|
}
|
||||||
|
|
||||||
|
storeSet.main.setAsyncRequest();
|
||||||
|
AmendmentsService.updateSoccorso(
|
||||||
|
amendmentId,
|
||||||
|
submitData,
|
||||||
|
(resp) => updateAmendmentCallback(resp, doClose),
|
||||||
|
errUpdateAmendmentCallback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateAmendmentCallback = (data, doClose = false) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setData(getFormattedData(data.data));
|
||||||
|
|
||||||
|
if (doClose) {
|
||||||
|
const submitData = {
|
||||||
|
internalNote
|
||||||
|
}
|
||||||
|
storeSet.main.setAsyncRequest();
|
||||||
|
AmendmentsService.closeSoccorso(amendmentId, submitData, closeAmendmentCallback, errCloseAmendmentCallback);
|
||||||
|
} else {
|
||||||
|
if (toast.current) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'success',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||||
|
if (cur.fieldValue) {
|
||||||
|
acc[cur.fieldId] = cur.fieldValue;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, formInitialData);
|
||||||
|
formDataInitial = {
|
||||||
|
...formDataInitial,
|
||||||
|
amendmentDocuments: data.data.amendmentDocuments
|
||||||
|
}
|
||||||
|
setFormInitialData(formDataInitial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errUpdateAmendmentCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const openCloseAmendmentDialog = () => {
|
||||||
|
setIsVisibleCloseAmendDialog(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerCloseAmendDialog = () => {
|
||||||
|
return <span>{__('Chiudi Soccorso Istruttorio', 'gepafin')}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideCloseAmendDialog = () => {
|
||||||
|
setIsVisibleCloseAmendDialog(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const footerCloseAmendDialog = () => {
|
||||||
|
return <div>
|
||||||
|
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideCloseAmendDialog} outlined/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={isAsyncRequest || isEmpty(data.internalNotes)}
|
||||||
|
label={__('Invia', 'gepafin')} onClick={doCloseAmendment}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const doCloseAmendment = () => {
|
||||||
|
doUpdateAmendment(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeAmendmentCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
if (toast.current) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'success',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data.data.status) {
|
||||||
|
updateNewAmendmentData(data.data.status, ['status']);
|
||||||
|
setIsVisibleCloseAmendDialog(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errCloseAmendmentCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
storeSet.main.unsetAsyncRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerExtendRespDialog = () => {
|
||||||
|
return <span>{__('Estendi scadenza', 'gepafin')}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideExtendRespDialog = () => {
|
||||||
|
setIsVisibleExtendTimeDialog(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const footerExtendRespDialog = () => {
|
||||||
|
return <div>
|
||||||
|
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideExtendRespDialog} outlined/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={isLoadingExtendingTime || isEmpty(extendedTime)}
|
||||||
|
label={__('Invia', 'gepafin')} onClick={doExtendTimeResponse}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const openExtendResponseTimeDialog = () => {
|
||||||
|
setIsVisibleExtendTimeDialog(true);
|
||||||
|
setExtendedTime(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
const doExtendTimeResponse = () => {
|
||||||
|
setIsLoadingExtendingTime(true);
|
||||||
|
AmendmentsService.extendSoccorso(amendmentId, extendedTime, extendCallback, errExtendCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
const extendCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
if (toast.current) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'success',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setIsVisibleExtendTimeDialog(false);
|
||||||
|
}
|
||||||
|
setIsLoadingExtendingTime(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errExtendCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
setIsLoadingExtendingTime(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendReminder = () => {
|
||||||
|
setIsLoadingReminding(true);
|
||||||
|
AmendmentsService.sendReminderForSoccorso(amendmentId, reminderCallback, errReminderCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
const reminderCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
if (toast.current) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'success',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsLoadingReminding(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errReminderCallback = (data) => {
|
||||||
|
if (toast.current && data.message) {
|
||||||
|
toast.current.show({
|
||||||
|
severity: 'error',
|
||||||
|
summary: '',
|
||||||
|
detail: data.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(data);
|
||||||
|
setIsLoadingReminding(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (formInitialData) {
|
||||||
|
Object.keys(formInitialData).map(k => setValue(k, formInitialData[k]));
|
||||||
|
trigger();
|
||||||
|
}
|
||||||
|
}, [formInitialData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const parsedSoccorsoId = parseInt(amendmentId);
|
||||||
|
const soccorsoEntityId = !isNaN(parsedSoccorsoId) ? parsedSoccorsoId : 0;
|
||||||
|
|
||||||
|
AmendmentsService.getSoccorsoById(getCallback, errGetCallback, [['id', soccorsoEntityId]]);
|
||||||
|
}, [amendmentId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Soccorso Istruttorio - Dettagli', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
<Toast ref={toast}/>
|
||||||
|
<BlockingOverlay shouldDisplay={isAsyncRequest}/>
|
||||||
|
|
||||||
|
<div className="appPageSection__row">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
onClick={goToEvaluationPage}
|
||||||
|
label={__('Indietro', 'gepafin')}
|
||||||
|
icon="pi pi-arrow-left" iconPos="left"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPage__content">
|
||||||
|
<div className="appPageSection__withBorder columns">
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('ID domanda', 'gepafin')}</span>
|
||||||
|
<span>{data.applicationId}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Bando', 'gepafin')}</span>
|
||||||
|
<span>{data.callName}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||||
|
<span>{data.beneficiaryName}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Inizio', 'gepafin')}</span>
|
||||||
|
<span>{getDateFromISOstring(data.startDate)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Scadenza', 'gepafin')}</span>
|
||||||
|
<span>{getDateFromISOstring(data.expirationDate)}</span>
|
||||||
|
</p>
|
||||||
|
<p className="appPageSection__pMeta">
|
||||||
|
<span>{__('Stato', 'gepafin')}</span>
|
||||||
|
<span>{getBandoLabel(data.status)}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Dettagli richiesta', 'gepafin')}</h2>
|
||||||
|
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
||||||
|
<div
|
||||||
|
className="appPageSection__emailTemplate">{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}</div>
|
||||||
|
</div>
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h3>{__('Documenti richiesti', 'gepafin')}</h3>
|
||||||
|
<ol className="appPageSection__list">
|
||||||
|
{data.formFields
|
||||||
|
? data.formFields.map((o, i) => <li key={o.fieldId}
|
||||||
|
style={{ flexDirection: 'row' }}>
|
||||||
|
<span>{o.label}</span>
|
||||||
|
</li>) : null}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Comunicazioni', 'gepafin')}</h2>
|
||||||
|
<SoccorsoComunications amendmentId={amendmentId} soccorsoStatus={data.status}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{data.formFields && !isEmpty(data.formFields)
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Documenti Ricevuti', 'gepafin')}</h2>
|
||||||
|
|
||||||
|
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{data.formFields.map((o, i) => {
|
||||||
|
return <FormField
|
||||||
|
key={o.fieldId}
|
||||||
|
disabled={['CLOSE', 'AWAITING', 'EXPIRED'].includes(data.status)}
|
||||||
|
type="fileupload"
|
||||||
|
setDataFn={setValue}
|
||||||
|
saveFormCallback={doUpdateAmendment}
|
||||||
|
fieldName={o.fieldId}
|
||||||
|
label={o.label}
|
||||||
|
control={control}
|
||||||
|
register={register}
|
||||||
|
errors={errors}
|
||||||
|
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
|
||||||
|
accept={[]}
|
||||||
|
source="AMENDMENT"
|
||||||
|
sourceId={amendmentId}
|
||||||
|
multiple={true}
|
||||||
|
/>
|
||||||
|
})}
|
||||||
|
</form>
|
||||||
|
</div> : null}
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h3>{__('Notes', 'gepafin')}</h3>
|
||||||
|
<div style={{ marginBottom: '30px', width: '100%', position: 'relative' }}>
|
||||||
|
<BlockingOverlay shouldDisplay={['CLOSE', 'AWAITING', 'EXPIRED'].includes(data.status)}/>
|
||||||
|
<Editor
|
||||||
|
value={data.amendmentNotes}
|
||||||
|
readOnly={['CLOSE', 'AWAITING', 'EXPIRED'].includes(data.status)}
|
||||||
|
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||||
|
headerTemplate={header}
|
||||||
|
onTextChange={(e) => updateNewAmendmentData(
|
||||||
|
e.htmlValue,
|
||||||
|
'amendmentNotes'
|
||||||
|
)}
|
||||||
|
style={{ height: 80 * 3, width: '100%' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<FormField
|
||||||
|
type="fileupload"
|
||||||
|
disabled={['CLOSE', 'AWAITING', 'EXPIRED'].includes(data.status)}
|
||||||
|
setDataFn={setValue}
|
||||||
|
saveFormCallback={doUpdateAmendment}
|
||||||
|
fieldName="amendmentDocuments"
|
||||||
|
label={__('I file', 'gepafin')}
|
||||||
|
control={control}
|
||||||
|
register={register}
|
||||||
|
errors={errors}
|
||||||
|
defaultValue={formInitialData.amendmentDocuments ? formInitialData.amendmentDocuments : []}
|
||||||
|
accept={[]}
|
||||||
|
source="amendment"
|
||||||
|
sourceId={amendmentId}
|
||||||
|
multiple={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection__hr">
|
||||||
|
<span>{__('Azioni', 'gepafin')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<div className="appPageSection__actions">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={sendReminder}
|
||||||
|
disabled={isLoadingReminding || ['CLOSE', 'EXPIRED'].includes(data.status)}
|
||||||
|
outlined
|
||||||
|
label={__('Invia Sollecito', 'gepafin')}
|
||||||
|
icon="pi pi-send"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={openExtendResponseTimeDialog}
|
||||||
|
disabled={isLoadingExtendingTime || ['CLOSE', 'EXPIRED'].includes(data.status)}
|
||||||
|
outlined
|
||||||
|
label={__('Estendi Scadenza', 'gepafin')}
|
||||||
|
icon="pi pi-stopwatch"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => doUpdateAmendment()}
|
||||||
|
disabled={isAsyncRequest || ['CLOSE', 'AWAITING', 'EXPIRED'].includes(data.status)}
|
||||||
|
label={__('Salva bozza', 'gepafin')}
|
||||||
|
icon="pi pi-save" iconPos="right"/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={openCloseAmendmentDialog}
|
||||||
|
disabled={isAsyncRequest || ['CLOSE', 'AWAITING'].includes(data.status)}
|
||||||
|
label={__('Chiudi Soccorso Istruttorio', 'gepafin')}
|
||||||
|
icon="pi pi-times" iconPos="right"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
visible={isVisibleExtendTimeDialog}
|
||||||
|
modal
|
||||||
|
header={headerExtendRespDialog}
|
||||||
|
footer={footerExtendRespDialog}
|
||||||
|
style={{ maxWidth: '600px', width: '100%' }}
|
||||||
|
onHide={hideExtendRespDialog}>
|
||||||
|
<div className="appForm__field">
|
||||||
|
<label
|
||||||
|
className={classNames({ 'p-error': isEmpty(extendedTime) })}>
|
||||||
|
{__('Giorni', 'gepafin')}*
|
||||||
|
</label>
|
||||||
|
<InputNumber
|
||||||
|
keyfilter="int"
|
||||||
|
disabled={['CLOSE', 'EXPIRED'].includes(data.status)}
|
||||||
|
value={extendedTime}
|
||||||
|
showButtons
|
||||||
|
onChange={(e) => setExtendedTime(e.value)}/>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
visible={isVisibleCloseAmendDialog}
|
||||||
|
modal
|
||||||
|
header={headerCloseAmendDialog}
|
||||||
|
footer={footerCloseAmendDialog}
|
||||||
|
style={{ maxWidth: '600px', width: '100%' }}
|
||||||
|
onHide={hideCloseAmendDialog}>
|
||||||
|
<div className="appForm__field">
|
||||||
|
<label>{__('Motivazioni', 'gepafin')}</label>
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
<BlockingOverlay shouldDisplay={data.status === 'CLOSE'}/>
|
||||||
|
<Editor
|
||||||
|
value={internalNote}
|
||||||
|
readOnly={['CLOSE', 'EXPIRED'].includes(data.status)}
|
||||||
|
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||||
|
headerTemplate={header}
|
||||||
|
onTextChange={(e) => setInternalNote(e.htmlValue)}
|
||||||
|
style={{ height: 80 * 3, width: '100%' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SoccorsoEditInstructorManager;
|
||||||
95
src/pages/SoccorsoIstruttorioInstructorManager/index.js
Normal file
95
src/pages/SoccorsoIstruttorioInstructorManager/index.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import DashboardService from '../../service/dashboard-service';
|
||||||
|
import { pathOr } from 'ramda';
|
||||||
|
import NumberFlow from '@number-flow/react';
|
||||||
|
import PreInstructorSoccorsiTable from '../SoccorsoIstruttorioPreInstructor/components/PreInstructorSoccorsiTable';
|
||||||
|
|
||||||
|
const SoccorsoIstruttorioInstructorManager = () => {
|
||||||
|
const [mainStats, setMainStats] = useState({});
|
||||||
|
|
||||||
|
const getStats = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setMainStats(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetStats = () => {}
|
||||||
|
|
||||||
|
const getStatValue = (key, fallback = '') => {
|
||||||
|
return pathOr(fallback, [key], mainStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
DashboardService.getAmendmentsStats(getStats, errGetStats);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Soccorso istruttorio panoramica', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection statsBigBadges">
|
||||||
|
<h2>{__('Riepilogo', 'gepafin')}</h2>
|
||||||
|
<div className="statsBigBadges__grid applStats">
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Totale richieste', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('totalAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('In attesa risposta', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('waitingForResponseAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Risposte ricevute', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('responseReceivedAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Tempo medio di risposta', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('averageResponseDays', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
suffix={` ${__('giorni', 'gepafin')}`}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Scadute', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('expiredAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Richieste in scadenza (48h)', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('expiringRequestsIn48Hours', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="en-US"/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<PreInstructorSoccorsiTable userId={0}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SoccorsoIstruttorioInstructorManager;
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
import React, { useState, useEffect} from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { is, uniq } from 'ramda';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { storeGet } from '../../../../store';
|
||||||
|
|
||||||
|
// api
|
||||||
|
import AmendmentsService from '../../../../service/amendments-service';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import getBandoLabel from '../../../../helpers/getBandoLabel';
|
||||||
|
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { FilterMatchMode, FilterOperator } from 'primereact/api';
|
||||||
|
import { DataTable } from 'primereact/datatable';
|
||||||
|
import { Column } from 'primereact/column';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
import { Calendar } from 'primereact/calendar';
|
||||||
|
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
||||||
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
|
import { Tag } from 'primereact/tag';
|
||||||
|
|
||||||
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
|
|
||||||
|
|
||||||
|
const InstructorManagerSoccorsiTable = () => {
|
||||||
|
const [items, setItems] = useState(null);
|
||||||
|
const [filters, setFilters] = useState(null);
|
||||||
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
|
const [statuses, setStatuses] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const userData = storeGet.main.userData();
|
||||||
|
setLocalAsyncRequest(true);
|
||||||
|
AmendmentsService.getSoccorsi(getCallback, errGetCallbacks, [
|
||||||
|
['userId', userData.id]
|
||||||
|
]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getCallback = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setItems(getFormattedData(data.data));
|
||||||
|
setStatuses(uniq(data.data.map(o => o.status)))
|
||||||
|
initFilters();
|
||||||
|
}
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetCallbacks = (data) => {
|
||||||
|
setLocalAsyncRequest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormattedData = (data) => {
|
||||||
|
return data.map((d) => {
|
||||||
|
d.startDate = is(String, d.startDate) ? new Date(d.startDate) : (d.startDate ? d.startDate : '');
|
||||||
|
d.evaluationEndDate = is(String, d.evaluationEndDate) ? new Date(d.evaluationEndDate) : (d.evaluationEndDate ? d.evaluationEndDate : '');
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (value) => {
|
||||||
|
return value.toLocaleDateString('it-IT', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
initFilters();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initFilters = () => {
|
||||||
|
setFilters({
|
||||||
|
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
|
||||||
|
callName: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||||
|
},
|
||||||
|
companyName: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||||
|
},
|
||||||
|
startDate: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
||||||
|
},
|
||||||
|
evaluationEndDate: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
return (
|
||||||
|
<div className="appTableHeader">
|
||||||
|
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateStartBodyTemplate = (rowData) => {
|
||||||
|
return formatDate(rowData.startDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateExpirationBodyTemplate = (rowData) => {
|
||||||
|
return rowData.evaluationEndDate ? formatDate(rowData.evaluationEndDate) : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateFilterTemplate = (options) => {
|
||||||
|
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusBodyTemplate = (rowData) => {
|
||||||
|
return <ProperBandoLabel status={rowData.status}/>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusFilterTemplate = (options) => {
|
||||||
|
return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter" showClear />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusItemTemplate = (option) => {
|
||||||
|
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const actionsBodyTemplate = (rowData) => {
|
||||||
|
return <Link to={`/mie-domande/${rowData.applicationId}/soccorso/${rowData.id}`}>
|
||||||
|
<Button severity="info" label={__('Dettagli', 'gepafin')} size="small" />
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = renderHeader();
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="appPageSection__table">
|
||||||
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
|
filters={filters} stripedRows removableSort
|
||||||
|
header={header}
|
||||||
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
onFilter={(e) => setFilters(e.filters)}>
|
||||||
|
<Column field="applicationId" header={__('ID domanda', 'gepafin')}
|
||||||
|
sortable filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '6rem' }}/>
|
||||||
|
<Column field="protocolNumber" header={__('Protocollo', 'gepafin')}
|
||||||
|
sortable filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '6rem' }}/>
|
||||||
|
<Column field="callName" header={__('Bando', 'gepafin')}
|
||||||
|
filter filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column field="companyName" header={__('Azienda Beneficiaria', 'gepafin')}
|
||||||
|
filter filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column header={__('Data richiesta', 'gepafin')}
|
||||||
|
filterField="startDate" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateStartBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||||
|
<Column header={__('Scadenza', 'gepafin')}
|
||||||
|
filterField="evaluationEndDate" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateExpirationBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||||
|
<Column field="status" header={__('Stato', 'gepafin')}
|
||||||
|
style={{ minWidth: '7rem' }} body={statusBodyTemplate} filter
|
||||||
|
filterElement={statusFilterTemplate} />
|
||||||
|
<Column header={__('Azioni', 'gepafin')}
|
||||||
|
body={actionsBodyTemplate}/>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InstructorManagerSoccorsiTable;
|
||||||
23
src/pages/SoccorsoIstruttorioMioInstructorManager/index.js
Normal file
23
src/pages/SoccorsoIstruttorioMioInstructorManager/index.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import InstructorManagerSoccorsiTable from './components/InstructorManagerSoccorsiTable';
|
||||||
|
|
||||||
|
const SoccorsoIstruttorioMioInstructorManager = () => {
|
||||||
|
return(
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Soccorso istruttorio', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<InstructorManagerSoccorsiTable/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SoccorsoIstruttorioMioInstructorManager;
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
import React, { useState, useEffect} from 'react';
|
import React, { useState, useEffect} from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { is, uniq } from 'ramda';
|
import { is, isNil, uniq } from 'ramda';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
// store
|
|
||||||
import { storeGet } from '../../../../store';
|
|
||||||
|
|
||||||
// api
|
// api
|
||||||
import AmendmentsService from '../../../../service/amendments-service';
|
import AmendmentsService from '../../../../service/amendments-service';
|
||||||
|
|
||||||
@@ -26,17 +23,25 @@ import { Tag } from 'primereact/tag';
|
|||||||
import translationStrings from '../../../../translationStringsForComponents';
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
|
|
||||||
|
|
||||||
const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
|
const PreInstructorSoccorsiTable = ({ userId = null }) => {
|
||||||
const [items, setItems] = useState(null);
|
const [items, setItems] = useState(null);
|
||||||
const [filters, setFilters] = useState(null);
|
const [filters, setFilters] = useState(null);
|
||||||
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||||
const [statuses, setStatuses] = useState([]);
|
const [statuses, setStatuses] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const userData = storeGet.main.userData()
|
if (!isNil(userId)) {
|
||||||
setLocalAsyncRequest(true);
|
setLocalAsyncRequest(true);
|
||||||
AmendmentsService.getSoccorsoByPreInstructorId(userData.id, getCallback, errGetCallbacks);
|
|
||||||
}, []);
|
if (userId === 0) {
|
||||||
|
AmendmentsService.getSoccorsi(getCallback, errGetCallbacks);
|
||||||
|
} else {
|
||||||
|
AmendmentsService.getSoccorsi(getCallback, errGetCallbacks, [
|
||||||
|
['userId', userId]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [userId]);
|
||||||
|
|
||||||
const getCallback = (data) => {
|
const getCallback = (data) => {
|
||||||
if (data.status === 'SUCCESS') {
|
if (data.status === 'SUCCESS') {
|
||||||
@@ -135,7 +140,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
|
|||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"
|
<DataTable value={items} paginator showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -1,20 +1,96 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState, useCallback } from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { pathOr } from 'ramda';
|
||||||
|
import NumberFlow from '@number-flow/react';
|
||||||
|
|
||||||
|
// store
|
||||||
|
import { useStore } from '../../store';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import PreInstructorSoccorsiTable from './components/PreInstructorSoccorsiTable';
|
import PreInstructorSoccorsiTable from './components/PreInstructorSoccorsiTable';
|
||||||
|
import DashboardService from '../../service/dashboard-service';
|
||||||
|
|
||||||
const SoccorsoIstruttorioPreInstructor = () => {
|
const SoccorsoIstruttorioPreInstructor = () => {
|
||||||
|
const [mainStats, setMainStats] = useState({});
|
||||||
|
const userData = useStore().main.userData()
|
||||||
|
|
||||||
|
const getStats = (data) => {
|
||||||
|
if (data.status === 'SUCCESS') {
|
||||||
|
setMainStats(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetStats = () => {}
|
||||||
|
|
||||||
|
const getStatValue = useCallback((key, fallback = '') => {
|
||||||
|
return pathOr(fallback, [key], mainStats);
|
||||||
|
}, [mainStats]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
DashboardService.getAmendmentsStats(getStats, errGetStats);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="appPage">
|
<div className="appPage">
|
||||||
<div className="appPage__pageHeader">
|
<div className="appPage__pageHeader">
|
||||||
<h1>{__('Soccorso Istruttorio', 'gepafin')}</h1>
|
<h1>{__('Soccorso istruttorio', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection statsBigBadges">
|
||||||
|
<h2>{__('Riepilogo', 'gepafin')}</h2>
|
||||||
|
<div className="statsBigBadges__grid applStats">
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Totale richieste', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('totalAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('In attesa risposta', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('waitingForResponseAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Risposte ricevute', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('responseReceivedAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Tempo medio di risposta', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('averageResponseDays', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
suffix={` ${__('giorni', 'gepafin')}`}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Scadute', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('expiredAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItem">
|
||||||
|
<span>{__('Richieste in scadenza (48h)', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('expiringRequestsIn48Hours', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="en-US"/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<PreInstructorSoccorsiTable/>
|
<PreInstructorSoccorsiTable userId={userData.id}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 <ProperBandoLabel status={rowData.status}/>;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="appPageSection__table">
|
||||||
|
<DataTable value={items} showGridlines rows={5} loading={localAsyncRequest} dataKey="id"
|
||||||
|
stripedRows
|
||||||
|
emptyMessage={translationStrings.emptyMessage}>
|
||||||
|
<Column field="callTitle" header={__('Bando', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column header={__('Anno', 'gepafin')} dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateSubmissionBodyTemplate}/>
|
||||||
|
<Column field="amountRequested"
|
||||||
|
header={__('Importo finanziato', 'gepafin')}
|
||||||
|
style={{ minWidth: '7rem' }}
|
||||||
|
body={importoBodyTemplate}/>
|
||||||
|
<Column field="status" header={__('Stato progetto', 'gepafin')}
|
||||||
|
style={{ minWidth: '7rem' }} body={statusBodyTemplate}/>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BeneficiarioUltimeDomandeTable;
|
||||||
112
src/pages/StatsBeneficiary/index.js
Normal file
112
src/pages/StatsBeneficiary/index.js
Normal file
@@ -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(
|
||||||
|
<div className="appPage">
|
||||||
|
<div className="appPage__pageHeader">
|
||||||
|
<h1>{__('Statistiche', 'gepafin')}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection statsBigBadges">
|
||||||
|
<h2>{__('Riepilogo', 'gepafin')}</h2>
|
||||||
|
<div className="statsBigBadges__grid doubleStatsItems">
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStatsBeneficiary">
|
||||||
|
<span>{__('Domande presentate', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('submittedApplication', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStatsBeneficiary">
|
||||||
|
<span>{__('Tasso di successo', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('waitingForResponseAmendments', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
suffix={` ${__('%', 'gepafin')}`}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStatsBeneficiary">
|
||||||
|
<span>{__('Domande approvate', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('approvedApplication', 0)}
|
||||||
|
format={{ notation: 'compact' }}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
<div className="statsBigBadges__gridItemDoubleStatsBeneficiary">
|
||||||
|
<span>{__('Importo totale finanziato', 'gepafin')}</span>
|
||||||
|
<span><NumberFlow
|
||||||
|
value={getStatValue('averageResponseDays', 0)}
|
||||||
|
format={{
|
||||||
|
notation: 'compact',
|
||||||
|
compactDisplay: 'short',
|
||||||
|
roundingMode: 'trunc',
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'EUR',
|
||||||
|
currencyDisplay: 'symbol'
|
||||||
|
}}
|
||||||
|
locales="it-IT"/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
{chartStats && !isEmpty(chartStats)
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Statistiche di sistema', 'gepafin')}</h2>
|
||||||
|
<div className="appPageSection columns">
|
||||||
|
<ChartRichiesteVsApprovate
|
||||||
|
title={__('Importi Richiesti VS Approvati', 'gepafin')}
|
||||||
|
data={chartStats.requestedVsApprovedAmount}/>
|
||||||
|
<ChartDomandePerStato
|
||||||
|
title={__('Domande per stato', 'gepafin')}
|
||||||
|
data={chartStats.applicationPerStatus}/>
|
||||||
|
</div>
|
||||||
|
</div> : null}
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
<div className="appPageSection">
|
||||||
|
<h2>{__('Ultime richieste di finanziamento', 'gepafin')}</h2>
|
||||||
|
<BeneficiarioUltimeDomandeTable/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StatsBeneficiary;
|
||||||
105
src/pages/UserActivity/components/UserActivityTable/index.js
Normal file
105
src/pages/UserActivity/components/UserActivityTable/index.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { is } from 'ramda';
|
||||||
|
|
||||||
|
// translation
|
||||||
|
import translationStrings from '../../../../translationStringsForComponents';
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { FilterMatchMode, FilterOperator } from 'primereact/api';
|
||||||
|
import { DataTable } from 'primereact/datatable';
|
||||||
|
import { Column } from 'primereact/column';
|
||||||
|
import { Button } from 'primereact/button';
|
||||||
|
|
||||||
|
|
||||||
|
const UserActivityTable = ({ data = [] }) => {
|
||||||
|
const [items, setItems] = useState([]);
|
||||||
|
const [filters, setFilters] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
setItems(getFormattedData(data));
|
||||||
|
initFilters();
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
const getFormattedData = (data) => {
|
||||||
|
return data.map((d) => {
|
||||||
|
d.createdDate = is(String, d.createdDate) ? new Date(d.createdDate) : (d.createdDate ? d.createdDate : '');
|
||||||
|
d.updatedDate = is(String, d.updatedDate) ? new Date(d.updatedDate) : (d.updatedDate ? d.updatedDate : '');
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (value) => {
|
||||||
|
return value.toLocaleDateString('it-IT', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
initFilters();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initFilters = () => {
|
||||||
|
setFilters({
|
||||||
|
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
|
||||||
|
actionType: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||||
|
},
|
||||||
|
ipAddress: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||||
|
},
|
||||||
|
createdDate: {
|
||||||
|
operator: FilterOperator.AND,
|
||||||
|
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
return (
|
||||||
|
<div className="appTableHeader">
|
||||||
|
<Button type="button" icon="pi pi-filter-slash" label={__('Pulisci', 'gepafin')} outlined
|
||||||
|
onClick={clearFilter}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateBodyTemplate = (rowData) => {
|
||||||
|
return formatDate(rowData.createdDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = renderHeader();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="appPageSection__table">
|
||||||
|
<DataTable value={items} paginator showGridlines rows={10} dataKey="id"
|
||||||
|
filters={filters} stripedRows removableSort
|
||||||
|
header={header}
|
||||||
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
onFilter={(e) => setFilters(e.filters)}>
|
||||||
|
<Column header={__('Timestamp', 'gepafin')}
|
||||||
|
filterField="createdDate" dataType="date"
|
||||||
|
style={{ minWidth: '8rem' }}
|
||||||
|
body={dateBodyTemplate}/>
|
||||||
|
<Column field="actionType" header={__('Tipo di attività', 'gepafin')}
|
||||||
|
filter sortable
|
||||||
|
filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column field="actionContext" header={__('Azione', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
<Column field="ipAddress" header={__('IP', 'gepafin')}
|
||||||
|
filter sortable
|
||||||
|
filterPlaceholder={__('Cerca', 'gepafin')}
|
||||||
|
style={{ minWidth: '8rem' }}/>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserActivityTable;
|
||||||
@@ -15,6 +15,8 @@ import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
|||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import { Dropdown } from 'primereact/dropdown';
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
|
import UserActionService from '../../service/user-action-service';
|
||||||
|
import UserActivityTable from './components/UserActivityTable';
|
||||||
|
|
||||||
|
|
||||||
const UserActivity = () => {
|
const UserActivity = () => {
|
||||||
@@ -25,6 +27,11 @@ const UserActivity = () => {
|
|||||||
const [user, setUser] = useState({});
|
const [user, setUser] = useState({});
|
||||||
const [roles, setRoles] = useState([]);
|
const [roles, setRoles] = useState([]);
|
||||||
const [chosenRole, setChosenRole] = useState(0);
|
const [chosenRole, setChosenRole] = useState(0);
|
||||||
|
const [actionsContext, setActionsContext] = useState([]);
|
||||||
|
const [userActions, setUserActions] = useState({});
|
||||||
|
const [chosenPeriod, setChosenPeriod] = useState('');
|
||||||
|
const [chosenActivity, setChosenActivity] = useState('');
|
||||||
|
|
||||||
|
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
navigate(`/utenti`);
|
navigate(`/utenti`);
|
||||||
@@ -56,13 +63,13 @@ const UserActivity = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getStatValue = (key, fallback = 0) => {
|
const getStatValue = (key, fallback = 0) => {
|
||||||
return pathOr(fallback, [key], {});
|
return pathOr(fallback, [key], userActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRoleUpdate = () => {
|
const handleRoleUpdate = () => {
|
||||||
if (user.role?.id !== chosenRole) {
|
if (user.role?.id !== chosenRole) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
UserService.updateUser(user.id, {roleId: chosenRole}, updateRoleCallback, errUpdateRoleCallback)
|
UserService.updateUser(user.id, { roleId: chosenRole }, updateRoleCallback, errUpdateRoleCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,11 +85,50 @@ const UserActivity = () => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getActionsContextCallback = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
setActionsContext(resp.data)
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetActionsContextCallback = (resp) => {
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserActionsCallback = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
setUserActions(resp.data)
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errGetUserActionsCallback = (resp) => {
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const doFilterUserActivity = () => {
|
||||||
|
let queryParams = [];
|
||||||
|
|
||||||
|
if (!isEmpty(chosenPeriod)) {
|
||||||
|
queryParams.push(['timeFilter', chosenPeriod])
|
||||||
|
}
|
||||||
|
if (!isEmpty(chosenActivity)) {
|
||||||
|
queryParams.push(['actionContext', chosenActivity])
|
||||||
|
}
|
||||||
|
|
||||||
|
UserActionService.getUserActions(id, getUserActionsCallback, errGetUserActionsCallback, queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id && !isEmpty(id)) {
|
if (id && !isEmpty(id)) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
UserService.getUser(id, getUserCallback, errGetUserCallback);
|
UserService.getUser(id, getUserCallback, errGetUserCallback);
|
||||||
UserService.getRoles(getRolesCallback, errGetRolesCallback);
|
UserService.getRoles(getRolesCallback, errGetRolesCallback);
|
||||||
|
UserActionService.getActionContext(id, getActionsContextCallback, errGetActionsContextCallback);
|
||||||
|
UserActionService.getUserActions(id, getUserActionsCallback, errGetUserActionsCallback);
|
||||||
}
|
}
|
||||||
}, [id])
|
}, [id])
|
||||||
|
|
||||||
@@ -143,7 +189,10 @@ const UserActivity = () => {
|
|||||||
disabled={isEmpty(roles) || loading}
|
disabled={isEmpty(roles) || loading}
|
||||||
value={chosenRole}
|
value={chosenRole}
|
||||||
onChange={(e) => setChosenRole(e.value)}
|
onChange={(e) => setChosenRole(e.value)}
|
||||||
options={roles.filter(o => [3, 5].includes(o.id)).map(o => ({ label: o.roleName, value: o.id }))}
|
options={roles.filter(o => [3, 5].includes(o.id)).map(o => ({
|
||||||
|
label: o.roleName,
|
||||||
|
value: o.id
|
||||||
|
}))}
|
||||||
optionLabel="label"
|
optionLabel="label"
|
||||||
placeholder={__('Seleziona ruolo', 'gepafin')}/>
|
placeholder={__('Seleziona ruolo', 'gepafin')}/>
|
||||||
<Button
|
<Button
|
||||||
@@ -159,33 +208,83 @@ const UserActivity = () => {
|
|||||||
|
|
||||||
<div className="appPage__spacer"></div>
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
{/*<div className="appPageSection">
|
{!isEmpty(userActions)
|
||||||
|
? <div className="appPageSection">
|
||||||
<h2>{__('Statistiche attività', 'gepafin')}</h2>
|
<h2>{__('Statistiche attività', 'gepafin')}</h2>
|
||||||
<div className="statsBigBadges__grid grid-small">
|
<div className="statsBigBadges__grid grid-small">
|
||||||
<div className="statsBigBadges__gridItem">
|
<div className="statsBigBadges__gridItem">
|
||||||
<span>{__('Login totali', 'gepafin')}</span>
|
<span>{__('Login totali', 'gepafin')}</span>
|
||||||
<span>{<NumberFlow
|
<span>{<NumberFlow
|
||||||
value={getStatValue('numberOfActiveCalls', 0)}
|
value={getStatValue('numberOfLoginAttempts', 0)}
|
||||||
format={{ notation: 'compact' }}
|
format={{ notation: 'compact' }}
|
||||||
locales="it-IT"/>}</span>
|
locales="it-IT"/>}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="statsBigBadges__gridItem">
|
<div className="statsBigBadges__gridItem">
|
||||||
<span>{__('Bandi gestiti', 'gepafin')}</span>
|
<span>{__('Bandi gestiti', 'gepafin')}</span>
|
||||||
<span>{<NumberFlow
|
<span>{<NumberFlow
|
||||||
value={getStatValue('numberOfActiveCalls', 0)}
|
value={getStatValue('applicationsProcessed', 0)}
|
||||||
format={{ notation: 'compact' }}
|
format={{ notation: 'compact' }}
|
||||||
locales="it-IT"/>}</span>
|
locales="it-IT"/>}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="statsBigBadges__gridItem">
|
{/*<div className="statsBigBadges__gridItem">
|
||||||
<span>{__('Domande processate', 'gepafin')}</span>
|
<span>{__('Domande processate', 'gepafin')}</span>
|
||||||
<span>{<NumberFlow
|
<span>{<NumberFlow
|
||||||
value={getStatValue('numberOfActiveCalls', 0)}
|
value={getStatValue('numberOfActiveCalls', 0)}
|
||||||
format={{ notation: 'compact' }}
|
format={{ notation: 'compact' }}
|
||||||
locales="it-IT"/>}</span>
|
locales="it-IT"/>}</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>*/}
|
</div>*/}
|
||||||
</div>
|
</div>
|
||||||
|
</div> : null}
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
{!isEmpty(userActions)
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Filtri attività', 'gepafin')}</h2>
|
||||||
|
<div className="appPageSection columns">
|
||||||
|
<div className="row">
|
||||||
|
<label>{__('Periodo', 'gepafin')}</label>
|
||||||
|
<Dropdown
|
||||||
|
value={chosenPeriod}
|
||||||
|
onChange={(e) => setChosenPeriod(e.value)}
|
||||||
|
options={[
|
||||||
|
{ value: 'LAST_WEEK', label: __('Ultima settimana', 'gepafin') },
|
||||||
|
{ value: 'LAST_QUARTER', label: __('Ultimo trimestre', 'gepafin') },
|
||||||
|
{ value: 'LAST_SEMESTER', label: __('Ultimo semestre', 'gepafin') },
|
||||||
|
{ value: 'LAST_YEAR', label: __('Ultimo anno', 'gepafin') }
|
||||||
|
]}
|
||||||
|
optionLabel="label"/>
|
||||||
|
</div>
|
||||||
|
{!isEmpty(actionsContext)
|
||||||
|
? <div className="row">
|
||||||
|
<label>{__('Tipo di attività', 'gepafin')}</label>
|
||||||
|
<Dropdown
|
||||||
|
className="fullWidth"
|
||||||
|
value={chosenActivity}
|
||||||
|
onChange={(e) => setChosenActivity(e.value)}
|
||||||
|
options={actionsContext.map(o => ({
|
||||||
|
value: o.actionContext,
|
||||||
|
label: o.description
|
||||||
|
}))}
|
||||||
|
optionLabel="label"/>
|
||||||
|
</div> : null}
|
||||||
|
<div className="row">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={doFilterUserActivity}
|
||||||
|
label={__('Applica', 'gepafin')}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> : null}
|
||||||
|
|
||||||
|
<div className="appPage__spacer"></div>
|
||||||
|
|
||||||
|
{!isEmpty(userActions)
|
||||||
|
? <div className="appPageSection">
|
||||||
|
<h2>{__('Attività dettagliate', 'gepafin')}</h2>
|
||||||
|
<UserActivityTable data={userActions.userActions}/>
|
||||||
|
</div> : null}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ const AllUsersTable = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="appPageSection__table">
|
<div className="appPageSection__table">
|
||||||
<DataTable value={users} paginator showGridlines rows={10} loading={loading} dataKey="id"
|
<DataTable value={users} paginator showGridlines rows={5} loading={loading} dataKey="id"
|
||||||
filters={filters} stripedRows removableSort
|
filters={filters} stripedRows removableSort
|
||||||
header={header}
|
header={header}
|
||||||
emptyMessage={translationStrings.emptyMessage}
|
emptyMessage={translationStrings.emptyMessage}
|
||||||
|
|||||||
@@ -41,6 +41,16 @@ import DomandeInstructorManager from './pages/DomandeInstructorManager';
|
|||||||
import DomandaEditInstructorManager from './pages/DomandaEditInstructorManager';
|
import DomandaEditInstructorManager from './pages/DomandaEditInstructorManager';
|
||||||
import UserActivity from './pages/UserActivity';
|
import UserActivity from './pages/UserActivity';
|
||||||
import DomandeArchive from './pages/DomandeArchive';
|
import DomandeArchive from './pages/DomandeArchive';
|
||||||
|
import BandiPreInstructor from './pages/BandiPreInstructor';
|
||||||
|
import BandoViewPreInstructor from './pages/BandoViewPreInstructor';
|
||||||
|
import DomandeArchivePreInstructor from './pages/DomandeArchivePreInstructor';
|
||||||
|
import DashboardInstructorManager from './pages/DashboardInstructorManager';
|
||||||
|
import DomandeMieInstructorManager from './pages/DomandeMieInstructorManager';
|
||||||
|
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 }) => {
|
const routes = ({ role, chosenCompanyId }) => {
|
||||||
|
|
||||||
@@ -51,19 +61,19 @@ const routes = ({ role, chosenCompanyId }) => {
|
|||||||
{'ROLE_SUPER_ADMIN' === role ? <Dashboard/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <Dashboard/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <DashboardBeneficiario/> : null}
|
{'ROLE_BENEFICIARY' === role ? <DashboardBeneficiario/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <DashboardPreInstructor/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <DashboardPreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DashboardPreInstructor/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DashboardInstructorManager/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/bandi" element={<DefaultLayout>
|
<Route path="/bandi" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <Bandi/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <Bandi/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <BandiBeneficiario/> : null}
|
{'ROLE_BENEFICIARY' === role ? <BandiBeneficiario/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <BandiPreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandiPreInstructor/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/bandi/:id" element={<DefaultLayout>
|
<Route path="/bandi/:id" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <BandoEdit/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <BandoEdit/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <BandoViewBeneficiario/> : null}
|
{'ROLE_BENEFICIARY' === role ? <BandoViewBeneficiario/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <BandoViewPreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandoViewPreInstructor/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/bandi/:id/preview" element={<DefaultLayout>
|
<Route path="/bandi/:id/preview" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <BandoView/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <BandoView/> : null}
|
||||||
@@ -117,7 +127,7 @@ const routes = ({ role, chosenCompanyId }) => {
|
|||||||
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <SoccorsoEditBeneficiario/> : null}
|
{'ROLE_BENEFICIARY' === role ? <SoccorsoEditBeneficiario/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandaEditPreInstructor/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandaEditPreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandaEditInstructorManager/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandaEditPreInstructor/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/domande/:id/preview" element={<DefaultLayout>
|
<Route path="/domande/:id/preview" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
|
||||||
@@ -128,7 +138,7 @@ const routes = ({ role, chosenCompanyId }) => {
|
|||||||
<Route path="/domande-archivio" element={<DefaultLayout>
|
<Route path="/domande-archivio" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <DomandeArchive/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <DomandeArchive/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandeArchive/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandeArchivePreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeArchive/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeArchive/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/domande-archivio/:id/preview" element={<DefaultLayout>
|
<Route path="/domande-archivio/:id/preview" element={<DefaultLayout>
|
||||||
@@ -141,7 +151,7 @@ const routes = ({ role, chosenCompanyId }) => {
|
|||||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoAddPreInstructor/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoAddPreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoAddPreInstructor/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/domande/:id/soccorso/:amendmentId" element={<DefaultLayout>
|
<Route path="/domande/:id/soccorso/:amendmentId" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
@@ -153,7 +163,37 @@ const routes = ({ role, chosenCompanyId }) => {
|
|||||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoIstruttorioInstructorManager/> : null}
|
||||||
|
</DefaultLayout>}/>
|
||||||
|
<Route path="/mie-domande" element={<DefaultLayout>
|
||||||
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeMieInstructorManager/> : null}
|
||||||
|
</DefaultLayout>}/>
|
||||||
|
<Route path="/mie-domande/:id/" element={<DefaultLayout>
|
||||||
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandaEditInstructorManager/> : null}
|
||||||
|
</DefaultLayout>}/>
|
||||||
|
<Route path="/mie-domande/:id/aggiungi-soccorso" element={<DefaultLayout>
|
||||||
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoAddInstructorManager/> : null}
|
||||||
|
</DefaultLayout>}/>
|
||||||
|
<Route path="/mie-domande/:id/soccorso/:amendmentId" element={<DefaultLayout>
|
||||||
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoEditInstructorManager/> : null}
|
||||||
|
</DefaultLayout>}/>
|
||||||
|
<Route path="/mio-soccorso-istruttorio/" element={<DefaultLayout>
|
||||||
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoIstruttorioMioInstructorManager/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
<Route path="/imieibandi" element={<DefaultLayout>
|
<Route path="/imieibandi" element={<DefaultLayout>
|
||||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
@@ -197,6 +237,12 @@ const routes = ({ role, chosenCompanyId }) => {
|
|||||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||||
</DefaultLayout>}/>
|
</DefaultLayout>}/>
|
||||||
|
<Route path="/stats" element={<DefaultLayout>
|
||||||
|
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_BENEFICIARY' === role ? <StatsBeneficiary/> : null}
|
||||||
|
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||||
|
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||||
|
</DefaultLayout>}/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path="/reset-password" element={<ResetPassword/>}/>
|
<Route exact path="/reset-password" element={<ResetPassword/>}/>
|
||||||
<Route exact path="/login" element={<Login/>}/>
|
<Route exact path="/login" element={<Login/>}/>
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ export default class AmendmentsService {
|
|||||||
NetworkService.get(`${API_BASE_URL}/amendments`, callback, errCallback, queryParams);
|
NetworkService.get(`${API_BASE_URL}/amendments`, callback, errCallback, queryParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
static getSoccorsoByPreInstructorId = (id, callback, errCallback, queryParams) => {
|
static getSoccorsi = (callback, errCallback, queryParams) => {
|
||||||
NetworkService.get(`${API_BASE_URL}/amendments/user/${id}`, callback, errCallback, queryParams);
|
NetworkService.get(`${API_BASE_URL}/amendments/user`, callback, errCallback, queryParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
static createSoccorso = (body, callback, errCallback, queryParams) => {
|
static createSoccorso = (body, callback, errCallback, queryParams) => {
|
||||||
|
|||||||
@@ -8,7 +8,21 @@ export default class ApplicationEvaluationService {
|
|||||||
NetworkService.get(`${API_BASE_URL}/applicationEvaluation/application`, callback, errCallback, queryParams);
|
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) => {
|
static updateEvaluation = (assignedApplicationId, body, callback, errCallback, queryParams) => {
|
||||||
NetworkService.put(`${API_BASE_URL}/applicationEvaluation/${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]
|
||||||
|
]);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user