- added 'bandi disponibili' page;

- improved some styles and displaying data in tables;
This commit is contained in:
Vitalii Kiiko
2024-09-23 16:55:28 +02:00
parent bbf117eb9b
commit 2341b9ff62
10 changed files with 266 additions and 75 deletions

View File

@@ -3,20 +3,10 @@ version: 0.2
phases: phases:
install: install:
runtime-versions: runtime-versions:
nodejs: 18 nodejs: 20
commands:
- npm install -g yarn
- echo yarn -v
- yarn -v
pre_build:
commands:
- yarn install
build: build:
commands: commands:
- yarn extract - npm install && npm run build:prod
- yarn compile
- mkdir -pv public/loaded-files
- yarn build:prod
artifacts: artifacts:
files: files:
- '**/*' - '**/*'

View File

@@ -1,3 +1,3 @@
REACT_APP_TAB_TITLE=Gepafin REACT_APP_TAB_TITLE=Gepafin
REACT_APP_API_EXECUTION_ADDRESS= REACT_APP_API_EXECUTION_ADDRESS=https://api-dev-gepafin.memento.credit/v1
REACT_APP_LOGO_FILENAME=logo.svg REACT_APP_LOGO_FILENAME=logo.svg

View File

@@ -10,7 +10,12 @@
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
line-height: normal; line-height: normal;
text-align: center; }
.appPageLogin__wrapper {
h1 {
text-align: center;
}
} }
} }
@@ -224,3 +229,31 @@
padding: 24px 0 48px; padding: 24px 0 48px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.appPageSection__tableActions {
display: flex;
gap: 24px;
padding: 0;
flex-wrap: wrap;
}
.appPageSection__addToFavourites {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
border: none;
background-color: var(--message-info-color);
color: white;
padding: 0;
&:hover {
cursor: pointer;
}
&[disabled] {
background-color: var(--message-info-background);
}
}

View File

