- added login and loginAdmin;

- fixed bug with saving application data;
This commit is contained in:
Vitalii Kiiko
2024-09-25 16:25:09 +02:00
parent b008fcd37a
commit 25b1b5ae7d
9 changed files with 226 additions and 112 deletions

View File

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

View File

@@ -1,8 +1,8 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import { klona } from 'klona';
import { head, range, is, isNil } from 'ramda';
import { head, range, is, pluck } from 'ramda';
import { useForm } from 'react-hook-form';
// store
@@ -40,6 +40,7 @@ const BandoApplication = () => {
const [bandoTitle, setBandoTitle] = useState('');
const [formId, setFormId] = useState('');
const [totalSteps, setTotalSteps] = useState(0);
const [completedSteps, setCompletedSteps] = useState(0);
const [activeStep, setActiveStep] = useState(1);
const [stepItems, setStepItems] = useState([{ label: 'Passo' }]);
const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -67,12 +68,52 @@ const BandoApplication = () => {
}
const onSubmit = () => {
const applId = getApplicationId();
storeSet.main.setAsyncRequest();
ApplicationService.updateStatusApplication(applId, {}, submitApplicationCallback, errSubmitApplicationCallback, [
['status', 'SUBMIT']
]);
};
const saveDraft = useCallback(() => {
const submitApplicationCallback = (data) => {
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('La domanda è stata presentata!', 'gepafin')
});
}
}
storeSet.main.unsetAsyncRequest();
}
const errSubmitApplicationCallback = (data) => {
storeSet.main.unsetAsyncRequest();
if (data.status === 'VALIDATION_ERROR') {
if (formMsgs.current) {
formMsgs.current.show([
{
id: '99',
sticky: true, severity: 'error', summary: '',
detail: data.data.join(', '),
closable: true
}
]);
}
} else {
set404FromErrorResponse(data);
}
}
const saveDraft = () => {
trigger();
const formValues = getValues();
const newFormValues = Object.keys(formValues).reduce((acc, cur) => {
const usedFieldsIds = pluck('id', formData);
const newFormValues = Object.keys(formValues)
.filter(v => usedFieldsIds.includes(v))
.reduce((acc, cur) => {
const formField = head(formData.filter(o => o.id === cur));
let fieldVal = formValues[cur];
@@ -103,32 +144,33 @@ const BandoApplication = () => {
formMsgs.current.clear();
}
ApplicationService.submitForm(applId, submitData, submitFormCallback, errSubmitFormCallback, [
ApplicationService.saveDraft(applId, submitData, saveDraftCallback, errSaveDraftCallback, [
['formId', formId]
]);
}
}, [errors]);
}
const getApplicationId = () => {
const parsed = parseInt(id)
return !isNaN(parsed) ? parsed : 0;
}
const submitFormCallback = (data) => {
const saveDraftCallback = (data) => {
if (data.status === 'SUCCESS') {
console.log(data.data);
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: __('Saved!', 'gepafin')
detail: __('Salvato!', 'gepafin')
});
}
// update info about application completeness
ApplicationService.getApplicationForm(data.data.id, getStatusCheckCallback, errGetStatusCheckCallbacks);
}
storeSet.main.unsetAsyncRequest();
}
const errSubmitFormCallback = (data) => {
const errSaveDraftCallback = (data) => {
storeSet.main.unsetAsyncRequest();
if (data.status === 'VALIDATION_ERROR') {
if (formMsgs.current) {
@@ -183,7 +225,8 @@ const BandoApplication = () => {
setFormId(data.data.formId);
setTotalSteps(data.data.totalFormSteps);
setActiveStep(data.data.currentStep)
setCompletedSteps(data.data.completedSteps);
setActiveStep(data.data.currentStep);
}
storeSet.main.unsetAsyncRequest();
}
@@ -203,9 +246,18 @@ const BandoApplication = () => {
}
}
const getStatusCheckCallback = (data) => {
if (data.status === 'SUCCESS') {
setCompletedSteps(data.data.completedSteps);
}
}
const errGetStatusCheckCallbacks = (data) => {
set404FromErrorResponse(data);
}
useEffect(() => {
const newFormData = klona(formInitialData);
console.log('newFormData', newFormData);
newFormData.map(o => setValue(o.fieldId, o.fieldValue));
}, [formInitialData]);
@@ -325,6 +377,11 @@ const BandoApplication = () => {
label={__('Vai avanti', 'gepafin')}
icon="pi pi-arrow-right"
iconPos="right"/> : null}
<Button
disabled={completedSteps === 0 || completedSteps !== totalSteps}
label={__('Invio', 'gepafin')}
icon="pi pi-check"
iconPos="right"/>
</div>
</div>
</form>

View File

@@ -145,6 +145,10 @@ const BandoFlowEdit = () => {
setInitialForm(data.data.initialForm);
setFinalForm(data.data.finalForm);
setBandoStatus(data.data.callStatus);
const chosenFieldItem = head(data.data.flowData.filter(o => !isEmpty(o.chosenField)));
if (chosenFieldItem) {
setMainField(chosenFieldItem.chosenField);
}
const flowDataItem = head(data.data.flowData.filter(o => !isEmpty(o.chosenField)));
if (flowDataItem) {

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { useParams, useNavigate } from 'react-router-dom';
import { isEmpty } from 'ramda';
import { is, isEmpty, isNil } from 'ramda';
import { classNames } from 'primereact/utils';
// components
@@ -14,6 +14,7 @@ import FormsService from '../../service/forms-service';
// store
import { storeSet } from '../../store';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import BandoService from '../../service/bando-service';
const BandoForms = () => {
const { id } = useParams();
@@ -22,6 +23,7 @@ const BandoForms = () => {
const [selectedTemplate, setSelectedTemplate] = useState(null);
const [selectedForm, setSelectedForm] = useState(null);
const [forms, setForms] = useState([]);
const [bandoStatus, setBandoStatus] = useState('');
const doCreateNewForm = () => {
navigate(`/bandi/${id}/forms/new`);
@@ -46,6 +48,18 @@ const BandoForms = () => {
//navigate(`/bandi/${id}`);
}
const getCallback = (data) => {
if (data.status === 'SUCCESS') {
setBandoStatus(data.data.status);
}
storeSet.main.unsetAsyncRequest();
}
const errGetCallback = (data) => {
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const getFormsCallback = (data) => {
if (data.status === 'SUCCESS') {
const forms = data.data.map(o => ({label: o.label, value: o.id}))
@@ -68,6 +82,7 @@ const BandoForms = () => {
])
storeSet.main.setAsyncRequest();
BandoService.getBando(id, getCallback, errGetCallback);
FormsService.getFormsForCall(bandoId, getFormsCallback, errGetFormsCallback);
}, [id]);
@@ -112,6 +127,7 @@ const BandoForms = () => {
<p>{__('Inizia con un form completamente vuoto e personalizzabil', 'gepafin')}</p>
<Button
type="button"
disabled={'PUBLISH' === bandoStatus}
onClick={doCreateNewForm}
label={__('Crea form', 'gepafin')}/>
</div>
@@ -134,7 +150,7 @@ const BandoForms = () => {
outlined
disabled={!selectedForm}
onClick={goToEditForm}
label={__('Modifica', 'gepafin')}
label={'PUBLISH' === bandoStatus ? __('Mostra', 'gepafin') : __('Modifica', 'gepafin')}
icon="pi pi-cog" iconPos="right"/>
</div>
</div>

View File

@@ -55,10 +55,8 @@ const MyLatestSubmissionsTable = () => {
const getFormattedBandiData = (data) => {
return [...(data || [])].map((d) => {
d.modify_date = new Date();
d.end_date = new Date();
d.name = `Bando ${d.callId}`;
d.progress = 37;
d.callEndDate = new Date(d.callEndDate);
d.modifiedDate = new Date(d.modifiedDate);
return d;
});
@@ -89,9 +87,9 @@ const MyLatestSubmissionsTable = () => {
const initFilters = () => {
setFilters({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
modify_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
callTitle: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
modifiedDate: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
callEndDate: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
});
setGlobalFilterValue('');
@@ -110,11 +108,11 @@ const MyLatestSubmissionsTable = () => {
};
const dateModifyBodyTemplate = (rowData) => {
return formatDate(rowData.modify_date);
return formatDate(rowData.modifiedDate);
};
const dateEndBodyTemplate = (rowData) => {
return formatDate(rowData.end_date);
return formatDate(rowData.callEndDate);
};
const dateFilterTemplate = (options) => {
@@ -152,12 +150,12 @@ const MyLatestSubmissionsTable = () => {
globalFilterFields={['name', 'status']}
header={header}
emptyMessage="Nothing found." onFilter={(e) => setFilters(e.filters)}>
<Column field="name" header={__('Bando', 'gepafin')} filter filterPlaceholder="Search by name"
<Column field="callTitle" header={__('Bando', 'gepafin')} filter filterPlaceholder="Search by name"
style={{ minWidth: '12rem' }}/>
<Column header={__('Scadenza', 'gepafin')} filterField="end_date" dataType="date"
<Column header={__('Scadenza', 'gepafin')} filterField="callEndDate" dataType="date"
style={{ minWidth: '10rem' }}
body={dateEndBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column header={__('Ultima modifica', 'gepafin')} filterField="modify_date" dataType="date"
<Column header={__('Ultima modifica', 'gepafin')} filterField="modifiedDate" dataType="date"
style={{ minWidth: '10rem' }}
body={dateModifyBodyTemplate} filter filterElement={dateFilterTemplate}/>
<Column field="status" header={__('Stato', 'gepafin')} filterMenuStyle={{ width: '14rem' }}

View File

@@ -1,66 +1,18 @@
import React, { useRef, useState, useEffect } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useForm } from 'react-hook-form';
import React, { useRef, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { classNames } from 'primereact/utils';
import { isEmpty } from 'ramda';
// tools
import AuthenticationService from '../../service/authentication-service';
// store
import { storeSet, useStore } from '../../store';
// components
import FormField from '../../components/FormField';
import LogoIcon from '../../icons/LogoIcon';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
const Login = () => {
const token = useStore().main.token();
const [loading, setLoading] = useState(false);
const errorMsgs = useRef(null);
const {
control,
handleSubmit,
formState: { errors },
} = useForm({ mode: 'onChange' });
const onSubmit = (formData) => {
errorMsgs.current.clear();
setLoading(true);
const request = {
...formData,
rememberMe: true
}
AuthenticationService.login(request, loginCallback, loginError);
};
const loginCallback = (data) => {
if (data.status === 'SUCCESS') {
storeSet.main.setAuthData({
token: data.data.token,
userData: data.data.user
});
} else {
errorMsgs.current.show([
{ sticky: true, severity: 'error', summary: '',
detail: data.message,
closable: true }
]);
}
setLoading(false);
}
const loginError = (err) => {
errorMsgs.current.show([
{ sticky: true, severity: 'error', summary: '',
detail: sprintf(__('%s', 'gepafin'), err),
closable: true }
]);
setLoading(false);
}
const loginWithSpid = () => {
console.log('spid')
@@ -68,7 +20,6 @@ const Login = () => {
useEffect(() => {
if (!isEmpty(token)) {
setLoading(true);
window.location.replace('/')
}
}, [token]);
@@ -106,39 +57,6 @@ const Login = () => {
<span>{__('Entra con SPID', 'gepafin')}</span>
</button>
<div className="appPage__spacer"></div>
<div className="appPageSection__hr">
<span>{__('Oppure', 'gepafin')}</span>
</div>
<div className="appPage__spacer"></div>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="textinput"
fieldName="email"
label={__('Email', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
placeholder="sample@example.com"
/>
<FormField
type="textinput"
inputtype="password"
fieldName="password"
label={__('Password', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
<Button
label={__('Accedi', 'gepafin')}
disabled={loading}/>
</form>
</div>
</div>
)

View File

@@ -0,0 +1,115 @@
import React, { useRef, useState, useEffect } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { useForm } from 'react-hook-form';
import { classNames } from 'primereact/utils';
import { isEmpty } from 'ramda';
// tools
import AuthenticationService from '../../service/authentication-service';
// store
import { storeSet, useStore } from '../../store';
// components
import FormField from '../../components/FormField';
import LogoIcon from '../../icons/LogoIcon';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';
const LoginAdmin = () => {
const token = useStore().main.token();
const [loading, setLoading] = useState(false);
const errorMsgs = useRef(null);
const {
control,
handleSubmit,
formState: { errors },
} = useForm({ mode: 'onChange' });
const onSubmit = (formData) => {
errorMsgs.current.clear();
setLoading(true);
const request = {
...formData,
rememberMe: true
}
AuthenticationService.login(request, loginCallback, loginError);
};
const loginCallback = (data) => {
if (data.status === 'SUCCESS') {
storeSet.main.setAuthData({
token: data.data.token,
userData: data.data.user
});
} else {
errorMsgs.current.show([
{ sticky: true, severity: 'error', summary: '',
detail: data.message,
closable: true }
]);
}
setLoading(false);
}
const loginError = (err) => {
errorMsgs.current.show([
{ sticky: true, severity: 'error', summary: '',
detail: sprintf(__('%s', 'gepafin'), err),
closable: true }
]);
setLoading(false);
}
useEffect(() => {
if (!isEmpty(token)) {
setLoading(true);
window.location.replace('/')
}
}, [token]);
return (
<div className={classNames(['appPage', 'appPageLogin'])}>
<div className="appPageLogin__wrapper">
<LogoIcon/>
<h1>{__('Accedi o Registrati', 'gepafin')}</h1>
<div className="appPage__spacer"></div>
<Messages ref={errorMsgs}/>
<div className="appPage__spacer"></div>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="textinput"
fieldName="email"
label={__('Email', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
placeholder="sample@example.com"
/>
<FormField
type="textinput"
inputtype="password"
fieldName="password"
label={__('Password', 'gepafin')}
control={control}
errors={errors}
config={{ required: __('È obbligatorio', 'gepafin') }}
/>
<Button
label={__('Accedi', 'gepafin')}
disabled={loading}/>
</form>
</div>
</div>
)
}
export default LoginAdmin;

View File

@@ -19,6 +19,7 @@ import Applications from './pages/Applications';
import BandoApplication from './pages/BandoApplication';
import Registration from './pages/Registration';
import BandiBeneficiario from './pages/BandiBeneficiario';
import LoginAdmin from './pages/LoginAdmin';
const routes = ({ role }) => {
return (
@@ -70,6 +71,7 @@ const routes = ({ role }) => {
</DefaultLayout>}/>
</Route>
<Route exact path="/login" element={<Login/>}/>
<Route exact path="/loginAdmin" element={<LoginAdmin/>}/>
<Route exact path="/registration" element={<Registration/>}/>
{/*<Route exact path="/forgot-password" element={<ForgotPassword/>}/>*/}
<Route path="*" element={<PageNotFound/>}/>

View File

@@ -20,7 +20,11 @@ export default class ApplicationService {
NetworkService.post(`${API_BASE_URL}/application/call/${id}`, body, callback, errCallback);
};
static submitForm = (id, body, callback, errCallback, queryParams) => {
static saveDraft = (id, body, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/application/${id}`, body, callback, errCallback, queryParams);
};
static updateStatusApplication = (id, body, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/application/${id}/status`, body, callback, errCallback, queryParams);
};
}