Merge branch 'develop' into feature/46-forms-flow-preview

This commit is contained in:
Vitalii Kiiko
2025-01-09 09:19:24 +01:00
24 changed files with 725 additions and 185 deletions

View File

@@ -1,6 +1,7 @@
REACT_APP_TAB_TITLE=Gepafin REACT_APP_TAB_TITLE=Gepafin
REACT_APP_API_EXECUTION_ADDRESS=https://bandi-api.gepafin.it/v1 REACT_APP_API_EXECUTION_ADDRESS=https://bandi-api.gepafin.it/v1
REACT_APP_API_ADDRESS=https://bandi-api.gepafin.it REACT_APP_API_ADDRESS=https://bandi-api.gepafin.it
REACT_APP_API_ADDRESS_WS=https://bandi-api.gepafin.it/wss
REACT_APP_LOGO_FILENAME=gepafin-logo.svg REACT_APP_LOGO_FILENAME=gepafin-logo.svg
REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico
REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs

View File

@@ -191,16 +191,108 @@
} }
.formElementSettings__repeater { .formElementSettings__repeater {
display: flex; display: grid;
flex-direction: column; grid-template-columns: 1fr;
gap: 0.5rem; gap: 0.5rem;
} }
.formElementSettings__repeaterItem { .formElementSettings__repeaterItem {
display: grid;
grid-template-columns: 4.5fr 2.4fr 1fr 1.4fr 0.7fr;
gap: 12px;
> div {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
input, select, .p-dropdown {
width: 100%;
box-sizing: border-box;
}
}
} }
.formElementSettings__subRepeater { .formElementSettings__subRepeaterWrapper {
padding: 10px 20px; display: grid;
background-color: #f9f9f9; grid-template-columns: 1fr;
gap: 7px;
}
.formElementSettings__subRepeaterItem {
display: grid;
grid-template-columns: 9.3fr 0.7fr;
gap: 12px;
> div {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
input, select, .p-dropdown {
width: 100%;
box-sizing: border-box;
}
}
}
.formElementSettings__repeaterItemIconBtn {
border: none;
background: transparent;
padding: 0;
font-size: 2rem;
color: var(--table-border-color);
i {
font-size: 2rem;
}
&:hover {
cursor: pointer;
color: var(--menuitem-active-background);
}
&:not([data-active="false"]) {
color: var(--menuitem-active-background);
}
}
.formElementSettings__lastRowHeader {
display: grid;
grid-template-columns: 8.3fr 1.7fr;
gap: 7px;
}
.formElementSettings__lastRowHeaderTitle {
display: flex;
height: 40px;
padding: 10.5px 17.5px;
justify-content: center;
align-items: center;
border-radius: 4px;
background: #f8f9fa;
border: 1px solid #dee2e6;
font-size: 14px;
font-style: normal;
font-weight: 700;
}
.formElementSettings__lastRowItem {
display: grid;
grid-template-columns: 1.7fr 8.3fr;
gap: 7px;
> div {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
input, select, .p-dropdown {
width: 100%;
box-sizing: border-box;
}
}
} }

View File

@@ -25,8 +25,8 @@
justify-content: space-between; justify-content: space-between;
padding: 16px; padding: 16px;
border-radius: 6px; border-radius: 6px;
border: 1px solid var(--yellow-500); border: 1px solid #858585;
background: var(--card-full-background-color-2); background: #cecece;
align-items: center; align-items: center;
gap: 48px; gap: 48px;
@@ -41,26 +41,73 @@
span:nth-last-of-type(1) { span:nth-last-of-type(1) {
font-size: 22px; font-size: 22px;
} }
}
&:nth-of-type(2) { .statsBigBadges__grid {
border: 1px solid var(--yellow-500); .statsBigBadges__gridItem {
background: var(--card-full-background-color-3); &:nth-of-type(1) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-2);
}
&:nth-of-type(2) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-3);
}
&:nth-of-type(3) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-4);
}
&:nth-of-type(4) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-1);
}
&:nth-of-type(5) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-5);
}
&:nth-of-type(6) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-6);
}
} }
&:nth-of-type(3) {
border: 1px solid var(--yellow-500); &.applStats {
background: var(--card-full-background-color-4); .statsBigBadges__gridItem {
} &:nth-of-type(1) {
&:nth-of-type(4) { border: 1px solid var(--yellow-500);
border: 1px solid var(--yellow-500); background: var(--card-full-background-color-2);
background: var(--card-full-background-color-1); }
}
&:nth-of-type(5) { &:nth-of-type(2) {
border: 1px solid var(--yellow-500); border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-5); background: var(--card-full-background-color-3);
} }
&:nth-of-type(6) {
border: 1px solid var(--yellow-500); &:nth-of-type(3) {
background: var(--card-full-background-color-6); border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-4);
}
&:nth-of-type(4) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-7);
}
&:nth-of-type(5) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-8);
}
&:nth-of-type(6) {
border: 1px solid var(--yellow-500);
background: var(--card-full-background-color-9);
}
}
} }
} }

View File

@@ -29,6 +29,9 @@
--card-full-background-color-1: #54965b; --card-full-background-color-1: #54965b;
--card-full-background-color-5: #4ba190; --card-full-background-color-5: #4ba190;
--card-full-background-color-6: #6d68c0; --card-full-background-color-6: #6d68c0;
--card-full-background-color-7: #06B6D4;
--card-full-background-color-8: #FF3D32;
--card-full-background-color-9: #F97316;
} }
@import "./components/layout.scss"; @import "./components/layout.scss";

View File

@@ -0,0 +1,25 @@
const DefaultCell = ({ getValue, row: { index }, column: { id }, table }) => {
const initialValue = getValue();
const disabled = table.options.meta?.disabled;
const onBlur = (e) => {
table.options.meta?.updateData(index, id, e.target.value);
};
const onFocus = (e) => {
e.target.select();
}
return (
<input
disabled={disabled}
value={initialValue ?? ''}
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)}
onBlur={onBlur}
onFocus={onFocus}
className="w-full px-2 py-1 border rounded"
/>
);
};
export default DefaultCell;

View File

