Merge branch 'develop'
This commit is contained in:
@@ -3,10 +3,12 @@ version: 0.2
|
|||||||
phases:
|
phases:
|
||||||
install:
|
install:
|
||||||
runtime-versions:
|
runtime-versions:
|
||||||
nodejs: 20
|
nodejs: 20
|
||||||
|
commands:
|
||||||
|
- npm install
|
||||||
build:
|
build:
|
||||||
commands:
|
commands:
|
||||||
- npm install && npm run build:dev
|
- npm run build:dev
|
||||||
artifacts:
|
artifacts:
|
||||||
files:
|
files:
|
||||||
- '**/*'
|
- '**/*'
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ phases:
|
|||||||
install:
|
install:
|
||||||
runtime-versions:
|
runtime-versions:
|
||||||
nodejs: 20
|
nodejs: 20
|
||||||
|
commands:
|
||||||
|
- npm install
|
||||||
build:
|
build:
|
||||||
commands:
|
commands:
|
||||||
- npm install && npm run build:prod
|
- npm run build:prod
|
||||||
artifacts:
|
artifacts:
|
||||||
files:
|
files:
|
||||||
- '**/*'
|
- '**/*'
|
||||||
base-directory: 'build'
|
base-directory: 'build'
|
||||||
|
|||||||
@@ -65,8 +65,8 @@
|
|||||||
"start:dev": "cp environments/dev/* public/loaded-files && rm public/loaded-files/dev.env && cp environments/dev/dev.env .env && PORT=8000 react-scripts start --mode development",
|
"start:dev": "cp environments/dev/* public/loaded-files && rm public/loaded-files/dev.env && cp environments/dev/dev.env .env && PORT=8000 react-scripts start --mode development",
|
||||||
"start:prod": "cp environments/prod/* public/loaded-files && rm public/loaded-files/prod.env && cp environments/prod/prod.env .env && react-scripts start --mode production",
|
"start:prod": "cp environments/prod/* public/loaded-files && rm public/loaded-files/prod.env && cp environments/prod/prod.env .env && react-scripts start --mode production",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"build:dev": "cp environments/dev/* public/loaded-files && rm public/loaded-files/dev.env && cp environments/dev/dev.env .env && react-scripts build --mode development",
|
"build:dev": "cp environments/dev/* public/loaded-files && rm public/loaded-files/dev.env && cp environments/dev/dev.env .env && GENERATE_SOURCEMAP=false NODE_OPTIONS=--max-old-space-size=1536 react-scripts build --mode development",
|
||||||
"build:prod": "cp environments/prod/* public/loaded-files && rm public/loaded-files/prod.env && cp environments/prod/prod.env .env && react-scripts build --mode production",
|
"build:prod": "cp environments/prod/* public/loaded-files && rm public/loaded-files/prod.env && cp environments/prod/prod.env .env && GENERATE_SOURCEMAP=false NODE_OPTIONS=--max-old-space-size=1536 react-scripts build --mode production",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"make-pot": "wpi18n makepot --domain-path=languages --domain=gepafin"
|
"make-pot": "wpi18n makepot --domain-path=languages --domain=gepafin"
|
||||||
|
|||||||
@@ -4,6 +4,24 @@ import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core';
|
|||||||
import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US';
|
import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US';
|
||||||
import '@univerjs/preset-sheets-core/lib/index.css';
|
import '@univerjs/preset-sheets-core/lib/index.css';
|
||||||
|
|
||||||
|
const TAG_RE = /^\{\{gepafin_field:[^|]+\|[^}]+}}$/;
|
||||||
|
|
||||||
|
const buildTagMap = (workbookData) => {
|
||||||
|
const map = {};
|
||||||
|
if (!workbookData?.sheets) return map;
|
||||||
|
const sheetId = workbookData.sheetOrder?.[0];
|
||||||
|
const sheet = sheetId ? workbookData.sheets[sheetId] : Object.values(workbookData.sheets)[0];
|
||||||
|
if (!sheet?.cellData) return map;
|
||||||
|
Object.entries(sheet.cellData).forEach(([r, row]) => {
|
||||||
|
Object.entries(row).forEach(([c, cell]) => {
|
||||||
|
if (typeof cell.f === 'string' && TAG_RE.test(cell.f)) {
|
||||||
|
map[`${r}:${c}`] = { v: cell.v, f: cell.f };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
};
|
||||||
|
|
||||||
const parseWorkbook = (val) => {
|
const parseWorkbook = (val) => {
|
||||||
if (!val) return null;
|
if (!val) return null;
|
||||||
if (typeof val === 'object' && val.sheets) return val;
|
if (typeof val === 'object' && val.sheets) return val;
|
||||||
@@ -23,6 +41,8 @@ const Spreadsheet = ({ fieldName, defaultValue, setDataFn, template }) => {
|
|||||||
const univerRef = useRef(null);
|
const univerRef = useRef(null);
|
||||||
const univerAPIRef = useRef(null);
|
const univerAPIRef = useRef(null);
|
||||||
const saveTimerRef = useRef(null);
|
const saveTimerRef = useRef(null);
|
||||||
|
const isRestoringRef = useRef(false);
|
||||||
|
const tagCellMapRef = useRef({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!containerRef.current) return;
|
if (!containerRef.current) return;
|
||||||
@@ -43,8 +63,40 @@ const Spreadsheet = ({ fieldName, defaultValue, setDataFn, template }) => {
|
|||||||
univerAPIRef.current = univerAPI;
|
univerAPIRef.current = univerAPI;
|
||||||
|
|
||||||
const initialData = parseWorkbook(defaultValue) || parseWorkbook(template) || { name: 'Sheet' };
|
const initialData = parseWorkbook(defaultValue) || parseWorkbook(template) || { name: 'Sheet' };
|
||||||
|
tagCellMapRef.current = buildTagMap(initialData);
|
||||||
univerAPI.createWorkbook(initialData);
|
univerAPI.createWorkbook(initialData);
|
||||||
|
|
||||||
|
const restoreTagCells = () => {
|
||||||
|
if (isRestoringRef.current) return;
|
||||||
|
const wb = univerAPIRef.current?.getActiveWorkbook();
|
||||||
|
if (!wb) return;
|
||||||
|
const sheet = wb.getActiveSheet();
|
||||||
|
if (!sheet) return;
|
||||||
|
const saved = wb.save();
|
||||||
|
if (!saved?.sheets) return;
|
||||||
|
const sheetId = saved.sheetOrder?.[0];
|
||||||
|
const sheetData = sheetId ? saved.sheets[sheetId] : Object.values(saved.sheets)[0];
|
||||||
|
if (!sheetData?.cellData) return;
|
||||||
|
|
||||||
|
const restorations = [];
|
||||||
|
Object.entries(sheetData.cellData).forEach(([r, row]) => {
|
||||||
|
Object.entries(row).forEach(([c, cell]) => {
|
||||||
|
if (typeof cell.v === 'string' && TAG_RE.test(cell.v)) {
|
||||||
|
const orig = tagCellMapRef.current[`${r}:${c}`];
|
||||||
|
if (orig) restorations.push({ r: +r, c: +c, v: orig.v, f: orig.f });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (restorations.length === 0) return;
|
||||||
|
isRestoringRef.current = true;
|
||||||
|
restorations.forEach(({ r, c, v, f }) => {
|
||||||
|
sheet.getRange(r, c, 1, 1).setValues([[{ v, f }]]);
|
||||||
|
});
|
||||||
|
isRestoringRef.current = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let restoreTimer;
|
||||||
univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, () => {
|
univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, () => {
|
||||||
clearTimeout(saveTimerRef.current);
|
clearTimeout(saveTimerRef.current);
|
||||||
saveTimerRef.current = setTimeout(() => {
|
saveTimerRef.current = setTimeout(() => {
|
||||||
@@ -53,10 +105,13 @@ const Spreadsheet = ({ fieldName, defaultValue, setDataFn, template }) => {
|
|||||||
setDataFn(fieldName, wb.save());
|
setDataFn(fieldName, wb.save());
|
||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
|
clearTimeout(restoreTimer);
|
||||||
|
restoreTimer = setTimeout(restoreTagCells, 80);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(saveTimerRef.current);
|
clearTimeout(saveTimerRef.current);
|
||||||
|
clearTimeout(restoreTimer);
|
||||||
if (univerRef.current) {
|
if (univerRef.current) {
|
||||||
univerRef.current.dispose();
|
univerRef.current.dispose();
|
||||||
univerRef.current = null;
|
univerRef.current = null;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import { isNil } from 'ramda';
|
import { isNil } from 'ramda';
|
||||||
import { classNames } from 'primereact/utils';
|
import { classNames } from 'primereact/utils';
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ import Table from './components/Table';
|
|||||||
import PasswordField from './components/PasswordField';
|
import PasswordField from './components/PasswordField';
|
||||||
import CriteriaTable from './components/CriteriaTable';
|
import CriteriaTable from './components/CriteriaTable';
|
||||||
import FileSelect from './components/FileSelect';
|
import FileSelect from './components/FileSelect';
|
||||||
import Spreadsheet from './components/Spreadsheet';
|
const Spreadsheet = React.lazy(() => import('./components/Spreadsheet'));
|
||||||
|
|
||||||
const FormField = (props) => {
|
const FormField = (props) => {
|
||||||
const fields = {
|
const fields = {
|
||||||
@@ -45,7 +45,9 @@ const FormField = (props) => {
|
|||||||
|
|
||||||
return (!isNil(Comp)
|
return (!isNil(Comp)
|
||||||
? <div className={classNames(['appForm__field', props.type, props.additionalClass])}>
|
? <div className={classNames(['appForm__field', props.type, props.additionalClass])}>
|
||||||
<Comp {...props} />
|
<Suspense fallback={null}>
|
||||||
|
<Comp {...props} />
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { Suspense, useEffect, useState } from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { head, is, isEmpty, isNil, uniq } from 'ramda';
|
import { head, is, isEmpty, isNil, uniq } from 'ramda';
|
||||||
|
|
||||||
@@ -18,13 +18,13 @@ import { InputSwitch } from 'primereact/inputswitch';
|
|||||||
import ElementSettingChips from '../ElementSettingChips';
|
import ElementSettingChips from '../ElementSettingChips';
|
||||||
import ElementSettingCriteriaTableColumns from '../ElementSettingCriteriaTableColumns';
|
import ElementSettingCriteriaTableColumns from '../ElementSettingCriteriaTableColumns';
|
||||||
import ElementSettingTableColumnsForCsv from '../ElementSettingTableColumnsForCsv';
|
import ElementSettingTableColumnsForCsv from '../ElementSettingTableColumnsForCsv';
|
||||||
import ElementSettingSpreadsheet from '../ElementSettingSpreadsheet';
|
|
||||||
|
|
||||||
import { mimeTypes } from '../../../../../../configData';
|
import { mimeTypes } from '../../../../../../configData';
|
||||||
import ElementSettingReportHeader from '../ElementSettingReportHeader';
|
import ElementSettingReportHeader from '../ElementSettingReportHeader';
|
||||||
import ElementSettingReportEnable from '../ElementSettingReportEnable';
|
import ElementSettingReportEnable from '../ElementSettingReportEnable';
|
||||||
import getTokens from '../../../../../../helpers/getTokens';
|
import getTokens from '../../../../../../helpers/getTokens';
|
||||||
|
|
||||||
|
const ElementSettingSpreadsheet = React.lazy(() => import('../ElementSettingSpreadsheet'));
|
||||||
|
|
||||||
|
|
||||||
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
||||||
const [existingVars, setExistingVars] = useState([]);
|
const [existingVars, setExistingVars] = useState([]);
|
||||||
@@ -159,10 +159,12 @@ const ElementSetting = ({ setting, changeFn, updateDataFn, bandoStatus }) => {
|
|||||||
bandoStatus={bandoStatus}
|
bandoStatus={bandoStatus}
|
||||||
setDataFn={updateDataFn}/>
|
setDataFn={updateDataFn}/>
|
||||||
} else if (setting.name === 'template') {
|
} else if (setting.name === 'template') {
|
||||||
return <ElementSettingSpreadsheet
|
return <Suspense fallback={null}>
|
||||||
value={setting.value}
|
<ElementSettingSpreadsheet
|
||||||
name={setting.name}
|
value={setting.value}
|
||||||
setDataFn={updateDataFn}/>;
|
name={setting.name}
|
||||||
|
setDataFn={updateDataFn}/>
|
||||||
|
</Suspense>;
|
||||||
} else if (setting.name === 'formula') {
|
} else if (setting.name === 'formula') {
|
||||||
const isInvalid = invalidFormula(setting.value);
|
const isInvalid = invalidFormula(setting.value);
|
||||||
return <>
|
return <>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { useStoreValue } from '../../../../../../store';
|
|||||||
// tools
|
// tools
|
||||||
import { xlsxToWorkbookData } from '../../../../../BandoEdit/components/BandoEditFormStep3Excel/xlsxToWorkbookData';
|
import { xlsxToWorkbookData } from '../../../../../BandoEdit/components/BandoEditFormStep3Excel/xlsxToWorkbookData';
|
||||||
|
|
||||||
|
const TAG_RE = /^\{\{gepafin_field:([^|]+)\|([^}]+)}}$/;
|
||||||
|
|
||||||
const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||||
const callFormFields = useStoreValue('callFormFields');
|
const callFormFields = useStoreValue('callFormFields');
|
||||||
const [tagTooltip, setTagTooltip] = useState(null);
|
const [tagTooltip, setTagTooltip] = useState(null);
|
||||||
@@ -19,6 +21,7 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
|||||||
const univerRef = useRef(null);
|
const univerRef = useRef(null);
|
||||||
const univerAPIRef = useRef(null);
|
const univerAPIRef = useRef(null);
|
||||||
const formFieldsRef = useRef([]);
|
const formFieldsRef = useRef([]);
|
||||||
|
const isRestoringRef = useRef(false);
|
||||||
const mousePos = useRef({ x: 0, y: 0 });
|
const mousePos = useRef({ x: 0, y: 0 });
|
||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
|
|
||||||
@@ -60,11 +63,54 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
|||||||
univerRef.current = univer;
|
univerRef.current = univer;
|
||||||
univerAPIRef.current = univerAPI;
|
univerAPIRef.current = univerAPI;
|
||||||
|
|
||||||
// Disable adding new sheets
|
// Restore tag cells whose display value was overwritten by raw tag on blur
|
||||||
|
const restoreTagCells = () => {
|
||||||
|
if (isRestoringRef.current) return;
|
||||||
|
const wb = univerAPIRef.current?.getActiveWorkbook();
|
||||||
|
if (!wb) return;
|
||||||
|
const sheet = wb.getActiveSheet();
|
||||||
|
if (!sheet) return;
|
||||||
|
const saved = wb.save();
|
||||||
|
if (!saved?.sheets) return;
|
||||||
|
const sheetId = saved.sheetOrder?.[0];
|
||||||
|
const sheetData = sheetId ? saved.sheets[sheetId] : Object.values(saved.sheets)[0];
|
||||||
|
if (!sheetData?.cellData) return;
|
||||||
|
|
||||||
|
const restorations = [];
|
||||||
|
Object.entries(sheetData.cellData).forEach(([r, row]) => {
|
||||||
|
Object.entries(row).forEach(([c, cell]) => {
|
||||||
|
const match = typeof cell.v === 'string' && cell.v.match(TAG_RE);
|
||||||
|
if (match) {
|
||||||
|
const tagIds = match[1].split(',');
|
||||||
|
const type = match[2];
|
||||||
|
const field = formFieldsRef.current.find(f =>
|
||||||
|
f.ids.some(id => tagIds.includes(String(id)))
|
||||||
|
);
|
||||||
|
const displayValue = type === 'value'
|
||||||
|
? (field?.placeholder || '')
|
||||||
|
: (field?.label || match[1]);
|
||||||
|
restorations.push({ r: +r, c: +c, v: displayValue, f: cell.v });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (restorations.length === 0) return;
|
||||||
|
isRestoringRef.current = true;
|
||||||
|
restorations.forEach(({ r, c, v, f }) => {
|
||||||
|
sheet.getRange(r, c, 1, 1).setValues([[{ v, f }]]);
|
||||||
|
});
|
||||||
|
isRestoringRef.current = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let restoreTimer;
|
||||||
|
|
||||||
|
// Disable adding new sheets; also schedule tag-cell restoration after each command
|
||||||
univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, (event) => {
|
univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, (event) => {
|
||||||
if (event.id === 'sheet.command.insert-sheet') {
|
if (event.id === 'sheet.command.insert-sheet') {
|
||||||
event.cancel = true;
|
event.cancel = true;
|
||||||
}
|
}
|
||||||
|
clearTimeout(restoreTimer);
|
||||||
|
restoreTimer = setTimeout(restoreTagCells, 80);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Context menu: "Inserisci variabile GEPAFIN"
|
// Context menu: "Inserisci variabile GEPAFIN"
|
||||||
@@ -113,6 +159,7 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
|||||||
setTagTooltip(null);
|
setTagTooltip(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}, []); // refs are stable
|
}, []); // refs are stable
|
||||||
|
|
||||||
// Keep formFieldsRef in sync with store value
|
// Keep formFieldsRef in sync with store value
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ const BuilderElementSettings = ({ closeSettingsFn, callStatus, context }) => {
|
|||||||
const chosenElementItemCfg = head(elementItems.filter(o => o.name === chosen.name));
|
const chosenElementItemCfg = head(elementItems.filter(o => o.name === chosen.name));
|
||||||
let settings = [];
|
let settings = [];
|
||||||
|
|
||||||
if (chosenElementItemCfg) {
|
if (chosenElementItemCfg && chosenElementItemCfg.settings) {
|
||||||
settings = chosenElementItemCfg.settings.map((o) => {
|
settings = chosenElementItemCfg.settings.map((o) => {
|
||||||
const setting = head(chosen.settings.filter(s => s.name === o.name));
|
const setting = head(chosen.settings.filter(s => s.name === o.name));
|
||||||
return setting ? klona(setting) : klona(o)
|
return setting ? klona(setting) : klona(o)
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ import { Tag } from 'primereact/tag';
|
|||||||
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
|
||||||
import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup';
|
import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup';
|
||||||
|
|
||||||
const DocumentsTable = ({ type, reload = 0 }) => {
|
const DocumentsTable = ({ type, reload = 0, companyId: companyIdProp }) => {
|
||||||
const chosenCompanyId = useStoreValue('chosenCompanyId');
|
const storedCompanyId = useStoreValue('chosenCompanyId');
|
||||||
|
const effectiveCompanyId = companyIdProp || storedCompanyId;
|
||||||
const companies = useStoreValue('companies');
|
const companies = useStoreValue('companies');
|
||||||
const [docs, setDocs] = useState([]);
|
const [docs, setDocs] = useState([]);
|
||||||
const [filters, setFilters] = useState(null);
|
const [filters, setFilters] = useState(null);
|
||||||
@@ -33,22 +34,26 @@ const DocumentsTable = ({ type, reload = 0 }) => {
|
|||||||
const [statuses, setStatuses] = useState([]);
|
const [statuses, setStatuses] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
|
const shouldFetch = companyIdProp
|
||||||
|
? !!effectiveCompanyId
|
||||||
|
: !!head(companies.filter(o => o.id === effectiveCompanyId));
|
||||||
|
|
||||||
if (!loading && existingCompany && reload !== 0) {
|
if (!loading && shouldFetch && reload !== 0) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
CompanyDocumentsService.getCompanyDocuments(chosenCompanyId, getCallback, errGetCallbacks, [
|
CompanyDocumentsService.getCompanyDocuments(effectiveCompanyId, getCallback, errGetCallbacks, [
|
||||||
['documentType', type]
|
['documentType', type]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}, [chosenCompanyId, reload, companies]);
|
}, [effectiveCompanyId, reload, companies]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const existingCompany = head(companies.filter(o => o.id === chosenCompanyId));
|
const shouldFetch = companyIdProp
|
||||||
|
? !!effectiveCompanyId
|
||||||
|
: !!head(companies.filter(o => o.id === effectiveCompanyId));
|
||||||
|
|
||||||
if (existingCompany) {
|
if (shouldFetch) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
CompanyDocumentsService.getCompanyDocuments(chosenCompanyId, getCallback, errGetCallbacks, [
|
CompanyDocumentsService.getCompanyDocuments(effectiveCompanyId, getCallback, errGetCallbacks, [
|
||||||
['documentType', type]
|
['documentType', type]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,30 @@
|
|||||||
import React, { useMemo, useState, useCallback, useEffect, useRef } from 'react';
|
import React, { useMemo, useState, useCallback, useEffect, useRef } from 'react';
|
||||||
import { useForm, useFieldArray } from 'react-hook-form';
|
import { useForm, useFieldArray } from 'react-hook-form';
|
||||||
import { isEmpty, head, pluck } from 'ramda';
|
import { isEmpty, head, isNil } from 'ramda';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { klona } from 'klona';
|
import { klona } from 'klona';
|
||||||
|
import { wrap } from 'object-path-immutable';
|
||||||
|
import { classNames } from 'primereact/utils';
|
||||||
|
|
||||||
// tools
|
// tools
|
||||||
import uniqid from '../../../../helpers/uniqid';
|
import uniqid from '../../../../helpers/uniqid';
|
||||||
|
import formatDateString from '../../../../helpers/formatDateString';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import FormField from '../../../../components/FormField';
|
import FormField from '../../../../components/FormField';
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { Toast } from 'primereact/toast';
|
import { Toast } from 'primereact/toast';
|
||||||
import CompanyService from '../../../../service/company-service';
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
import FileSelect from '../../../../components/FormField/components/FileSelect';
|
import { InputText } from 'primereact/inputtext';
|
||||||
import ApplicationService from '../../../../service/application-service';
|
import { Calendar } from 'primereact/calendar';
|
||||||
|
import { FileUpload } from 'primereact/fileupload';
|
||||||
|
import DocumentsTable from '../../../DocumentsBeneficiary/components/DocumentsTable';
|
||||||
|
|
||||||
|
// services
|
||||||
|
import CompanyDocumentsService from '../../../../service/company-documents-service';
|
||||||
|
import DocumentCategoryService from '../../../../service/document-category-service';
|
||||||
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
|
||||||
import { storeSet } from '../../../../store';
|
|
||||||
|
|
||||||
const EvaluationExtraFiles = ({
|
const EvaluationExtraFiles = ({
|
||||||
sourceId,
|
sourceId,
|
||||||
@@ -32,9 +40,16 @@ const EvaluationExtraFiles = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [chosen, setChosen] = useState('');
|
const [chosen, setChosen] = useState('');
|
||||||
const [isVisibleCompanyDocsDialog, setIsVisibleCompanyDocsDialog] = useState(false);
|
const [isVisibleCompanyDocsDialog, setIsVisibleCompanyDocsDialog] = useState(false);
|
||||||
const [companyDocs, setCompanyDocs] = useState([]);
|
const [isVisibleAddDocDialog, setIsVisibleAddDocDialog] = useState(false);
|
||||||
const [companyDocsSelected, setCompanyDocsSelected] = useState([]);
|
const [newDocData, setNewDocData] = useState({});
|
||||||
|
const [docFileAttached, setDocFileAttached] = useState([]);
|
||||||
|
const [documentCategories, setDocumentCategories] = useState([]);
|
||||||
|
const [addDocLoading, setAddDocLoading] = useState(false);
|
||||||
|
const [reloadHash, setReloadHash] = useState(0);
|
||||||
const toast = useRef(null);
|
const toast = useRef(null);
|
||||||
|
const today = new Date();
|
||||||
|
const tomorrow = new Date(today);
|
||||||
|
tomorrow.setDate(today.getDate() + 1);
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -107,74 +122,113 @@ const EvaluationExtraFiles = ({
|
|||||||
|
|
||||||
const hideCompanyDocsDialog = () => {
|
const hideCompanyDocsDialog = () => {
|
||||||
setIsVisibleCompanyDocsDialog(false);
|
setIsVisibleCompanyDocsDialog(false);
|
||||||
setCompanyDocsSelected([]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const footerPreTecEvalDialog = useCallback(() => {
|
const footerCompanyDocsDialog = () => {
|
||||||
return <div>
|
return <div>
|
||||||
<Button type="button" label={__('Annulla', 'gepafin')} onClick={hideCompanyDocsDialog} outlined/>
|
<Button type="button" label={__('Chiudi', 'gepafin')} onClick={hideCompanyDocsDialog} outlined/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const openAddDocDialog = () => {
|
||||||
|
setNewDocData({
|
||||||
|
name: '',
|
||||||
|
documentCategoryId: 0,
|
||||||
|
expirationDate: ''
|
||||||
|
});
|
||||||
|
setDocFileAttached([]);
|
||||||
|
setIsVisibleAddDocDialog(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideAddDocDialog = () => {
|
||||||
|
setIsVisibleAddDocDialog(false);
|
||||||
|
setNewDocData({});
|
||||||
|
setDocFileAttached([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerAddDocDialog = () => {
|
||||||
|
return <span>{__('Aggiungi documento aziendale', 'gepafin')}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDocFormValid = useCallback(() => {
|
||||||
|
return !isEmpty(docFileAttached)
|
||||||
|
&& !isEmpty(newDocData.name) && !isNil(newDocData.name)
|
||||||
|
&& newDocData.documentCategoryId !== 0 && !isNil(newDocData.documentCategoryId)
|
||||||
|
&& !isEmpty(newDocData.expirationDate) && !isNil(newDocData.expirationDate);
|
||||||
|
}, [docFileAttached, newDocData]);
|
||||||
|
|
||||||
|
const footerAddDocDialog = () => {
|
||||||
|
return <div>
|
||||||
|
<Button type="button" label={__('Annulla', 'gepafin')} onClick={hideAddDocDialog} outlined/>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
disabled={isEmpty(companyDocsSelected)}
|
disabled={addDocLoading || !isDocFormValid()}
|
||||||
label={__('Aggiungi', 'gepafin')} onClick={doImportCompanyDocs}/>
|
label={__('Salva', 'gepafin')}
|
||||||
|
onClick={doAddNewDoc}/>
|
||||||
</div>
|
</div>
|
||||||
}, [companyDocsSelected]);
|
}
|
||||||
|
|
||||||
const doImportCompanyDocs = useCallback(() => {
|
const onUpdateDocFieldValue = useCallback((value, name) => {
|
||||||
if (!isEmpty(companyDocsSelected)) {
|
setNewDocData(prev => wrap(prev).set([name], value).value());
|
||||||
const ids = pluck('id', companyDocsSelected);
|
}, []);
|
||||||
ApplicationService.setApplicationDocuments(applicationId, setDocsCallback, errSetDocsCallback, [
|
|
||||||
['companyDocumentIds', ids]
|
const onDocFileSelect = (file) => {
|
||||||
])
|
setDocFileAttached(file.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
const doAddNewDoc = useCallback(() => {
|
||||||
|
const submitData = {
|
||||||
|
...newDocData,
|
||||||
|
expirationDate: formatDateString(newDocData.expirationDate),
|
||||||
|
documentType: 'COMPANY_DOCUMENT'
|
||||||
|
};
|
||||||
|
const queryParams = Object.keys(submitData).map(k => [k, submitData[k]]);
|
||||||
|
|
||||||
|
if (!isEmpty(docFileAttached)) {
|
||||||
|
const formData = new FormData();
|
||||||
|
for (const file of docFileAttached) {
|
||||||
|
formData.append('file', file);
|
||||||
|
}
|
||||||
|
setAddDocLoading(true);
|
||||||
|
CompanyDocumentsService.uploadCompanyDocumenFromEvaluation(companyId, applicationId, formData, uploadDocCallback, errUploadDocCallback, queryParams);
|
||||||
}
|
}
|
||||||
}, [companyDocsSelected]);
|
}, [docFileAttached, newDocData, companyId, applicationId]);
|
||||||
|
|
||||||
const setDocsCallback = (resp) => {
|
const uploadDocCallback = (resp) => {
|
||||||
if (resp.status === 'SUCCESS') {
|
if (resp.status === 'SUCCESS') {
|
||||||
|
hideAddDocDialog();
|
||||||
|
setReloadHash(new Date().getTime());
|
||||||
|
} else {
|
||||||
if (toast.current && resp.message) {
|
if (toast.current && resp.message) {
|
||||||
toast.current.show({
|
toast.current.show({
|
||||||
severity: 'success',
|
severity: 'error',
|
||||||
summary: '',
|
summary: '',
|
||||||
detail: resp.message
|
detail: resp.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsVisibleCompanyDocsDialog(false);
|
setAddDocLoading(false);
|
||||||
setCompanyDocsSelected([]);
|
|
||||||
storeSet('unsetAsyncRequest');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 2500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const errSetDocsCallback = (resp) => {
|
const errUploadDocCallback = (resp) => {
|
||||||
if (toast.current && resp.message) {
|
if (toast.current && resp.message) {
|
||||||
toast.current.show({
|
toast.current.show({
|
||||||
severity: resp.status === 'SUCCESS' ? 'info' : 'error',
|
severity: 'error',
|
||||||
summary: '',
|
summary: '',
|
||||||
detail: resp.message
|
detail: resp.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setIsVisibleCompanyDocsDialog(false);
|
|
||||||
setCompanyDocsSelected([]);
|
|
||||||
set404FromErrorResponse(resp);
|
set404FromErrorResponse(resp);
|
||||||
storeSet('unsetAsyncRequest');
|
setAddDocLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDocsCallback = (resp) => {
|
|
||||||
if (resp.status === 'SUCCESS') {
|
|
||||||
setCompanyDocs(resp.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const errGetDocsCallback = () => {}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
CompanyService.getCompanyDocuments(companyId, getDocsCallback, errGetDocsCallback, [
|
DocumentCategoryService.getCategories((resp) => {
|
||||||
['documentType', 'COMPANY_DOCUMENT']
|
if (resp.status === 'SUCCESS') {
|
||||||
])
|
setDocumentCategories(resp.data.map(o => ({ value: o.id, label: o.description })));
|
||||||
}, [companyId]);
|
}
|
||||||
|
}, () => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -240,7 +294,7 @@ const EvaluationExtraFiles = ({
|
|||||||
className="fieldsRepeater__addNew"
|
className="fieldsRepeater__addNew"
|
||||||
outlined
|
outlined
|
||||||
type="button"
|
type="button"
|
||||||
disabled={(watchFields && watchFields.filter(o => isEmpty(o.nameValue) || isEmpty(o.fileValue)).length > 0) || shouldDisable}
|
disabled={shouldDisable}
|
||||||
onClick={openCompanyArchive}
|
onClick={openCompanyArchive}
|
||||||
label={__('Documenti aziendali', 'gepafin')}
|
label={__('Documenti aziendali', 'gepafin')}
|
||||||
/>
|
/>
|
||||||
@@ -251,41 +305,79 @@ const EvaluationExtraFiles = ({
|
|||||||
visible={isVisibleCompanyDocsDialog}
|
visible={isVisibleCompanyDocsDialog}
|
||||||
modal
|
modal
|
||||||
header={headerCompanyDocsDialog}
|
header={headerCompanyDocsDialog}
|
||||||
footer={footerPreTecEvalDialog}
|
footer={footerCompanyDocsDialog}
|
||||||
style={{ maxWidth: '600px', width: '100%' }}
|
style={{ maxWidth: '900px', width: '100%' }}
|
||||||
onHide={hideCompanyDocsDialog}>
|
onHide={hideCompanyDocsDialog}>
|
||||||
<div className="appForm__field">
|
<div style={{ marginBottom: '1rem' }}>
|
||||||
{/*<label
|
<Button
|
||||||
className={classNames({
|
type="button"
|
||||||
'p-error': isEmpty(companyDocsSelected)
|
label={__('Aggiungi nuovo documento', 'gepafin')}
|
||||||
})}>
|
icon="pi pi-plus"
|
||||||
{__('Documenti', 'gepafin')}
|
iconPos="right"
|
||||||
</label>*/}
|
onClick={openAddDocDialog}/>
|
||||||
<FileSelect
|
</div>
|
||||||
fieldName="companyDocsSelected"
|
<DocumentsTable type="COMPANY_DOCUMENT" companyId={companyId} reload={reloadHash}/>
|
||||||
label={null}
|
</Dialog>
|
||||||
errors={{}}
|
<Dialog
|
||||||
register={() => {}}
|
visible={isVisibleAddDocDialog}
|
||||||
key={companyDocsSelected}
|
modal
|
||||||
defaultValue={companyDocsSelected}
|
header={headerAddDocDialog}
|
||||||
options={companyDocs}
|
footer={footerAddDocDialog}
|
||||||
sourceId="0"
|
style={{ maxWidth: '600px', width: '100%' }}
|
||||||
source="DOCUMENT"
|
onHide={hideAddDocDialog}>
|
||||||
documentCategories={[]}
|
<div className="appForm__cols">
|
||||||
attachFilesCallback={(o) => {
|
<div className="appForm__field">
|
||||||
setCompanyDocsSelected(prev => {
|
<label
|
||||||
const newSelected = [...prev];
|
className={classNames({ 'p-error': isEmpty(newDocData.name) || isNil(newDocData.name) })}>
|
||||||
if (!newSelected.find(s => s.id === o.id)) {
|
{__('Nome', 'gepafin')}*
|
||||||
newSelected.push(o);
|
</label>
|
||||||
}
|
<InputText
|
||||||
return newSelected;
|
value={newDocData.name || ''}
|
||||||
})
|
invalid={isEmpty(newDocData.name || '') || isNil(newDocData.name)}
|
||||||
}}
|
onChange={(e) => onUpdateDocFieldValue(e.target.value, 'name')}/>
|
||||||
/>
|
</div>
|
||||||
|
<div className="appForm__field">
|
||||||
|
<label
|
||||||
|
className={classNames({ 'p-error': !newDocData.documentCategoryId || newDocData.documentCategoryId === 0 })}>
|
||||||
|
{__('Categoria', 'gepafin')}*
|
||||||
|
</label>
|
||||||
|
<Dropdown
|
||||||
|
value={newDocData.documentCategoryId}
|
||||||
|
invalid={!newDocData.documentCategoryId || newDocData.documentCategoryId === 0}
|
||||||
|
onChange={(e) => onUpdateDocFieldValue(e.value, 'documentCategoryId')}
|
||||||
|
options={documentCategories}
|
||||||
|
optionLabel="label"
|
||||||
|
optionValue="value"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="appForm__cols">
|
||||||
|
<div className="appForm__field">
|
||||||
|
<label
|
||||||
|
className={classNames({ 'p-error': isEmpty(newDocData.expirationDate || '') || isNil(newDocData.expirationDate) })}>
|
||||||
|
{__('Scadenza', 'gepafin')}*
|
||||||
|
</label>
|
||||||
|
<Calendar
|
||||||
|
value={newDocData.expirationDate}
|
||||||
|
minDate={tomorrow}
|
||||||
|
invalid={isEmpty(newDocData.expirationDate || '') || isNil(newDocData.expirationDate)}
|
||||||
|
onChange={(e) => onUpdateDocFieldValue(e.value, 'expirationDate')}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="appForm__cols">
|
||||||
|
<div className="appForm__field">
|
||||||
|
<label
|
||||||
|
className={classNames({ 'p-error': isEmpty(docFileAttached) })}>
|
||||||
|
{__('File', 'gepafin')}*
|
||||||
|
</label>
|
||||||
|
<FileUpload
|
||||||
|
mode="basic"
|
||||||
|
name="file"
|
||||||
|
onSelect={onDocFileSelect}/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EvaluationExtraFiles;
|
export default EvaluationExtraFiles;
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ export default class CompanyDocumentsService {
|
|||||||
NetworkService.postMultiPart(`${API_BASE_URL}/companyDocument/company/${id}/upload`, body, callback, errCallback, queryParams);
|
NetworkService.postMultiPart(`${API_BASE_URL}/companyDocument/company/${id}/upload`, body, callback, errCallback, queryParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uploadCompanyDocumenFromEvaluation = (id, applicationId, body, callback, errCallback, queryParams) => {
|
||||||
|
NetworkService.postMultiPart(`${API_BASE_URL}/companyDocument/company/${id}/application/${applicationId}/upload`, body, callback, errCallback, queryParams);
|
||||||
|
};
|
||||||
|
|
||||||
static attachCompanyDocumentToAppl = (id, callback, errCallback, queryParams) => {
|
static attachCompanyDocumentToAppl = (id, callback, errCallback, queryParams) => {
|
||||||
NetworkService.put(`${API_BASE_URL}/companyDocument/${id}/document/upload`, {}, callback, errCallback, queryParams);
|
NetworkService.put(`${API_BASE_URL}/companyDocument/${id}/document/upload`, {}, callback, errCallback, queryParams);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user