@@ -21,7 +21,7 @@ const AppSidebar = () => {
enable: true enable: true
}, },
{ {
label: __('Gestione Bandi', 'gepafin'), label: __('Gestione bandi', 'gepafin'),
icon: 'pi pi-file', icon: 'pi pi-file',
href: '/bandi', href: '/bandi',
id: 2, id: 2,
@@ -34,6 +34,13 @@ const AppSidebar = () => {
id: 11, id: 11,
enable: intersection(permissions, ['APPLY_CALLS']).length enable: intersection(permissions, ['APPLY_CALLS']).length
}, },
{
label: __('Bandi disponibili', 'gepafin'),
icon: 'pi pi-bookmark',
href: '/bandi',
id: 12,
enable: intersection(permissions, ['VIEW_CALLS']).length
},
{ {
label: __('Gestione Utenti', 'gepafin'), label: __('Gestione Utenti', 'gepafin'),
icon: 'pi pi-users', icon: 'pi pi-users',

View File

@@ -10,7 +10,7 @@ const Applications = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const gotToBandiDisponibili = () => { const gotToBandiDisponibili = () => {
navigate('') navigate('/bandi')
} }
return( return(
@@ -34,7 +34,6 @@ const Applications = () => {
<div className="appPageSection"> <div className="appPageSection">
<div className="appPageSection__actions"> <div className="appPageSection__actions">
<Button <Button
disabled={true}
onClick={gotToBandiDisponibili} onClick={gotToBandiDisponibili}
label={__('Bandi disponibili', 'gepafin')} icon="pi pi-bookmark" iconPos="right"/> label={__('Bandi disponibili', 'gepafin')} icon="pi pi-bookmark" iconPos="right"/>
<Button <Button

View File

@@ -0,0 +1,130 @@
import React, { useState, useEffect} from 'react';
import { __ } from '@wordpress/i18n';
import { is, uniq } from 'ramda';
// store
import { storeSet, storeGet } from '../../../../store';
// tools
import getBandoSeverity from '../../../../helpers/getBandoSeverity';
import getBandoLabel from '../../../../helpers/getBandoLabel';
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
// api
import BandoService from '../../../../service/bando-service';
// components
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Dropdown } from 'primereact/dropdown';
import { Tag } from 'primereact/tag';
import ProperBandoLabel from '../../../../components/ProperBandoLabel';
import getNumberWithCurrency from '../../../../helpers/getNumberWithCurrency';
import renderHtmlContent from '../../../../helpers/renderHtmlContent';
import { Button } from 'primereact/button';
import { useNavigate } from 'react-router-dom';
const AllBandiAccordion = () => {
const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null);
const [loading, setLoading] = useState(false);
const [expandedRows, setExpandedRows] = useState(null);
const [statuses, setStatuses] = useState([]);
const navigate = useNavigate();
useEffect(() => {
storeSet.main.setAsyncRequest();
BandoService.getBandi(getCallback, errGetCallbacks);
}, []);
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setItems(getFormattedBandiData(data.data));
setStatuses(uniq(data.data.map(o => o.status)))
}
storeSet.main.unsetAsyncRequest();
}
const errGetCallbacks = (data) => {
console.log('errGetCallbacks', data)
storeSet.main.unsetAsyncRequest();
}
const getFormattedBandiData = (data) => {
return data.map((d) => {
d.dates = d.dates.map(v => is(String, v) ? new Date(v) : (v ? v : ''));
return d;
});
};
const amountBodyTemplate = (rowData) => {
return getNumberWithCurrency(rowData.amount);
};
const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>;
};
const statusFilterTemplate = (options) => {
return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder="Select One" className="p-column-filter" showClear />;
};
const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
};
const addToFavourites = () => {
console.log('addToFavourites');
}
const goToBandoPage = (id) => {
navigate(`/bandi/${id}`)
}
const actionsBodyTemplate = (rowData) => {
return <div className="appPageSection__tableActions">
<button type="button" className="appPageSection__addToFavourites" onClick={addToFavourites} disabled={true}>
<i className="pi pi-heart" style={{ fontSize: '1rem' }}></i>
</button>
</div>
}
const rowExpansionTemplate = (data) => {
return (
<div className="p-3">
{renderHtmlContent(data.descriptionShort)}
<p>{__('Scadenza', 'gepafin')}: {getDateFromISOstring(data.dates[1])}</p>
<Button onClick={() => goToBandoPage(data.id)} severity="info">
{__('Partecipa', 'gepafin')}
</Button>
</div>
);
};
const allowExpansion = (rowData) => {
return true;
};
return(
<div className="appPageSection__table">
<DataTable value={items} paginator rows={10} loading={loading} dataKey="id"
filters={filters} emptyMessage="Nothing found."
expandedRows={expandedRows} onRowToggle={(e) => setExpandedRows(e.data)}
rowExpansionTemplate={rowExpansionTemplate}
onFilter={(e) => setFilters(e.filters)}>
<Column expander={allowExpansion} style={{ width: '5rem' }} />
<Column field="name" header={__('Bando', 'gepafin')} style={{ minWidth: '12rem' }}/>
<Column header={__('Importo totale', 'gepafin')} filterField="amount"
style={{ minWidth: '10rem' }} body={amountBodyTemplate} sortable/>
<Column field="status" header={__('Stato', 'gepafin')} filterMenuStyle={{ width: '14rem' }}
style={{ width: '120px' }} body={statusBodyTemplate} filter sortable
filterElement={statusFilterTemplate}/>
<Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/>
</DataTable>
</div>
)
}
export default AllBandiAccordion;

View File

@@ -0,0 +1,25 @@
import React from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate } from 'react-router-dom';
// components
import AllBandiAccordion from './components/AllBandiAccordion';
import { Button } from 'primereact/button';
const BandiBeneficiario = () => {
return(
<div className="appPage">
<div className="appPage__pageHeader">
<h1>{__('Bandi disponibili', 'gepafin')}</h1>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection">
<AllBandiAccordion/>
</div>
</div>
)
}
export default BandiBeneficiario;

View File