@@ -0,0 +1,21 @@
import { head, isEmpty, isNil, sum } from 'ramda';
const LastRowCell = ({columnId, lastRows, columnMeta = {}, getColumnDataFn}) => {
const cellData = head(lastRows.filter(o => !isNil(o[columnId])));
let cellValue = cellData[columnId];
if (columnMeta.enableFormula) {
const getAllRowsValues = getColumnDataFn(columnId)
.map(v => isEmpty(v) || isNil(v) ? 0 : v);
if (cellValue === 'sum') {
cellValue = sum(getAllRowsValues);
} else {
cellValue = 0;
}
}
return <td>{cellValue}</td>;
};
export default LastRowCell;

View File

@@ -0,0 +1,34 @@
const NumericFormulaCell = ({ getValue, row: { index }, column: { id }, table }) => {
const initialValue = getValue();
const disabled = table.options.meta?.disabled;
const onBlur = (e) => {
const numValue = e.target.value === 0 ? null : Number(e.target.value);
table.options.meta?.updateData(index, id, numValue);
};
const onFocus = (e) => {
e.target.select();
}
const onChange = (e) => {
if (e.target.value === 0 || !isNaN(e.target.value)) {
table.options.meta?.updateData(index, id, e.target.value);
}
};
return (
<input
type="number"
disabled={disabled}
value={initialValue ?? 0}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
step="any"
className="w-full px-2 py-1 border rounded"
/>
);
};
export default NumericFormulaCell;

View File

@@ -1,31 +1,22 @@
import React from 'react'; import React from 'react';
import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
import { wrap } from 'object-path-immutable'; import { wrap } from 'object-path-immutable';
import { isEmpty } from 'ramda';
const RenderTable = ({ data, columns, setRowsFn, disabled }) => { // components
import DefaultCell from './components/DefaultCell';
import LastRowCell from './components/LastRowCell';
const RenderTable = ({ data, columns, lastRow, setRowsFn, disabled }) => {
const table = useReactTable({ const table = useReactTable({
data, data,
columns, columns,
defaultColumn: { defaultColumn: {
cell: ({ getValue, row: { index }, column: { id }, table }) => { cell: DefaultCell
const initialValue = getValue();
const onBlur = (e) => {
table.options.meta?.updateData(index, id, e.target.value);
};
return (
<input
disabled={disabled}
value={initialValue ? initialValue : ''}
onChange={(e) => table.options.meta?.updateData(index, id, e.target.value)}
onBlur={onBlur}
/>
);
},
}, },
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
meta: { meta: {
disabled,
updateData: (rowIndex, columnId, value) => { updateData: (rowIndex, columnId, value) => {
const newRowsData = wrap(data).set([rowIndex, columnId], value).value(); const newRowsData = wrap(data).set([rowIndex, columnId], value).value();
setRowsFn(newRowsData); setRowsFn(newRowsData);
@@ -33,6 +24,11 @@ const RenderTable = ({ data, columns, setRowsFn, disabled }) => {
} }
}); });
const getColumnData = (columnId) => {
const rows = table.getRowModel().rows;
return rows.map(row => row.getValue(columnId));
};
return ( return (
<table> <table>
<thead> <thead>
@@ -72,6 +68,16 @@ const RenderTable = ({ data, columns, setRowsFn, disabled }) => {
</tr> </tr>
); );
})} })}
{!isEmpty(lastRow)
? <tr>
{columns.map((o) => <LastRowCell
key={o.accessorKey}
columnId={o.accessorKey}
columnMeta={o.meta}
lastRows={lastRow}
getColumnDataFn={getColumnData}/>)}
</tr>
: null}
</tbody> </tbody>
</table> </table>
) )

View File

