- merged with develop;
This commit is contained in:
3
.env
3
.env
@@ -1,8 +1,9 @@
|
||||
REACT_APP_TAB_TITLE=Gepafin
|
||||
REACT_APP_API_EXECUTION_ADDRESS=https://api-dev-gepafin.memento.credit/v1
|
||||
REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit
|
||||
REACT_APP_API_ADDRESS_WS=https://api-dev-gepafin.memento.credit/wss
|
||||
REACT_APP_LOGO_FILENAME=gepafin-logo.svg
|
||||
REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico
|
||||
REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs
|
||||
REACT_APP_EVALUATION_FLOW_ID=1
|
||||
REACT_APP_LOCAL_DEVELOPMENT=1
|
||||
REACT_APP_LOCAL_DEVELOPMENT=1
|
||||
|
||||
@@ -5,3 +5,7 @@ Gepafin Front End
|
||||
`npm run start` - start development server
|
||||
`npm run build:dev` - make build based on 'dev' env variables
|
||||
`npm run build:prod` - make build based on 'prod' env variables
|
||||
|
||||
# HUB IDs
|
||||
`p4lk3bcx1RStqTaIVVbXs` - gepafin
|
||||
`t7jh5wfg9QXylNaTZkPoE` - sviluppumbria
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
REACT_APP_TAB_TITLE=Gepafin
|
||||
REACT_APP_API_EXECUTION_ADDRESS=https://api-dev-gepafin.memento.credit/v1
|
||||
REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit
|
||||
REACT_APP_API_ADDRESS_WS=https://api-dev-gepafin.memento.credit/wss
|
||||
REACT_APP_LOGO_FILENAME=gepafin-logo.svg
|
||||
REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico
|
||||
REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs
|
||||
REACT_APP_EVALUATION_FLOW_ID=1
|
||||
REACT_APP_EVALUATION_FLOW_ID=1
|
||||
REACT_APP_LOCAL_DEVELOPMENT=0
|
||||
@@ -4,4 +4,5 @@ REACT_APP_API_ADDRESS=https://bandi-api.gepafin.it
|
||||
REACT_APP_LOGO_FILENAME=gepafin-logo.svg
|
||||
REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico
|
||||
REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs
|
||||
REACT_APP_EVALUATION_FLOW_ID=1
|
||||
REACT_APP_EVALUATION_FLOW_ID=1
|
||||
REACT_APP_LOCAL_DEVELOPMENT=0
|
||||
@@ -9,7 +9,8 @@
|
||||
"@emailjs/browser": "4.4.1",
|
||||
"@emotion/styled": "11.13.5",
|
||||
"@number-flow/react": "0.4.2",
|
||||
"@sentry/browser": "^8.41.0",
|
||||
"@sentry/browser": "^8.42.0",
|
||||
"@stomp/stompjs": "^7.0.0",
|
||||
"@tanstack/react-table": "^8.20.5",
|
||||
"@wordpress/i18n": "5.13.0",
|
||||
"@wordpress/react-i18n": "4.13.0",
|
||||
@@ -36,6 +37,7 @@
|
||||
"react-hook-form": "7.53.2",
|
||||
"react-router-dom": "7.0.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"sockjs-client": "^1.6.1",
|
||||
"validate.js": "0.13.1",
|
||||
"zustand": "4.5.4",
|
||||
"zustand-x": "3.0.4"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
|
||||
.appPageLogin__wrapper {
|
||||
h1 {
|
||||
text-align: center;
|
||||
@@ -43,6 +43,10 @@
|
||||
margin-left: 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
span.companyName {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.appPage__spacer {
|
||||
@@ -85,6 +89,7 @@
|
||||
}
|
||||
|
||||
.appPageSection {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
@@ -95,7 +100,7 @@
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
width: 100%;
|
||||
|
||||
|
||||
/*> div {
|
||||
max-width: 50%;
|
||||
}*/
|
||||
@@ -126,7 +131,7 @@
|
||||
padding: 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -184,7 +189,7 @@
|
||||
|
||||
ul, ol {
|
||||
padding-left: 1rem;
|
||||
|
||||
|
||||
li {
|
||||
color: var(--global-textColor);
|
||||
}
|
||||
@@ -213,7 +218,8 @@
|
||||
|
||||
.appPageSection__pMeta {
|
||||
margin-bottom: 1em;
|
||||
|
||||
break-inside: avoid;
|
||||
|
||||
span:nth-of-type(1) {
|
||||
max-width: 30%;
|
||||
}
|
||||
@@ -258,8 +264,8 @@
|
||||
.appPageSection__checklist {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
gap: 1.2rem;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
@@ -290,11 +296,11 @@
|
||||
color: var(--message-info-color);
|
||||
border-color: var(--message-info-color);
|
||||
}
|
||||
|
||||
|
||||
.summary {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
@@ -397,7 +403,7 @@
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
|
||||
&.lessGap {
|
||||
gap: 12px;
|
||||
}
|
||||
@@ -414,7 +420,7 @@
|
||||
background-color: transparent;
|
||||
color: var(--global-textColor);
|
||||
padding: 0;
|
||||
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: var(--message-info-color);
|
||||
@@ -430,10 +436,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.appPageSection__emailTemplate {
|
||||
> div {
|
||||
max-width: 100%!important;
|
||||
> div {
|
||||
max-width: 100%!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.appPageSection {
|
||||
&.columns {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
src/assets/scss/components/fieldsRepeater.scss
Normal file
45
src/assets/scss/components/fieldsRepeater.scss
Normal file
@@ -0,0 +1,45 @@
|
||||
.fieldsRepeater {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fieldsRepeater form {
|
||||
display: contents;
|
||||
|
||||
}
|
||||
|
||||
.fieldsRepeater__panel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fieldsRepeater__heading {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> span {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: var(--menuitem-active-background);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-hide="true"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.fieldsRepeater__fields {
|
||||
&[data-hide="true"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.fieldsRepeater__addNew {
|
||||
}
|
||||
55
src/assets/scss/components/notificationsSidebar.scss
Normal file
55
src/assets/scss/components/notificationsSidebar.scss
Normal file
@@ -0,0 +1,55 @@
|
||||
.notificationsIcon {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.notificationsSidebar {
|
||||
max-width: 360px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.notificationsSidebar__loading {
|
||||
padding: 30px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.notificationsSidebar__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.notificationsSidebar__listItem {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #e7e7e7;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: var(--primary-text);
|
||||
}
|
||||
}
|
||||
|
||||
.notificationsSidebar__listItemContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.notificationsSidebar__listItemChosen {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 5px;
|
||||
}
|
||||
@@ -5,11 +5,15 @@
|
||||
display: grid;
|
||||
align-items: stretch;
|
||||
/*grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));*/
|
||||
grid-template-columns: repeat(2, minmax(220px,1fr));
|
||||
grid-template-columns: repeat(2, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
container-name: big-badges-grid;
|
||||
container-type: inline-size;
|
||||
|
||||
&.grid-small {
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.statsBigBadges__grid .statsBigBadges__gridItem span {
|
||||
|
||||
@@ -44,4 +44,6 @@
|
||||
@import "./components/flowBuilder.scss";
|
||||
@import "./components/error404.scss";
|
||||
@import "./components/myTable.scss";
|
||||
@import "./components/evaluation.scss";
|
||||
@import "./components/evaluation.scss";
|
||||
@import "./components/fieldsRepeater.scss";
|
||||
@import "./components/notificationsSidebar.scss";
|
||||
|
||||
@@ -38,7 +38,8 @@ const Fileupload = ({
|
||||
source = 'application',
|
||||
disabled = false,
|
||||
saveFormCallback = () => {
|
||||
}
|
||||
},
|
||||
deleteOnBackend = true
|
||||
}) => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [stateFieldData, setStateFieldData] = useState([]);
|
||||
@@ -97,7 +98,7 @@ const Fileupload = ({
|
||||
};
|
||||
|
||||
const onTemplateRemove = (file) => {
|
||||
if (file.id) {
|
||||
if (file.id && deleteOnBackend) {
|
||||
FileUploadService.deleteFile(
|
||||
{},
|
||||
(data) => deleteCallback(data, file.id),
|
||||
@@ -108,6 +109,11 @@ const Fileupload = ({
|
||||
const files = inputRef.current.getFiles()
|
||||
const newFiles = files.filter(o => o.lastModified !== file.lastModified && o.name !== file.name);
|
||||
inputRef.current.setFiles(newFiles);
|
||||
if (file.id) {
|
||||
const uploadedFiles = inputRef.current.getUploadedFiles();
|
||||
const newUploadedFiles = uploadedFiles.filter(o => o.id !== file.id);
|
||||
inputRef.current.setUploadedFiles(newUploadedFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
|
||||
const RenderTable = ({ data, columns, setRowsFn }) => {
|
||||
const RenderTable = ({ data, columns, setRowsFn, disabled }) => {
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
@@ -16,6 +16,7 @@ const RenderTable = ({ data, columns, setRowsFn }) => {
|
||||
|
||||
return (
|
||||
<input
|
||||
disabled={disabled}
|
||||
value={initialValue ? initialValue : ''}
|
||||
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)}
|
||||
onBlur={onBlur}
|
||||
|
||||
@@ -17,6 +17,7 @@ const Table = ({
|
||||
label,
|
||||
register,
|
||||
errors,
|
||||
disabled = false,
|
||||
config = {},
|
||||
defaultValue = [],
|
||||
tableColumns = []
|
||||
@@ -29,6 +30,9 @@ const Table = ({
|
||||
const [rowIndexToDelete, rowRowIndexToDelete] = useState(null);
|
||||
|
||||
const addNewRow = () => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
const obj = columnsCfg
|
||||
.reduce((acc, cur) => {
|
||||
acc[cur.name] = ''
|
||||
@@ -94,6 +98,7 @@ const Table = ({
|
||||
header: () => '',
|
||||
footer: (props) => props.column.id,
|
||||
cell: ({row: { index }}) => <Button
|
||||
disabled={disabled}
|
||||
type="button"
|
||||
icon="pi pi-times"
|
||||
className="p-button-danger"
|
||||
@@ -139,9 +144,11 @@ const Table = ({
|
||||
{label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
|
||||
? <span className="appForm__field--required">*</span> : null}
|
||||
</label>
|
||||
{rows ? <RenderTable columns={columns} data={rows} setRowsFn={updateRows}/> : null}
|
||||
{rows ? <RenderTable columns={columns} data={rows} setRowsFn={updateRows} disabled={disabled}/> : null}
|
||||
{!isEmpty(columns) && !shouldDisableNewRows
|
||||
? <div className="addNewTableRow" onClick={addNewRow}>{__('Aggiungi una riga', 'gepafin')}</div>
|
||||
? <div className="addNewTableRow" onClick={addNewRow}>
|
||||
{__('Aggiungi una riga', 'gepafin')}
|
||||
</div>
|
||||
: null}
|
||||
</>)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
|
||||
|
||||
const NotificationItem = ({ item, clickFn }) => {
|
||||
const handleClick = () => {
|
||||
clickFn(item.id);
|
||||
}
|
||||
|
||||
return (
|
||||
<li className="notificationsSidebar__listItem" onClick={handleClick}>
|
||||
<div className="notificationsSidebar__listItemContent">
|
||||
{item.status === 'READ'
|
||||
? <p>{item.title}</p>
|
||||
: <strong>{item.title}</strong>}
|
||||
<span>{getDateFromISOstring(item.createdDate)}</span>
|
||||
</div>
|
||||
<i className="pi pi-angle-right"></i>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationItem;
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Button } from 'primereact/button';
|
||||
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
|
||||
|
||||
const NotificationItemChosen = ({ item, closeFn, markReadFn }) => {
|
||||
return (
|
||||
<div className="notificationsSidebar__listItemChosen">
|
||||
<Button
|
||||
style={{marginBottom: '20px'}}
|
||||
type="button"
|
||||
outlined
|
||||
onClick={closeFn}
|
||||
label={__('Indietro', 'gepafin')}
|
||||
icon="pi pi-arrow-left" iconPos="left"/>
|
||||
<strong>{item.title}</strong>
|
||||
<span>{getDateFromISOstring(item.createdDate)}</span>
|
||||
{item.message}
|
||||
|
||||
<Button
|
||||
style={{marginTop: '20px'}}
|
||||
type="button"
|
||||
outlined
|
||||
onClick={() => markReadFn(item.id)}
|
||||
label={__('Letto', 'gepafin')}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationItemChosen;
|
||||
277
src/components/NotificationsSidebar/index.js
Normal file
277
src/components/NotificationsSidebar/index.js
Normal file
@@ -0,0 +1,277 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { head, isEmpty, pathOr } from 'ramda';
|
||||
import SockJS from 'sockjs-client';
|
||||
import { Stomp } from '@stomp/stompjs';
|
||||
|
||||
// store
|
||||
import { storeGet, useStore } from '../../store';
|
||||
|
||||
// api
|
||||
import NotificationService from '../../service/notification-service';
|
||||
|
||||
// tools
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
|
||||
// components
|
||||
import { Badge } from 'primereact/badge';
|
||||
import { Sidebar } from 'primereact/sidebar';
|
||||
import { TabPanel, TabView } from 'primereact/tabview';
|
||||
import NotificationItem from './components/NotificationItem';
|
||||
import NotificationItemChosen from './components/NotificationItemChosen';
|
||||
|
||||
const socketUrl = process.env.REACT_APP_API_ADDRESS_WS;
|
||||
|
||||
const NotificationsSidebar = () => {
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const userData = useStore().main.userData();
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [notificationsVisible, setNotificationsVisible] = useState(false);
|
||||
const [notifications, setNotifications] = useState([]);
|
||||
const [notificationsRead, setNotificationsRead] = useState([]);
|
||||
const [chosenMsg, setChosenMsg] = useState({});
|
||||
const socket = useRef(null);
|
||||
const stomp = useRef(null);
|
||||
const [currentSubscription, setCurrentSubscription] = useState(null);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
|
||||
// Handle tab change
|
||||
const handleTabChange = (e) => {
|
||||
setActiveIndex(e.index);
|
||||
fetchTabData(e.index);
|
||||
};
|
||||
|
||||
const fetchTabData = (index) => {
|
||||
setChosenMsg({});
|
||||
|
||||
if (0 === index) {
|
||||
fetchMessages();
|
||||
} else {
|
||||
fetchMessages('READ');
|
||||
}
|
||||
}
|
||||
|
||||
const chooseNotification = (id) => {
|
||||
const properItems = activeIndex === 0 ? notifications : notificationsRead;
|
||||
const chosen = head(properItems.filter(o => o.id === id));
|
||||
if (chosen) {
|
||||
setChosenMsg(chosen);
|
||||
}
|
||||
}
|
||||
|
||||
const closeChosenMsg = () => {
|
||||
setChosenMsg({});
|
||||
}
|
||||
|
||||
const fetchMessages = (status = 'UNREAD') => {
|
||||
const chosenCompanyId = storeGet.main.chosenCompanyId();
|
||||
const userData = storeGet.main.userData();
|
||||
const role = pathOr('', ['role', 'roleType'], userData);
|
||||
|
||||
if (currentSubscription) {
|
||||
//console.log('UNsubscribed')
|
||||
currentSubscription.unsubscribe();
|
||||
setCurrentSubscription(null);
|
||||
}
|
||||
|
||||
if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') {
|
||||
setLoading(true);
|
||||
NotificationService.getNotifications(
|
||||
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,
|
||||
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
||||
errGetNotifications,
|
||||
[
|
||||
['status', status]
|
||||
]
|
||||
);
|
||||
if (isConnected && socket.current) {
|
||||
subscribeTo(`/topic/notifications_user_${userData.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getNotifications = (resp) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
setNotifications(resp.data);
|
||||
}
|
||||
set404FromErrorResponse(resp);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const getNotificationsRead = (resp) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
setNotificationsRead(resp.data);
|
||||
}
|
||||
set404FromErrorResponse(resp);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errGetNotifications = (resp) => {
|
||||
set404FromErrorResponse(resp);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const makeNotificationRead = (id) => {
|
||||
NotificationService.notificationMakeRead(id, makeReadCallback, makeReadErrorCallback)
|
||||
}
|
||||
|
||||
const makeReadCallback = (resp) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
if (0 === activeIndex) {
|
||||
const msgs = notifications.map(o => o.id === resp.data.id ? resp.data : o);
|
||||
setNotifications(msgs);
|
||||
} else {
|
||||
const msgs = notificationsRead.map(o => o.id === resp.data.id ? resp.data : o);
|
||||
setNotificationsRead(msgs);
|
||||
}
|
||||
}
|
||||
set404FromErrorResponse(resp);
|
||||
}
|
||||
|
||||
const makeReadErrorCallback = (resp) => {
|
||||
set404FromErrorResponse(resp);
|
||||
}
|
||||
|
||||
const connectWebSocket = () => {
|
||||
socket.current = new SockJS(socketUrl);
|
||||
stomp.current = Stomp.over(socket.current);
|
||||
|
||||
stomp.current.configure({
|
||||
debug: function(str) {
|
||||
//console.log(str);
|
||||
},
|
||||
reconnectDelay: 5000,
|
||||
heartbeatIncoming: 20000,
|
||||
heartbeatOutgoing: 20000
|
||||
});
|
||||
|
||||
stomp.current.connect(
|
||||
{},
|
||||
() => {
|
||||
//console.log('Websocket connected');
|
||||
setIsConnected(true);
|
||||
},
|
||||
(error) => {
|
||||
//console.error('WebSocket Connection Error:', error);
|
||||
setIsConnected(false);
|
||||
setTimeout(connectWebSocket, 5000);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const subscribeTo = (topic) => {
|
||||
const subscription = stomp.current.subscribe(
|
||||
topic,
|
||||
(message) => {
|
||||
try {
|
||||
const notification = JSON.parse(message.body);
|
||||
setNotifications(prev => [notification, ...prev]);
|
||||
} catch (error) {
|
||||
console.error('Error parsing notification:', error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
setCurrentSubscription(subscription);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchMessages();
|
||||
}, [chosenCompanyId, userData.id, isConnected]);
|
||||
|
||||
useEffect(() => {
|
||||
connectWebSocket();
|
||||
|
||||
return () => {
|
||||
if (currentSubscription) {
|
||||
currentSubscription.unsubscribe();
|
||||
setCurrentSubscription(null);
|
||||
}
|
||||
|
||||
if (stomp.current) {
|
||||
stomp.current.disconnect(() => {
|
||||
//console.log('WebSocket Disconnected');
|
||||
});
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon"
|
||||
onClick={() => setNotificationsVisible(true)}>
|
||||
<Badge value={notifications.length}></Badge>
|
||||
</i>
|
||||
<Sidebar
|
||||
className="notificationsSidebar"
|
||||
position="left"
|
||||
visible={notificationsVisible}
|
||||
onHide={() => setNotificationsVisible(false)}>
|
||||
<TabView activeIndex={activeIndex} onTabChange={handleTabChange}>
|
||||
<TabPanel header={__('Da leggere', 'gepafin')}>
|
||||
{loading
|
||||
? <div className="notificationsSidebar__loading">
|
||||
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
|
||||
</div>
|
||||
: !isEmpty(chosenMsg)
|
||||
? <NotificationItemChosen
|
||||
item={chosenMsg}
|
||||
closeFn={closeChosenMsg}
|
||||
markReadFn={makeNotificationRead}/>
|
||||
: (notifications.length > 0
|
||||
? <ul className="notificationsSidebar__list">
|
||||
{notifications.map(o => <NotificationItem
|
||||
key={o.id}
|
||||
item={o}
|
||||
clickFn={chooseNotification}/>)}
|
||||
</ul>
|
||||
: <div className="notificationsSidebar__loading">
|
||||
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
|
||||
{__('Vuoto', 'gepafin')}
|
||||
</div>)}
|
||||
</TabPanel>
|
||||
<TabPanel header={__('Letti', 'gepafin')}>
|
||||
{loading
|
||||
? <div className="notificationsSidebar__loading">
|
||||
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
|
||||
</div>
|
||||
: !isEmpty(chosenMsg)
|
||||
? <NotificationItemChosen
|
||||
item={chosenMsg}
|
||||
closeFn={closeChosenMsg}
|
||||
markReadFn={makeNotificationRead}/>
|
||||
: (notificationsRead.length > 0
|
||||
? <ul className="notificationsSidebar__list">
|
||||
{notificationsRead.map(o => <NotificationItem
|
||||
key={o.id}
|
||||
item={o}
|
||||
clickFn={chooseNotification}/>)}
|
||||
</ul>
|
||||
:
|
||||
<div className="notificationsSidebar__loading">
|
||||
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
|
||||
{__('Vuoto', 'gepafin')}
|
||||
</div>)}
|
||||
</TabPanel>
|
||||
</TabView>
|
||||
</Sidebar>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationsSidebar;
|
||||
@@ -67,87 +67,87 @@ export const protocolType = [
|
||||
|
||||
export const classificationType = [
|
||||
{
|
||||
'idClassificazione': 101,
|
||||
'idClassificazione': 1,
|
||||
'name': 'BILANCIO',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 102,
|
||||
'idClassificazione': 2,
|
||||
'name': 'DICHHIARAZIONE DEI REDDITI',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 103,
|
||||
'idClassificazione': 3,
|
||||
'name': 'SITUAZIONE CONTABILE',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 104,
|
||||
'idClassificazione': 4,
|
||||
'name': 'PROSPETTO CONTO ECONOMICO',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 105,
|
||||
'idClassificazione': 5,
|
||||
'name': 'CENTRALE DEI RISCHI',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 106,
|
||||
'idClassificazione': 6,
|
||||
'name': 'RELAZIONE AZIENDALE ILLUSTRATIVA (MOD R1C, R1I, R1R, R1R A SECONDO DEI ',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 107,
|
||||
'idClassificazione': 7,
|
||||
'name': 'DOCUMENTO IDENTITA\'',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 108,
|
||||
'idClassificazione': 8,
|
||||
'name': 'MODELLO SP1',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 109,
|
||||
'idClassificazione': 9,
|
||||
'name': 'PRIVACY',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 110,
|
||||
'idClassificazione': 10,
|
||||
'name': 'DOCUMENTAZIONE CHE ATTESTA POSSIBILITA\' DI RILASCIARE GAA FAVORE',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 111,
|
||||
'idClassificazione': 11,
|
||||
'name': 'MODELLO AR1 D.LG 231/2007',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 112,
|
||||
'idClassificazione': 12,
|
||||
'name': 'DOCUMENTO IDENTITA\' FIRMATORIO DICHHIARAZIONE SOSTITUTIVA',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 113,
|
||||
'idClassificazione': 13,
|
||||
'name': 'PRIVACY FIRMATARIO DICHHIARAZIONE SOSTITUTIVA',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 114,
|
||||
'idClassificazione': 14,
|
||||
'name': 'NULLAOSTA ANTIMAFIA',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 201,
|
||||
'idClassificazione': 1,
|
||||
'name': 'LETTERA ESITO DELIBERA',
|
||||
'idTipoprotocollo': 2
|
||||
},
|
||||
{
|
||||
'idClassificazione': 202,
|
||||
'idClassificazione': 2,
|
||||
'name': 'LETTERA DI GARANZIA',
|
||||
'idTipoprotocollo': 1
|
||||
},
|
||||
{
|
||||
'idClassificazione': 203,
|
||||
'idClassificazione': 3,
|
||||
'name': 'GENERICO',
|
||||
'idTipoprotocollo': 3
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ const getBandoLabel = (status) => {
|
||||
case 'ADMISSIBLE':
|
||||
return __('Ammisibile', 'gepafin');
|
||||
|
||||
case 'RESPONSE_RECEIVED':
|
||||
return __('Riposta ricevuta', 'gepafin');
|
||||
|
||||
case 'SOCCORSO':
|
||||
return __('Soccorso', 'gepafin');
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ const getBandoSeverity = (status) => {
|
||||
case 'ADMISSIBLE':
|
||||
return 'info';
|
||||
|
||||
case 'RESPONSE_RECEIVED':
|
||||
return 'warning';
|
||||
|
||||
case 'SOCCORSO':
|
||||
return 'warning';
|
||||
|
||||
|
||||
28
src/helpers/getStrippedHtmlBodyTags.js
Normal file
28
src/helpers/getStrippedHtmlBodyTags.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import parse from 'html-react-parser';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
const getEmailTemplateForSoccorso = (content = '', fallback = '') => {
|
||||
const config = {
|
||||
FORBID_TAGS: ['html', 'body'],
|
||||
WHOLE_DOCUMENT: false,
|
||||
RETURN_DOM: false,
|
||||
RETURN_DOM_FRAGMENT: false,
|
||||
RETURN_DOM_IMPORT: false,
|
||||
FORCE_BODY: false,
|
||||
ADD_TAGS: ['*'],
|
||||
ADD_ATTR: ['*']
|
||||
};
|
||||
try {
|
||||
const wrappedHtml = `<div>${content}</div>`;
|
||||
const cleaned = DOMPurify.sanitize(wrappedHtml, config);
|
||||
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.innerHTML = cleaned;
|
||||
return parse(tempDiv.innerHTML);
|
||||
} catch (error) {
|
||||
console.error('DOMPurify cleaning error:', error);
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
export default getEmailTemplateForSoccorso;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { storeSet } from '../store';
|
||||
//import { storeSet } from '../store';
|
||||
|
||||
const set404FromErrorResponse = (data) => {
|
||||
if (data && data.status === 'NOT_FOUND') {
|
||||
|
||||
@@ -8,9 +8,9 @@ import LogoIcon from '../../../../icons/LogoIcon';
|
||||
import { IconField } from 'primereact/iconfield';
|
||||
import { InputIcon } from 'primereact/inputicon';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import { Badge } from 'primereact/badge';
|
||||
import { Button } from 'primereact/button';
|
||||
import TopBarProfileMenu from '../../../../components/TopBarProfileMenu';
|
||||
import NotificationsSidebar from '../../../../components/NotificationsSidebar';
|
||||
|
||||
const AppTopbar = () => {
|
||||
const menuLeft = useRef(null);
|
||||
@@ -24,14 +24,13 @@ const AppTopbar = () => {
|
||||
<InputIcon className="pi pi-search"> </InputIcon>
|
||||
<InputText v-model="value1" placeholder={__('Cerca', 'gepafin')} disabled={true}/>
|
||||
</IconField>
|
||||
<i className="pi pi-bell p-overlay-badge topBar__icon">
|
||||
<Badge value="0"></Badge>
|
||||
</i>
|
||||
<NotificationsSidebar/>
|
||||
<i className="pi pi-envelope topBar__icon"></i>
|
||||
{/*<i className="pi pi-envelope p-overlay-badge topBar__icon">
|
||||
<Badge severity="danger"></Badge>
|
||||
</i>*/}
|
||||
<Button
|
||||
type="button"
|
||||
className="topBar__profileBtn"
|
||||
outlined
|
||||
onClick={(event) => menuLeft.current.toggle(event)} aria-controls="topBar_profileMenu" aria-haspopup>
|
||||
@@ -46,4 +45,4 @@ const AppTopbar = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default AppTopbar;
|
||||
export default AppTopbar;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { isEmpty, head } from 'ramda';
|
||||
import { klona } from 'klona';
|
||||
@@ -29,6 +29,7 @@ const AddCompany = () => {
|
||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||
const infoMsgs = useRef(null);
|
||||
const [, debouncedPivaValue, setInputPiva] = useDebounce('', 1000);
|
||||
const [vatCheckResponse, setVatCheckResponse] = useState({});
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -54,14 +55,19 @@ const AddCompany = () => {
|
||||
address: '',
|
||||
companyName: ''
|
||||
}
|
||||
setVatCheckResponse({});
|
||||
Object.keys(formData).map(k => setValue(k, formData[k]));
|
||||
}
|
||||
|
||||
const onSubmit = (formData) => {
|
||||
infoMsgs.current.clear();
|
||||
storeSet.main.setAsyncRequest();
|
||||
const submitData = {
|
||||
...formData,
|
||||
vatCheckResponse
|
||||
}
|
||||
|
||||
CompanyService.createCompany(formData, updateCallback, updateError);
|
||||
CompanyService.createCompany(submitData, updateCallback, updateError);
|
||||
};
|
||||
|
||||
const updateCallback = (data) => {
|
||||
@@ -109,7 +115,7 @@ const AddCompany = () => {
|
||||
|
||||
const checkVatCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
const resp = data.data.data;
|
||||
const resp = data.data.vatCheckResponse.data;
|
||||
if (!isEmpty(resp)) {
|
||||
const {
|
||||
cap, cf, denominazione, piva, indirizzo, comune, dettaglio: { pec }
|
||||
@@ -126,6 +132,7 @@ const AddCompany = () => {
|
||||
companyName: denominazione
|
||||
}
|
||||
Object.keys(formData).map(k => setValue(k, formData[k]));
|
||||
setVatCheckResponse(data.data.vatCheckResponse);
|
||||
}
|
||||
//setData(getFormattedBandiData(data.data));
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { head } from 'ramda';
|
||||
|
||||
// store
|
||||
import { useStore } from '../../store';
|
||||
|
||||
// components
|
||||
import MyLatestSubmissionsTable from '../DashboardBeneficiario/components/MyLatestSubmissionsTable';
|
||||
@@ -9,6 +13,9 @@ import ErrorBoundary from '../../components/ErrorBoundary';
|
||||
|
||||
const Applications = () => {
|
||||
const navigate = useNavigate();
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const companies = useStore().main.companies();
|
||||
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
||||
|
||||
const gotToBandiDisponibili = () => {
|
||||
navigate('/bandi')
|
||||
@@ -18,6 +25,7 @@ const Applications = () => {
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Domande in Lavorazione', 'gepafin')}</h1>
|
||||
{company ? <span className="companyName">{company.companyName}</span> : null}
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
@@ -97,7 +97,14 @@ const AllBandiTable = () => {
|
||||
};
|
||||
|
||||
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={statuses}
|
||||
onChange={(e) => options.filterCallback(e.value, options.index)}
|
||||
itemTemplate={statusItemTemplate}
|
||||
placeholder={translationStrings.selectOneLabel}
|
||||
className="p-column-filter"
|
||||
showClear />;
|
||||
};
|
||||
|
||||
const statusItemTemplate = (option) => {
|
||||
@@ -139,4 +146,4 @@ const AllBandiTable = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default AllBandiTable;
|
||||
export default AllBandiTable;
|
||||
|
||||
@@ -30,6 +30,8 @@ import { Button } from 'primereact/button';
|
||||
// i18n
|
||||
import translationStrings from '../../../../translationStringsForComponents';
|
||||
|
||||
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||
|
||||
const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||
@@ -182,11 +184,13 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
|
||||
<div className="p-3">
|
||||
{renderHtmlContent(data.descriptionShort)}
|
||||
<p>{__('Scadenza', 'gepafin')}: {getDateFromISOstring(data.dates[1])}</p>
|
||||
{!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && !data.confidi
|
||||
{!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && (!data.confidi
|
||||
|| (data.confidi && data.id === 6 && REACT_APP_HUB_ID === 'p4lk3bcx1RStqTaIVVbXs'))
|
||||
? <Button onClick={() => goToBandoPage(data.id)} severity="info">
|
||||
{__('Partecipa', 'gepafin')}
|
||||
</Button> : null}
|
||||
{!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && data.confidi
|
||||
&& (data.id !== 6 || (data.id === 6 && REACT_APP_HUB_ID !== 'p4lk3bcx1RStqTaIVVbXs'))
|
||||
? <Button onClick={() => goToBandoPage(data.id)} severity="info">
|
||||
{__('Mostra', 'gepafin')}
|
||||
</Button> : null}
|
||||
@@ -229,4 +233,4 @@ const AllBandiAccordion = ({ showOnlyPreferred = false }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default AllBandiAccordion;
|
||||
export default AllBandiAccordion;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { isEmpty } from 'ramda';
|
||||
import { head, isEmpty } from 'ramda';
|
||||
|
||||
// store
|
||||
import { useStore } from '../../store';
|
||||
@@ -12,11 +12,14 @@ import ErrorBoundary from '../../components/ErrorBoundary';
|
||||
|
||||
const BandiBeneficiario = () => {
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const companies = useStore().main.companies();
|
||||
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
||||
|
||||
return (
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Bandi disponibili', 'gepafin')}</h1>
|
||||
{company ? <span className="companyName">{company.companyName}</span> : null}
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { isEmpty } from 'ramda';
|
||||
import { head, isEmpty } from 'ramda';
|
||||
|
||||
// store
|
||||
import { useStore } from '../../store';
|
||||
@@ -11,11 +11,14 @@ import AllBandiAccordion from '../BandiBeneficiario/components/AllBandiAccordion
|
||||
|
||||
const BandiPreferredBeneficiario = () => {
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const companies = useStore().main.companies();
|
||||
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
||||
|
||||
return (
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Bandi osservati', 'gepafin')}</h1>
|
||||
{company ? <span className="companyName">{company.companyName}</span> : null}
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
@@ -86,8 +86,8 @@ const BandoApplicationPreview = () => {
|
||||
ApplicationService.validateApplication(applId, {}, validateApplicationCallback, errValidateApplicationCallback);
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
};
|
||||
/*const onSubmit = () => {
|
||||
};*/
|
||||
|
||||
const validateApplicationCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
@@ -155,31 +155,6 @@ const BandoApplicationPreview = () => {
|
||||
user: {}
|
||||
};
|
||||
|
||||
/*if (company) {
|
||||
dynamicData = Object.keys(company).reduce((acc, cur) => {
|
||||
if ([
|
||||
'companyName', 'vatNumber', 'codiceFiscale', 'address', 'phoneNumber',
|
||||
'city', 'province', 'cap', 'country', 'pec', 'email', 'contactName', 'contactEmail'
|
||||
].includes(cur)) {
|
||||
acc.company[cur] = company[cur];
|
||||
}
|
||||
return acc;
|
||||
}, dynamicData);
|
||||
}
|
||||
|
||||
const userData = storeGet.main.userData();
|
||||
Object.keys(userData).reduce((acc, cur) => {
|
||||
if ([
|
||||
'email', 'firstName', 'lastName', 'phoneNumber', 'codiceFiscale'
|
||||
].includes(cur)) {
|
||||
acc.user[cur] = userData[cur];
|
||||
}
|
||||
if (['dateOfBirth'].includes(cur)) {
|
||||
acc.user[cur] = new Date(userData[cur]);
|
||||
}
|
||||
return acc;
|
||||
}, dynamicData);*/
|
||||
|
||||
if (data.data.applicationFormResponse.content) {
|
||||
// eslint-disable-next-line array-callback-return
|
||||
data.data.applicationFormResponse.content.map((o) => {
|
||||
@@ -252,33 +227,25 @@ const BandoApplicationPreview = () => {
|
||||
{activeStep > 1 && activeStep <= totalSteps
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={'SUBMIT' === applicationStatus}
|
||||
onClick={goBackward}
|
||||
label={__('Vai indietro', 'gepafin')}
|
||||
icon="pi pi-arrow-left"
|
||||
iconPos="left"/> : null}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={isAsyncRequest || 'SUBMIT' === applicationStatus}
|
||||
disabled={isAsyncRequest}
|
||||
onClick={saveDraft}
|
||||
outlined
|
||||
label={__('Controlla', 'gepafin')} icon="pi pi-verified" iconPos="right"/>
|
||||
{activeStep < totalSteps
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={'SUBMIT' === applicationStatus}
|
||||
onClick={goForward}
|
||||
label={__('Vai avanti', 'gepafin')}
|
||||
icon="pi pi-arrow-right"
|
||||
iconPos="right"/> : null}
|
||||
{/*<Button
|
||||
disabled={'SUBMIT' === applicationStatus}
|
||||
label={__('Convalidare', 'gepafin')}
|
||||
icon="pi pi-check"
|
||||
iconPos="right"/>*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={'SUBMIT' === applicationStatus}
|
||||
onClick={onDownloadApplicationPdf}
|
||||
label={__('Scarica PDF', 'gepafin')}
|
||||
icon="pi pi-download"
|
||||
@@ -373,7 +340,7 @@ const BandoApplicationPreview = () => {
|
||||
: <FormField
|
||||
key={o.id}
|
||||
type={o.name}
|
||||
disabled={o.name === 'fileupload'}
|
||||
disabled={o.name === 'fileupload' || 'DRAFT' !== applicationStatus}
|
||||
fieldName={o.id}
|
||||
label={label ? label.value : ''}
|
||||
placeholder={placeholder ? placeholder.value : ''}
|
||||
|
||||
@@ -104,7 +104,7 @@ const BuilderElement = ({ id, name, label, index, bandoStatus }) => {
|
||||
</div>
|
||||
: <div ref={ref} className="formBuilder__element" style={{ opacity }} data-handler-id={handlerId}>
|
||||
<div className="meta">
|
||||
<Tag value={name} severity="info"/>
|
||||
<Tag value={label} severity="info"/>
|
||||
<BuilderElementProperLabel id={id} defaultLabel={label}/>
|
||||
</div>
|
||||
<div className="actions">
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Editor } from 'primereact/editor';
|
||||
|
||||
import { mimeTypes } from '../../../../../../configData';
|
||||
import ElementSettingTableColumns from '../ElementSettingTableColumns';
|
||||
import { InputSwitch } from 'primereact/inputswitch';
|
||||
|
||||
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||
|
||||
@@ -17,6 +18,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||
label: __('Label', 'gepafin'),
|
||||
placeholder: __('Segnaposto', 'gepafin'),
|
||||
step: __('Numero Decimali', 'gepafin'),
|
||||
isRequestedAmount: __('Importo richiesto', 'gepafin'),
|
||||
options: __('Opzioni', 'gepafin'),
|
||||
mime: __('Tipo di file', 'gepafin'),
|
||||
text: __('Testo formattato', 'gepafin'),
|
||||
@@ -78,6 +80,10 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||
name={setting.name}
|
||||
bandoStatus={bandoStatus}
|
||||
setDataFn={updateDataFn}/>
|
||||
} else if (setting.name === 'isRequestedAmount') {
|
||||
return <InputSwitch
|
||||
checked={setting.value}
|
||||
onChange={(e) => changeFn(e.value, setting.name)}/>
|
||||
} else {
|
||||
return <InputText id={setting.name} aria-describedby={`${setting.name}-help`}
|
||||
value={setting.value}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
import { findIndex, propEq } from 'ramda';
|
||||
import { pathOr } from 'ramda';
|
||||
|
||||
// components
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
@@ -14,7 +14,8 @@ import uniqid from '../../../../../../helpers/uniqid';
|
||||
const ElementSettingTableColumns = ({
|
||||
value,
|
||||
name,
|
||||
setDataFn
|
||||
setDataFn,
|
||||
bandoStatus
|
||||
}) => {
|
||||
const [stateFieldData, setStateFieldData] = useState([]);
|
||||
const [rowsData, setRowsData] = useState([]);
|
||||
@@ -28,18 +29,19 @@ const ElementSettingTableColumns = ({
|
||||
setStateFieldData([...stateFieldData, { name: uniqid('o'), label: '', predefined: false }]);
|
||||
}
|
||||
|
||||
const addNewRow = (index) => {
|
||||
const newStateFieldData = wrap(stateFieldData)
|
||||
.insert([index, 'rows'], { label: '' }, stateFieldData[index].rows.length)
|
||||
.value();
|
||||
setStateFieldData(newStateFieldData);
|
||||
const addNewRow = () => {
|
||||
const obj = stateFieldData
|
||||
.filter(o => o.predefined)
|
||||
.reduce((acc, cur) => {
|
||||
acc[cur.name] = ''
|
||||
return acc;
|
||||
}, {});
|
||||
setRowsData([...rowsData, obj]);
|
||||
}
|
||||
|
||||
const removeRow = (index, indexK) => {
|
||||
const newStateFieldData = wrap(stateFieldData)
|
||||
.del([index, 'rows', indexK])
|
||||
.value();
|
||||
setStateFieldData(newStateFieldData);
|
||||
const removeRow = (index) => {
|
||||
const newRowsData = wrap(rowsData).del([index]).value();
|
||||
setRowsData(newRowsData);
|
||||
}
|
||||
|
||||
const onInputChange = (e, index) => {
|
||||
@@ -53,24 +55,31 @@ const ElementSettingTableColumns = ({
|
||||
setStateFieldData(newData);
|
||||
}
|
||||
|
||||
const onSubInputChange = (e, index, indexK) => {
|
||||
const onSubInputChange = (e, name, index) => {
|
||||
const { value } = e.target;
|
||||
const newStateFieldData = wrap(stateFieldData)
|
||||
.set([index, 'rows', indexK, 'label'], value)
|
||||
.value();
|
||||
setStateFieldData(newStateFieldData);
|
||||
const newRowsData = wrap(rowsData).set([index, name], value).value();
|
||||
setRowsData(newRowsData);
|
||||
}
|
||||
|
||||
const setChecked = (value, index) => {
|
||||
let name = '';
|
||||
const newData = stateFieldData.map((o, i) => {
|
||||
if (i === index) {
|
||||
o.predefined = value;
|
||||
if (value === false) {
|
||||
o.rows = [];
|
||||
}
|
||||
name = o.name;
|
||||
}
|
||||
return o;
|
||||
})
|
||||
});
|
||||
|
||||
let newRowsData = [];
|
||||
|
||||
if (value === false) {
|
||||
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
|
||||
} else {
|
||||
newRowsData = rowsData.map(o => wrap(o).set([name], '').value());
|
||||
}
|
||||
|
||||
setRowsData(newRowsData);
|
||||
setStateFieldData(newData);
|
||||
}
|
||||
|
||||
@@ -79,23 +88,31 @@ const ElementSettingTableColumns = ({
|
||||
<InputText value={item.label} onInput={(e) => onInputChange(e, i)}/>
|
||||
<div className="flex-1">
|
||||
<span>{__('Predefinito?', 'gepafin')}</span>
|
||||
<InputSwitch checked={item.predefined} onChange={(e) => setChecked(e.value, i)}/>
|
||||
<InputSwitch
|
||||
checked={item.predefined}
|
||||
disabled={bandoStatus === 'PUBLISH'}
|
||||
onChange={(e) => setChecked(e.value, i)}/>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
const properSubField = (item, i, k) => {
|
||||
return <InputText value={item.label} onInput={(e) => onSubInputChange(e, i, k)}/>
|
||||
const properSubField = (item, i, name) => {
|
||||
return <InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/>
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const storeFieldData = value ?? [];
|
||||
setStateFieldData(storeFieldData);
|
||||
const stateFieldData = pathOr([], ['stateFieldData'], value);
|
||||
setStateFieldData(stateFieldData);
|
||||
const rowsData = pathOr([], ['rowsData'], value);
|
||||
setRowsData(rowsData);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setDataFn(name, [...stateFieldData]);
|
||||
}, [stateFieldData]);
|
||||
setDataFn(name, {
|
||||
stateFieldData,
|
||||
rowsData
|
||||
});
|
||||
}, [stateFieldData, rowsData]);
|
||||
|
||||
stateFieldData.filter(o => o.predefined)
|
||||
|
||||
@@ -105,10 +122,10 @@ const ElementSettingTableColumns = ({
|
||||
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
|
||||
<div className="p-inputgroup flex-1">
|
||||
{properField(o, i)}
|
||||
<Button icon="pi pi-times" className="p-button-danger" onClick={() => removeItem(i)}/>
|
||||
<Button icon="pi pi-times" disabled={bandoStatus === 'PUBLISH'} className="p-button-danger" onClick={() => removeItem(i)}/>
|
||||
</div>
|
||||
</div>)}
|
||||
<Button type="button" outlined label={__('Aggiungi', 'gepafin')} onClick={addNewItem}/>
|
||||
<Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined label={__('Aggiungi', 'gepafin')} onClick={addNewItem}/>
|
||||
</div>
|
||||
{stateFieldData
|
||||
.filter(o => o.predefined)
|
||||
@@ -116,19 +133,22 @@ const ElementSettingTableColumns = ({
|
||||
<div className="formElementSettings__repeater formElementSettings__subRepeater">
|
||||
<label>{__('Righe per colonna:', 'gepafin')} <strong>{o.label}</strong></label>
|
||||
<div className="formElementSettings__repeater">
|
||||
{o.rows.map((c, k) => {
|
||||
const properIndex = findIndex(propEq(o.name, 'name'))(stateFieldData);
|
||||
{rowsData.map((c, k) => {
|
||||
return <div key={k} className="formElementSettings__repeaterItem">
|
||||
<div className="p-inputgroup flex-1">
|
||||
{properSubField(c, properIndex, k)}
|
||||
<Button icon="pi pi-times" className="p-button-danger"
|
||||
onClick={() => removeRow(properIndex, k)}/>
|
||||
{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
|
||||
<Button type="button"
|
||||
outlined
|
||||
disabled={bandoStatus === 'PUBLISH'}
|
||||
label={__('Aggiungi una riga', 'gepafin')}
|
||||
onClick={() => addNewRow(findIndex(propEq(o.name, 'name'))(stateFieldData))}/>
|
||||
onClick={addNewRow}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>)}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { klona } from 'klona';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
|
||||
// store
|
||||
import { storeSet, useStore } from '../../../../store';
|
||||
import { storeGet, storeSet, useStore } from '../../../../store';
|
||||
|
||||
// components
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
@@ -128,10 +128,20 @@ const BuilderElementSettings = ({ closeSettingsFn, bandoStatus }) => {
|
||||
|
||||
useEffect(() => {
|
||||
const chosen = head(elements.filter(o => o.id === activeElement));
|
||||
const elementItems = storeGet.main.elementItems();
|
||||
const chosenElementItemCfg = head(elementItems.filter(o => o.name === chosen.name));
|
||||
let settings = [];
|
||||
|
||||
if (chosenElementItemCfg) {
|
||||
settings = chosenElementItemCfg.settings.map((o) => {
|
||||
const setting = head(chosen.settings.filter(s => s.name === o.name));
|
||||
return setting ? klona(setting) : klona(o)
|
||||
});
|
||||
}
|
||||
|
||||
if (chosen) {
|
||||
setActiveElementData(klona(chosen));
|
||||
setSettings(klona(chosen.settings));
|
||||
setSettings(settings);
|
||||
setValidators(klona(chosen.validators));
|
||||
setDynamicData(chosen.dynamicData ? chosen.dynamicData : '');
|
||||
setCriteria(chosen.criteria ? chosen.criteria : []);
|
||||
|
||||
@@ -30,6 +30,8 @@ import { Editor } from 'primereact/editor';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import PreferredBandoService from '../../service/preferred-bando-service';
|
||||
|
||||
const REACT_APP_HUB_ID = process.env.REACT_APP_HUB_ID;
|
||||
|
||||
const BandoViewBeneficiario = () => {
|
||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
@@ -89,30 +91,52 @@ const BandoViewBeneficiario = () => {
|
||||
}
|
||||
|
||||
const submitBtnLabel = () => {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
return __('Vai alla domanda', 'gepafin');
|
||||
} else {
|
||||
if (REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE') {
|
||||
return __('Presenta domanda', 'gepafin');
|
||||
} else {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
return __('Vai alla domanda', 'gepafin');
|
||||
} else {
|
||||
return __('Presenta domanda', 'gepafin');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const submitBtnIcon = () => {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
return 'pi pi-arrow-right';
|
||||
} else {
|
||||
if (REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE') {
|
||||
return 'pi pi-save';
|
||||
} else {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
return 'pi pi-arrow-right';
|
||||
} else {
|
||||
return 'pi pi-save';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const submitApplication = () => {
|
||||
if (data.confidi) {
|
||||
displayConfidiPopup();
|
||||
} else {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
navigate(`/imieibandi/${applicationObj.id}`);
|
||||
if (data.id === 6 && REACT_APP_HUB_ID === 'p4lk3bcx1RStqTaIVVbXs') {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
navigate(`/imieibandi/${applicationObj.id}`);
|
||||
} else {
|
||||
const bandoId = getBandoId();
|
||||
ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]);
|
||||
}
|
||||
} else {
|
||||
displayConfidiPopup();
|
||||
}
|
||||
} else {
|
||||
if (REACT_APP_HUB_ID === 't7jh5wfg9QXylNaTZkPoE') {
|
||||
const bandoId = getBandoId();
|
||||
ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]);
|
||||
} else {
|
||||
if (applicationObj && applicationObj.id) {
|
||||
navigate(`/imieibandi/${applicationObj.id}`);
|
||||
} else {
|
||||
const bandoId = getBandoId();
|
||||
ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,6 +219,7 @@ const BandoViewBeneficiario = () => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
setData(getFormattedBandiData(data.data));
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errGetBandoCallback = (data) => {
|
||||
@@ -206,6 +231,7 @@ const BandoViewBeneficiario = () => {
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const getFormattedBandiData = (data) => {
|
||||
@@ -291,10 +317,13 @@ const BandoViewBeneficiario = () => {
|
||||
BandoService.getBando(bandoId, getBandoCallback, errGetBandoCallback, [
|
||||
['companyId', chosenCompanyId]
|
||||
]);
|
||||
ApplicationService.getApplications(getApplCallback, errGetApplCallback, [
|
||||
['callId', bandoId],
|
||||
['companyId', chosenCompanyId]
|
||||
]);
|
||||
if (REACT_APP_HUB_ID !== 't7jh5wfg9QXylNaTZkPoE') {
|
||||
storeSet.main.setAsyncRequest();
|
||||
ApplicationService.getApplications(getApplCallback, errGetApplCallback, [
|
||||
['callId', bandoId],
|
||||
['companyId', chosenCompanyId]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}, [id, chosenCompanyId]);
|
||||
|
||||
@@ -521,4 +550,4 @@ const BandoViewBeneficiario = () => {
|
||||
|
||||
}
|
||||
|
||||
export default BandoViewBeneficiario;
|
||||
export default BandoViewBeneficiario;
|
||||
|
||||
@@ -42,7 +42,7 @@ const DraftApplicationsTable = () => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (is(Array, data.data)) {
|
||||
setItems(getFormattedBandiData(data.data));
|
||||
setStatuses(uniq(items.map(o => o.status)))
|
||||
setStatuses(uniq(data.data.map(o => o.status)))
|
||||
initFilters();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,23 @@ const MyLatestSubmissionsTable = () => {
|
||||
setLocalAsyncRequest(false);
|
||||
}
|
||||
|
||||
const handleDeleteApplication = (id) => {
|
||||
setLocalAsyncRequest(true);
|
||||
ApplicationService.deleteApplication(id, (resp) => delApplCallback(resp, id), errDelApplCallback)
|
||||
}
|
||||
|
||||
const delApplCallback = (resp, id) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
const newItems = items.filter(o => o.id !== id);
|
||||
setItems(newItems);
|
||||
}
|
||||
setLocalAsyncRequest(false);
|
||||
}
|
||||
|
||||
const errDelApplCallback = (data) => {
|
||||
setLocalAsyncRequest(false);
|
||||
}
|
||||
|
||||
const getFormattedBandiData = (data) => {
|
||||
return [...(data || [])].map((d) => {
|
||||
d.callEndDate = new Date(d.callEndDate);
|
||||
@@ -130,7 +147,8 @@ const MyLatestSubmissionsTable = () => {
|
||||
const statusFilterTemplate = (options) => {
|
||||
return <Dropdown value={options.value} options={statuses}
|
||||
onChange={(e) => options.filterCallback(e.value, options.index)}
|
||||
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
|
||||
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel}
|
||||
className="p-column-filter"
|
||||
showClear/>;
|
||||
};
|
||||
|
||||
@@ -143,13 +161,24 @@ const MyLatestSubmissionsTable = () => {
|
||||
};
|
||||
|
||||
const actionsBodyTemplate = (rowData) => {
|
||||
return <Link to={`/imieibandi/${rowData.id}`}>
|
||||
{'DRAFT' === rowData.status
|
||||
? <Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
|
||||
return 'DRAFT' === rowData.status
|
||||
? <div className="appPageSection__tableActions lessGap">
|
||||
<Link to={`/imieibandi/${rowData.id}`}>
|
||||
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
|
||||
iconPos="right"/>
|
||||
</Link>
|
||||
<Button severity="danger"
|
||||
onClick={() => handleDeleteApplication(rowData.id)}
|
||||
label={__('Cancella', 'gepafin')}
|
||||
icon="pi pi-trash"
|
||||
size="small"
|
||||
iconPos="right"/>
|
||||
</div>
|
||||
: <Link to={`/imieibandi/${rowData.id}`}>
|
||||
<Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small"
|
||||
iconPos="right"/>
|
||||
: <Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small"
|
||||
iconPos="right"/>}
|
||||
</Link>
|
||||
|
||||
}
|
||||
|
||||
const header = renderHeader();
|
||||
|
||||
@@ -21,6 +21,7 @@ const DashboardBeneficiario = () => {
|
||||
const [mainStats, setMainStats] = useState({});
|
||||
const companies = useStore().main.companies();
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
||||
|
||||
const goToAllSubmissions = () => {
|
||||
navigate('/bandi');
|
||||
@@ -51,6 +52,7 @@ const DashboardBeneficiario = () => {
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Dashboard', 'gepafin')}</h1>
|
||||
{company ? <span className="companyName">{company.companyName}</span> : null}
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
960
src/pages/DomandaEditInstructorManager/index.js
Normal file
960
src/pages/DomandaEditInstructorManager/index.js
Normal file
@@ -0,0 +1,960 @@
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { is, isEmpty, isNil, sum, pathOr, head } from 'ramda';
|
||||
import { klona } from 'klona';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
|
||||
// store
|
||||
import { storeGet, storeSet, useStore } from '../../store';
|
||||
|
||||
// api
|
||||
import ApplicationEvaluationService from '../../service/application-evaluation-service';
|
||||
import AmendmentsService from '../../service/amendments-service';
|
||||
import AppointmentService from '../../service/appointment-service';
|
||||
|
||||
// tools
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
import getBandoLabel from '../../helpers/getBandoLabel';
|
||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||
|
||||
// components
|
||||
import { Skeleton } from 'primereact/skeleton';
|
||||
import { Button } from 'primereact/button';
|
||||
import { Tag } from 'primereact/tag';
|
||||
import { Checkbox } from 'primereact/checkbox';
|
||||
import { Editor } from 'primereact/editor';
|
||||
import { InputNumber } from 'primereact/inputnumber';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import HelpIcon from '../../icons/HelpIcon';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import DownloadApplicationArchive from '../DomandaEditPreInstructor/components/DownloadApplicationArchive';
|
||||
import DownloadCompanyDelegation from '../DomandaEditPreInstructor/components/DownloadCompanyDelegation';
|
||||
import DownloadSignedApplication from '../DomandaEditPreInstructor/components/DownloadSignedApplication';
|
||||
import ListOfFiles from '../DomandaEditPreInstructor/components/ListOfFiles';
|
||||
import RepeaterFields from '../DomandaEditPreInstructor/components/RepeaterFields';
|
||||
|
||||
const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
|
||||
|
||||
const DomandaEditPreInstructor = () => {
|
||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [data, setData] = useState({});
|
||||
const [isVisibleCriterionData, setIsVisibleCriterionData] = useState(0);
|
||||
const [criterionDataTitle, setCriterionDataTitle] = useState('');
|
||||
const [criterionDataContent, setCriterionDataContent] = useState('');
|
||||
const [isAdmissible, setIsAdmissible] = useState(false);
|
||||
const [connectedSoccorsoId, setConnectedSoccorsoId] = useState(0);
|
||||
const toast = useRef(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isVisibleCompleteDialog, setIsVisibleCompleteDialog] = useState(false);
|
||||
const [operationType, setOperationType] = useState('');
|
||||
const [motivation, setMotivation] = useState('');
|
||||
const [isVisibleAppointmentDialog, setIsVisibleAppointmentDialog] = useState(false);
|
||||
const [allFilesRated, setAllFilesRated] = useState(false);
|
||||
const [atLeastOneChecked, setAtLeastOneChecked] = useState(false);
|
||||
const [allChecksChecked, setAllChecksChecked] = useState(false);
|
||||
const [appointmentData, setAppointmentData] = useState({
|
||||
title: '',
|
||||
text: '',
|
||||
duration: 0,
|
||||
amount: 0
|
||||
});
|
||||
|
||||
const goToEvaluationsPage = () => {
|
||||
navigate('/domande');
|
||||
}
|
||||
|
||||
const updateFlagsForSoccorso = (data) => {
|
||||
let nonRatedFilesLength = 0;
|
||||
|
||||
if (data.files) {
|
||||
const nonRatedFiles = data.files
|
||||
.map(el => el.valid)
|
||||
.filter(v => isNil(v));
|
||||
nonRatedFilesLength = nonRatedFiles.length;
|
||||
}
|
||||
|
||||
if (data.amendmentDetails) {
|
||||
const nonRatedFiles = data.amendmentDetails
|
||||
.map(el => el.valid)
|
||||
.filter(v => isNil(v));
|
||||
nonRatedFilesLength = nonRatedFiles.length;
|
||||
}
|
||||
|
||||
setAllFilesRated(nonRatedFilesLength === 0);
|
||||
|
||||
if (data.checklist) {
|
||||
const checkedChecklistItems = data.checklist
|
||||
.map(el => el.valid)
|
||||
.filter(v => v);
|
||||
setAtLeastOneChecked(checkedChecklistItems.length > 0);
|
||||
setAllChecksChecked(checkedChecklistItems.length === data.checklist.length)
|
||||
}
|
||||
}
|
||||
|
||||
const doNewSoccorso = () => {
|
||||
if (connectedSoccorsoId !== 0) {
|
||||
navigate(`/domande/${id}/soccorso/${connectedSoccorsoId}`);
|
||||
} else {
|
||||
doSaveDraft(`/domande/${id}/aggiungi-soccorso/`)
|
||||
}
|
||||
}
|
||||
|
||||
const getCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
setData(getFormattedData(data.data));
|
||||
setMotivation(data.data.motivation);
|
||||
updateFlagsForSoccorso(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 getFormattedData = (data) => {
|
||||
data.submissionDate = is(String, data.submissionDate) ? new Date(data.submissionDate) : (data.submissionDate ? data.submissionDate : '');
|
||||
data.evaluationDate = is(String, data.evaluationDate) ? new Date(data.evaluationDate) : (data.evaluationDate ? data.evaluationDate : '');
|
||||
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 updateEvaluationValue = (value, path, maxValue = null) => {
|
||||
let finalValue = value;
|
||||
|
||||
if (maxValue || maxValue === 0) {
|
||||
finalValue = value > maxValue ? maxValue : value;
|
||||
}
|
||||
|
||||
const newData = wrap(data).set(path, finalValue).value();
|
||||
setData(newData);
|
||||
updateFlagsForSoccorso(newData);
|
||||
}
|
||||
|
||||
const doSaveDraft = useCallback((doRedirect = '') => {
|
||||
const formData = {
|
||||
criteria: klona(data.criteria),
|
||||
checklist: klona(data.checklist),
|
||||
files: klona(data.files),
|
||||
evaluationDocument: klona(data.evaluationDocument.map(o => ({
|
||||
...o,
|
||||
fileValue: o.fileValue[0] ? o.fileValue[0].id : ''
|
||||
})
|
||||
)),
|
||||
amendmentDetails: klona(data.amendmentDetails),
|
||||
note: data.note
|
||||
}
|
||||
|
||||
ApplicationEvaluationService.updateEvaluation(
|
||||
data.assignedApplicationId,
|
||||
formData,
|
||||
(data) => updateCallback(data, doRedirect),
|
||||
errUpdateCallback
|
||||
);
|
||||
}, [data]);
|
||||
|
||||
const updateCallback = (data, doRedirect = '') => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
setData(getFormattedData(data.data));
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
if (!isEmpty(doRedirect)) {
|
||||
navigate(doRedirect);
|
||||
}
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errUpdateCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const doApprove = () => {
|
||||
const formData = {
|
||||
applicationStatus: 'APPROVED',
|
||||
criteria: klona(data.criteria),
|
||||
checklist: klona(data.checklist),
|
||||
files: klona(data.files),
|
||||
note: data.note,
|
||||
motivation
|
||||
}
|
||||
|
||||
setIsVisibleCompleteDialog(false);
|
||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
||||
}
|
||||
|
||||
const doReject = () => {
|
||||
const formData = {
|
||||
applicationStatus: 'REJECTED',
|
||||
criteria: klona(data.criteria),
|
||||
checklist: klona(data.checklist),
|
||||
files: klona(data.files),
|
||||
note: data.note,
|
||||
motivation
|
||||
}
|
||||
|
||||
setIsVisibleCompleteDialog(false);
|
||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
||||
}
|
||||
|
||||
const updateStatusCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
setData(getFormattedData(data.data));
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errUpdateStatusCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const displayCriterionData = (id) => {
|
||||
const criterion = head(data.criteria.filter(o => o.id === id));
|
||||
setCriterionDataTitle(criterion.label);
|
||||
const content = <div className="criterionRelatedData">
|
||||
<h3>{__('I campi correlati')}</h3>
|
||||
{criterion.criteriaMappedFields ? criterion.criteriaMappedFields.map(o => criteriaDataItem(o)) : null}
|
||||
</div>;
|
||||
setCriterionDataContent(content);
|
||||
setIsVisibleCriterionData(id);
|
||||
}
|
||||
|
||||
const criteriaDataItem = (item) => {
|
||||
let content = '';
|
||||
|
||||
switch (item.fieldName) {
|
||||
case 'fileupload' :
|
||||
content = <ul>
|
||||
{item.fieldValue
|
||||
? item.fieldValue.map(o => <li key={o.id}>
|
||||
{o.filePath ? <a href={o.filePath}>{o.name}</a> : null}
|
||||
</li>)
|
||||
: null}
|
||||
</ul>;
|
||||
break;
|
||||
case 'table' :
|
||||
const th = Object.keys(item.fieldValue[0]);
|
||||
content = <table>
|
||||
<thead>
|
||||
<tr>
|
||||
{th.map(v => <th key={v}>{v}</th>)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{item.fieldValue
|
||||
? item.fieldValue.map((o, i) => <tr key={i}>
|
||||
{Object.values(o).map(v => <td key={v}>{v}</td>)}
|
||||
</tr>)
|
||||
: null}
|
||||
</tbody>
|
||||
</table>;
|
||||
break;
|
||||
default :
|
||||
content = item.fieldValue;
|
||||
break;
|
||||
}
|
||||
|
||||
return <div key={item.id} className="criterionRelatedData__item">
|
||||
<strong>{item.fieldLabel}</strong>
|
||||
{content}
|
||||
</div>
|
||||
}
|
||||
|
||||
const hideCriterionData = () => {
|
||||
setIsVisibleCriterionData(0);
|
||||
setCriterionDataTitle('');
|
||||
setCriterionDataContent('');
|
||||
}
|
||||
|
||||
const getAmendmentsCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (data.data.length) {
|
||||
setConnectedSoccorsoId(data.data[0].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errGetAmendmentsCallback = () => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
}
|
||||
|
||||
const shouldDisableField = (fieldName) => {
|
||||
return !['EVALUATION'].includes(data.applicationStatus)
|
||||
|| (['ADMISSIBLE'].includes(data.applicationStatus) && fieldName !== 'criteria')
|
||||
}
|
||||
|
||||
const headerCompleteDialog = () => {
|
||||
return 'approve' === operationType
|
||||
? <span>{__('Confermare l\'approvazione', 'gepafin')}</span>
|
||||
: <span>{__('Confermare il rifiuto', 'gepafin')}</span>;
|
||||
}
|
||||
|
||||
const hideCompleteDialog = () => {
|
||||
setIsVisibleCompleteDialog(false);
|
||||
setOperationType('');
|
||||
setMotivation('');
|
||||
}
|
||||
|
||||
const footerCompleteDialog = () => {
|
||||
return <div>
|
||||
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideCompleteDialog} outlined/>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={loading}
|
||||
label={__('Invia', 'gepafin')} onClick={'approve' === operationType ? doApprove : doReject}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
const initiateApproving = () => {
|
||||
setOperationType('approve');
|
||||
setIsVisibleCompleteDialog(true);
|
||||
|
||||
}
|
||||
|
||||
const initiateRejecting = () => {
|
||||
setOperationType('reject');
|
||||
setIsVisibleCompleteDialog(true);
|
||||
}
|
||||
|
||||
const doCheckNDG = () => {
|
||||
storeSet.main.setAsyncRequest();
|
||||
doSaveDraft();
|
||||
setTimeout(() => {
|
||||
AppointmentService.getNdg(id, getNdgCallback, errGetNdgCallback);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
const getNdgCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errGetNdgCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: data.status === 'SUCCESS' ? 'info' : 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const doCreateAppointment = () => {
|
||||
setAppointmentData({
|
||||
title: '',
|
||||
text: '',
|
||||
duration: 0,
|
||||
amount: 0
|
||||
});
|
||||
setIsVisibleAppointmentDialog(true);
|
||||
}
|
||||
|
||||
const setValue = (name, value) => {
|
||||
const newData = wrap(appointmentData).set(name, value).value();
|
||||
setAppointmentData(newData);
|
||||
}
|
||||
|
||||
const headerAppointmentDialog = () => {
|
||||
return <span>{__('Crea appuntamento', 'gepafin')}</span>;
|
||||
}
|
||||
|
||||
const hideAppointmentDialog = () => {
|
||||
setIsVisibleAppointmentDialog(false);
|
||||
setAppointmentData({});
|
||||
}
|
||||
|
||||
const footerAppointmentDialog = () => {
|
||||
return <div>
|
||||
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideAppointmentDialog} outlined/>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={loading}
|
||||
label={__('Invia', 'gepafin')} onClick={doCreateAppointmentRequest}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
const doCreateAppointmentRequest = () => {
|
||||
if (
|
||||
!isEmpty(appointmentData.title) && !isEmpty(appointmentData.text) && !isEmpty(appointmentData.amount)
|
||||
&& !isEmpty(appointmentData.duration) && appointmentData.duration !== 0 && appointmentData.amount !== 0
|
||||
) {
|
||||
storeSet.main.setAsyncRequest();
|
||||
const submitData = {
|
||||
'importoBreveTermine': appointmentData.amount,
|
||||
'durataMesiFinanziamento': appointmentData.duration,
|
||||
'nota': {
|
||||
'titolo': appointmentData.title,
|
||||
'testo': appointmentData.text
|
||||
}
|
||||
}
|
||||
|
||||
AppointmentService.createAppointment(id, submitData, getAppointemntCallback, errGetAppointemntCallback);
|
||||
}
|
||||
}
|
||||
|
||||
const getAppointemntCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
}
|
||||
setIsVisibleAppointmentDialog(false);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errGetAppointemntCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: data.status === 'SUCCESS' ? 'info' : 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
setIsVisibleAppointmentDialog(false);
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const doMakeAdmisible = () => {
|
||||
// TODO
|
||||
}
|
||||
|
||||
const evaluationShouldBeBlocked = (data = {}) => {
|
||||
const userData = storeGet.main.userData()
|
||||
return isAsyncRequest || userData.id !== data.assignedUserId;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const maxScore = pathOr(0, ['minScore'], data);
|
||||
const criteria = pathOr([], ['criteria'], data);
|
||||
const scoreSum = sum(criteria.map(o => o.score));
|
||||
|
||||
setIsAdmissible(scoreSum !== 0 && scoreSum >= maxScore);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
const parsed = parseInt(id)
|
||||
const entityId = !isNaN(parsed) ? parsed : 0;
|
||||
|
||||
storeSet.main.setAsyncRequest();
|
||||
ApplicationEvaluationService.getEvaluationByApplId(getCallback, errGetCallback, [
|
||||
['applicationId', entityId]
|
||||
]);
|
||||
AmendmentsService.getSoccorsoByApplId(entityId, getAmendmentsCallback, errGetAmendmentsCallback, [
|
||||
['statuses', 'AWAITING']
|
||||
]);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Valuta domanda', 'gepafin')}</h1>
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
<Toast ref={toast}/>
|
||||
|
||||
<div className="appPageSection__row">
|
||||
<Button
|
||||
type="button"
|
||||
outlined
|
||||
onClick={goToEvaluationsPage}
|
||||
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 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>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('NDG', 'gepafin')}</span>
|
||||
<span>{data.ndg}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Appuntamento', 'gepafin')}</span>
|
||||
<span>{data.appointmentId}</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.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>{getDateFromISOstring(data.submissionDate)}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Data assegnazione', 'gepafin')}</span>
|
||||
<span>{getDateFromISOstring(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 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>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
||||
<RepeaterFields
|
||||
defaultValue={data.evaluationDocument ?? []}
|
||||
updateFn={(data) => updateEvaluationValue(
|
||||
data,
|
||||
['evaluationDocument']
|
||||
)}
|
||||
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
||||
sourceId={data.assignedApplicationId}
|
||||
sourceName="evaluation"/>
|
||||
</div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
|
||||
<div className="appPageSection columns">
|
||||
<div>
|
||||
<h3>{__('Lista', 'gepafin')}</h3>
|
||||
<div className="appPageSection__withBorder grey" style={{ marginBottom: '20px' }}>
|
||||
<div className="appPageSection__checklist">
|
||||
{data.checklist.map((o, i) => <div key={o.id}>
|
||||
<Checkbox
|
||||
disabled={shouldDisableField('checklist') || evaluationShouldBeBlocked(data)}
|
||||
inputId={`checklist_${o.id}`}
|
||||
onChange={(e) => updateEvaluationValue(
|
||||
e.checked,
|
||||
['checklist', i, 'valid']
|
||||
)}
|
||||
checked={o.valid}></Checkbox>
|
||||
<label htmlFor={`checklist_${o.id}`}>{o.label}</label>
|
||||
</div>)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{__('Note', 'gepafin')}</h3>
|
||||
<div>
|
||||
<Editor
|
||||
value={data.note}
|
||||
readOnly={shouldDisableField('note') || evaluationShouldBeBlocked(data)}
|
||||
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||
headerTemplate={header}
|
||||
onTextChange={(e) => updateEvaluationValue(
|
||||
e.htmlValue,
|
||||
['note']
|
||||
)}
|
||||
style={{ height: 80 * 3, width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{__('Documenti allegati', 'gepafin')}</h3>
|
||||
<ListOfFiles
|
||||
files={data.files}
|
||||
updateFn={updateEvaluationValue}
|
||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
||||
name="files"
|
||||
ndg={data.ndg}
|
||||
applicationId={id}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isEmpty(data.amendmentDetails)
|
||||
? <div className="appPageSection">
|
||||
<h2>{__('Documenti di soccorso', 'gepafin')}</h2>
|
||||
<ListOfFiles
|
||||
files={data.amendmentDetails}
|
||||
updateFn={updateEvaluationValue}
|
||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
||||
name="amendmentDetails"
|
||||
ndg={data.ndg}
|
||||
applicationId={id}/>
|
||||
</div> : null}
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
|
||||
{data.criteria
|
||||
? <table className="myTable">
|
||||
<thead className="myThead">
|
||||
<tr>
|
||||
<th>{__('Parametro', 'gepafin')}</th>
|
||||
<th style={{ width: 200 }}>{__('Punteggio', 'gepafin')}</th>
|
||||
<th style={{ width: 220 }}>{__('Stato', 'gepafin')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="myTbody">
|
||||
{data.criteria.map((o, i) => <tr key={o.id}>
|
||||
<td>{o.label}</td>
|
||||
<td>
|
||||
<div className="p-inputgroup">
|
||||
<InputNumber
|
||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
||||
placeholder={__('Punteggio', 'gepafin')}
|
||||
keyfilter="int"
|
||||
value={o.score}
|
||||
max={o.maxScore}
|
||||
onChange={(e) => updateEvaluationValue(
|
||||
e.value,
|
||||
['criteria', i, 'score'],
|
||||
o.criteria
|
||||
)}/>
|
||||
<span className="p-inputgroup-addon">
|
||||
/ {o.maxScore}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="appPageSection__iconActions">
|
||||
{!isEmpty(o.criteriaMappedFields)
|
||||
? <Button icon="pi pi-eye"
|
||||
rounded outlined severity="info"
|
||||
onClick={() => displayCriterionData(o.id)}
|
||||
aria-label={__('Mostra', 'gepafin')}/> : null}
|
||||
<Button icon="pi pi-thumbs-up" rounded outlined
|
||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
||||
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
||||
onClick={() => updateEvaluationValue(
|
||||
true,
|
||||
['criteria', i, 'valid']
|
||||
)}
|
||||
aria-label={__('Su', 'gepafin')}/>
|
||||
<Button icon="pi pi-thumbs-down" rounded outlined
|
||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
||||
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
|
||||
onClick={() => updateEvaluationValue(
|
||||
false,
|
||||
['criteria', i, 'valid']
|
||||
)}
|
||||
aria-label={__('Giu', 'gepafin')}/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>)}
|
||||
<tr>
|
||||
<td>{__('Punteggio:', 'gepafin')}</td>
|
||||
<td>{sum(data.criteria.map(o => o.score))}</td>
|
||||
<td>
|
||||
{isAdmissible
|
||||
? <Tag icon="pi pi-check" severity="success"
|
||||
value={__('Ammissibile')}></Tag> : null}
|
||||
{!isAdmissible
|
||||
? <Tag icon="pi pi-times" severity="warning"
|
||||
value={__('Inammissibile')}></Tag> : null}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot className="myTfoot">
|
||||
<tr>
|
||||
<td colSpan="3">{sprintf(__('Punteggio minimo per l\'ammissione: %d'), data.minScore)}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table> : null}
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
<div className="appPageSection__hr">
|
||||
<span>{__('Azioni rapide', 'gepafin')}</span>
|
||||
</div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<div className="appPageSection__actions">
|
||||
{['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)
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id || !allFilesRated || !allChecksChecked || evaluationShouldBeBlocked(data)}
|
||||
onClick={doCheckNDG}
|
||||
label={__('Controlla NDG', 'gepafin')}
|
||||
/> : null}*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={true}
|
||||
onClick={() => {}}
|
||||
label={__('Controlla NDG', 'gepafin')}
|
||||
/>
|
||||
{/*{APP_EVALUATION_FLOW_ID === '1' && ['NDG'].includes(data.applicationStatus) && data.ndg
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id || evaluationShouldBeBlocked(data)}
|
||||
onClick={doCreateAppointment}
|
||||
label={__('Crea l\'appuntamento', 'gepafin')}
|
||||
/> : null}*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={true}
|
||||
onClick={() => {}}
|
||||
label={__('Crea l\'appuntamento', 'gepafin')}
|
||||
/>
|
||||
{/*{APP_EVALUATION_FLOW_ID === '1' && ['APPOINTMENT'].includes(data.applicationStatus)
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id || evaluationShouldBeBlocked(data)}
|
||||
onClick={doMakeAdmisible}
|
||||
label={__('Ammissibile', 'gepafin')}
|
||||
/> : null}*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={true}
|
||||
onClick={() => {}}
|
||||
label={__('Ammissibile', 'gepafin')}
|
||||
/>
|
||||
{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!isAdmissible || ['APPROVED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
||||
/*disabled={!isAdmissible
|
||||
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus))}*/
|
||||
onClick={initiateApproving}
|
||||
label={__('Approva Domanda', 'gepafin')}
|
||||
icon="pi pi-check" iconPos="right"/> : null}
|
||||
{/*{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)}
|
||||
onClick={initiateRejecting}
|
||||
label={__('Respingi Domanda', 'gepafin')}
|
||||
icon="pi pi-times" 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>
|
||||
|
||||
<Dialog
|
||||
header={criterionDataTitle}
|
||||
visible={isVisibleCriterionData !== 0}
|
||||
style={{ width: '50vw' }}
|
||||
onHide={hideCriterionData}>
|
||||
{criterionDataContent}
|
||||
</Dialog>
|
||||
|
||||
<Dialog
|
||||
visible={isVisibleCompleteDialog}
|
||||
modal
|
||||
header={headerCompleteDialog}
|
||||
footer={footerCompleteDialog}
|
||||
style={{ maxWidth: '600px', width: '100%' }}
|
||||
onHide={hideCompleteDialog}>
|
||||
<div className="appForm__field">
|
||||
<label>{__('Motivazione', 'gepafin')}</label>
|
||||
<Editor
|
||||
value={motivation}
|
||||
readOnly={loading}
|
||||
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||
headerTemplate={header}
|
||||
onTextChange={(e) => setMotivation(e.htmlValue)}
|
||||
style={{ height: 80 * 3, width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<Dialog
|
||||
visible={isVisibleAppointmentDialog}
|
||||
modal
|
||||
header={headerAppointmentDialog}
|
||||
footer={footerAppointmentDialog}
|
||||
style={{ maxWidth: '600px', width: '100%' }}
|
||||
onHide={hideAppointmentDialog}>
|
||||
<div className="appForm__field">
|
||||
<label
|
||||
className={classNames({ 'p-error': isEmpty(appointmentData.amount) || appointmentData.amount === 0 })}>
|
||||
{__('Importo', 'gepafin')}
|
||||
</label>
|
||||
<InputNumber
|
||||
value={appointmentData.amount}
|
||||
keyfilter="int"
|
||||
invalid={isEmpty(appointmentData.amount) || appointmentData.amount === 0}
|
||||
onChange={(e) => setValue('amount', e.value)}/>
|
||||
</div>
|
||||
<div className="appForm__field">
|
||||
<label
|
||||
className={classNames({ 'p-error': isEmpty(appointmentData.duration) || appointmentData.duration === 0 })}>
|
||||
{__('Durata', 'gepafin')}
|
||||
</label>
|
||||
<InputNumber
|
||||
value={appointmentData.duration}
|
||||
keyfilter="int"
|
||||
invalid={isEmpty(appointmentData.duration) || appointmentData.duration === 0}
|
||||
onChange={(e) => setValue('duration', e.value)}/>
|
||||
</div>
|
||||
<div className="appForm__field">
|
||||
<label className={classNames({ 'p-error': isEmpty(appointmentData.title) })}>
|
||||
{__('Titolo', 'gepafin')}
|
||||
</label>
|
||||
<InputText
|
||||
value={appointmentData.title}
|
||||
invalid={isEmpty(appointmentData.title)}
|
||||
onChange={(e) => setValue('title', e.target.value)}/>
|
||||
</div>
|
||||
<div className="appForm__field">
|
||||
<label className={classNames({ 'p-error': isEmpty(appointmentData.text) })}>
|
||||
{__('Messaggio', 'gepafin')}
|
||||
</label>
|
||||
<InputTextarea
|
||||
value={appointmentData.text}
|
||||
invalid={isEmpty(appointmentData.text)}
|
||||
onChange={(e) => setValue('text', e.target.value)}
|
||||
rows={3}
|
||||
cols={30}/>
|
||||
</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 DomandaEditPreInstructor;
|
||||
@@ -1,8 +1,14 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { isEmpty } from 'ramda';
|
||||
import { isEmpty, pathOr, isNil } from 'ramda';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
|
||||
// store
|
||||
import AppointmentService from '../../../../service/appointment-service';
|
||||
|
||||
// tools
|
||||
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
|
||||
|
||||
// components
|
||||
import { Button } from 'primereact/button';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
@@ -11,14 +17,11 @@ import { Dropdown } from 'primereact/dropdown';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { InputSwitch } from 'primereact/inputswitch';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
|
||||
import { classificationType, protocolType } from '../../../../configData';
|
||||
import AppointmentService from '../../../../service/appointment-service';
|
||||
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
|
||||
import { storeSet } from '../../../../store';
|
||||
import { Toast } from 'primereact/toast';
|
||||
|
||||
const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => {
|
||||
import { classificationType, protocolType } from '../../../../configData';
|
||||
|
||||
const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0, docAttachmentId = null, updateFn = () => {} }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isVisibleDialog, setIsVisibleDialog] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
@@ -87,19 +90,29 @@ const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => {
|
||||
|
||||
const submitCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
console.log(data.data);
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
const documentAttachmentId = pathOr('fake_id', ['documentAttachmentId'], data.data);
|
||||
updateFn(documentAttachmentId);
|
||||
}
|
||||
setIsVisibleDialog(false);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errSubmitCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'error',
|
||||
severity: data.status === 'SUCCESS' ? 'info' : 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
setIsVisibleDialog(false);
|
||||
set404FromErrorResponse(data);
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -119,7 +132,7 @@ const ArchiveDocument = ({ applicationId, ndg = '', fileId = 0 }) => {
|
||||
setTypes(protocolType.map(o => ({ value: o.id, label: o.name })));
|
||||
}, []);
|
||||
|
||||
return (!isEmpty(ndg)
|
||||
return (!isEmpty(ndg) && !isNil(ndg) && !docAttachmentId
|
||||
? <>
|
||||
<Toast ref={toast}/>
|
||||
<Button icon="pi pi-file-export"
|
||||
|
||||
@@ -3,22 +3,35 @@ import { Button } from 'primereact/button';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { isNil } from 'ramda';
|
||||
import ArchiveDocument from '../ArchiveDocument';
|
||||
import renderHtmlContent from '../../../../helpers/renderHtmlContent';
|
||||
import uniqid from '../../../../helpers/uniqid';
|
||||
|
||||
const ListOfFiles = ({ files, updateFn, shouldDisableFieldFn, name, ndg, applicationId }) => {
|
||||
|
||||
return (
|
||||
<ol className="appPageSection__list">
|
||||
{files.map((o, i) => <li key={o.id} className="appPageSection__listItem">
|
||||
{files.map((o, i) => <li key={`${o.id}_${uniqid('f')}`} className="appPageSection__listItem">
|
||||
<div className="appPageSection__listItemRow">
|
||||
<span>{o.label}</span>
|
||||
<div>{renderHtmlContent(o.label)}</div>
|
||||
<div className="appPageSection__iconActions">
|
||||
{o.fileDetail && o.fileDetail.length === 1
|
||||
? <Button icon="pi pi-eye" rounded
|
||||
? <>
|
||||
<Button icon="pi pi-eye" rounded
|
||||
onClick={() => {
|
||||
window.open(o.fileDetail[0].filePath, '_blank').focus()
|
||||
}}
|
||||
outlined severity="info"
|
||||
aria-label={__('Mostra', 'gepafin')}/> : null}
|
||||
aria-label={__('Mostra', 'gepafin')}/>
|
||||
<ArchiveDocument
|
||||
ndg={ndg}
|
||||
applicationId={applicationId}
|
||||
fileId={o.fileDetail[0].id}
|
||||
updateFn={(val) => updateFn(
|
||||
val,
|
||||
[name, i, 'fileDetail', 0, 'documentAttachmentId']
|
||||
)}
|
||||
docAttachmentId={o.fileDetail[0].documentAttachmentId}/>
|
||||
</> : null}
|
||||
<Button icon="pi pi-thumbs-up" rounded outlined
|
||||
disabled={shouldDisableFieldFn(name)}
|
||||
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
||||
@@ -45,7 +58,7 @@ const ListOfFiles = ({ files, updateFn, shouldDisableFieldFn, name, ndg, applica
|
||||
flexDirection: 'column',
|
||||
gap: '10px'
|
||||
}}>
|
||||
{o.fileDetail.map((k) => <li key={k.id} style={{
|
||||
{o.fileDetail.map((k, ind) => <li key={k.id} style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@@ -53,7 +66,15 @@ const ListOfFiles = ({ files, updateFn, shouldDisableFieldFn, name, ndg, applica
|
||||
}}>
|
||||
<span>{k.name}</span>
|
||||
<div className="appPageSection__iconActions">
|
||||
<ArchiveDocument ndg={ndg} applicationId={applicationId} fileId={k.id}/>
|
||||
<ArchiveDocument
|
||||
ndg={ndg}
|
||||
applicationId={applicationId}
|
||||
fileId={k.id}
|
||||
updateFn={(val) => updateFn(
|
||||
val,
|
||||
[name, i, 'fileDetail', ind, 'documentAttachmentId']
|
||||
)}
|
||||
docAttachmentId={k.documentAttachmentId}/>
|
||||
<Button icon="pi pi-eye" rounded
|
||||
onClick={() => {
|
||||
window.open(k.filePath, '_blank').focus()
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import { useForm, useFieldArray } from 'react-hook-form';
|
||||
import { isEmpty, head } from 'ramda';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { klona } from 'klona';
|
||||
|
||||
// tools
|
||||
import uniqid from '../../../../helpers/uniqid';
|
||||
|
||||
// components
|
||||
import FormField from '../../../../components/FormField';
|
||||
import { Button } from 'primereact/button';
|
||||
|
||||
const RepeaterFields = ({
|
||||
sourceId,
|
||||
sourceName,
|
||||
updateFn = () => {
|
||||
},
|
||||
updateCallbackFn = () => {
|
||||
},
|
||||
defaultValue = [],
|
||||
shouldDisable = false
|
||||
}) => {
|
||||
const [chosen, setChosen] = useState('');
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
register,
|
||||
trigger,
|
||||
getValues,
|
||||
watch
|
||||
} = useForm({
|
||||
defaultValues: useMemo(() => {
|
||||
return {
|
||||
items: defaultValue || []
|
||||
};
|
||||
}, [defaultValue]), mode: 'onChange'
|
||||
});
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control,
|
||||
name: 'items'
|
||||
});
|
||||
|
||||
const watchFields = watch('items');
|
||||
|
||||
const onSubmit = () => {
|
||||
}
|
||||
|
||||
const doUpdateAfterFileUploaded = () => {
|
||||
const formData = getValues();
|
||||
updateFn(formData.items);
|
||||
updateCallbackFn(formData.items);
|
||||
}
|
||||
|
||||
const addNew = () => {
|
||||
const uid = uniqid('f');
|
||||
const newItem = {
|
||||
fieldId: uid,
|
||||
nameValue: '',
|
||||
fileValue: []
|
||||
}
|
||||
append(newItem);
|
||||
setChosen(newItem.fieldId);
|
||||
trigger();
|
||||
};
|
||||
|
||||
const setNewChosen = useCallback((id) => {
|
||||
const chosenObj = head(fields.filter(o => id === o.fieldId));
|
||||
if (chosenObj) {
|
||||
setChosen(chosen === id ? '' : id);
|
||||
}
|
||||
}, [fields, chosen]);
|
||||
|
||||
const removeItem = useCallback((index) => {
|
||||
const chosenObj = klona(fields[index]);
|
||||
remove(index);
|
||||
if (chosen === chosenObj.fieldId) {
|
||||
setChosen('');
|
||||
}
|
||||
const formData = getValues();
|
||||
updateFn(formData.items);
|
||||
updateCallbackFn(formData.items);
|
||||
}, [fields, chosen]);
|
||||
|
||||
return (
|
||||
<div className="fieldsRepeater">
|
||||
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
|
||||
{watchFields
|
||||
? watchFields.map((o, index) => <div key={o.fieldId}
|
||||
className="fieldsRepeater__panel p-panel p-component">
|
||||
<div className="fieldsRepeater__heading p-panel p-panel-header">
|
||||
<span onClick={() => setNewChosen(o.fieldId)}>{o.nameValue}</span>
|
||||
<Button icon="pi pi-times"
|
||||
disabled={shouldDisable}
|
||||
outlined
|
||||
severity="danger"
|
||||
className="actionBtn"
|
||||
type="button"
|
||||
aria-label={__('Cancella', 'gepafin')}
|
||||
onClick={() => removeItem(index)}/>
|
||||
</div>
|
||||
<div className="fieldsRepeater__fields p-panel-content" data-hide={chosen !== o.fieldId}>
|
||||
<FormField
|
||||
type="textinput"
|
||||
disabled={shouldDisable}
|
||||
fieldName={`items.${index}.nameValue`}
|
||||
label={__('Titolo del file', 'gepafin')}
|
||||
control={control}
|
||||
errors={errors}
|
||||
defaultValue={o.nameValue}
|
||||
config={{ required: __('È obbligatorio', 'gepafin') }}
|
||||
/>
|
||||
<FormField
|
||||
type="fileupload"
|
||||
disabled={isEmpty(o.nameValue) || shouldDisable}
|
||||
setDataFn={setValue}
|
||||
saveFormCallback={doUpdateAfterFileUploaded}
|
||||
fieldName={`items.${index}.fileValue`}
|
||||
label={__('File', 'gepafin')}
|
||||
control={control}
|
||||
register={register}
|
||||
errors={errors}
|
||||
defaultValue={o.fileValue ? o.fileValue : []}
|
||||
accept={[]}
|
||||
source={sourceName}
|
||||
sourceId={sourceId}
|
||||
multiple={false}
|
||||
deleteOnBackend={false}
|
||||
config={{ required: __('È obbligatorio', 'gepafin') }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</form>
|
||||
<Button
|
||||
className="fieldsRepeater__addNew"
|
||||
outlined
|
||||
type="button"
|
||||
disabled={(watchFields && watchFields.filter(o => isEmpty(o.nameValue) || isEmpty(o.fileValue)).length > 0) || shouldDisable}
|
||||
onClick={addNew}
|
||||
label={__('Aggiungi nuovo file', 'gepafin')}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RepeaterFields;
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { is, isEmpty, isNil, sum, pathOr, head } from 'ramda';
|
||||
@@ -6,11 +6,12 @@ import { klona } from 'klona';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
|
||||
// store
|
||||
import { storeSet, useStore } from '../../store';
|
||||
import { storeGet, storeSet, useStore } from '../../store';
|
||||
|
||||
// api
|
||||
import ApplicationEvaluationService from '../../service/application-evaluation-service';
|
||||
import AmendmentsService from '../../service/amendments-service';
|
||||
import AppointmentService from '../../service/appointment-service';
|
||||
|
||||
// tools
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
@@ -24,19 +25,18 @@ import { Tag } from 'primereact/tag';
|
||||
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 HelpIcon from '../../icons/HelpIcon';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import ArchiveDocument from './components/ArchiveDocument';
|
||||
import HelpIcon from '../../icons/HelpIcon';
|
||||
import BlockingOverlay from '../../components/BlockingOverlay';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { InputTextarea } from 'primereact/inputtextarea';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
import DownloadApplicationArchive from './components/DownloadApplicationArchive';
|
||||
import DownloadCompanyDelegation from './components/DownloadCompanyDelegation';
|
||||
import DownloadSignedApplication from './components/DownloadSignedApplication';
|
||||
import AppointmentService from '../../service/appointment-service';
|
||||
import ListOfFiles from './components/ListOfFiles';
|
||||
import RepeaterFields from './components/RepeaterFields';
|
||||
|
||||
const APP_EVALUATION_FLOW_ID = process.env.REACT_APP_EVALUATION_FLOW_ID;
|
||||
|
||||
@@ -71,12 +71,24 @@ const DomandaEditPreInstructor = () => {
|
||||
}
|
||||
|
||||
const updateFlagsForSoccorso = (data) => {
|
||||
let nonRatedFilesLength = 0;
|
||||
|
||||
if (data.files) {
|
||||
const nonRatedFiles = data.files
|
||||
.map(el => el.valid)
|
||||
.filter(v => isNil(v));
|
||||
setAllFilesRated(nonRatedFiles.length === 0);
|
||||
nonRatedFilesLength = nonRatedFiles.length;
|
||||
}
|
||||
|
||||
if (data.amendmentDetails) {
|
||||
const nonRatedFiles = data.amendmentDetails
|
||||
.map(el => el.valid)
|
||||
.filter(v => isNil(v));
|
||||
nonRatedFilesLength = nonRatedFiles.length;
|
||||
}
|
||||
|
||||
setAllFilesRated(nonRatedFilesLength === 0);
|
||||
|
||||
if (data.checklist) {
|
||||
const checkedChecklistItems = data.checklist
|
||||
.map(el => el.valid)
|
||||
@@ -88,7 +100,7 @@ const DomandaEditPreInstructor = () => {
|
||||
|
||||
const doNewSoccorso = () => {
|
||||
if (connectedSoccorsoId !== 0) {
|
||||
doSaveDraft(`/domande/${id}/soccorso/${connectedSoccorsoId}`)
|
||||
navigate(`/domande/${id}/soccorso/${connectedSoccorsoId}`);
|
||||
} else {
|
||||
doSaveDraft(`/domande/${id}/aggiungi-soccorso/`)
|
||||
}
|
||||
@@ -153,11 +165,17 @@ const DomandaEditPreInstructor = () => {
|
||||
updateFlagsForSoccorso(newData);
|
||||
}
|
||||
|
||||
const doSaveDraft = (doRedirect = '') => {
|
||||
const doSaveDraft = useCallback((doRedirect = '') => {
|
||||
const formData = {
|
||||
criteria: klona(data.criteria),
|
||||
checklist: klona(data.checklist),
|
||||
files: klona(data.files),
|
||||
evaluationDocument: klona(data.evaluationDocument.map(o => ({
|
||||
...o,
|
||||
fileValue: o.fileValue[0] ? o.fileValue[0].id : ''
|
||||
})
|
||||
)),
|
||||
amendmentDetails: klona(data.amendmentDetails),
|
||||
note: data.note
|
||||
}
|
||||
|
||||
@@ -167,7 +185,7 @@ const DomandaEditPreInstructor = () => {
|
||||
(data) => updateCallback(data, doRedirect),
|
||||
errUpdateCallback
|
||||
);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const updateCallback = (data, doRedirect = '') => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
@@ -208,7 +226,7 @@ const DomandaEditPreInstructor = () => {
|
||||
motivation
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setIsVisibleCompleteDialog(false);
|
||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
||||
}
|
||||
|
||||
@@ -222,12 +240,13 @@ const DomandaEditPreInstructor = () => {
|
||||
motivation
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setIsVisibleCompleteDialog(false);
|
||||
ApplicationEvaluationService.updateEvaluation(data.assignedApplicationId, formData, updateStatusCallback, errUpdateStatusCallback);
|
||||
}
|
||||
|
||||
const updateStatusCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
setData(getFormattedData(data.data));
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
@@ -236,7 +255,7 @@ const DomandaEditPreInstructor = () => {
|
||||
});
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errUpdateStatusCallback = (data) => {
|
||||
@@ -248,7 +267,7 @@ const DomandaEditPreInstructor = () => {
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
setLoading(false);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const displayCriterionData = (id) => {
|
||||
@@ -376,7 +395,13 @@ const DomandaEditPreInstructor = () => {
|
||||
|
||||
const getNdgCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
console.log('data', data.data);
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
@@ -384,7 +409,7 @@ const DomandaEditPreInstructor = () => {
|
||||
const errGetNdgCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'error',
|
||||
severity: data.status === 'SUCCESS' ? 'info' : 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
@@ -432,15 +457,56 @@ const DomandaEditPreInstructor = () => {
|
||||
!isEmpty(appointmentData.title) && !isEmpty(appointmentData.text) && !isEmpty(appointmentData.amount)
|
||||
&& !isEmpty(appointmentData.duration) && appointmentData.duration !== 0 && appointmentData.amount !== 0
|
||||
) {
|
||||
console.log(appointmentData);
|
||||
//setLoading(true);
|
||||
storeSet.main.setAsyncRequest();
|
||||
const submitData = {
|
||||
'importoBreveTermine': appointmentData.amount,
|
||||
'durataMesiFinanziamento': appointmentData.duration,
|
||||
'nota': {
|
||||
'titolo': appointmentData.title,
|
||||
'testo': appointmentData.text
|
||||
}
|
||||
}
|
||||
|
||||
AppointmentService.createAppointment(id, submitData, getAppointemntCallback, errGetAppointemntCallback);
|
||||
}
|
||||
}
|
||||
|
||||
const getAppointemntCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
}
|
||||
setIsVisibleAppointmentDialog(false);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errGetAppointemntCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: data.status === 'SUCCESS' ? 'info' : 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
setIsVisibleAppointmentDialog(false);
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const doMakeAdmisible = () => {
|
||||
// TODO
|
||||
}
|
||||
|
||||
const evaluationShouldBeBlocked = (data = {}) => {
|
||||
const userData = storeGet.main.userData()
|
||||
return isAsyncRequest || userData.id !== data.assignedUserId;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const maxScore = pathOr(0, ['minScore'], data);
|
||||
const criteria = pathOr([], ['criteria'], data);
|
||||
@@ -507,11 +573,11 @@ const DomandaEditPreInstructor = () => {
|
||||
<span>{data.callName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Beneficiario', 'gepafin')}</span>
|
||||
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||
<span>{data.beneficiary}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Azienda', 'gepafin')}</span>
|
||||
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
|
||||
<span>{data.companyName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
@@ -541,17 +607,29 @@ const DomandaEditPreInstructor = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
||||
<RepeaterFields
|
||||
defaultValue={data.evaluationDocument ?? []}
|
||||
updateFn={(data) => updateEvaluationValue(
|
||||
data,
|
||||
['evaluationDocument']
|
||||
)}
|
||||
shouldDisable={['APPROVED', 'REJECTED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
||||
sourceId={data.assignedApplicationId}
|
||||
sourceName="evaluation"/>
|
||||
</div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Checklist Valutazione', 'gepafin')}</h2>
|
||||
<div className="appPageSection columns">
|
||||
<div>
|
||||
|
||||
<h3>{__('Lista', 'gepafin')}</h3>
|
||||
<div className="appPageSection__withBorder grey" style={{ marginBottom: '20px' }}>
|
||||
<div className="appPageSection__checklist">
|
||||
{data.checklist.map((o, i) => <div key={o.id}>
|
||||
<Checkbox
|
||||
disabled={shouldDisableField('checklist')}
|
||||
disabled={shouldDisableField('checklist') || evaluationShouldBeBlocked(data)}
|
||||
inputId={`checklist_${o.id}`}
|
||||
onChange={(e) => updateEvaluationValue(
|
||||
e.checked,
|
||||
@@ -567,7 +645,7 @@ const DomandaEditPreInstructor = () => {
|
||||
<div>
|
||||
<Editor
|
||||
value={data.note}
|
||||
readOnly={shouldDisableField('note')}
|
||||
readOnly={shouldDisableField('note') || evaluationShouldBeBlocked(data)}
|
||||
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||
headerTemplate={header}
|
||||
onTextChange={(e) => updateEvaluationValue(
|
||||
@@ -583,7 +661,7 @@ const DomandaEditPreInstructor = () => {
|
||||
<ListOfFiles
|
||||
files={data.files}
|
||||
updateFn={updateEvaluationValue}
|
||||
shouldDisableFieldFn={shouldDisableField}
|
||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
||||
name="files"
|
||||
ndg={data.ndg}
|
||||
applicationId={id}/>
|
||||
@@ -591,6 +669,18 @@ const DomandaEditPreInstructor = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isEmpty(data.amendmentDetails)
|
||||
? <div className="appPageSection">
|
||||
<h2>{__('Documenti di soccorso', 'gepafin')}</h2>
|
||||
<ListOfFiles
|
||||
files={data.amendmentDetails}
|
||||
updateFn={updateEvaluationValue}
|
||||
shouldDisableFieldFn={(name) => shouldDisableField(name) || evaluationShouldBeBlocked(data)}
|
||||
name="amendmentDetails"
|
||||
ndg={data.ndg}
|
||||
applicationId={id}/>
|
||||
</div> : null}
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Punteggi di valutazione', 'gepafin')}</h2>
|
||||
{data.criteria
|
||||
@@ -608,7 +698,7 @@ const DomandaEditPreInstructor = () => {
|
||||
<td>
|
||||
<div className="p-inputgroup">
|
||||
<InputNumber
|
||||
disabled={shouldDisableField('criteria')}
|
||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
||||
placeholder={__('Punteggio', 'gepafin')}
|
||||
keyfilter="int"
|
||||
value={o.score}
|
||||
@@ -631,7 +721,7 @@ const DomandaEditPreInstructor = () => {
|
||||
onClick={() => displayCriterionData(o.id)}
|
||||
aria-label={__('Mostra', 'gepafin')}/> : null}
|
||||
<Button icon="pi pi-thumbs-up" rounded outlined
|
||||
disabled={shouldDisableField('criteria')}
|
||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
||||
severity={!isNil(o.valid) && o.valid ? 'success' : 'secondary'}
|
||||
onClick={() => updateEvaluationValue(
|
||||
true,
|
||||
@@ -639,7 +729,7 @@ const DomandaEditPreInstructor = () => {
|
||||
)}
|
||||
aria-label={__('Su', 'gepafin')}/>
|
||||
<Button icon="pi pi-thumbs-down" rounded outlined
|
||||
disabled={shouldDisableField('criteria')}
|
||||
disabled={shouldDisableField('criteria') || evaluationShouldBeBlocked(data)}
|
||||
severity={!isNil(o.valid) && !o.valid ? 'danger' : 'secondary'}
|
||||
onClick={() => updateEvaluationValue(
|
||||
false,
|
||||
@@ -681,7 +771,8 @@ const DomandaEditPreInstructor = () => {
|
||||
{['EVALUATION', 'SOCCORSO', 'CLOSE'].includes(data.applicationStatus)
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id || data.status === 'CLOSE' || !allFilesRated || !atLeastOneChecked}
|
||||
disabled={!data.id || data.status === 'CLOSE' || (data.applicationStatus === 'EVALUATION'
|
||||
&& (!allFilesRated || !atLeastOneChecked)) || evaluationShouldBeBlocked(data)}
|
||||
onClick={doNewSoccorso}
|
||||
outlined
|
||||
label={<>
|
||||
@@ -696,7 +787,7 @@ const DomandaEditPreInstructor = () => {
|
||||
{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={data.status === 'CLOSE'}
|
||||
disabled={data.status === 'CLOSE' || evaluationShouldBeBlocked(data)}
|
||||
onClick={() => doSaveDraft()}
|
||||
outlined
|
||||
label={__('Salva bozza valutazione', 'gepafin')}
|
||||
@@ -706,41 +797,72 @@ const DomandaEditPreInstructor = () => {
|
||||
onClick={() => doSaveDraft()}
|
||||
label={__('Crea valutazione', 'gepafin')}
|
||||
icon="pi pi-save" iconPos="right"/>}
|
||||
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
|
||||
{/*{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus)
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id || !allFilesRated || !allChecksChecked}
|
||||
disabled={!data.id || !allFilesRated || !allChecksChecked || evaluationShouldBeBlocked(data)}
|
||||
onClick={doCheckNDG}
|
||||
label={__('Controlla NDG', 'gepafin')}
|
||||
/> : null}
|
||||
{APP_EVALUATION_FLOW_ID === '1' && ['EVALUATION'].includes(data.applicationStatus) && data.ndg
|
||||
/> : null}*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={true}
|
||||
onClick={() => {
|
||||
}}
|
||||
label={__('Controlla NDG', 'gepafin')}
|
||||
/>
|
||||
{/*{APP_EVALUATION_FLOW_ID === '1' && ['NDG'].includes(data.applicationStatus) && data.ndg
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id}
|
||||
disabled={!data.id || evaluationShouldBeBlocked(data)}
|
||||
onClick={doCreateAppointment}
|
||||
label={__('Crea l\'appuntamento', 'gepafin')}
|
||||
/> : null}
|
||||
{APP_EVALUATION_FLOW_ID === '1' && ['APPOINTMENT'].includes(data.applicationStatus)
|
||||
/> : null}*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={true}
|
||||
onClick={() => {
|
||||
}}
|
||||
label={__('Crea l\'appuntamento', 'gepafin')}
|
||||
/>
|
||||
{/*{APP_EVALUATION_FLOW_ID === '1' && ['APPOINTMENT'].includes(data.applicationStatus)
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!data.id}
|
||||
disabled={!data.id || evaluationShouldBeBlocked(data)}
|
||||
onClick={doMakeAdmisible}
|
||||
label={__('Ammissibile', 'gepafin')}
|
||||
/> : null}
|
||||
/> : null}*/}
|
||||
<Button
|
||||
type="button"
|
||||
disabled={true}
|
||||
onClick={() => {
|
||||
}}
|
||||
label={__('Ammissibile', 'gepafin')}
|
||||
/>
|
||||
{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={!isAdmissible
|
||||
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus))}
|
||||
disabled={!isAdmissible || ['APPROVED'].includes(data.applicationStatus) || evaluationShouldBeBlocked(data)}
|
||||
/*disabled={!isAdmissible
|
||||
|| (APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus))}*/
|
||||
onClick={initiateApproving}
|
||||
label={__('Approva Domanda', 'gepafin')}
|
||||
icon="pi pi-check" iconPos="right"/> : null}
|
||||
{data.id
|
||||
{/*{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={APP_EVALUATION_FLOW_ID === '1' && !['ADMISSIBLE', 'APPOINTMENT'].includes(data.applicationStatus)}
|
||||
onClick={initiateRejecting}
|
||||
label={__('Respingi Domanda', 'gepafin')}
|
||||
icon="pi pi-times" 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>
|
||||
@@ -840,4 +962,4 @@ const DomandaEditPreInstructor = () => {
|
||||
|
||||
}
|
||||
|
||||
export default DomandaEditPreInstructor;
|
||||
export default DomandaEditPreInstructor;
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { is, uniq } from 'ramda';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
// api
|
||||
import ApplicationService from '../../../../service/application-service';
|
||||
|
||||
// tools
|
||||
import getBandoLabel from '../../../../helpers/getBandoLabel';
|
||||
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
|
||||
|
||||
// translation
|
||||
import translationStrings from '../../../../translationStringsForComponents';
|
||||
|
||||
// components
|
||||
import { FilterMatchMode, FilterOperator } from 'primereact/api';
|
||||
import { DataTable } from 'primereact/datatable';
|
||||
@@ -13,14 +20,16 @@ import { Column } from 'primereact/column';
|
||||
import { Button } from 'primereact/button';
|
||||
import { Calendar } from 'primereact/calendar';
|
||||
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
||||
import translationStrings from '../../../../translationStringsForComponents';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
import { Tag } from 'primereact/tag';
|
||||
|
||||
|
||||
const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
const [items, setItems] = useState(null);
|
||||
const [filters, setFilters] = useState(null);
|
||||
const [localAsyncRequest, setLocalAsyncRequest] = useState(false);
|
||||
const [, setStatuses] = useState([]);
|
||||
const [statuses, setStatuses] = useState([]);
|
||||
const location = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
setLocalAsyncRequest(true);
|
||||
@@ -81,7 +90,8 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
callEndDate: {
|
||||
operator: FilterOperator.AND,
|
||||
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
||||
}
|
||||
},
|
||||
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -98,9 +108,12 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
return formatDate(rowData.submissionDate);
|
||||
};
|
||||
|
||||
/*const dateEndBodyTemplate = (rowData) => {
|
||||
return formatDate(rowData.callEndDate);
|
||||
};*/
|
||||
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 dateFilterTemplate = (options) => {
|
||||
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)}
|
||||
@@ -111,17 +124,22 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
return <ProperBandoLabel status={rowData.status}/>;
|
||||
};
|
||||
|
||||
const statusItemTemplate = (option) => {
|
||||
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
|
||||
};
|
||||
|
||||
const actionsBodyTemplate = (rowData) => {
|
||||
return <div className="appPageSection__tableActions lessGap">
|
||||
{openDialogFn
|
||||
{openDialogFn && ['SUBMIT', 'EVALUATION', 'SOCCORSO'].includes(rowData.status)
|
||||
? <Button severity="info"
|
||||
onClick={() => openDialogFn(rowData.id)}
|
||||
label={__('Assegnare', 'gepafin')}
|
||||
icon="pi pi-pencil" size="small" iconPos="right"/>
|
||||
: <Link to={'/domande'}>
|
||||
<Button severity="info" label={__('Gestire', 'gepafin')} size="small"/>
|
||||
</Link>}
|
||||
<Link to={`/domande/${rowData.id}`}>
|
||||
: location.pathname !== '/domande'
|
||||
? <Link to={'/domande'}>
|
||||
<Button severity="info" label={__('Gestire', 'gepafin')} size="small"/>
|
||||
</Link> : null}
|
||||
<Link to={`/domande/${rowData.id}/preview`}>
|
||||
<Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small"
|
||||
iconPos="right"/>
|
||||
</Link>
|
||||
@@ -147,7 +165,7 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
filter sortable
|
||||
filterPlaceholder={__('Cerca', 'gepafin')}
|
||||
style={{ minWidth: '10rem' }}/>
|
||||
<Column field="companyName" header={__('Azienda', 'gepafin')}
|
||||
<Column field="companyName" header={__('Azienda Beneficiaria', 'gepafin')}
|
||||
filter sortable
|
||||
filterPlaceholder={__('Cerca il nome', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
@@ -155,12 +173,14 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
filterField="submissionDate" dataType="date"
|
||||
style={{ minWidth: '8rem' }}
|
||||
body={dateAppliedBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||
{/*<Column header={__('Scadenza', 'gepafin')}
|
||||
filterField="callEndDate" dataType="date"
|
||||
style={{ minWidth: '8rem' }}
|
||||
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>*/}
|
||||
<Column field="assignedUserName" header={__('Assegnato', 'gepafin')}
|
||||
filter sortable
|
||||
filterPlaceholder={__('Cerca il nome', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
<Column field="status" header={__('Stato', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }} body={statusBodyTemplate}/>
|
||||
style={{ minWidth: '8rem' }} body={statusBodyTemplate}
|
||||
filter
|
||||
filterElement={statusFilterTemplate}/>
|
||||
<Column header={__('Azioni', 'gepafin')}
|
||||
body={actionsBodyTemplate}/>
|
||||
</DataTable>
|
||||
@@ -168,4 +188,4 @@ const AllDomandeTable = ({ openDialogFn, updaterString = '' }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default AllDomandeTable;
|
||||
export default AllDomandeTable;
|
||||
|
||||
@@ -24,7 +24,7 @@ import DraftApplicationsTable from '../Dashboard/components/DraftApplicationsTab
|
||||
const Domande = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isVisibleEditDialog, setIsVisibleEditDialog] = useState(false);
|
||||
const [roleId, setRoleId] = useState(0);
|
||||
const [roleIds, setRoleIds] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [chosenUser, setChosenUser] = useState(0);
|
||||
const [chosenApplication, setChosenApplication] = useState(0);
|
||||
@@ -34,10 +34,8 @@ const Domande = () => {
|
||||
const getRolesCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
const roles = data.data
|
||||
.filter(o => ['ROLE_PRE_INSTRUCTOR'].includes(o.roleType));
|
||||
if (roles.length) {
|
||||
setRoleId(roles[0].id);
|
||||
}
|
||||
.filter(o => ['ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.roleType));
|
||||
setRoleIds(roles.map(o => o.id));
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -65,7 +63,7 @@ const Domande = () => {
|
||||
}
|
||||
|
||||
const headerEditDialog = () => {
|
||||
return <span>{__('Assign application', 'gepafin')}</span>
|
||||
return <span>{__('Assegni la domanda', 'gepafin')}</span>
|
||||
}
|
||||
|
||||
const hideEditDialog = () => {
|
||||
@@ -126,11 +124,11 @@ const Domande = () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (roleId !== 0) {
|
||||
if (roleIds.length > 0) {
|
||||
setLoading(true);
|
||||
UserService.getUsers(getUsersCallback, errGetUsersCallback, [['roleId', roleId]])
|
||||
UserService.getUsers(getUsersCallback, errGetUsersCallback, [['roleIds', roleIds]])
|
||||
}
|
||||
}, [roleId]);
|
||||
}, [roleIds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisibleEditDialog) {
|
||||
|
||||
@@ -33,7 +33,7 @@ const BeneficiarioDomandeTable = () => {
|
||||
const [statuses, setStatuses] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0) {
|
||||
if (!isEmpty(chosenCompanyId) && chosenCompanyId !== 0 && !localAsyncRequest) {
|
||||
setLocalAsyncRequest(true);
|
||||
ApplicationService.getApplications(getApplCallback, errGetApplCallback, [
|
||||
['companyId', chosenCompanyId],
|
||||
@@ -126,7 +126,8 @@ const BeneficiarioDomandeTable = () => {
|
||||
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"
|
||||
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel}
|
||||
className="p-column-filter"
|
||||
showClear/>;
|
||||
};
|
||||
|
||||
@@ -139,11 +140,17 @@ const BeneficiarioDomandeTable = () => {
|
||||
};
|
||||
|
||||
const actionsBodyTemplate = (rowData) => {
|
||||
return rowData.status === 'SOCCORSO'
|
||||
? <Link to={`/domande/${rowData.id}`}>
|
||||
<Button severity="info" label={__('Dettagli', 'gepafin')} icon="pi pi-eye" size="small"
|
||||
return <>
|
||||
{rowData.status === 'SOCCORSO'
|
||||
? <Link to={`/domande/${rowData.id}`}>
|
||||
<Button severity="info" label={__('Dettagli', 'gepafin')} icon="pi pi-eye" size="small"
|
||||
iconPos="right"/>
|
||||
</Link> : null}
|
||||
<Link to={`/domande/${rowData.id}/preview`}>
|
||||
<Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small"
|
||||
iconPos="right"/>
|
||||
</Link> : null;
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
|
||||
const header = renderHeader();
|
||||
@@ -165,7 +172,7 @@ const BeneficiarioDomandeTable = () => {
|
||||
filter sortable
|
||||
filterPlaceholder={__('Cerca il nome', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
<Column field="companyName" header={__('Azienda', 'gepafin')}
|
||||
<Column field="companyName" header={__('Azienda Beneficiaria', 'gepafin')}
|
||||
filter sortable
|
||||
filterPlaceholder={__('Cerca il nome', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
@@ -184,4 +191,4 @@ const BeneficiarioDomandeTable = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default BeneficiarioDomandeTable;
|
||||
export default BeneficiarioDomandeTable;
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import React from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { head } from 'ramda';
|
||||
|
||||
// store
|
||||
import { useStore } from '../../store';
|
||||
|
||||
// components
|
||||
import BeneficiarioDomandeTable from './components/BeneficiarioDomandeTable';
|
||||
|
||||
const DomandePreInstructor = () => {
|
||||
const chosenCompanyId = useStore().main.chosenCompanyId();
|
||||
const companies = useStore().main.companies();
|
||||
const company = head(companies.filter(o => o.id === chosenCompanyId));
|
||||
|
||||
return(
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Archivio domande', 'gepafin')}</h1>
|
||||
{company ? <span className="companyName">{company.companyName}</span> : null}
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
184
src/pages/DomandeInstructorManager/index.js
Normal file
184
src/pages/DomandeInstructorManager/index.js
Normal file
@@ -0,0 +1,184 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { isEmpty } from 'ramda';
|
||||
|
||||
// store
|
||||
import { storeSet } from '../../store';
|
||||
|
||||
// tools
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
import uniqid from '../../helpers/uniqid';
|
||||
|
||||
// api
|
||||
import AssignedApplicationService from '../../service/assigned-application-service';
|
||||
import UserService from '../../service/user-service';
|
||||
|
||||
// components
|
||||
import PreInstructorDomandeTable from '../DashboardPreInstructor/components/PreInstructorDomandeTable';
|
||||
import AllDomandeTable from '../Domande/components/AllDomandeTable';
|
||||
import { classNames } from 'primereact/utils';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import { Button } from 'primereact/button';
|
||||
|
||||
const DomandeInstructorManager = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isVisibleEditDialog, setIsVisibleEditDialog] = useState(false);
|
||||
const [roleIds, setRoleIds] = useState(0);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [chosenUser, setChosenUser] = useState(0);
|
||||
const [chosenApplication, setChosenApplication] = useState(0);
|
||||
const [updaterString, setUpdaterString] = useState('');
|
||||
const toast = useRef(null);
|
||||
|
||||
const getRolesCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
const roles = data.data
|
||||
.filter(o => ['ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.roleType));
|
||||
setRoleIds(roles.map(o => o.id));
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errGetRolesCallback = (data) => {
|
||||
set404FromErrorResponse(data);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const getUsersCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
const users = data.data
|
||||
.map(o => ({
|
||||
name: `${o.firstName} ${o.lastName} (${o.email})`,
|
||||
value: o.id
|
||||
}));
|
||||
setUsers(users);
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errGetUsersCallback = (data) => {
|
||||
set404FromErrorResponse(data);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const headerEditDialog = () => {
|
||||
return <span>{__('Assegni la domanda', 'gepafin')}</span>
|
||||
}
|
||||
|
||||
const hideEditDialog = () => {
|
||||
setIsVisibleEditDialog(false);
|
||||
setChosenUser(0);
|
||||
setChosenApplication(0);
|
||||
}
|
||||
|
||||
const footerEditDialog = () => {
|
||||
return <div>
|
||||
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideEditDialog} outlined/>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={loading}
|
||||
label={__('Invia', 'gepafin')} onClick={saveEditDialog}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
const openAssignDialog = (applId) => {
|
||||
setChosenApplication(applId)
|
||||
setIsVisibleEditDialog(true);
|
||||
}
|
||||
|
||||
const saveEditDialog = () => {
|
||||
if (chosenUser !== 0 && chosenApplication !== 0) {
|
||||
storeSet.main.setAsyncRequest();
|
||||
AssignedApplicationService.assignApplication(chosenApplication, assignApplCallback, errAssignApplCallback, [
|
||||
['userId', chosenUser]
|
||||
]);
|
||||
hideEditDialog();
|
||||
}
|
||||
}
|
||||
|
||||
const assignApplCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
setUpdaterString(uniqid());
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const errAssignApplCallback = (data) => {
|
||||
if (toast.current && data.message) {
|
||||
toast.current.show({
|
||||
severity: 'error',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
set404FromErrorResponse(data);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (roleIds.length > 0) {
|
||||
setLoading(true);
|
||||
UserService.getUsers(getUsersCallback, errGetUsersCallback, [['roleIds', roleIds]])
|
||||
}
|
||||
}, [roleIds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisibleEditDialog) {
|
||||
setLoading(true);
|
||||
UserService.getRoles(getRolesCallback, errGetRolesCallback)
|
||||
}
|
||||
}, [isVisibleEditDialog]);
|
||||
|
||||
return(
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Domande da valutare', 'gepafin')}</h1>
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<PreInstructorDomandeTable/>
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Domande pubblicate', 'gepafin')}</h2>
|
||||
<AllDomandeTable openDialogFn={openAssignDialog} updaterString={updaterString}/>
|
||||
</div>
|
||||
|
||||
<Dialog
|
||||
visible={isVisibleEditDialog}
|
||||
modal
|
||||
header={headerEditDialog}
|
||||
footer={footerEditDialog}
|
||||
style={{ maxWidth: '600px', width: '100%' }}
|
||||
onHide={hideEditDialog}>
|
||||
<div className="appForm__field">
|
||||
<label
|
||||
className={classNames({ 'p-error': isEmpty(chosenUser) || chosenUser === 0 || chosenApplication === 0 })}>
|
||||
{__('Istruttore', 'gepafin')}*
|
||||
</label>
|
||||
<Dropdown
|
||||
value={chosenUser}
|
||||
invalid={isEmpty(chosenUser) || chosenUser === 0 || chosenApplication === 0}
|
||||
onChange={(e) => setChosenUser(e.value)}
|
||||
options={users}
|
||||
optionLabel="name"
|
||||
optionValue="value"/>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DomandeInstructorManager;
|
||||
@@ -8,7 +8,7 @@ const DomandePreInstructor = () => {
|
||||
return(
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Archivio domande', 'gepafin')}</h1>
|
||||
<h1>{__('Domande da valutare', 'gepafin')}</h1>
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
@@ -185,7 +185,7 @@ const SoccorsoAddPreInstructor = () => {
|
||||
<span>{data.callName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Beneficiario', 'gepafin')}</span>
|
||||
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||
<span>{data.beneficiaryName}</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -193,7 +193,7 @@ const SoccorsoAddPreInstructor = () => {
|
||||
<div className="appPageSection">
|
||||
<div className="appPageSection columns">
|
||||
<div>
|
||||
<h3>{__('Note', 'gepafin')}</h3>
|
||||
<h3>{__('Pec/Email', 'gepafin')}</h3>
|
||||
<div style={{marginBottom: '30px'}}>
|
||||
<Editor
|
||||
value={formData.note}
|
||||
@@ -281,6 +281,7 @@ const SoccorsoAddPreInstructor = () => {
|
||||
<Button
|
||||
type="button"
|
||||
outlined
|
||||
onClick={goToEvaluationPage}
|
||||
label={__('Anulla', 'gepafin')}
|
||||
icon="pi pi-times" iconPos="right"/>
|
||||
<Button
|
||||
@@ -307,4 +308,4 @@ const SoccorsoAddPreInstructor = () => {
|
||||
|
||||
}
|
||||
|
||||
export default SoccorsoAddPreInstructor;
|
||||
export default SoccorsoAddPreInstructor;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { is, isEmpty } from 'ramda';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { klona } from 'klona';
|
||||
import { wrap } from 'object-path-immutable';
|
||||
|
||||
// store
|
||||
import { storeSet, useStore } from '../../store';
|
||||
@@ -16,7 +17,6 @@ import ApplicationService from '../../service/application-service';
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
import getBandoLabel from '../../helpers/getBandoLabel';
|
||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||
|
||||
// components
|
||||
import { Button } from 'primereact/button';
|
||||
@@ -25,8 +25,10 @@ import { Toast } from 'primereact/toast';
|
||||
import { Dialog } from 'primereact/dialog';
|
||||
import FormField from '../../components/FormField';
|
||||
import SoccorsoComunications from '../SoccorsoEditPreInstructor/components/SoccorsoComunications';
|
||||
import { Editor } from 'primereact/editor';
|
||||
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
|
||||
|
||||
const DomandaBeneficiario = () => {
|
||||
const SoccorsoEditBeneficiario = () => {
|
||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
@@ -67,12 +69,16 @@ const DomandaBeneficiario = () => {
|
||||
if (data.data.length) {
|
||||
const amendmentObj = data.data[0];
|
||||
setData(getFormattedData(amendmentObj));
|
||||
const formDataInitial = amendmentObj.applicationFormFields.reduce((acc, cur) => {
|
||||
let formDataInitial = amendmentObj.applicationFormFields.reduce((acc, cur) => {
|
||||
if (cur.fieldValue) {
|
||||
acc[cur.fieldId] = cur.fieldValue;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
formDataInitial = {
|
||||
...formDataInitial,
|
||||
amendmentDocuments: amendmentObj.amendmentDocuments
|
||||
}
|
||||
setFormInitialData(formDataInitial);
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
} else {
|
||||
@@ -101,7 +107,7 @@ const DomandaBeneficiario = () => {
|
||||
}
|
||||
|
||||
const getFormattedData = (data) => {
|
||||
data.submissionDate = is(String, data.submissionDate) ? new Date(data.submissionDate) : (data.submissionDate ? data.submissionDate : '');
|
||||
data.evaluationEndDate = is(String, data.evaluationEndDate) ? new Date(data.evaluationEndDate) : (data.evaluationEndDate ? data.evaluationEndDate : '');
|
||||
data.startDate = is(String, data.startDate) ? new Date(data.startDate) : (data.startDate ? data.startDate : '');
|
||||
data.expirationDate = is(String, data.expirationDate) ? new Date(data.expirationDate) : (data.expirationDate ? data.expirationDate : '');
|
||||
return data;
|
||||
@@ -110,10 +116,11 @@ const DomandaBeneficiario = () => {
|
||||
const onSubmit = () => {
|
||||
};
|
||||
|
||||
const doUpdateAmendment = () => {
|
||||
const doUpdateAmendment = (doClose = false) => {
|
||||
trigger();
|
||||
let formValues = klona(getValues());
|
||||
const newFormValues = Object.keys(formValues)
|
||||
.filter(v => v !== 'amendmentDocuments')
|
||||
.reduce((acc, cur) => {
|
||||
let fieldVal = formValues[cur];
|
||||
|
||||
@@ -126,32 +133,59 @@ const DomandaBeneficiario = () => {
|
||||
});
|
||||
return acc;
|
||||
}, []);
|
||||
const newAmendDocs = formValues.amendmentDocuments
|
||||
? formValues.amendmentDocuments.map(o => o.id).join(',')
|
||||
: '';
|
||||
|
||||
const submitData = {
|
||||
applicationFormFields: newFormValues,
|
||||
amendmentDocuments: newAmendDocs,
|
||||
amendmentNotes: data.amendmentNotes
|
||||
}
|
||||
const amendmentId = data.id;
|
||||
|
||||
storeSet.main.setAsyncRequest();
|
||||
AmendmentsService.updateSoccorso(amendmentId, submitData, updateAmendmentCallback, errUpdateAmendmentCallback);
|
||||
|
||||
AmendmentsService.updateSoccorso(
|
||||
amendmentId,
|
||||
submitData,
|
||||
(resp) => updateAmendmentCallback(resp, doClose),
|
||||
errUpdateAmendmentCallback
|
||||
);
|
||||
}
|
||||
|
||||
const updateAmendmentCallback = (data) => {
|
||||
const doUpdateAmendmentAndCompleteTask = () => {
|
||||
doUpdateAmendment(true);
|
||||
}
|
||||
|
||||
const updateAmendmentCallback = (data, doClose = false) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
const newFormDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||
if (cur.fieldValue) {
|
||||
acc[cur.fieldId] = cur.fieldValue;
|
||||
setData(getFormattedData(data.data));
|
||||
|
||||
if (doClose) {
|
||||
AmendmentsService.updateStatusSoccorso(data.data.id, updateAmendmentCallback, errUpdateAmendmentCallback, [
|
||||
['status', 'RESPONSE_RECEIVED']
|
||||
]);
|
||||
} else {
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, formInitialData);
|
||||
setFormInitialData(newFormDataInitial);
|
||||
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();
|
||||
}
|
||||
@@ -168,6 +202,31 @@ const DomandaBeneficiario = () => {
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const updateNewAmendmentData = (value, path) => {
|
||||
const newData = wrap(data).set(path, value).value();
|
||||
setData(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();
|
||||
|
||||
useEffect(() => {
|
||||
if (formInitialData) {
|
||||
//reset();
|
||||
@@ -182,7 +241,7 @@ const DomandaBeneficiario = () => {
|
||||
{data.id
|
||||
? <h1>
|
||||
{sprintf(__('Soccorso Istruttorio: richiesta integrazione documenti per domanda #%s', 'gepafin'), id)}
|
||||
</h1> : null}
|
||||
</h1> : null}
|
||||
{dataAppl.id
|
||||
? <h1>
|
||||
{sprintf(__('Dettagli: domanda #%s', 'gepafin'), dataAppl.id)}
|
||||
@@ -216,11 +275,11 @@ const DomandaBeneficiario = () => {
|
||||
<span>{data.callName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Beneficiario', 'gepafin')}</span>
|
||||
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||
<span>{data.beneficiaryName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Azienda', 'gepafin')}</span>
|
||||
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
|
||||
<span></span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
@@ -239,7 +298,7 @@ const DomandaBeneficiario = () => {
|
||||
{dataAppl.id
|
||||
? <div className="appPageSection__withBorder columns">
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('ID domanda', 'gepafin')}</span>
|
||||
<span>{__('ID domanda', 'gepafin')}</span>
|
||||
<span>{dataAppl.id}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
@@ -247,7 +306,7 @@ const DomandaBeneficiario = () => {
|
||||
<span>{dataAppl.callTitle}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Azienda', 'gepafin')}</span>
|
||||
<span>{__('Azienda Beneficiaria', 'gepafin')}</span>
|
||||
<span>{dataAppl.companyName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
@@ -268,10 +327,13 @@ const DomandaBeneficiario = () => {
|
||||
? <div className="appPageSection">
|
||||
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
|
||||
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
||||
<div className="appPageSection__withBorder grey ql-editor"
|
||||
style={{ minHeight: '100px' }}>
|
||||
{renderHtmlContent(data.note)}
|
||||
</div>
|
||||
<div>{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}</div>
|
||||
</div> : null}
|
||||
|
||||
{data.id
|
||||
? <div className="appPageSection">
|
||||
<h2>{__('Comunicazioni', 'gepafin')}</h2>
|
||||
<SoccorsoComunications amendmentId={data.id} soccorsoStatus={data.status}/>
|
||||
</div> : null}
|
||||
|
||||
{data.id
|
||||
@@ -282,7 +344,7 @@ const DomandaBeneficiario = () => {
|
||||
? data.formFields.map((o, i) => {
|
||||
return <FormField
|
||||
key={o.fieldId}
|
||||
disabled={data.status === 'CLOSE'}
|
||||
disabled={data.status !== 'AWAITING'}
|
||||
type="fileupload"
|
||||
setDataFn={setValue}
|
||||
saveFormCallback={doUpdateAmendment}
|
||||
@@ -294,58 +356,100 @@ const DomandaBeneficiario = () => {
|
||||
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
|
||||
accept={[]}
|
||||
source="AMENDMENT"
|
||||
sourceId={data.applicationId}
|
||||
sourceId={data.id}
|
||||
multiple={true}
|
||||
/>
|
||||
}) : null}
|
||||
</form>
|
||||
{/*<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>*/}
|
||||
<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> : null}
|
||||
|
||||
{data.id
|
||||
? <div className="appPageSection">
|
||||
<h2>{__('Comunicazioni', 'gepafin')}</h2>
|
||||
<SoccorsoComunications amendmentId={data.id} soccorsoStatus={data.status}/>
|
||||
</div> : null}
|
||||
<h2>{__('Documenti aggiuntivi', 'gepafin')}</h2>
|
||||
<div className="appPageSection">
|
||||
<h3>{__('Notes', 'gepafin')}</h3>
|
||||
<div style={{ marginBottom: '30px', width: '100%', position: 'relative' }}>
|
||||
<BlockingOverlay shouldDisplay={data.status !== 'AWAITING'}/>
|
||||
<Editor
|
||||
value={data.amendmentNotes}
|
||||
readOnly={data.status !== 'AWAITING'}
|
||||
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={data.status !== 'AWAITING'}
|
||||
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={data.id}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
</div> : null}
|
||||
|
||||
{data.id
|
||||
? <div className="appPageSection__message warning">
|
||||
<i className="pi pi-exclamation-triangle"></i>
|
||||
<span className="summary">{__('Attenzione', 'gepafin')}</span>
|
||||
<span>{__('Inviare la documentazione richiesta completa delle integrazioni esclusivamente via PEC. In caso contarrio l’integrazione non può essere ritenuta valida.', 'gepafin')}</span>
|
||||
</div> : null}
|
||||
<i className="pi pi-exclamation-triangle"></i>
|
||||
<span className="summary">{__('Attenzione', 'gepafin')}</span>
|
||||
<span>{__('Inviare la documentazione richiesta completa delle integrazioni esclusivamente via PEC. In caso contarrio l’integrazione non può essere ritenuta valida.', 'gepafin')}</span>
|
||||
</div> : null}
|
||||
|
||||
<div className="appPageSection">
|
||||
<div className="appPageSection__actions">
|
||||
{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
disabled={isAsyncRequest}
|
||||
onClick={() => setIsVisibleEmailDialog(true)}
|
||||
label={__('Invia documenti via PEC', 'gepafin')}
|
||||
icon="pi pi-envelope" iconPos="right"/> : null}
|
||||
type="button"
|
||||
disabled={isAsyncRequest || data.status !== 'AWAITING'}
|
||||
onClick={doUpdateAmendmentAndCompleteTask}
|
||||
label={__('Invia documenti', 'gepafin')}
|
||||
icon="pi pi-save" iconPos="right"/> : null}
|
||||
{data.id
|
||||
? <Button
|
||||
type="button"
|
||||
outlined
|
||||
disabled={isAsyncRequest || data.status !== 'AWAITING'}
|
||||
onClick={() => doUpdateAmendment()}
|
||||
label={__('Salva bozza', 'gepafin')}
|
||||
icon="pi pi-save" iconPos="right"/> : null}
|
||||
<Button
|
||||
type="button"
|
||||
outlined
|
||||
onClick={goToArchivePage}
|
||||
disabled={isAsyncRequest}
|
||||
label={__('Chiudi', 'gepafin')}
|
||||
icon="pi pi-times" iconPos="right"/>
|
||||
label={__('Indietro', 'gepafin')}
|
||||
icon="pi pi-arrow-left" iconPos="left"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog
|
||||
header={__('Invia documenti via PEC', 'gepafin')}
|
||||
header={__('Invia documenti', 'gepafin')}
|
||||
visible={isVisibleEmailDialog}
|
||||
style={{ width: '50vw' }}
|
||||
onHide={() => {if (!isVisibleEmailDialog) return; setIsVisibleEmailDialog(false); }}>
|
||||
onHide={() => {
|
||||
if (!isVisibleEmailDialog) return;
|
||||
setIsVisibleEmailDialog(false);
|
||||
}}>
|
||||
<p className="m-0">
|
||||
{data.callEmail}
|
||||
</p>
|
||||
@@ -355,4 +459,4 @@ const DomandaBeneficiario = () => {
|
||||
|
||||
}
|
||||
|
||||
export default DomandaBeneficiario;
|
||||
export default SoccorsoEditBeneficiario;
|
||||
@@ -16,7 +16,7 @@ import AmendmentsService from '../../service/amendments-service';
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
import getBandoLabel from '../../helpers/getBandoLabel';
|
||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
||||
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
|
||||
|
||||
// components
|
||||
import { Button } from 'primereact/button';
|
||||
@@ -35,10 +35,12 @@ const SoccorsoEditPreInstructor = () => {
|
||||
const { id, amendmentId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [data, setData] = useState({});
|
||||
const [isVisibleCloseAmendDialog, setIsVisibleCloseAmendDialog] = useState(false);
|
||||
const [isVisibleExtendTimeDialog, setIsVisibleExtendTimeDialog] = useState(false);
|
||||
const [extendedTime, setExtendedTime] = useState(3);
|
||||
const [isLoadingExtendingTime, setIsLoadingExtendingTime] = useState(false);
|
||||
const [isLoadingReminding, setIsLoadingReminding] = useState(false);
|
||||
const [internalNote, setInternalNote] = useState('');
|
||||
const toast = useRef(null);
|
||||
const [formInitialData, setFormInitialData] = useState({});
|
||||
const {
|
||||
@@ -62,12 +64,16 @@ const SoccorsoEditPreInstructor = () => {
|
||||
const getCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
setData(getFormattedData(data.data));
|
||||
const formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||
let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||
if (cur.fieldValue) {
|
||||
acc[cur.fieldId] = cur.fieldValue;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
formDataInitial = {
|
||||
...formDataInitial,
|
||||
amendmentDocuments: data.data.amendmentDocuments
|
||||
}
|
||||
setFormInitialData(formDataInitial);
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
@@ -112,17 +118,18 @@ const SoccorsoEditPreInstructor = () => {
|
||||
const header = renderHeader();
|
||||
|
||||
const updateNewAmendmentData = (value, path) => {
|
||||
const newData = wrap(data).set(path.split('.'), value).value();
|
||||
const newData = wrap(data).set(path, value).value();
|
||||
setData(newData);
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
};
|
||||
|
||||
const doUpdateAmendment = () => {
|
||||
const doUpdateAmendment = (doClose = false) => {
|
||||
trigger();
|
||||
let formValues = klona(getValues());
|
||||
const newFormValues = Object.keys(formValues)
|
||||
.filter(v => v !== 'amendmentDocuments')
|
||||
.reduce((acc, cur) => {
|
||||
let fieldVal = formValues[cur];
|
||||
|
||||
@@ -135,30 +142,55 @@ const SoccorsoEditPreInstructor = () => {
|
||||
});
|
||||
return acc;
|
||||
}, []);
|
||||
const newAmendDocs = formValues.amendmentDocuments
|
||||
? formValues.amendmentDocuments.map(o => o.id).join(',')
|
||||
: '';
|
||||
|
||||
const submitData = {
|
||||
applicationFormFields: newFormValues
|
||||
applicationFormFields: newFormValues,
|
||||
amendmentDocuments: newAmendDocs,
|
||||
amendmentNotes: data.amendmentNotes
|
||||
}
|
||||
|
||||
storeSet.main.setAsyncRequest();
|
||||
AmendmentsService.updateSoccorso(amendmentId, submitData, updateAmendmentCallback, errUpdateAmendmentCallback);
|
||||
AmendmentsService.updateSoccorso(
|
||||
amendmentId,
|
||||
submitData,
|
||||
(resp) => updateAmendmentCallback(resp, doClose),
|
||||
errUpdateAmendmentCallback
|
||||
);
|
||||
}
|
||||
|
||||
const updateAmendmentCallback = (data) => {
|
||||
const updateAmendmentCallback = (data, doClose = false) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
const newFormDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||
if (cur.fieldValue) {
|
||||
acc[cur.fieldId] = cur.fieldValue;
|
||||
setData(getFormattedData(data.data));
|
||||
console.log('internalNote', internalNote)
|
||||
if (doClose) {
|
||||
const submitData = {
|
||||
internalNote
|
||||
}
|
||||
return acc;
|
||||
}, formInitialData);
|
||||
setFormInitialData(newFormDataInitial);
|
||||
storeSet.main.setAsyncRequest();
|
||||
AmendmentsService.closeSoccorso(amendmentId, submitData, closeAmendmentCallback, errCloseAmendmentCallback);
|
||||
} else {
|
||||
if (toast.current) {
|
||||
toast.current.show({
|
||||
severity: 'success',
|
||||
summary: '',
|
||||
detail: data.message
|
||||
});
|
||||
}
|
||||
let formDataInitial = data.data.applicationFormFields.reduce((acc, cur) => {
|
||||
if (cur.fieldValue) {
|
||||
acc[cur.fieldId] = cur.fieldValue;
|
||||
}
|
||||
return acc;
|
||||
}, formInitialData);
|
||||
formDataInitial = {
|
||||
...formDataInitial,
|
||||
amendmentDocuments: data.data.amendmentDocuments
|
||||
}
|
||||
setFormInitialData(formDataInitial);
|
||||
}
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
@@ -175,12 +207,30 @@ const SoccorsoEditPreInstructor = () => {
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
}
|
||||
|
||||
const openCloseAmendmentDialog = () => {
|
||||
setIsVisibleCloseAmendDialog(true);
|
||||
}
|
||||
|
||||
const headerCloseAmendDialog = () => {
|
||||
return <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 = () => {
|
||||
const submitData = {
|
||||
internalNote: data.internalNote
|
||||
}
|
||||
storeSet.main.setAsyncRequest();
|
||||
AmendmentsService.closeSoccorso(amendmentId, submitData, closeAmendmentCallback, errCloseAmendmentCallback);
|
||||
doUpdateAmendment(true);
|
||||
}
|
||||
|
||||
const closeAmendmentCallback = (data) => {
|
||||
@@ -193,7 +243,8 @@ const SoccorsoEditPreInstructor = () => {
|
||||
});
|
||||
}
|
||||
if (data.data.status) {
|
||||
updateNewAmendmentData(data.data.status, 'status')
|
||||
updateNewAmendmentData(data.data.status, ['status']);
|
||||
setIsVisibleCloseAmendDialog(false);
|
||||
}
|
||||
}
|
||||
storeSet.main.unsetAsyncRequest();
|
||||
@@ -297,7 +348,6 @@ const SoccorsoEditPreInstructor = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (formInitialData) {
|
||||
//reset();
|
||||
Object.keys(formInitialData).map(k => setValue(k, formInitialData[k]));
|
||||
trigger();
|
||||
}
|
||||
@@ -342,7 +392,7 @@ const SoccorsoEditPreInstructor = () => {
|
||||
<span>{data.callName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Beneficiario', 'gepafin')}</span>
|
||||
<span>{__('Referente Aziendale', 'gepafin')}</span>
|
||||
<span>{data.beneficiaryName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
@@ -361,26 +411,19 @@ const SoccorsoEditPreInstructor = () => {
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
|
||||
<div className="appPageSection columns">
|
||||
<div>
|
||||
<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>
|
||||
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
||||
<div className="appPageSection__withBorder grey ql-editor"
|
||||
style={{ minHeight: '200px' }}>
|
||||
{renderHtmlContent(data.note)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<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">
|
||||
@@ -388,15 +431,15 @@ const SoccorsoEditPreInstructor = () => {
|
||||
<SoccorsoComunications amendmentId={amendmentId} soccorsoStatus={data.status}/>
|
||||
</div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h2>{__('Documenti Ricevuti', 'gepafin')}</h2>
|
||||
{data.formFields && !isEmpty(data.formFields)
|
||||
? <div className="appPageSection">
|
||||
<h2>{__('Documenti Ricevuti', 'gepafin')}</h2>
|
||||
|
||||
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
|
||||
{data.formFields
|
||||
? data.formFields.map((o, i) => {
|
||||
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
|
||||
{data.formFields.map((o, i) => {
|
||||
return <FormField
|
||||
key={o.fieldId}
|
||||
disabled={data.status === 'CLOSE'}
|
||||
disabled={['CLOSE', 'AWAITING', 'EXPIRED'].includes(data.status)}
|
||||
type="fileupload"
|
||||
setDataFn={setValue}
|
||||
saveFormCallback={doUpdateAmendment}
|
||||
@@ -408,27 +451,46 @@ const SoccorsoEditPreInstructor = () => {
|
||||
defaultValue={formInitialData[o.fieldId] ? formInitialData[o.fieldId] : []}
|
||||
accept={[]}
|
||||
source="AMENDMENT"
|
||||
sourceId={data.applicationId}
|
||||
sourceId={amendmentId}
|
||||
multiple={true}
|
||||
/>
|
||||
}) : null}
|
||||
</form>
|
||||
</div>
|
||||
})}
|
||||
</form>
|
||||
</div> : null}
|
||||
|
||||
<div className="appForm__field">
|
||||
<label>{__('Motivazioni / Note Interne', 'gepafin')}</label>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<BlockingOverlay shouldDisplay={data.status === 'CLOSE'}/>
|
||||
<Editor
|
||||
value={data.internalNote}
|
||||
readOnly={data.status === 'CLOSE'}
|
||||
placeholder={__('Digita qui il messagio', 'gepafin')}
|
||||
headerTemplate={header}
|
||||
onTextChange={(e) => updateNewAmendmentData(
|
||||
e.htmlValue,
|
||||
'internalNote'
|
||||
)}
|
||||
style={{ height: 80 * 3, width: '100%' }}
|
||||
<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>
|
||||
@@ -444,7 +506,7 @@ const SoccorsoEditPreInstructor = () => {
|
||||
<Button
|
||||
type="button"
|
||||
onClick={sendReminder}
|
||||
disabled={isLoadingReminding || data.status === 'CLOSE'}
|
||||
disabled={isLoadingReminding || ['CLOSE', 'EXPIRED'].includes(data.status)}
|
||||
outlined
|
||||
label={__('Invia Sollecito', 'gepafin')}
|
||||
icon="pi pi-send"
|
||||
@@ -452,21 +514,21 @@ const SoccorsoEditPreInstructor = () => {
|
||||
<Button
|
||||
type="button"
|
||||
onClick={openExtendResponseTimeDialog}
|
||||
disabled={isLoadingExtendingTime || data.status === 'CLOSE'}
|
||||
disabled={isLoadingExtendingTime || ['CLOSE', 'EXPIRED'].includes(data.status)}
|
||||
outlined
|
||||
label={__('Estendi Scadenza', 'gepafin')}
|
||||
icon="pi pi-stopwatch"
|
||||
/>
|
||||
{/*<Button
|
||||
type="button"
|
||||
onClick={doUpdateAmendment}
|
||||
disabled={isAsyncRequest || data.status === 'CLOSE'}
|
||||
label={__('Salva bozza', 'gepafin')}
|
||||
icon="pi pi-save" iconPos="right"/>*/}
|
||||
<Button
|
||||
type="button"
|
||||
onClick={doCloseAmendment}
|
||||
disabled={isAsyncRequest || data.status === 'CLOSE'}
|
||||
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', 'EXPIRED'].includes(data.status)}
|
||||
label={__('Chiudi Soccorso Istruttorio', 'gepafin')}
|
||||
icon="pi pi-times" iconPos="right"/>
|
||||
</div>
|
||||
@@ -488,15 +550,38 @@ const SoccorsoEditPreInstructor = () => {
|
||||
</label>
|
||||
<InputNumber
|
||||
keyfilter="int"
|
||||
disabled={data.status === 'CLOSE'}
|
||||
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 SoccorsoEditPreInstructor;
|
||||
export default SoccorsoEditPreInstructor;
|
||||
|
||||
@@ -78,7 +78,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
|
||||
operator: FilterOperator.AND,
|
||||
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||
},
|
||||
beneficiaryName: {
|
||||
companyName: {
|
||||
operator: FilterOperator.AND,
|
||||
constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
|
||||
},
|
||||
@@ -149,7 +149,7 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
|
||||
<Column field="callName" header={__('Bando', 'gepafin')}
|
||||
filter filterPlaceholder={__('Cerca', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
<Column field="beneficiaryName" header={__('Beneficiario', 'gepafin')}
|
||||
<Column field="companyName" header={__('Azienda Beneficiaria', 'gepafin')}
|
||||
filter filterPlaceholder={__('Cerca', 'gepafin')}
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
<Column header={__('Data Richiesta', 'gepafin')}
|
||||
@@ -170,4 +170,4 @@ const PreInstructorSoccorsiTable = ({ openDialogFn }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default PreInstructorSoccorsiTable;
|
||||
export default PreInstructorSoccorsiTable;
|
||||
|
||||
192
src/pages/UserActivity/index.js
Normal file
192
src/pages/UserActivity/index.js
Normal file
@@ -0,0 +1,192 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { isEmpty, pathOr } from 'ramda';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import NumberFlow from '@number-flow/react';
|
||||
|
||||
// service
|
||||
import UserService from '../../service/user-service';
|
||||
|
||||
// tools
|
||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||
|
||||
// components
|
||||
import { Button } from 'primereact/button';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
|
||||
|
||||
const UserActivity = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const toast = useRef(null);
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const [user, setUser] = useState({});
|
||||
const [roles, setRoles] = useState([]);
|
||||
const [chosenRole, setChosenRole] = useState(0);
|
||||
|
||||
const goBack = () => {
|
||||
navigate(`/utenti`);
|
||||
}
|
||||
|
||||
const getUserCallback = (resp) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
setUser(resp.data)
|
||||
setChosenRole(resp.data.role?.id);
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errGetUserCallback = (resp) => {
|
||||
set404FromErrorResponse(resp);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const getRolesCallback = (resp) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
setRoles(resp.data)
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errGetRolesCallback = (resp) => {
|
||||
set404FromErrorResponse(resp);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const getStatValue = (key, fallback = 0) => {
|
||||
return pathOr(fallback, [key], {});
|
||||
}
|
||||
|
||||
const handleRoleUpdate = () => {
|
||||
if (user.role?.id !== chosenRole) {
|
||||
setLoading(true);
|
||||
UserService.updateUser(user.id, {roleId: chosenRole}, updateRoleCallback, errUpdateRoleCallback)
|
||||
}
|
||||
}
|
||||
|
||||
const updateRoleCallback = (resp) => {
|
||||
if (resp.status === 'SUCCESS') {
|
||||
setUser(resp.data)
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const errUpdateRoleCallback = (resp) => {
|
||||
set404FromErrorResponse(resp);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (id && !isEmpty(id)) {
|
||||
setLoading(true);
|
||||
UserService.getUser(id, getUserCallback, errGetUserCallback);
|
||||
UserService.getRoles(getRolesCallback, errGetRolesCallback);
|
||||
}
|
||||
}, [id])
|
||||
|
||||
return (
|
||||
<div className="appPage">
|
||||
<div className="appPage__pageHeader">
|
||||
<h1>{__('Controllo attività utenti', 'gepafin')}</h1>
|
||||
</div>
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
<Toast ref={toast}/>
|
||||
|
||||
<div className="appPageSection">
|
||||
<div className="appPageSection__actions">
|
||||
<Button
|
||||
onClick={goBack}
|
||||
outlined
|
||||
label={__('Indietro', 'gepafin')} icon="pi pi-arrow-left" iconPos="left"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="appPageSection__withBorder columns">
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Nome utente', 'gepafin')}</span>
|
||||
<span>{`${user.firstName} ${user.lastName}`}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Email', 'gepafin')}</span>
|
||||
<span>{user.email}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Ruolo', 'gepafin')}</span>
|
||||
<span>{user.role?.roleName}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Data registrazione', 'gepafin')}</span>
|
||||
<span>{getDateFromISOstring(user.createdDate)}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Ultimo accesso', 'gepafin')}</span>
|
||||
<span>{getDateFromISOstring(user.lastLogin)}</span>
|
||||
</p>
|
||||
<p className="appPageSection__pMeta">
|
||||
<span>{__('Stato account', 'gepafin')}</span>
|
||||
<span>{user.status}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{['ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(user.role?.roleType)
|
||||
? <>
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
<div className="appPageSection">
|
||||
<h3>{__('Cambia ruolo', 'gepafin')}</h3>
|
||||
<div className="row">
|
||||
<Dropdown
|
||||
id="form"
|
||||
disabled={isEmpty(roles) || loading}
|
||||
value={chosenRole}
|
||||
onChange={(e) => setChosenRole(e.value)}
|
||||
options={roles.filter(o => [3, 5].includes(o.id)).map(o => ({ label: o.roleName, value: o.id }))}
|
||||
optionLabel="label"
|
||||
placeholder={__('Seleziona ruolo', 'gepafin')}/>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={loading}
|
||||
outlined
|
||||
onClick={handleRoleUpdate}
|
||||
label={__('Modifica', 'gepafin')}
|
||||
icon="pi pi-cog" iconPos="right"/>
|
||||
</div>
|
||||
</div>
|
||||
</> : null}
|
||||
|
||||
<div className="appPage__spacer"></div>
|
||||
|
||||
{/*<div className="appPageSection">
|
||||
<h2>{__('Statistiche attività', 'gepafin')}</h2>
|
||||
<div className="statsBigBadges__grid grid-small">
|
||||
<div className="statsBigBadges__gridItem">
|
||||
<span>{__('Login totali', 'gepafin')}</span>
|
||||
<span>{<NumberFlow
|
||||
value={getStatValue('numberOfActiveCalls', 0)}
|
||||
format={{ notation: 'compact' }}
|
||||
locales="it-IT"/>}</span>
|
||||
</div>
|
||||
<div className="statsBigBadges__gridItem">
|
||||
<span>{__('Bandi gestiti', 'gepafin')}</span>
|
||||
<span>{<NumberFlow
|
||||
value={getStatValue('numberOfActiveCalls', 0)}
|
||||
format={{ notation: 'compact' }}
|
||||
locales="it-IT"/>}</span>
|
||||
</div>
|
||||
<div className="statsBigBadges__gridItem">
|
||||
<span>{__('Domande processate', 'gepafin')}</span>
|
||||
<span>{<NumberFlow
|
||||
value={getStatValue('numberOfActiveCalls', 0)}
|
||||
format={{ notation: 'compact' }}
|
||||
locales="it-IT"/>}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>*/}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserActivity;
|
||||
@@ -24,6 +24,7 @@ import { Calendar } from 'primereact/calendar';
|
||||
import { Tag } from 'primereact/tag';
|
||||
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
||||
import translationStrings from '../../../../translationStringsForComponents';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const AllUsersTable = () => {
|
||||
const users = useStore().main.users();
|
||||
@@ -53,7 +54,7 @@ const AllUsersTable = () => {
|
||||
|
||||
const getFormattedData = (data) => {
|
||||
return data
|
||||
.filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR'].includes(o.role.roleType));
|
||||
.filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.role.roleType));
|
||||
};
|
||||
|
||||
const clearFilter = () => {
|
||||
@@ -125,12 +126,16 @@ const AllUsersTable = () => {
|
||||
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
|
||||
};
|
||||
|
||||
/*const actionsBodyTemplate = (rowData) => {
|
||||
/!*return <Link to={`/utenti/${rowData.id}`}>
|
||||
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small" iconPos="right"/>
|
||||
</Link>*!/
|
||||
return null;
|
||||
}*/
|
||||
const actionsBodyTemplate = (rowData) => {
|
||||
return <Link to={`/utenti/${rowData.id}`}>
|
||||
<Button
|
||||
severity="info"
|
||||
label={__('Attività', 'gepafin')}
|
||||
icon="pi pi-eye"
|
||||
size="small"
|
||||
iconPos="right"/>
|
||||
</Link>
|
||||
}
|
||||
|
||||
const header = renderHeader();
|
||||
|
||||
@@ -149,22 +154,22 @@ const AllUsersTable = () => {
|
||||
filter sortable
|
||||
field="email"
|
||||
filterPlaceholder={__('Cerca per email', 'gepafin')}
|
||||
style={{ minWidth: '12rem' }}/>
|
||||
style={{ minWidth: '10rem' }}/>
|
||||
<Column body={roleBodyTemplate} header={__('Ruolo', 'gepafin')}
|
||||
style={{ minWidth: '12rem' }}/>
|
||||
style={{ minWidth: '8rem' }}/>
|
||||
<Column field="status" header={__('Stato', 'gepafin')}
|
||||
filterMenuStyle={{ width: '14rem' }}
|
||||
style={{ width: '120px' }} body={statusBodyTemplate}
|
||||
filterElement={statusFilterTemplate}/>
|
||||
<Column header={__('Ultimo accesso', 'gepafin')}
|
||||
filterField="lastLogin" dataType="date"
|
||||
style={{ minWidth: '10rem' }}
|
||||
style={{ minWidth: '7rem' }}
|
||||
body={dateLastAccessBodyTemplate} filter filterElement={dateFilterTemplate}/>
|
||||
{/*<Column header={__('Azioni', 'gepafin')}
|
||||
body={actionsBodyTemplate}/>*/}
|
||||
<Column header={__('Azioni', 'gepafin')}
|
||||
body={actionsBodyTemplate}/>
|
||||
</DataTable>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AllUsersTable;
|
||||
export default AllUsersTable;
|
||||
|
||||
@@ -121,7 +121,7 @@ const Users = () => {
|
||||
const getRolesCallback = (data) => {
|
||||
if (data.status === 'SUCCESS') {
|
||||
const roles = data.data
|
||||
.filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR'].includes(o.roleType))
|
||||
.filter(o => ['ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(o.roleType))
|
||||
.map(o => ({
|
||||
name: o.roleName,
|
||||
value: o.id
|
||||
|
||||
@@ -34,9 +34,12 @@ import SoccorsoIstruttorioPreInstructor from './pages/SoccorsoIstruttorioPreInst
|
||||
import SoccorsoEditPreInstructor from './pages/SoccorsoEditPreInstructor';
|
||||
import SoccorsoAddPreInstructor from './pages/SoccorsoAddPreInstructor';
|
||||
import DomandeBeneficiario from './pages/DomandeBeneficiario';
|
||||
import DomandaBeneficiario from './pages/DomandaBeneficiario';
|
||||
import SoccorsoEditBeneficiario from './pages/SoccorsoEditBeneficiario';
|
||||
import BandoApplicationPreview from './pages/BandoApplicationPreview';
|
||||
import BandiPreferredBeneficiario from './pages/BandiPreferredBeneficiario';
|
||||
import DomandeInstructorManager from './pages/DomandeInstructorManager';
|
||||
import DomandaEditInstructorManager from './pages/DomandaEditInstructorManager';
|
||||
import UserActivity from './pages/UserActivity';
|
||||
|
||||
const routes = ({ role, chosenCompanyId }) => {
|
||||
|
||||
@@ -47,106 +50,139 @@ const routes = ({ role, chosenCompanyId }) => {
|
||||
{'ROLE_SUPER_ADMIN' === role ? <Dashboard/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <DashboardBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <DashboardPreInstructor/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DashboardPreInstructor/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <Bandi/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <BandiBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoEdit/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <BandoViewBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id/preview" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoView/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id/preview-evaluation" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoView/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id/forms" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoForms/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id/forms/:formId" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoFormsEdit/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id/forms/:formId/preview" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoFormsPreview/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi/:id/flow" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoFlowEdit/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/bandi-osservati" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <BandiPreferredBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/domande" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <Domande/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <DomandeBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandePreInstructor/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandeInstructorManager/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/domande/:id/" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <DomandaBeneficiario/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <SoccorsoEditBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <DomandaEditPreInstructor/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <DomandaEditInstructorManager/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/domande/:id/preview" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <BandoApplicationPreview/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <BandoApplicationPreview/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <BandoApplicationPreview/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <BandoApplicationPreview/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/domande/:id/aggiungi-soccorso" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoAddPreInstructor/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoAddPreInstructor/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/domande/:id/soccorso/:amendmentId" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoEditPreInstructor/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoEditPreInstructor/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/soccorso-istruttorio/" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <SoccorsoIstruttorioPreInstructor/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/imieibandi" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <Applications/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/imieibandi/:id/" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <BandoApplication/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/profilo" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <Profile/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <ProfileBeneficiario/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <Profile/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <Profile/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/profilo-aziendale" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role && chosenCompanyId > 0 ? <ProfileCompany/> : <PageNotFound/>}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/agguingi-azienda" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <AddCompany/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/utenti" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <Users/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
<Route path="/utenti/:id" element={<DefaultLayout>
|
||||
{'ROLE_SUPER_ADMIN' === role ? <UserActivity/> : null}
|
||||
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_PRE_INSTRUCTOR' === role ? <PageNotFound/> : null}
|
||||
{'ROLE_INSTRUCTOR_MANAGER' === role ? <PageNotFound/> : null}
|
||||
</DefaultLayout>}/>
|
||||
</Route>
|
||||
<Route exact path="/reset-password" element={<ResetPassword/>}/>
|
||||
|
||||
@@ -28,6 +28,10 @@ export default class AmendmentsService {
|
||||
NetworkService.put(`${API_BASE_URL}/amendments/${id}`, body, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static updateStatusSoccorso = (id, callback, errCallback, queryParams) => {
|
||||
NetworkService.put(`${API_BASE_URL}/amendments/${id}/status`, {}, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static extendSoccorso = (id, days, callback, errCallback, queryParams) => {
|
||||
NetworkService.put(`${API_BASE_URL}/amendments/${id}/extendExpiration`, {}, callback, errCallback, [
|
||||
['extendedDays', days]
|
||||
|
||||
@@ -48,6 +48,10 @@ export default class ApplicationService {
|
||||
NetworkService.delete(`${API_BASE_URL}/application/${id}/signedDocument`, {}, callback, errCallback);
|
||||
};
|
||||
|
||||
static deleteApplication = (id, callback, errCallback) => {
|
||||
NetworkService.delete(`${API_BASE_URL}/application/${id}`, {}, callback, errCallback);
|
||||
};
|
||||
|
||||
static downloadCompleteZip = (id, callback, errCallback, queryParams) => {
|
||||
NetworkService.getBlob(`${API_BASE_URL}/application/${id}/documents/zip`, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
@@ -4,11 +4,15 @@ const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS;
|
||||
|
||||
export default class AppointmentService {
|
||||
|
||||
static getNdg = (id, callback, errCallback, queryParams) => {
|
||||
NetworkService.get(`${API_BASE_URL}/appointment/application/${id}/check-ndg`, callback, errCallback, queryParams);
|
||||
static getNdg = (applicationId, callback, errCallback, queryParams) => {
|
||||
NetworkService.get(`${API_BASE_URL}/appointment/application/${applicationId}/check-ndg`, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static archiveDocument = (applicationId, documentId, body, callback, errCallback, queryParams) => {
|
||||
NetworkService.post(`${API_BASE_URL}/appointment/application/${applicationId}/document/${documentId}`, {}, callback, errCallback, queryParams);
|
||||
NetworkService.post(`${API_BASE_URL}/appointment/document/${documentId}`, body, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static createAppointment = (applicationId, body, callback, errCallback, queryParams) => {
|
||||
NetworkService.post(`${API_BASE_URL}/appointment/application/${applicationId}`, body, callback, errCallback, queryParams);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ export class NetworkService {
|
||||
}
|
||||
}
|
||||
|
||||
if (url.charAt(url.length) === '&')
|
||||
if (url.charAt(url.length) === '&') {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
|
||||
22
src/service/notification-service.js
Normal file
22
src/service/notification-service.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { NetworkService } from './network-service';
|
||||
|
||||
const API_BASE_URL = process.env.REACT_APP_API_EXECUTION_ADDRESS;
|
||||
|
||||
export default class NotificationService {
|
||||
|
||||
static getNotifications = (id, callback, errCallback, queryParams) => {
|
||||
NetworkService.get(`${API_BASE_URL}/notification/user/${id}`, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static notificationMakeRead = (id, callback, errCallback) => {
|
||||
NetworkService.put(`${API_BASE_URL}/notification/${id}`, {}, callback, errCallback, [
|
||||
['status', 'READ']
|
||||
]);
|
||||
};
|
||||
|
||||
static notificationMakeUnread = (id, callback, errCallback) => {
|
||||
NetworkService.put(`${API_BASE_URL}/notification/${id}`, {}, callback, errCallback, [
|
||||
['status', 'UNREAD']
|
||||
]);
|
||||
};
|
||||
}
|
||||
@@ -8,6 +8,10 @@ export default class UserService {
|
||||
NetworkService.get(`${API_BASE_URL}/user`, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static getUser = (id, callback, errCallback, queryParams) => {
|
||||
NetworkService.get(`${API_BASE_URL}/user/${id}`, callback, errCallback, queryParams);
|
||||
};
|
||||
|
||||
static updateUser = (id, body, callback, errCallback) => {
|
||||
NetworkService.put(`${API_BASE_URL}/user/${id}`, body, callback, errCallback);
|
||||
};
|
||||
|
||||
@@ -88,6 +88,10 @@ export const elementItems = [
|
||||
{
|
||||
name: "step",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "isRequestedAmount",
|
||||
value: false
|
||||
}
|
||||
],
|
||||
validators: {
|
||||
|
||||
Reference in New Issue
Block a user