@@ -102,6 +102,25 @@ const BandoApplication = () => {
return !isNaN(parsed) ? parsed : 0; return !isNaN(parsed) ? parsed : 0;
} }
const submitFormCallback = (data) => {
if (data.status === 'SUCCESS') {
console.log(data.data);
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('Saved!', 'gepafin')
});
}
}
storeSet.main.unsetAsyncRequest();
}
const errSubmitFormCallback = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const goBackward = () => { const goBackward = () => {
if (formId) { if (formId) {
const applId = getApplicationId(); const applId = getApplicationId();
@@ -124,28 +143,8 @@ const BandoApplication = () => {
} }
} }
const submitFormCallback = (data) => {
if (data.status === 'SUCCESS') {
console.log(data.data);
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('Saved!', 'gepafin')
});
}
}
storeSet.main.unsetAsyncRequest();
}
const errSubmitFormCallback = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const getApplFormCallback = (data) => { const getApplFormCallback = (data) => {
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
console.log('getApplFormCallback', data.data);
setBandoTitle(data.data.callTitle); setBandoTitle(data.data.callTitle);
setFormData(data.data.applicationFormResponse.content); setFormData(data.data.applicationFormResponse.content);
setFormId(data.data.formId); setFormId(data.data.formId);
@@ -156,8 +155,18 @@ const BandoApplication = () => {
} }
const errGetApplFormCallbacks = (data) => { const errGetApplFormCallbacks = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest(); storeSet.main.unsetAsyncRequest();
if (data.status === 'VALIDATION_ERROR') {
if (toast.current) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
} else {
set404FromErrorResponse(data);
}
} }
useEffect(() => { useEffect(() => {

View File

@@ -14,53 +14,51 @@ import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield'; import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon'; import { InputIcon } from 'primereact/inputicon';
import { Dropdown } from 'primereact/dropdown'; import { Dropdown } from 'primereact/dropdown';
import { InputNumber } from 'primereact/inputnumber'; import { ProgressBar } from 'primereact/progressbar';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { Calendar } from 'primereact/calendar'; import { Calendar } from 'primereact/calendar';
import { Tag } from 'primereact/tag'; 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 ApplicationService from '../../../../service/application-service';
import { storeSet, useStore } from '../../../../store';
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';
const MyLatestSubmissionsTable = () => { const MyLatestSubmissionsTable = () => {
const isAsyncRequest = useStore().main.isAsyncRequest();
const [items, setItems] = useState(null); const [items, setItems] = useState(null);
const [filters, setFilters] = useState(null); const [filters, setFilters] = useState(null);
const [loading, setLoading] = useState(false);
const [globalFilterValue, setGlobalFilterValue] = useState(''); const [globalFilterValue, setGlobalFilterValue] = useState('');
const [statuses, setStatuses] = useState([]); const [statuses, setStatuses] = useState([]);
useEffect(() => { useEffect(() => {
// TODO storeSet.main.setAsyncRequest();
const items = [ ApplicationService.getApplications(getApplCallback, errGetApplCallback)
{
name: 'Bando Innovazione 2024',
end_date: '2024-08-08T00:00:00+00:00',
modify_date: '2024-08-30T00:00:00+00:00',
progress: 50,
status: 'DRAFT',
id: 33,
callId: 52
},
{
name: 'Bando Sostenibilità 2024',
end_date: '2024-07-28T00:00:00+00:00',
modify_date: '2024-08-15T00:00:00+00:00',
progress: 25,
status: 'DRAFT',
id: 34,
callId: 53
}
]
setItems(getFormattedBandiData(items));
setStatuses(uniq(items.map(o => o.status)))
setLoading(false);
initFilters();
}, []); }, []);
const getApplCallback = (data) => {
if (data.status === 'SUCCESS') {
if(data.data.length) {
setItems(getFormattedBandiData(data.data));
setStatuses(uniq(items.map(o => o.status)))
initFilters();
}
}
storeSet.main.unsetAsyncRequest();
}
const errGetApplCallback = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const getFormattedBandiData = (data) => { const getFormattedBandiData = (data) => {
return [...(data || [])].map((d) => { return [...(data || [])].map((d) => {
d.modify_date = new Date(d.modify_date); d.modify_date = new Date();
d.end_date = new Date(d.end_date); d.end_date = new Date();
d.name = `Bando ${d.callId}`;
d.progress = 37;
return d; return d;
}); });
@@ -123,10 +121,6 @@ const MyLatestSubmissionsTable = () => {
return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />; return <Calendar value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />;
}; };
const balanceFilterTemplate = (options) => {
return <InputNumber value={options.value} onChange={(e) => options.filterCallback(e.value, options.index)} />;
};
const statusBodyTemplate = (rowData) => { const statusBodyTemplate = (rowData) => {
return <ProperBandoLabel status={rowData.status}/>; return <ProperBandoLabel status={rowData.status}/>;
}; };
@@ -135,6 +129,10 @@ const MyLatestSubmissionsTable = () => {
return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder="Select One" className="p-column-filter" showClear />; return <Dropdown value={options.value} options={statuses} onChange={(e) => options.filterCallback(e.value, options.index)} itemTemplate={statusItemTemplate} placeholder="Select One" className="p-column-filter" showClear />;
}; };
const progressBodyTemplate = (options) => {
return <ProgressBar value={options.progress} color={'#64748B'}></ProgressBar>;
};
const statusItemTemplate = (option) => { const statusItemTemplate = (option) => {
return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />; return <Tag value={getBandoLabel(option)} severity={getBandoSeverity(option)} />;
}; };
@@ -149,7 +147,7 @@ const MyLatestSubmissionsTable = () => {
return( return(
<div className="appPageSection__table"> <div className="appPageSection__table">
<DataTable value={items} paginator showGridlines rows={10} loading={loading} dataKey="id" <DataTable value={items} paginator showGridlines rows={10} loading={isAsyncRequest} dataKey="id"
filters={filters} filters={filters}
globalFilterFields={['name', 'status']} globalFilterFields={['name', 'status']}
header={header} header={header}
@@ -166,8 +164,7 @@ const MyLatestSubmissionsTable = () => {
style={{ width: '120px' }} body={statusBodyTemplate} filter style={{ width: '120px' }} body={statusBodyTemplate} filter
filterElement={statusFilterTemplate}/> filterElement={statusFilterTemplate}/>
<Column header={__('Progressi', 'gepafin')} <Column header={__('Progressi', 'gepafin')}
style={{ minWidth: '10rem' }} field="progress" style={{ minWidth: '10rem' }} field="progress" body={progressBodyTemplate}/>
filterElement={balanceFilterTemplate}/>
<Column header={__('Azioni', 'gepafin')} <Column header={__('Azioni', 'gepafin')}
body={actionsBodyTemplate}/> body={actionsBodyTemplate}/>
</DataTable> </DataTable>

View File

@@ -18,6 +18,7 @@ import BandoFlowEdit from './pages/BandoFlowEdit';
import Applications from './pages/Applications'; import Applications from './pages/Applications';
import BandoApplication from './pages/BandoApplication'; import BandoApplication from './pages/BandoApplication';
import Registration from './pages/Registration'; import Registration from './pages/Registration';
import BandiBeneficiario from './pages/BandiBeneficiario';
const routes = ({ role }) => { const routes = ({ role }) => {
return ( return (
@@ -29,7 +30,7 @@ const routes = ({ role }) => {
</DefaultLayout>}/> </DefaultLayout>}/>
<Route path="/bandi" element={<DefaultLayout> <Route path="/bandi" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <Bandi/> : null} {'ROLE_SUPER_ADMIN' === role ? <Bandi/> : null}
{'ROLE_BENEFICIARY' === role ? <PageNotFound/> : null} {'ROLE_BENEFICIARY' === role ? <BandiBeneficiario/> : null}
</DefaultLayout>}/> </DefaultLayout>}/>
<Route path="/bandi/:id" element={<DefaultLayout> <Route path="/bandi/:id" element={<DefaultLayout>
{'ROLE_SUPER_ADMIN' === role ? <BandoEdit/> : null} {'ROLE_SUPER_ADMIN' === role ? <BandoEdit/> : null}