@@ -10,6 +10,7 @@ import { Button } from 'primereact/button';
import RenderTable from './RenderTable'; import RenderTable from './RenderTable';
import { klona } from 'klona'; import { klona } from 'klona';
import { nonEmptyTables } from '../../../../helpers/validators'; import { nonEmptyTables } from '../../../../helpers/validators';
import NumericFormulaCell from './RenderTable/components/NumericFormulaCell';
const Table = ({ const Table = ({
fieldName, fieldName,
@@ -25,6 +26,7 @@ const Table = ({
const [columnsCfg, setColumnsCfg] = useState([]); const [columnsCfg, setColumnsCfg] = useState([]);
const [rowsCfg, setRowsCfg] = useState([]); const [rowsCfg, setRowsCfg] = useState([]);
const [columns, setColumns] = useState([]); const [columns, setColumns] = useState([]);
const [lastRow, setLastRow] = useState([]);
const [rows, setRows] = useState(null); const [rows, setRows] = useState(null);
const [shouldDisableNewRows, setShouldDisableNewRows] = useState(false); const [shouldDisableNewRows, setShouldDisableNewRows] = useState(false);
const [rowIndexToDelete, rowRowIndexToDelete] = useState(null); const [rowIndexToDelete, rowRowIndexToDelete] = useState(null);
@@ -72,19 +74,23 @@ const Table = ({
useEffect(() => { useEffect(() => {
let shouldDisableNewRows = false; let shouldDisableNewRows = false;
let newColumns = columnsCfg.map((o) => { let newColumns = columnsCfg.map((o) => {
const item = { const item = {
accessorKey: o.name, accessorKey: o.name,
header: () => o.label, header: () => o.label,
footer: (props) => props.column.id footer: (props) => props.column.id,
meta: {
predefined: o.predefined,
enableFormula: o.enableFormula,
fieldtype: o.fieldtype
}
} }
if (o.predefined) { if (o.predefined) {
shouldDisableNewRows = true; shouldDisableNewRows = true;
item.cell = (info) => { item.cell = (info) => info.getValue();
return info.getValue(); } else if (o.enableFormula || o.fieldtype === 'numeric') {
} item.cell = NumericFormulaCell;
} }
return item; return item;
@@ -97,7 +103,7 @@ const Table = ({
accessorKey: 'actions', accessorKey: 'actions',
header: () => '', header: () => '',
footer: (props) => props.column.id, footer: (props) => props.column.id,
cell: ({row: { index }}) => <Button cell: ({ row: { index } }) => <Button
disabled={disabled} disabled={disabled}
type="button" type="button"
icon="pi pi-times" icon="pi pi-times"
@@ -108,7 +114,7 @@ const Table = ({
} }
setColumns(newColumns); setColumns(newColumns);
}, [columnsCfg]); }, [columnsCfg, disabled]);
useEffect(() => { useEffect(() => {
setRows(rowsCfg); setRows(rowsCfg);
@@ -125,7 +131,26 @@ const Table = ({
rowsData = isEmpty(rowsData) ? [obj] : rowsData; rowsData = isEmpty(rowsData) ? [obj] : rowsData;
setColumnsCfg(stateFieldData); setColumnsCfg(stateFieldData);
setRowsCfg(rowsData); setRowsCfg(rowsData);
}, [tableColumns]);
let lastRowData = stateFieldData.reduce((acc, cur) => {
const value = cur.enableFormula ? cur.lastRowFormula : (cur.lastRowText ? cur.lastRowText : '');
acc.push({ [cur.name]: value });
return acc;
}, []);
if (!shouldDisableNewRows) {
lastRowData.push({ actions: '' })
}
const lastRowValues = lastRowData
.map(o => {
const values = Object.values(o);
return values[0];
})
.filter(v => !isEmpty(v));
setLastRow(!isEmpty(lastRowValues) ? lastRowData : []);
}, [tableColumns, shouldDisableNewRows]);
useEffect(() => { useEffect(() => {
if (!equal(rows, defaultValue)) { if (!equal(rows, defaultValue)) {
@@ -144,11 +169,16 @@ const Table = ({
{label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables) {label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
? <span className="appForm__field--required">*</span> : null} ? <span className="appForm__field--required">*</span> : null}
</label> </label>
{rows ? <RenderTable columns={columns} data={rows} setRowsFn={updateRows} disabled={disabled}/> : null} {rows ? <RenderTable
columns={columns}
data={rows}
lastRow={lastRow}
setRowsFn={updateRows}
disabled={disabled}/> : null}
{!isEmpty(columns) && !shouldDisableNewRows {!isEmpty(columns) && !shouldDisableNewRows
? <div className="addNewTableRow" onClick={addNewRow}> ? <div className="addNewTableRow" onClick={addNewRow}>
{__('Aggiungi una riga', 'gepafin')} {__('Aggiungi una riga', 'gepafin')}
</div> </div>
: null} : null}
</>) </>)
} }

View File

@@ -215,7 +215,7 @@ const NotificationsSidebar = () => {
<> <>
<i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon" <i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon"
onClick={() => setNotificationsVisible(true)}> onClick={() => setNotificationsVisible(true)}>
<Badge value={notifications.length}></Badge> <Badge value={notifications.filter(o => o.status === 'UNREAD').length}></Badge>
</i> </i>
<Sidebar <Sidebar
className="notificationsSidebar" className="notificationsSidebar"

View File

@@ -290,21 +290,23 @@ const BandoForms = () => {
<h2>{__('Modifica form esistente', 'gepafin')}</h2> <h2>{__('Modifica form esistente', 'gepafin')}</h2>
<div className="row"> <div className="row">
<p>{__('Continua a lavorare su un form precedentemente salvato', 'gepafin')}</p> <p>{__('Continua a lavorare su un form precedentemente salvato', 'gepafin')}</p>
<Dropdown <div className="row">
id="form" <Dropdown
disabled={isEmpty(forms)} id="form"
value={selectedForm} disabled={isEmpty(forms)}
onChange={(e) => setSelectedForm(e.value)} value={selectedForm}
options={forms} onChange={(e) => setSelectedForm(e.value)}
optionLabel="label" options={forms}
placeholder={__('Seleziona form', 'gepafin')}/> optionLabel="label"
<Button placeholder={__('Seleziona form', 'gepafin')}/>
type="button" <Button
outlined type="button"
disabled={!selectedForm} outlined
onClick={goToEditForm} disabled={!selectedForm}
label={__('Modifica', 'gepafin')} onClick={goToEditForm}
icon="pi pi-cog" iconPos="right"/> label={__('Modifica', 'gepafin')}
icon="pi pi-cog" iconPos="right"/>
</div>
</div> </div>
</div> </div>

View File

@@ -19,10 +19,11 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
placeholder: __('Segnaposto', 'gepafin'), placeholder: __('Segnaposto', 'gepafin'),
step: __('Numero Decimali', 'gepafin'), step: __('Numero Decimali', 'gepafin'),
isRequestedAmount: __('Importo richiesto', 'gepafin'), isRequestedAmount: __('Importo richiesto', 'gepafin'),
isDelegation: __('Delega', 'gepafin'),
options: __('Opzioni', 'gepafin'), options: __('Opzioni', 'gepafin'),
mime: __('Tipo di file', 'gepafin'), mime: __('Tipo di file', 'gepafin'),
text: __('Testo formattato', 'gepafin'), text: __('Testo formattato', 'gepafin'),
table_columns: __('Colonne', 'gepafin'), table_columns: '',
} }
const renderHeader = () => { const renderHeader = () => {
@@ -80,7 +81,7 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
name={setting.name} name={setting.name}
bandoStatus={bandoStatus} bandoStatus={bandoStatus}
setDataFn={updateDataFn}/> setDataFn={updateDataFn}/>
} else if (setting.name === 'isRequestedAmount') { } else if (['isRequestedAmount', 'isDelegation'].includes(setting.name)) {
return <InputSwitch return <InputSwitch
checked={setting.value} checked={setting.value}
onChange={(e) => changeFn(e.value, setting.name)}/> onChange={(e) => changeFn(e.value, setting.name)}/>

View File

@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { wrap } from 'object-path-immutable'; import { wrap } from 'object-path-immutable';
import { pathOr } from 'ramda'; import { isEmpty, pathOr } from 'ramda';
// components // components
import { InputText } from 'primereact/inputtext'; import { InputText } from 'primereact/inputtext';
@@ -10,6 +10,8 @@ import { InputSwitch } from 'primereact/inputswitch';
// tools // tools
import uniqid from '../../../../../../helpers/uniqid'; import uniqid from '../../../../../../helpers/uniqid';
import { Dropdown } from 'primereact/dropdown';
import { Accordion, AccordionTab } from 'primereact/accordion';
const ElementSettingTableColumns = ({ const ElementSettingTableColumns = ({
value, value,
@@ -55,6 +57,37 @@ const ElementSettingTableColumns = ({
setStateFieldData(newData); setStateFieldData(newData);
} }
const onLastRowInputChange = (e, index) => {
const { value } = e.target;
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.lastRowText = value;
}
return o;
})
setStateFieldData(newData);
}
const onTypeChange = (value, index) => {
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.fieldtype = value;
}
return o;
})
setStateFieldData(newData);
}
const onLastRowFormulaChange = (value, index) => {
const newData = stateFieldData.map((o, i) => {
if (i === index) {
o.lastRowFormula = value;
}
return o;
})
setStateFieldData(newData);
}
const onSubInputChange = (e, name, index) => { const onSubInputChange = (e, name, index) => {
const { value } = e.target; const { value } = e.target;
const newRowsData = wrap(rowsData).set([index, name], value).value(); const newRowsData = wrap(rowsData).set([index, name], value).value();
@@ -83,23 +116,133 @@ const ElementSettingTableColumns = ({
setStateFieldData(newData); setStateFieldData(newData);
} }
const properField = (item, i) => { const setColFormulaChecked = (index) => {
const newData = stateFieldData.map((o, i) => {
if (i === index) {
const newVal = o.enableFormula !== true;
o.enableFormula = newVal;
if (newVal) {
o.lastRowFormula = 'sum';
o.fieldtype = 'numeric';
delete o.lastRowText;
} else {
delete o.lastRowFormula;
delete o.fieldtype;
o.lastRowText = '';
}
}
return o;
});
setStateFieldData(newData);
}
const handleClearLastRowData = useCallback(() => {
const newData = stateFieldData.map((o) => {
delete o.lastRowFormula;
o.lastRowText = '';
delete o.enableFormula;
return o;
});
setStateFieldData(newData);
}, [stateFieldData]);
const properFields = (item, i) => {
return <> return <>
<InputText value={item.label} onInput={(e) => onInputChange(e, i)}/> <div>
<div className="flex-1"> <InputText
<span>{__('Predefinito?', 'gepafin')}</span> value={item.label}
placeholder={sprintf(__('Colonna %d', 'gepafin'), i + 1)}
onInput={(e) => onInputChange(e, i)}/>
</div>
<div>
<Dropdown
disabled={item.enableFormula}
value={item.fieldtype ? item.fieldtype : 'text'}
onChange={(e) => onTypeChange(e.value, i)}
options={[
{ value: 'text', label: __('Testo', 'gepafin') },
{ value: 'numeric', label: __('Numerico', 'gepafin') }
]}/>
</div>
<div>
<button
className="formElementSettings__repeaterItemIconBtn"
onClick={() => setColFormulaChecked(i)}
data-active={item.enableFormula ? item.enableFormula : false}
type="button">
<i className="pi pi-calculator"></i>
</button>
</div>
<div>
<InputSwitch <InputSwitch
checked={item.predefined} checked={item.predefined}
disabled={bandoStatus === 'PUBLISH'} disabled={bandoStatus === 'PUBLISH'}
onChange={(e) => setChecked(e.value, i)}/> onChange={(e) => setChecked(e.value, i)}/>
</div> </div>
<div>
<Button icon="pi pi-times"
disabled={bandoStatus === 'PUBLISH'}
className="p-button-danger"
onClick={() => removeItem(i)}/>
</div>
</> </>
} }
const properSubField = (item, i, name) => { const properSubField = (item, i, name) => {
return <InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/> return <>
<div>
<InputText value={item[name]} onInput={(e) => onSubInputChange(e, name, i)}/>
</div>
<div>
<Button icon="pi pi-times"
disabled={bandoStatus === 'PUBLISH'}
className="p-button-danger"
onClick={() => removeRow(i)}/>
</div>
</>
} }
const properFieldsLastRow = useCallback((item, i) => {
return <>
<div>
<span>{sprintf(__('Colonna %d'), i + 1)}</span>
</div>
{item.enableFormula
? <div>
<Dropdown
value={item.lastRowFormula}
onChange={(e) => onLastRowFormulaChange(e.value, i)}
options={[
{ value: 'sum', label: __('Somma automatica', 'gepafin') }
]}/>
</div>
: <div>
<InputText
value={item.lastRowText ? item.lastRowText : ''}
onInput={(e) => onLastRowInputChange(e, i)}/>
</div>}
</>
}, [stateFieldData]);
const lastRow = <div className="formElementSettings__repeater">
<div className="formElementSettings__lastRowHeader">
<div className="formElementSettings__lastRowHeaderTitle">
{__('Definisci ultima righa', 'gepafin')}
</div>
<Button type="button"
outlined
label={__('Pulisci', 'gepafin')}
iconPos="right"
icon="pi pi-refresh"
onClick={handleClearLastRowData}/>
</div>
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__lastRowItem">
{properFieldsLastRow(o, i)}
</div>)}
</div>;
useEffect(() => { useEffect(() => {
const stateFieldData = pathOr([], ['stateFieldData'], value); const stateFieldData = pathOr([], ['stateFieldData'], value);
setStateFieldData(stateFieldData); setStateFieldData(stateFieldData);
@@ -114,44 +257,51 @@ const ElementSettingTableColumns = ({
}); });
}, [stateFieldData, rowsData]); }, [stateFieldData, rowsData]);
stateFieldData.filter(o => o.predefined)
return ( return (
<> <>
<div className="formElementSettings__repeater"> <div className="formElementSettings__repeater">
{stateFieldData.length > 0
? <div className="formElementSettings__repeaterItem">
<div>{__('Colonne', 'gepafin')}</div>
<div>{__('Tipo', 'gepafin')}</div>
<div>{__('Calcola', 'gepafin')}</div>
<div>{__('Predefinito?', 'gepafin')}</div>
<div></div>
</div> : null}
{stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem"> {stateFieldData.map((o, i) => <div key={i} className="formElementSettings__repeaterItem">
<div className="p-inputgroup flex-1"> {properFields(o, i)}
{properField(o, i)}
<Button icon="pi pi-times" disabled={bandoStatus === 'PUBLISH'} className="p-button-danger" onClick={() => removeItem(i)}/>
</div>
</div>)} </div>)}
<Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined label={__('Aggiungi', 'gepafin')} onClick={addNewItem}/> <Button type="button" disabled={bandoStatus === 'PUBLISH'} outlined
label={__('Aggiungi colonna', 'gepafin')} onClick={addNewItem}/>
</div> </div>
{stateFieldData {stateFieldData
.filter(o => o.predefined) .filter(o => o.predefined).length > 0
.map((o, i) => <div key={i} className="formElementSettings__repeaterItem"> ? <div className="formElementSettings__subRepeaterWrapper">
<div className="formElementSettings__repeater formElementSettings__subRepeater"> <Accordion activeIndex={0}>
<label>{__('Righe per colonna:', 'gepafin')} <strong>{o.label}</strong></label> {stateFieldData
<div className="formElementSettings__repeater"> //.filter(o => o.predefined)
{rowsData.map((c, k) => { .map((o, i) =>
return <div key={k} className="formElementSettings__repeaterItem"> o.predefined
<div className="p-inputgroup flex-1"> ? <AccordionTab
{properSubField(c, k, o.name)} key={i}
<Button icon="pi pi-times" header={sprintf(__('Righe per colonna: %s'), !isEmpty(o.label) ? o.label : i + 1)}>
disabled={bandoStatus === 'PUBLISH'} <div className="formElementSettings__subRepeaterWrapper">
className="p-button-danger" {rowsData.map((c, k) => {
onClick={() => removeRow(k)}/> return <div key={k} className="formElementSettings__subRepeaterItem">
</div> {properSubField(c, k, o.name)}
</div> </div>
})} })}
<Button type="button" <Button type="button"
outlined outlined
disabled={bandoStatus === 'PUBLISH'} disabled={bandoStatus === 'PUBLISH'}
label={__('Aggiungi una riga', 'gepafin')} label={__('Aggiungi una riga', 'gepafin')}
onClick={addNewRow}/> onClick={addNewRow}/>
</div> </div>
</div> </AccordionTab> : null)}
</div>)} </Accordion>
</div>
: null}
{lastRow}
</> </>
) )
} }

View File

@@ -155,8 +155,8 @@ const BandoFormsPreview = () => {
}, {}); }, {});
return ['paragraph'].includes(o.name) && text return ['paragraph'].includes(o.name) && text
? <div> ? <div key={o.id}>
<div className="ql-editor" key={o.id}> <div className="ql-editor">
{renderHtmlContent(text.value)} {renderHtmlContent(text.value)}
</div> </div>
</div> </div>

View File

@@ -24,6 +24,7 @@ import { Tag } from 'primereact/tag';
import ProperBandoLabel from '../../../../components/ProperBandoLabel'; import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import translationStrings from '../../../../translationStringsForComponents'; import translationStrings from '../../../../translationStringsForComponents';
import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup';
const MyLatestSubmissionsTable = () => { const MyLatestSubmissionsTable = () => {
const chosenCompanyId = useStore().main.chosenCompanyId(); const chosenCompanyId = useStore().main.chosenCompanyId();
@@ -167,8 +168,10 @@ const MyLatestSubmissionsTable = () => {
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small" <Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
iconPos="right"/> iconPos="right"/>
</Link> </Link>
<ConfirmPopup/>
<Button severity="danger" <Button severity="danger"
onClick={() => handleDeleteApplication(rowData.id)} /*onClick={() => handleDeleteApplication(rowData.id)}*/
onClick={(event) => confirmDelete(event, rowData.id)}
label={__('Cancella', 'gepafin')} label={__('Cancella', 'gepafin')}
icon="pi pi-trash" icon="pi pi-trash"
size="small" size="small"
@@ -183,6 +186,22 @@ const MyLatestSubmissionsTable = () => {
const header = renderHeader(); const header = renderHeader();
const confirmDelete = (event, id) => {
confirmPopup({
target: event.currentTarget,
message: __('Sei sicuro di voler rimuovere la domanda?', 'gepafin'),
acceptLabel: __('Si', 'gepafin'),
icon: 'pi pi-info-circle',
defaultFocus: 'reject',
acceptClassName: 'p-button-danger',
accept: () => {
handleDeleteApplication(id);
},
reject: () => {
}
});
};
return ( return (
<div className="appPageSection__table"> <div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id" <DataTable value={items} paginator showGridlines rows={10} loading={localAsyncRequest} dataKey="id"

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { isEmpty } from 'ramda'; import { isEmpty, pathOr } from 'ramda';
// api // api
import UserService from '../../service/user-service'; import UserService from '../../service/user-service';
@@ -20,6 +20,8 @@ import { Button } from 'primereact/button';
import { classNames } from 'primereact/utils'; import { classNames } from 'primereact/utils';
import { Dropdown } from 'primereact/dropdown'; import { Dropdown } from 'primereact/dropdown';
import DraftApplicationsTable from '../Dashboard/components/DraftApplicationsTable'; import DraftApplicationsTable from '../Dashboard/components/DraftApplicationsTable';
import NumberFlow from '@number-flow/react';
import DashboardService from '../../service/dashboard-service';
const Domande = () => { const Domande = () => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -29,6 +31,7 @@ const Domande = () => {
const [chosenUser, setChosenUser] = useState(0); const [chosenUser, setChosenUser] = useState(0);
const [chosenApplication, setChosenApplication] = useState(0); const [chosenApplication, setChosenApplication] = useState(0);
const [updaterString, setUpdaterString] = useState(''); const [updaterString, setUpdaterString] = useState('');
const [mainStats, setMainStats] = useState({});
const toast = useRef(null); const toast = useRef(null);
const getRolesCallback = (data) => { const getRolesCallback = (data) => {
@@ -123,6 +126,18 @@ const Domande = () => {
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
} }
const getStatValue = (key, fallback = '') => {
return pathOr(fallback, [key], mainStats);
}
const getStats = (data) => {
if (data.status === 'SUCCESS') {
setMainStats(data.data);
}
}
const errGetStats = () => {}
useEffect(() => { useEffect(() => {
if (roleIds.length > 0) { if (roleIds.length > 0) {
setLoading(true); setLoading(true);
@@ -137,6 +152,10 @@ const Domande = () => {
} }
}, [isVisibleEditDialog]); }, [isVisibleEditDialog]);
useEffect(() => {
DashboardService.getApplicationsStats(getStats, errGetStats);
}, []);
return ( return (
<div className="appPage"> <div className="appPage">
<div className="appPage__pageHeader"> <div className="appPage__pageHeader">
@@ -152,6 +171,57 @@ const Domande = () => {
<div className="appPage__spacer"></div> <div className="appPage__spacer"></div>
<div className="appPageSection statsBigBadges">
<h2>{__('Riepilogo', 'gepafin')}</h2>
<div className="statsBigBadges__grid applStats">
<div className="statsBigBadges__gridItem">
<span>{__('Totale domande', 'gepafin')}</span>
<span><NumberFlow
value={getStatValue('numberOfApplication', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/></span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('Assegnate', 'gepafin')}</span>
<span><NumberFlow
value={getStatValue('numberOfAssignedApplication', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/></span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('Completate', 'gepafin')}</span>
<span><NumberFlow
value={getStatValue('numberOfAcceptedApplication', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/></span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('Tempo medio di valutazione', 'gepafin')}</span>
<span><NumberFlow
value={getStatValue('evaluationAverageTime', 0)}
format={{ notation: 'compact' }}
suffix={` ${__('minuti', 'gepafin')}`}
locales="it-IT"/></span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('In soccorso istruttorio', 'gepafin')}</span>
<span><NumberFlow
value={getStatValue('numberOfApplicationInAmendmentState', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/></span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('Domande in scadenza (48h)', 'gepafin')}</span>
<span><NumberFlow
value={getStatValue('numberOfDueApplication', 0)}
format={{ notation: 'compact' }}
locales="en-US"/></span>
</div>
</div>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection"> <div className="appPageSection">
<h2>{__('Domande in bozza', 'gepafin')}</h2> <h2>{__('Domande in bozza', 'gepafin')}</h2>
<DraftApplicationsTable/> <DraftApplicationsTable/>

View File

@@ -140,7 +140,7 @@ const BeneficiarioDomandeTable = () => {
}; };
const actionsBodyTemplate = (rowData) => { const actionsBodyTemplate = (rowData) => {
return <> return <div className="appPageSection__tableActions">
{rowData.status === 'SOCCORSO' {rowData.status === 'SOCCORSO'
? <Link to={`/domande/${rowData.id}`}> ? <Link to={`/domande/${rowData.id}`}>
<Button severity="info" label={__('Dettagli', 'gepafin')} icon="pi pi-eye" size="small" <Button severity="info" label={__('Dettagli', 'gepafin')} icon="pi pi-eye" size="small"
@@ -150,7 +150,7 @@ const BeneficiarioDomandeTable = () => {
<Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small" <Button severity="info" label={__('Anteprima', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/> iconPos="right"/>
</Link> </Link>
</> </div>
} }
const header = renderHeader(); const header = renderHeader();

View File

@@ -4,7 +4,7 @@ import { isEmpty, pathOr, head } from 'ramda';
import { klona } from 'klona'; import { klona } from 'klona';
import { wrap } from 'object-path-immutable'; import { wrap } from 'object-path-immutable';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import emailjs from '@emailjs/browser'; //import emailjs from '@emailjs/browser';
//import { useNavigate } from 'react-router-dom'; //import { useNavigate } from 'react-router-dom';
// store // store
@@ -27,8 +27,11 @@ import FileuploadDelega from '../../components/FileuploadDelega';
import { Toast } from 'primereact/toast'; import { Toast } from 'primereact/toast';
import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText'; import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
import { defaultMaxFileSize } from '../../configData'; import { defaultMaxFileSize } from '../../configData';
import { Dialog } from 'primereact/dialog'; //import { Dialog } from 'primereact/dialog';
import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup'; import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup';
import { useNavigate } from 'react-router-dom';
const APP_HUB_ID = process.env.REACT_APP_HUB_ID;
const ProfileCompany = () => { const ProfileCompany = () => {
const isAsyncRequest = useStore().main.isAsyncRequest(); const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -37,8 +40,9 @@ const ProfileCompany = () => {
const infoMsgs = useRef(null); const infoMsgs = useRef(null);
const [formInitialData, setFormInitialData] = useState({}); const [formInitialData, setFormInitialData] = useState({});
const [delegaData, setDelegaData] = useState({}); const [delegaData, setDelegaData] = useState({});
const navigate = useNavigate();
const [delega, setDelega] = useState([]); const [delega, setDelega] = useState([]);
const [isVisibleRemoveDialog, setIsVisibleRemoveDialog] = useState(false); //const [isVisibleRemoveDialog, setIsVisibleRemoveDialog] = useState(false);
const { delegaFirstName = '', delegaLastName = '', delegaCodiceFiscale = '' } = delegaData; const { delegaFirstName = '', delegaLastName = '', delegaCodiceFiscale = '' } = delegaData;
const toast = useRef(null); const toast = useRef(null);
//const navigate = useNavigate(); //const navigate = useNavigate();
@@ -90,7 +94,6 @@ const ProfileCompany = () => {
} else { } else {
newCompanies = [...companies, company]; newCompanies = [...companies, company];
storeSet.main.chosenCompanyId(company.id); storeSet.main.chosenCompanyId(company.id);
console.log('set company 3', company.id)
} }
storeSet.main.companies(newCompanies); storeSet.main.companies(newCompanies);
@@ -206,28 +209,28 @@ const ProfileCompany = () => {
const confirmDelete = (event) => { const confirmDelete = (event) => {
confirmPopup({ confirmPopup({
target: event.currentTarget, target: event.currentTarget,
message: __('Sei sicuro di rimuovere la azienda?', 'gepafin'), message: __('Sei sicuro di voler rimuovere l\'azienda?', 'gepafin'),
acceptLabel: __('Si', 'gepafin'), acceptLabel: __('Si', 'gepafin'),
icon: 'pi pi-info-circle', icon: 'pi pi-info-circle',
defaultFocus: 'reject', defaultFocus: 'reject',
acceptClassName: 'p-button-danger', acceptClassName: 'p-button-danger',
accept: () => { accept: () => {
doRemoveCompany(); doRemoveCompanyAPI();
}, },
reject: () => { reject: () => {
} }
}); });
}; };
const headerRemoveDialog = () => { /*const headerRemoveDialog = () => {
return <span>{__('Rimuovi azienda', 'gepafin')}</span> return <span>{__('Rimuovi azienda', 'gepafin')}</span>
} }
const hideRemoveDialog = () => { const hideRemoveDialog = () => {
setIsVisibleRemoveDialog(false); setIsVisibleRemoveDialog(false);
} }*/
const doRemoveCompany = () => { /*const doRemoveCompany = () => {
const userData = storeGet.main.userData(); const userData = storeGet.main.userData();
let chosenCompany = {}; let chosenCompany = {};
@@ -251,13 +254,13 @@ const ProfileCompany = () => {
publicKey: 'TPWwaPLM2dDuEIa10' publicKey: 'TPWwaPLM2dDuEIa10'
} }
).then(() => { ).then(() => {
/*if (toast.current) { /!*if (toast.current) {
toast.current.show({ toast.current.show({
severity: 'success', severity: 'success',
summary: '', summary: '',
detail: __('La richiesta è stata inviata!', 'gepafin') detail: __('La richiesta è stata inviata!', 'gepafin')
}); });
}*/ }*!/
setIsVisibleRemoveDialog(true); setIsVisibleRemoveDialog(true);
}) })
.catch((err) => { .catch((err) => {
@@ -270,10 +273,9 @@ const ProfileCompany = () => {
}); });
} }
}); });
} }*/
// TODO delete company functionality by API, ready to be shipped const doRemoveCompanyAPI = () => {
/*const doRemoveCompanyAPI = () => {
storeSet.main.setAsyncRequest(); storeSet.main.setAsyncRequest();
CompanyService.deleteCompany(formInitialData.id, deleteCompanyCallback, errDeleteCompanyCallback) CompanyService.deleteCompany(formInitialData.id, deleteCompanyCallback, errDeleteCompanyCallback)
} }
@@ -282,13 +284,16 @@ const ProfileCompany = () => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
const userData = storeGet.main.userData(); const userData = storeGet.main.userData();
const newCompanies = companies.filter(o => o.id !== chosenCompanyId); const newCompanies = companies.filter(o => o.id !== chosenCompanyId);
const newUserData = wrap(userData).set('company', newCompanies).value(); storeSet.main.companies(newCompanies);
storeSet.main.companies(newUserData.companies); const newUserData = wrap(userData).set('companies', newCompanies).value();
storeSet.main.userData(newUserData); storeSet.main.userData(newUserData);
if (!isEmpty(newCompanies)) { if (!isEmpty(newCompanies)) {
const newChosenCompanyId = newCompanies[0].id; const newChosenCompanyId = newCompanies[0].id;
storeSet.main.chosenCompanyId(newChosenCompanyId); storeSet.main.chosenCompanyId(newChosenCompanyId);
} else {
storeSet.main.chosenCompanyId(0);
navigate(`/`);
} }
} }
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
@@ -297,7 +302,7 @@ const ProfileCompany = () => {
const errDeleteCompanyCallback = (data) => { const errDeleteCompanyCallback = (data) => {
set404FromErrorResponse(data); set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
}*/ }
useEffect(() => { useEffect(() => {
const newFormData = klona(formInitialData); const newFormData = klona(formInitialData);
@@ -516,7 +521,7 @@ const ProfileCompany = () => {
? <div className="appForm__delegaForm"> ? <div className="appForm__delegaForm">
<div className="appForm__delegaFormHeader"> <div className="appForm__delegaFormHeader">
<legend>{__('Compilazione Delega', 'gepafin')}</legend> <legend>{__('Compilazione Delega', 'gepafin')}</legend>
<p className="appForm__delegaFormText">{__('Per procedere come delegato, compila il form seguente, scarica il documento della delega, fallo firmare dal rappresentante legale e ricaricalo.', 'gepafin')}</p> <p className="appForm__delegaFormText">{__('Per procedere come delegato, compila il form seguente, scarica il documento della delega, fallo firmare dal rappresentante legale e ricaricalo nel form di domanda.', 'gepafin')}</p>
</div> </div>
<div className="appForm__cols"> <div className="appForm__cols">
@@ -554,50 +559,35 @@ const ProfileCompany = () => {
</div> </div>
</div> </div>
<div> {APP_HUB_ID === 'nonexisting' // hide it from all hub
<Button ? <div>
disabled={isEmpty(delegaCodiceFiscale) || isEmpty(delegaFirstName) || isEmpty(delegaLastName)} <Button
onClick={downloadDelega} disabled={isEmpty(delegaCodiceFiscale) || isEmpty(delegaFirstName) || isEmpty(delegaLastName)}
type="button" onClick={downloadDelega}
label={__('Genera documento Delega', 'gepafin')} type="button"
icon="pi pi-check" iconPos="right"/> label={__('Genera documento Delega', 'gepafin')}
</div> icon="pi pi-check" iconPos="right"/>
</div> : null}
<div className="appForm__field"> {APP_HUB_ID === 'nonexisting' // hide it from all hub
<label htmlFor="delega"> ? <div className="appForm__field">
{__('Carica documento Delega Firmato', 'gepafin')} <label htmlFor="delega">
<span className="appForm__field--required">*</span> {__('Carica documento Delega Firmato', 'gepafin')}
{' (.p7m) '} <span className="appForm__field--required">*</span>
{`(max ${getFormatedFileSizeText(defaultMaxFileSize)})`} {' (.p7m) '}
</label> {`(max ${getFormatedFileSizeText(defaultMaxFileSize)})`}
<FileuploadDelega </label>
setDataFn={setDelegaFile} <FileuploadDelega
fieldName="delega" setDataFn={setDelegaFile}
defaultValue={delega} fieldName="delega"
accept={['.p7m,application/pkcs7-mime,application/x-pkcs7-mime']} defaultValue={delega}
chooseLabel={__('Aggiungi documento', 'gepafin')} accept={['.p7m,application/pkcs7-mime,application/x-pkcs7-mime']}
multiple={false} chooseLabel={__('Aggiungi documento', 'gepafin')}
doctype="document" multiple={false}
companyId={formInitialData.id} doctype="document"
/> companyId={formInitialData.id}
</div> />
</div> : null}
{/*<div className="appForm__delegaFormActions">
<Button
type="button"
disabled={true}
outlined
onClick={() => {
}}
label={__('Visualizza delega', 'gepafin')} icon="pi pi-eye" iconPos="right"/>
<Button
type="button"
disabled={true}
outlined
onClick={() => {
}}
label={__('Sostituisci delega', 'gepafin')} icon="pi pi-sync" iconPos="right"/>
</div>*/}
</div> : <div className="appPage__spacer"></div>} </div> : <div className="appPage__spacer"></div>}
@@ -622,15 +612,15 @@ const ProfileCompany = () => {
</div> </div>
</div> </div>
<Dialog {/*<Dialog
visible={isVisibleRemoveDialog} visible={isVisibleRemoveDialog}
modal modal
header={headerRemoveDialog} header={headerRemoveDialog}
/*footer={footerRemoveDialog}*/ footer={footerRemoveDialog}
style={{ maxWidth: '600px', width: '100%' }} style={{ maxWidth: '600px', width: '100%' }}
onHide={hideRemoveDialog}> onHide={hideRemoveDialog}>
<p>Abbiamo preso in carica la tua richiesta a breve l'azienda sarà rimossa dal tuo profilo</p> <p>Abbiamo preso in carica la tua richiesta a breve l'azienda sarà rimossa dal tuo profilo</p>
</Dialog> </Dialog>*/}
</div> </div>
) )

View File

@@ -50,7 +50,8 @@ const Registration = () => {
const newFormData = { const newFormData = {
...formData, ...formData,
dateOfBirth: originalDateOfBirth, dateOfBirth: originalDateOfBirth,
hubUuid: APP_HUB_ID hubUuid: APP_HUB_ID,
roleId: 1
} }
AuthenticationService.registerUser(newFormData, regCallback, regError, [ AuthenticationService.registerUser(newFormData, regCallback, regError, [

View File

@@ -23,6 +23,7 @@ import BlockingOverlay from '../../components/BlockingOverlay';
import { Toast } from 'primereact/toast'; import { Toast } from 'primereact/toast';
import { InputSwitch } from 'primereact/inputswitch'; import { InputSwitch } from 'primereact/inputswitch';
import ApplicationEvaluationService from '../../service/application-evaluation-service'; import ApplicationEvaluationService from '../../service/application-evaluation-service';
import { Dialog } from 'primereact/dialog';
const SoccorsoAddPreInstructor = () => { const SoccorsoAddPreInstructor = () => {
const isAsyncRequest = useStore().main.isAsyncRequest(); const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -31,6 +32,7 @@ const SoccorsoAddPreInstructor = () => {
const [data, setData] = useState({}); const [data, setData] = useState({});
const [evaluationId, setEvaluationId] = useState(0); const [evaluationId, setEvaluationId] = useState(0);
const [formData, setFormData] = useState({}); const [formData, setFormData] = useState({});
const [isVisibleConfirmDialog, setIsVisibleConfirmDialog] = useState(false)
const toast = useRef(null); const toast = useRef(null);
const goToEvaluationPage = () => { const goToEvaluationPage = () => {
@@ -49,8 +51,8 @@ const SoccorsoAddPreInstructor = () => {
const getCallbackEvaluation = (data) => { const getCallbackEvaluation = (data) => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
setEvaluationId(data.data.assignedApplicationId); setEvaluationId(data.data.id);
AmendmentsService.getSoccorsoByApplEvalId(data.data.assignedApplicationId, getCallback, errGetCallback) AmendmentsService.getSoccorsoByApplEvalId(data.data.id, getCallback, errGetCallback)
} }
} }
@@ -152,6 +154,32 @@ const SoccorsoAddPreInstructor = () => {
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
} }
const initCreationProcess = () => {
setIsVisibleConfirmDialog(true);
}
const headerConfirmDialog = () => {
return <span>{__('Richiesta di conferma', 'gepafin')}</span>;
}
const hideConfirmDialog = () => {
setIsVisibleConfirmDialog(false);
}
const footerConfirmDialog = () => {
return <div>
<Button type="button" label={__('No', 'gepafin')} onClick={goToEvaluationPage} outlined/>
<Button
type="button"
label={__('Si', 'gepafin')} onClick={doConfirm}/>
</div>
}
const doConfirm = () => {
setIsVisibleConfirmDialog(false);
doCreate();
}
return ( return (
<div className="appPage"> <div className="appPage">
<div className="appPage__pageHeader"> <div className="appPage__pageHeader">
@@ -286,12 +314,24 @@ const SoccorsoAddPreInstructor = () => {
icon="pi pi-times" iconPos="right"/> icon="pi pi-times" iconPos="right"/>
<Button <Button
type="button" type="button"
onClick={doCreate} onClick={initCreationProcess}
label={__('Invia richiesta', 'gepafin')} label={__('Invia richiesta', 'gepafin')}
icon="pi pi-check" iconPos="right"/> icon="pi pi-check" iconPos="right"/>
</div> </div>
</div> </div>
<Dialog
visible={isVisibleConfirmDialog}
modal
header={headerConfirmDialog}
footer={footerConfirmDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideConfirmDialog}>
<div className="appForm__field">
<p>{__('Soccorso istruttorio autorizzato dal direttore e autorizzazione caricata su portale a seguito del quale parte l\'email?', 'gepafin')}</p>
</div>
</Dialog>
</div> </div>
: <> : <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton> <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>

View File

@@ -528,7 +528,7 @@ const SoccorsoEditPreInstructor = () => {
<Button <Button
type="button" type="button"
onClick={openCloseAmendmentDialog} onClick={openCloseAmendmentDialog}
disabled={isAsyncRequest || ['CLOSE', 'EXPIRED'].includes(data.status)} disabled={isAsyncRequest || ['CLOSE', 'AWAITING'].includes(data.status)}
label={__('Chiudi Soccorso Istruttorio', 'gepafin')} label={__('Chiudi Soccorso Istruttorio', 'gepafin')}
icon="pi pi-times" iconPos="right"/> icon="pi pi-times" iconPos="right"/>
</div> </div>

View File

@@ -37,6 +37,6 @@ export default class CompanyService {
}; };
static deleteCompany = (id, callback, errCallback) => { static deleteCompany = (id, callback, errCallback) => {
NetworkService.delete(`${API_BASE_URL}/company/${id}`, {}, callback, errCallback); NetworkService.delete(`${API_BASE_URL}/company/user/${id}`, {}, callback, errCallback);
}; };
} }

View File

@@ -8,6 +8,10 @@ export default class DashboardService {
NetworkService.get(`${API_BASE_URL}/dashboard`, callback, errCallback); NetworkService.get(`${API_BASE_URL}/dashboard`, callback, errCallback);
}; };
static getApplicationsStats = (callback, errCallback) => {
NetworkService.get(`${API_BASE_URL}/dashboard/application`, callback, errCallback);
};
static getBeneficiaryStatsForCompany = (id, callback, errCallback) => { static getBeneficiaryStatsForCompany = (id, callback, errCallback) => {
NetworkService.get(`${API_BASE_URL}/dashboard/beneficiary/company/${id}`, callback, errCallback); NetworkService.get(`${API_BASE_URL}/dashboard/beneficiary/company/${id}`, callback, errCallback);
}; };

View File

@@ -214,6 +214,10 @@ export const elementItems = [
{ {
name: "mime", name: "mime",
value: [] value: []
},
{
name: "isDelegation",
value: false
} }
], ],
validators: { validators: {