- fixed displaying tables;

- fixed uploading signed pdf for application;
- added downloading modullistica archive;
- added basic table related validator;
This commit is contained in:
Vitalii Kiiko
2024-10-13 12:20:47 +02:00
parent 2bedcee172
commit cd54246313
16 changed files with 194 additions and 56 deletions

View File

@@ -94,7 +94,6 @@ const FileuploadApplicationSignedPdf = ({
setStateFieldData(prevState => {
const newFiles = prevState.filter(o => o.id !== id);
inputRef.current.setUploadedFiles(newFiles);
console.log('dCallback - newFiles', newFiles)
return newFiles;
});
}
@@ -144,7 +143,8 @@ const FileuploadApplicationSignedPdf = ({
}, [defaultValue]);
useEffect(() => {
const properMime = accept
const properMime = accept.map
? accept
.map(v => {
const found = head(mimeTypes.filter(o => o.code.includes(v)));
let res = v;
@@ -154,7 +154,7 @@ const FileuploadApplicationSignedPdf = ({
}
return res;
})
}) : [];
// eslint-disable-next-line no-useless-escape
setAcceptFormats(properMime.join(',').replace(/\*/g, '.\*').replace(/,/g, '|'));
setFormatsForInput(properMime.join(','))
@@ -162,7 +162,7 @@ const FileuploadApplicationSignedPdf = ({
useEffect(() => {
if (inputRef.current) {
inputRef.current.setUploadedFiles(stateFieldData);
inputRef.current.setUploadedFiles(stateFieldData ? stateFieldData : []);
}
setDataFn(fieldName, stateFieldData, { shouldValidate: true });
}, [stateFieldData])

View File

@@ -143,7 +143,8 @@ const FileuploadDelega = ({
}, [defaultValue]);
useEffect(() => {
const properMime = accept
const properMime = accept.map
? accept
.map(v => {
const found = head(mimeTypes.filter(o => o.code.includes(v)));
let res = v;
@@ -153,7 +154,7 @@ const FileuploadDelega = ({
}
return res;
})
}) : [];
// eslint-disable-next-line no-useless-escape
setAcceptFormats(properMime.join(',').replace(/\*/g, '.\*').replace(/,/g, '|'));
setFormatsForInput(properMime.join(','))

View File

@@ -19,7 +19,6 @@ import { mimeTypes } from '../../../../configData';
const Fileupload = ({
fieldName,
setDataFn,
control,
label,
errors,
register,
@@ -161,7 +160,8 @@ const Fileupload = ({
}, [defaultValue]);
useEffect(() => {
const properMime = accept
const properMime = accept.map
? accept
.map(v => {
const found = head(mimeTypes.filter(o => o.code.includes(v)));
let res = v;
@@ -171,7 +171,7 @@ const Fileupload = ({
}
return res;
})
}) : [];
// eslint-disable-next-line no-useless-escape
setAcceptFormats(properMime.join(',').replace(/\*/g, '.\*').replace(/,/g, '|'));
setFormatsForInput(properMime.join(','))

View File

@@ -161,7 +161,8 @@ const FileuploadAsync = ({
}, [defaultValue]);
useEffect(() => {
const properMime = accept
const properMime = accept.map
? accept
.map(v => {
const found = head(mimeTypes.filter(o => o.code.includes(v)));
let res = v;
@@ -171,7 +172,7 @@ const FileuploadAsync = ({
}
return res;
})
}) : [];
// eslint-disable-next-line no-useless-escape
setAcceptFormats(properMime.join(',').replace(/\*/g, '.\*').replace(/,/g, '|'));
setFormatsForInput(properMime.join(','))

View File

@@ -1,12 +1,15 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useCallback } from 'react';
import { classNames } from 'primereact/utils';
import { __ } from '@wordpress/i18n';
import { pathOr, isEmpty, isNil } from 'ramda';
import { wrap } from 'object-path-immutable';
import equal from 'fast-deep-equal';
//components
import { Button } from 'primereact/button';
import RenderTable from './RenderTable';
import { klona } from 'klona';
import { nonEmptyTables } from '../../../../helpers/validators';
const Table = ({
fieldName,
@@ -21,7 +24,7 @@ const Table = ({
const [columnsCfg, setColumnsCfg] = useState([]);
const [rowsCfg, setRowsCfg] = useState([]);
const [columns, setColumns] = useState([]);
const [rows, setRows] = useState([]);
const [rows, setRows] = useState(null);
const [shouldDisableNewRows, setShouldDisableNewRows] = useState(false);
const [rowIndexToDelete, rowRowIndexToDelete] = useState(null);
@@ -32,24 +35,33 @@ const Table = ({
return acc;
}, {});
const newRowsData = [...rows, obj];
setRows(newRowsData);
setDataFn(fieldName, newRowsData, { shouldValidate: true });
updateRows(newRowsData);
}
const removeRow = (index) => {
rowRowIndexToDelete(index);
}
const updateRows = (data) => {
const updateRows = useCallback((data) => {
setRows(data);
setDataFn(fieldName, data, { shouldValidate: true });
}, [rows, defaultValue]);
const properConfig = (config) => {
let newConfig = klona(config);
if (config.validate && config.validate.nonEmptyTables) {
newConfig = wrap(newConfig)
.set(['validate', 'nonEmptyTables'], (v) => nonEmptyTables(v, tableColumns))
.value();
}
return newConfig;
}
useEffect(() => {
if (!isNil(rowIndexToDelete)) {
const newRowsData = wrap(rows).del([rowIndexToDelete]).value();
setRows(newRowsData);
setDataFn(fieldName, [...newRowsData], { shouldValidate: true });
updateRows(newRowsData);
}
rowRowIndexToDelete(null);
}, [rowIndexToDelete]);
@@ -111,11 +123,14 @@ const Table = ({
}, [tableColumns]);
useEffect(() => {
setRows(defaultValue)
if (!equal(rows, defaultValue)) {
setRows(defaultValue);
}
}, [defaultValue]);
useEffect(() => {
register(fieldName, config);
setRows(defaultValue);
register(fieldName, properConfig(config));
}, []);
return (
@@ -123,7 +138,7 @@ const Table = ({
<label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
{label}{config.required || config.isRequired ? <span className="appForm__field--required">*</span> : null}
</label>
<RenderTable columns={columns} data={rows} setRowsFn={updateRows}/>
{rows ? <RenderTable columns={columns} data={rows} setRowsFn={updateRows}/> : null}
{!isEmpty(columns) && !shouldDisableNewRows
? <div className="addNewTableRow" onClick={addNewRow}>{__('Aggiungi una riga', 'gepafin')}</div>
: null}

View File

@@ -65,4 +65,14 @@ export const minChecks = (v, num) => {
export const maxChecks = (v, num) => {
return is(Array, v) ? v.length <= parseInt(num) : false;
}
export const nonEmptyTables = (v = [], colsCfg = []) => {
//console.log('nonEmptyTables',v)
/*const cellValues = v.map(row => {
return isEmpty(row)
});
console.log('cellValues', cellValues, colsCfg)*/
return is(Array, v) ? v.length >= 1 : false;
}

View File

@@ -147,7 +147,7 @@ const AddCompany = () => {
return (
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Profilo aziendale', 'gepafin')}</h1>
<h1>{__('Agguingi azienda', 'gepafin')}</h1>
</div>
<div className="appPage__spacer"></div>

View File

@@ -20,7 +20,7 @@ import {
isEmail,
isEmailPEC,
isUrl,
isMarcaDaBollo
isMarcaDaBollo, minChecks, maxChecks, nonEmptyTables
} from '../../helpers/validators';
import renderHtmlContent from '../../helpers/renderHtmlContent';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
@@ -34,7 +34,7 @@ import { Messages } from 'primereact/messages';
import ApplicationSteps from './ApplicationSteps';
import BlockingOverlay from '../../components/BlockingOverlay';
import { Dialog } from 'primereact/dialog';
//import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
import FileuploadApplicationSignedPdf from '../../components/FileuploadApplicationSignedPdf';
const BandoApplication = () => {
const { id } = useParams();
@@ -47,8 +47,7 @@ const BandoApplication = () => {
const [visibleConfirmation, setVisibleConfirmation] = useState(false);
const [applicationStatus, setApplicationStatus] = useState('');
const [activeStep, setActiveStep] = useState(1);
// TODO
//const [signedPdfFile, setSignedPdfFile] = useState([]);
const [signedPdfFile, setSignedPdfFile] = useState([]);
const isAsyncRequest = useStore().main.isAsyncRequest();
const toast = useRef(null);
const formMsgs = useRef(null);
@@ -75,7 +74,10 @@ const BandoApplication = () => {
isEmail,
isEmailPEC,
isUrl,
isMarcaDaBollo
isMarcaDaBollo,
minChecks,
maxChecks,
nonEmptyTables
}
const activeStepIndex = activeStep - 1;
const values = getValues();
@@ -362,8 +364,32 @@ const BandoApplication = () => {
const errPdfCallback = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const getSignedPdfCallback = (data) => {
if (data.status === 'SUCCESS') {
setSignedPdfFile([data.data]);
}
storeSet.main.unsetAsyncRequest();
}
const errSignedPdfCallbacks = (data) => {
//set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
useEffect(() => {
if ('SUBMIT' === applicationStatus) {
const applId = getApplicationId();
if (applId) {
storeSet.main.setAsyncRequest();
ApplicationService.getApplicationSignedPdf(applId, getSignedPdfCallback, errSignedPdfCallbacks);
}
}
}, [applicationStatus])
useEffect(() => {
if (formInitialData) {
reset();
@@ -455,6 +481,13 @@ const BandoApplication = () => {
return acc;
}, {});
/*if (o.name === 'table') {
validations.required = true;
validations.validate = {
nonEmptyTables: (v) => nonEmptyTables(v)
};
}*/
//console.log('validations', validations, o.name)
return ['paragraph'].includes(o.name) && text
@@ -498,18 +531,17 @@ const BandoApplication = () => {
iconPos="right"/>
</div> : null}
{/*{'SUBMIT' === applicationStatus
{'SUBMIT' === applicationStatus
? <div className="appPageSection">
<div className="appForm__field">
<label htmlFor="signedPdfFile">
{__('Carica documento della domanda firmato', 'gepafin')}
<span className="appForm__field--required">*</span>
(.p7m)
</label>
<FileuploadApplicationSignedPdf
setDataFn={setSignedPdfFile}
fieldName="signedPdfFile"
defaultValue={signedPdfFile}
defaultValue={is(Array, signedPdfFile) ? signedPdfFile : []}
accept={['.p7m,application/pkcs7-mime,application/x-pkcs7-mime']}
chooseLabel={__('Aggiungi documento', 'gepafin')}
multiple={false}
@@ -518,7 +550,7 @@ const BandoApplication = () => {
/>
</div>
</div>
: null}*/}
: null}
<div className="appPage__spacer"></div>

View File

@@ -213,7 +213,6 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, getFormErrors, st
}
const acceptAllFormats = () => {
console.log(mimeTypes.map(o => o.code))
return mimeTypes.map(o => o.code);
}

View File

@@ -14,6 +14,7 @@ import { TabView, TabPanel } from 'primereact/tabview';
import { InputSwitch } from 'primereact/inputswitch';
import ElementSetting from './components/ElementSetting';
import { Dropdown } from 'primereact/dropdown';
import { maxChecks, minChecks } from '../../../../helpers/validators';
const BuilderElementSettings = ({ closeSettings }) => {
const elements = useStore().main.formElements();
@@ -30,7 +31,10 @@ const BuilderElementSettings = ({ closeSettings }) => {
{ value: 'isEmail', label: 'isEmail' },
{ value: 'isEmailPEC', label: 'isEmailPEC' },
{ value: 'isUrl', label: 'isUrl' },
{ value: 'isMarcaDaBollo', label: 'isMarcaDaBollo' }
{ value: 'isMarcaDaBollo', label: 'isMarcaDaBollo' },
{ value: 'minChecks', label: 'minChecks' },
{ value: 'maxChecks', label: 'maxChecks' },
{ value: 'nonEmptyTables', label: 'nonEmptyTables' }
]
const onChange = (value, name) => {

View File

@@ -23,7 +23,7 @@ import FormsService from '../../service/forms-service';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
// TODO temp data
//import { elementItems } from '../../tempData';
import { elementItems } from '../../tempData';
const BandoFormsEdit = () => {
const { id, formId } = useParams();
@@ -215,8 +215,8 @@ const BandoFormsEdit = () => {
const getElementItemsCallback = (data) => {
if (data.status === 'SUCCESS') {
//storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder));
storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder));
//storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder));
}
storeSet.main.unsetAsyncRequest();
}

View File

@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { klona } from 'klona';
import { head } from 'ramda';
import { head, isNil } from 'ramda';
import { useForm } from 'react-hook-form';
// store
@@ -26,7 +26,7 @@ import {
isIBAN,
isMarcaDaBollo,
isPIVA,
isUrl
isUrl, minChecks, maxChecks, nonEmptyTables
} from '../../helpers/validators';
import renderHtmlContent from '../../helpers/renderHtmlContent';
@@ -53,7 +53,10 @@ const BandoFormsPreview = () => {
isEmail,
isEmailPEC,
isUrl,
isMarcaDaBollo
isMarcaDaBollo,
minChecks,
maxChecks,
nonEmptyTables
}
const onSubmit = () => {
@@ -93,7 +96,7 @@ const BandoFormsPreview = () => {
return (
<div className="appPage">
{!isAsyncRequest
{!isAsyncRequest && !isNil(formName)
? <div className="appPage__pageHeader">
<h1>{formName}</h1>
</div>
@@ -116,7 +119,8 @@ const BandoFormsPreview = () => {
</div>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
{formData.map(o => {
{!isNil(formName)
? formData.map(o => {
const label = head(o.settings.filter(o => o.name === 'label'));
const text = head(o.settings.filter(o => o.name === 'text'));
const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
@@ -149,6 +153,8 @@ const BandoFormsPreview = () => {
return acc;
}, {});
//console.log('validations', validations, o.name)
return ['paragraph'].includes(o.name) && text
? <div className="appForm__content" key={o.id}>{renderHtmlContent(text.value)}</div>
: <FormField
@@ -160,7 +166,7 @@ const BandoFormsPreview = () => {
control={control}
register={register}
errors={errors}
defaultValue={values[o.id]}
defaultValue={values[o.id] ? values[o.id] : ''}
maxFractionDigits={step ? step.value : 0}
accept={mimeValue}
config={validations}
@@ -170,7 +176,7 @@ const BandoFormsPreview = () => {
useGrouping={false}
tableColumns={tableColumns ? tableColumns.value : {}}
/>
})}
}) : null}
</form>
<div className="appPageSection__preview">

View File

@@ -12,6 +12,11 @@ import getDateFromISOstring from '../../helpers/getDateFromISOstring';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import renderHtmlContent from '../../helpers/renderHtmlContent';
// api
import BandoService from '../../service/bando-service';
import FaqItemService from '../../service/faq-item-service';
import ApplicationService from '../../service/application-service';
// components
import { Skeleton } from 'primereact/skeleton';
import { Accordion } from 'primereact/accordion';
@@ -20,11 +25,6 @@ import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
import { Message } from 'primereact/message';
import { Toast } from 'primereact/toast';
// api
import BandoService from '../../service/bando-service';
import FaqItemService from '../../service/faq-item-service';
import ApplicationService from '../../service/application-service';
import { Editor } from 'primereact/editor';
const BandoViewBeneficiario = () => {
@@ -38,12 +38,37 @@ const BandoViewBeneficiario = () => {
const bandoMsgs = useRef(null);
const toast = useRef(null);
const scaricaBando = () => {
/*const scaricaBando = () => {
}
}*/
const scaricaModulistica = () => {
const bandoId = getBandoId();
BandoService.getBandoPdf(bandoId, getCallPdfCallback, errCallPdfCallback);
}
const getCallPdfCallback = (data) => {
const bandoId = getBandoId();
const pdfFile = new Blob([data], { type: 'application/zip' })
const url = window.URL.createObjectURL(pdfFile);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `modulistica-bando-${bandoId}.zip`);
document.body.appendChild(link);
link.click();
link.remove();
storeSet.main.unsetAsyncRequest();
}
const errCallPdfCallback = (data) => {
if (toast.current) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
storeSet.main.unsetAsyncRequest();
}
const getBandoId = () => {
@@ -56,7 +81,7 @@ const BandoViewBeneficiario = () => {
navigate(`/imieibandi/${applicationObj.id}`);
} else {
const bandoId = getBandoId();
ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]])
ApplicationService.createApplication(bandoId, {}, createApplCallback, errCreateApplCallback, [['companyId', chosenCompanyId]]);
}
}
@@ -352,19 +377,18 @@ const BandoViewBeneficiario = () => {
<div className="appPageSection">
<h2>{__('Download Documenti', 'gepafin')}</h2>
<div className="appPageSection__actions">
<Button
{/* <Button
type="button"
disabled={true}
outlined
onClick={scaricaBando}
label={__('Scarica Bando Completo', 'gepafin')}
icon="pi pi-download" iconPos="right"/>
icon="pi pi-download" iconPos="right"/>*/}
<Button
type="button"
disabled={true}
outlined
onClick={scaricaModulistica}
label={__('Scarica Modulistica', 'gepafin')}
label={__('Scarica Bando Completo e Modulistica', 'gepafin')}
icon="pi pi-download" iconPos="right"/>
<Button
type="button"

View File

@@ -31,4 +31,8 @@ export default class BandoService {
static updateBandoStatus = (id, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/call/${id}/status`, {}, callback, errCallback, queryParams);
};
static getBandoPdf = (id, callback, errCallback) => {
NetworkService.getBlob(`${API_BASE_URL}/call/${id}/documents/zip`, callback, errCallback);
};
}

View File

@@ -389,6 +389,46 @@ export class NetworkService {
};
static getBlob = (url, callback, errorCallback, queryParams) => {
if (queryParams) {
url += '?'
for (let i = 0; i < queryParams.length; i++) {
if (queryParams[i] && this.isNotBlank(queryParams[i][0]) && this.isNotBlank(queryParams[i][1])) {
let param = queryParams[i][0] + '=' + queryParams[i][1]
if (i !== queryParams.length - 1)
param += '&'
url += param;
}
}
if (url.charAt(url.length) === '&')
url = url.substring(0, url.length - 1);
}
fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + storeGet.main.getToken(),
},
})
.then(async response => {
let status = response.status;
return { response: await response.blob(), status: status }
})
.then(data => {
if (data.status >= 400 && data.status <= 599)
errorCallback(data.response)
else
callback(data.response)
})
.catch(err => errorCallback(err));
};
static promiseGet = async (url, queryParams = null) => {
const response = await fetch(url, {
method: 'GET',

View File

@@ -416,6 +416,8 @@ export const elementItems = [
value: {}
}
],
validators: {}
validators: {
custom: 'nonEmptyTables'
}
}
]