Merge branch 'develop' into master-sync/07-12-2024

This commit is contained in:
Vitalii Kiiko
2025-01-07 08:28:11 +01:00
31 changed files with 776 additions and 80 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty, head } from 'ramda';
import { klona } from 'klona';
@@ -29,6 +29,7 @@ const AddCompany = () => {
const isAsyncRequest = useStore().main.isAsyncRequest();
const infoMsgs = useRef(null);
const [, debouncedPivaValue, setInputPiva] = useDebounce('', 1000);
const [vatCheckResponse, setVatCheckResponse] = useState({});
const {
control,
@@ -54,14 +55,19 @@ const AddCompany = () => {
address: '',
companyName: ''
}
setVatCheckResponse({});
Object.keys(formData).map(k => setValue(k, formData[k]));
}
const onSubmit = (formData) => {
infoMsgs.current.clear();
storeSet.main.setAsyncRequest();
const submitData = {
...formData,
vatCheckResponse
}
CompanyService.createCompany(formData, updateCallback, updateError);
CompanyService.createCompany(submitData, updateCallback, updateError);
};
const updateCallback = (data) => {
@@ -109,7 +115,7 @@ const AddCompany = () => {
const checkVatCallback = (data) => {
if (data.status === 'SUCCESS') {
const resp = data.data.data;
const resp = data.data.vatCheckResponse.data;
if (!isEmpty(resp)) {
const {
cap, cf, denominazione, piva, indirizzo, comune, dettaglio: { pec }
@@ -126,6 +132,7 @@ const AddCompany = () => {
companyName: denominazione
}
Object.keys(formData).map(k => setValue(k, formData[k]));
setVatCheckResponse(data.data.vatCheckResponse);
}
//setData(getFormattedBandiData(data.data));
} else {

View File

@@ -39,7 +39,7 @@ const BandoApplicationPreview = () => {
const [formData, setFormData] = useState([]);
const [formInitialData, setFormInitialData] = useState(null);
const [bandoTitle, setBandoTitle] = useState('');
const [bandoId, setBandoId] = useState(0);
const [, setBandoId] = useState(0);
const [formId, setFormId] = useState('');
const [totalSteps, setTotalSteps] = useState(0);
const [applicationStatus, setApplicationStatus] = useState('');
@@ -86,8 +86,8 @@ const BandoApplicationPreview = () => {
ApplicationService.validateApplication(applId, {}, validateApplicationCallback, errValidateApplicationCallback);
};
const onSubmit = () => {
};
/*const onSubmit = () => {
};*/
const validateApplicationCallback = (data) => {
if (data.status === 'SUCCESS') {

View File

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

View File

@@ -57,6 +57,23 @@ const MyLatestSubmissionsTable = () => {
setLocalAsyncRequest(false);
}
const handleDeleteApplication = (id) => {
setLocalAsyncRequest(true);
ApplicationService.deleteApplication(id, (resp) => delApplCallback(resp, id), errDelApplCallback)
}
const delApplCallback = (resp, id) => {
if (resp.status === 'SUCCESS') {
const newItems = items.filter(o => o.id !== id);
setItems(newItems);
}
setLocalAsyncRequest(false);
}
const errDelApplCallback = (data) => {
setLocalAsyncRequest(false);
}
const getFormattedBandiData = (data) => {
return [...(data || [])].map((d) => {
d.callEndDate = new Date(d.callEndDate);
@@ -130,7 +147,8 @@ const MyLatestSubmissionsTable = () => {
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses}
onChange={(e) => options.filterCallback(e.value, options.index)}
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel} className="p-column-filter"
itemTemplate={statusItemTemplate} placeholder={translationStrings.selectOneLabel}
className="p-column-filter"
showClear/>;
};
@@ -143,13 +161,24 @@ const MyLatestSubmissionsTable = () => {
};
const actionsBodyTemplate = (rowData) => {
return <Link to={`/imieibandi/${rowData.id}`}>
{'DRAFT' === rowData.status
? <Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
return 'DRAFT' === rowData.status
? <div className="appPageSection__tableActions lessGap">
<Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small"
iconPos="right"/>
</Link>
<Button severity="danger"
onClick={() => handleDeleteApplication(rowData.id)}
label={__('Cancella', 'gepafin')}
icon="pi pi-trash"
size="small"
iconPos="right"/>
</div>
: <Link to={`/imieibandi/${rowData.id}`}>
<Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/>
: <Button severity="info" label={__('Mostra', 'gepafin')} icon="pi pi-eye" size="small"
iconPos="right"/>}
</Link>
}
const header = renderHeader();

View File

@@ -138,7 +138,7 @@ const RepeaterFields = ({
className="fieldsRepeater__addNew"
outlined
type="button"
disabled={watchFields && watchFields.filter(o => isEmpty(o.nameValue) || isEmpty(o.fileValue)).length > 0 || shouldDisable}
disabled={(watchFields && watchFields.filter(o => isEmpty(o.nameValue) || isEmpty(o.fileValue)).length > 0) || shouldDisable}
onClick={addNew}
label={__('Aggiungi nuovo file', 'gepafin')}
/>

View File

@@ -4,7 +4,7 @@ import { isEmpty, pathOr, head } from 'ramda';
import { klona } from 'klona';
import { wrap } from 'object-path-immutable';
import { useForm } from 'react-hook-form';
import emailjs from '@emailjs/browser';
//import emailjs from '@emailjs/browser';
//import { useNavigate } from 'react-router-dom';
// store
@@ -27,7 +27,7 @@ import { InputText } from 'primereact/inputtext';
import { Toast } from 'primereact/toast';
//import getFormatedFileSizeText from '../../helpers/getFormatedFileSizeText';
//import { defaultMaxFileSize } from '../../configData';
import { Dialog } from 'primereact/dialog';
//import { Dialog } from 'primereact/dialog';
import { confirmPopup, ConfirmPopup } from 'primereact/confirmpopup';
const ProfileCompany = () => {
@@ -38,7 +38,7 @@ const ProfileCompany = () => {
const [formInitialData, setFormInitialData] = useState({});
const [delegaData, setDelegaData] = useState({});
//const [delega, setDelega] = useState([]);
const [isVisibleRemoveDialog, setIsVisibleRemoveDialog] = useState(false);
//const [isVisibleRemoveDialog, setIsVisibleRemoveDialog] = useState(false);
const { delegaFirstName = '', delegaLastName = '', delegaCodiceFiscale = '' } = delegaData;
const toast = useRef(null);
//const navigate = useNavigate();
@@ -212,22 +212,22 @@ const ProfileCompany = () => {
defaultFocus: 'reject',
acceptClassName: 'p-button-danger',
accept: () => {
doRemoveCompany();
doRemoveCompanyAPI();
},
reject: () => {
}
});
};
const headerRemoveDialog = () => {
/*const headerRemoveDialog = () => {
return <span>{__('Rimuovi azienda', 'gepafin')}</span>
}
const hideRemoveDialog = () => {
setIsVisibleRemoveDialog(false);
}
}*/
const doRemoveCompany = () => {
/*const doRemoveCompany = () => {
const userData = storeGet.main.userData();
let chosenCompany = {};
@@ -251,13 +251,13 @@ const ProfileCompany = () => {
publicKey: 'TPWwaPLM2dDuEIa10'
}
).then(() => {
/*if (toast.current) {
/!*if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('La richiesta è stata inviata!', 'gepafin')
});
}*/
}*!/
setIsVisibleRemoveDialog(true);
})
.catch((err) => {
@@ -270,10 +270,9 @@ const ProfileCompany = () => {
});
}
});
}
}*/
// TODO delete company functionality by API, ready to be shipped
/*const doRemoveCompanyAPI = () => {
const doRemoveCompanyAPI = () => {
storeSet.main.setAsyncRequest();
CompanyService.deleteCompany(formInitialData.id, deleteCompanyCallback, errDeleteCompanyCallback)
}
@@ -289,6 +288,8 @@ const ProfileCompany = () => {
if (!isEmpty(newCompanies)) {
const newChosenCompanyId = newCompanies[0].id;
storeSet.main.chosenCompanyId(newChosenCompanyId);
} else {
storeSet.main.chosenCompanyId(0);
}
}
storeSet.main.unsetAsyncRequest();
@@ -297,7 +298,7 @@ const ProfileCompany = () => {
const errDeleteCompanyCallback = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}*/
}
useEffect(() => {
const newFormData = klona(formInitialData);
@@ -622,15 +623,15 @@ const ProfileCompany = () => {
</div>
</div>
<Dialog
{/*<Dialog
visible={isVisibleRemoveDialog}
modal
header={headerRemoveDialog}
/*footer={footerRemoveDialog}*/
footer={footerRemoveDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideRemoveDialog}>
<p>Abbiamo preso in carica la tua richiesta a breve l'azienda sarà rimossa dal tuo profilo</p>
</Dialog>
</Dialog>*/}
</div>
)

View File

@@ -17,7 +17,6 @@ import ApplicationService from '../../service/application-service';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import getBandoLabel from '../../helpers/getBandoLabel';
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
import renderHtmlContent from '../../helpers/renderHtmlContent';
// components
import { Button } from 'primereact/button';
@@ -27,6 +26,7 @@ import { Dialog } from 'primereact/dialog';
import FormField from '../../components/FormField';
import SoccorsoComunications from '../SoccorsoEditPreInstructor/components/SoccorsoComunications';
import { Editor } from 'primereact/editor';
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
const SoccorsoEditBeneficiario = () => {
const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -327,10 +327,7 @@ const SoccorsoEditBeneficiario = () => {
? <div className="appPageSection">
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey ql-editor"
style={{ minHeight: '100px' }}>
{renderHtmlContent(data.note)}
</div>
<div>{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}</div>
</div> : null}
{data.id
@@ -440,7 +437,7 @@ const SoccorsoEditBeneficiario = () => {
outlined
onClick={goToArchivePage}
label={__('Indietro', 'gepafin')}
icon="pi pi-times" iconPos="right"/>
icon="pi pi-arrow-left" iconPos="left"/>
</div>
</div>
</div>

View File

@@ -16,7 +16,7 @@ import AmendmentsService from '../../service/amendments-service';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import getBandoLabel from '../../helpers/getBandoLabel';
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
import renderHtmlContent from '../../helpers/renderHtmlContent';
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
// components
import { Button } from 'primereact/button';
@@ -411,26 +411,19 @@ const SoccorsoEditPreInstructor = () => {
<div className="appPageSection">
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
<div className="appPageSection columns">
<div>
<h3>{__('Documenti Richiesti', 'gepafin')}</h3>
<ol className="appPageSection__list">
{data.formFields
? data.formFields.map((o, i) => <li key={o.fieldId}
style={{ flexDirection: 'row' }}>
<span>{o.label}</span>
</li>) : null}
</ol>
</div>
<div>
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
<div className="appPageSection__withBorder grey ql-editor"
style={{ minHeight: '200px' }}>
{renderHtmlContent(data.note)}
</div>
</div>
</div>
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
<div
className="appPageSection__emailTemplate">{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}</div>
</div>
<div className="appPageSection">
<h3>{__('Documenti Richiesti', 'gepafin')}</h3>
<ol className="appPageSection__list">
{data.formFields
? data.formFields.map((o, i) => <li key={o.fieldId}
style={{ flexDirection: 'row' }}>
<span>{o.label}</span>
</li>) : null}
</ol>
</div>
<div className="appPageSection">

View File

@@ -0,0 +1,192 @@
import React, { useState, useEffect, useRef } from 'react';
import { __ } from '@wordpress/i18n';
import { isEmpty, pathOr } from 'ramda';
import { useNavigate, useParams } from 'react-router-dom';
import NumberFlow from '@number-flow/react';
// service
import UserService from '../../service/user-service';
// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
// components
import { Button } from 'primereact/button';
import { Toast } from 'primereact/toast';
import { Dropdown } from 'primereact/dropdown';
const UserActivity = () => {
const [loading, setLoading] = useState(false);
const toast = useRef(null);
const navigate = useNavigate();
const { id } = useParams();
const [user, setUser] = useState({});
const [roles, setRoles] = useState([]);
const [chosenRole, setChosenRole] = useState(0);
const goBack = () => {
navigate(`/utenti`);
}
const getUserCallback = (resp) => {
if (resp.status === 'SUCCESS') {
setUser(resp.data)
setChosenRole(resp.data.role?.id);
}
setLoading(false);
}
const errGetUserCallback = (resp) => {
set404FromErrorResponse(resp);
setLoading(false);
}
const getRolesCallback = (resp) => {
if (resp.status === 'SUCCESS') {
setRoles(resp.data)
}
setLoading(false);
}
const errGetRolesCallback = (resp) => {
set404FromErrorResponse(resp);
setLoading(false);
}
const getStatValue = (key, fallback = 0) => {
return pathOr(fallback, [key], {});
}
const handleRoleUpdate = () => {
if (user.role?.id !== chosenRole) {
setLoading(true);
UserService.updateUser(user.id, {roleId: chosenRole}, updateRoleCallback, errUpdateRoleCallback)
}
}
const updateRoleCallback = (resp) => {
if (resp.status === 'SUCCESS') {
setUser(resp.data)
}
setLoading(false);
}
const errUpdateRoleCallback = (resp) => {
set404FromErrorResponse(resp);
setLoading(false);
}
useEffect(() => {
if (id && !isEmpty(id)) {
setLoading(true);
UserService.getUser(id, getUserCallback, errGetUserCallback);
UserService.getRoles(getRolesCallback, errGetRolesCallback);
}
}, [id])
return (
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Controllo attività utenti', 'gepafin')}</h1>
</div>
<div className="appPage__spacer"></div>
<Toast ref={toast}/>
<div className="appPageSection">
<div className="appPageSection__actions">
<Button
onClick={goBack}
outlined
label={__('Indietro', 'gepafin')} icon="pi pi-arrow-left" iconPos="left"/>
</div>
</div>
<div className="appPageSection__withBorder columns">
<p className="appPageSection__pMeta">
<span>{__('Nome utente', 'gepafin')}</span>
<span>{`${user.firstName} ${user.lastName}`}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Email', 'gepafin')}</span>
<span>{user.email}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Ruolo', 'gepafin')}</span>
<span>{user.role?.roleName}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Data registrazione', 'gepafin')}</span>
<span>{getDateFromISOstring(user.createdDate)}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Ultimo accesso', 'gepafin')}</span>
<span>{getDateFromISOstring(user.lastLogin)}</span>
</p>
<p className="appPageSection__pMeta">
<span>{__('Stato account', 'gepafin')}</span>
<span>{user.status}</span>
</p>
</div>
{['ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER'].includes(user.role?.roleType)
? <>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<h3>{__('Cambia ruolo', 'gepafin')}</h3>
<div className="row">
<Dropdown
id="form"
disabled={isEmpty(roles) || loading}
value={chosenRole}
onChange={(e) => setChosenRole(e.value)}
options={roles.filter(o => [3, 5].includes(o.id)).map(o => ({ label: o.roleName, value: o.id }))}
optionLabel="label"
placeholder={__('Seleziona ruolo', 'gepafin')}/>
<Button
type="button"
disabled={loading}
outlined
onClick={handleRoleUpdate}
label={__('Modifica', 'gepafin')}
icon="pi pi-cog" iconPos="right"/>
</div>
</div>
</> : null}
<div className="appPage__spacer"></div>
{/*<div className="appPageSection">
<h2>{__('Statistiche attività', 'gepafin')}</h2>
<div className="statsBigBadges__grid grid-small">
<div className="statsBigBadges__gridItem">
<span>{__('Login totali', 'gepafin')}</span>
<span>{<NumberFlow
value={getStatValue('numberOfActiveCalls', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/>}</span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('Bandi gestiti', 'gepafin')}</span>
<span>{<NumberFlow
value={getStatValue('numberOfActiveCalls', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/>}</span>
</div>
<div className="statsBigBadges__gridItem">
<span>{__('Domande processate', 'gepafin')}</span>
<span>{<NumberFlow
value={getStatValue('numberOfActiveCalls', 0)}
format={{ notation: 'compact' }}
locales="it-IT"/>}</span>
</div>
</div>
</div>*/}
</div>
)
}
export default UserActivity;

View File

@@ -24,6 +24,7 @@ import { Calendar } from 'primereact/calendar';
import { Tag } from 'primereact/tag';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import translationStrings from '../../../../translationStringsForComponents';
import { Link } from 'react-router-dom';
const AllUsersTable = () => {
const users = useStore().main.users();
@@ -125,12 +126,16 @@ const AllUsersTable = () => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)}/>;
};
/*const actionsBodyTemplate = (rowData) => {
/!*return <Link to={`/utenti/${rowData.id}`}>
<Button severity="info" label={__('Modifica', 'gepafin')} icon="pi pi-pencil" size="small" iconPos="right"/>
</Link>*!/
return null;
}*/
const actionsBodyTemplate = (rowData) => {
return <Link to={`/utenti/${rowData.id}`}>
<Button
severity="info"
label={__('Attività', 'gepafin')}
icon="pi pi-eye"
size="small"
iconPos="right"/>
</Link>
}
const header = renderHeader();
@@ -149,22 +154,22 @@ const AllUsersTable = () => {
filter sortable
field="email"
filterPlaceholder={__('Cerca per email', 'gepafin')}
style={{ minWidth: '12rem' }}/>
style={{ minWidth: '10rem' }}/>
<Column body={roleBodyTemplate} header={__('Ruolo', 'gepafin')}
style={{ minWidth: '12rem' }}/>
style={{ minWidth: '8rem' }}/>
<Column field="status" header={__('Stato', 'gepafin')}
filterMenuStyle={{ width: '14rem' }}
style={{ width: '120px' }} body={statusBodyTemplate}
filterElement={statusFilterTemplate}/>
<Column header={__('Ultimo accesso', 'gepafin')}
filterField="lastLogin" dataType="date"
style={{ minWidth: '10rem' }}
style={{ minWidth: '7rem' }}
body={dateLastAccessBodyTemplate} filter filterElement={dateFilterTemplate}/>
{/*<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>*/}
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default AllUsersTable;
export default AllUsersTable;