- saving progress;

This commit is contained in:
Vitalii Kiiko
2024-10-30 11:38:18 +01:00
parent 8bd557cb6f
commit 579cb2da3b
9 changed files with 358 additions and 52 deletions

View File

@@ -2,6 +2,7 @@
display: flex;
flex-direction: column;
gap: 24px;
width: 100%;
}
.appForm__field {
position: relative;

View File

@@ -22,6 +22,10 @@ body {
h2, h3, p, label, .appPageSection__hr {
color: var(--global-textColor);
}
textarea {
max-width: 100%;
}
}
#root, .wrapper {

View File

@@ -17,6 +17,9 @@ const getBandoLabel = (status) => {
case 'READY':
return __('Pronto', 'gepafin');
case 'SOCCORSO':
return __('Soccorso', 'gepafin');
case 'DRAFT':
return __('Bozza', 'gepafin');
@@ -38,6 +41,9 @@ const getBandoLabel = (status) => {
case 'EXPIRED':
return __('Scaduto', 'gepafin');
case 'CLOSE':
return __('Chiuso', 'gepafin');
default:
return '';
}

View File

@@ -15,6 +15,9 @@ const getBandoSeverity = (status) => {
case 'READY':
return 'info';
case 'SOCCORSO':
return 'warning';
case 'DRAFT':
return 'warning';
@@ -36,6 +39,9 @@ const getBandoSeverity = (status) => {
case 'EXPIRED':
return 'closed';
case 'CLOSE':
return 'closed';
default:
return 'info';
}

View File

@@ -406,8 +406,7 @@ const BandoViewBeneficiario = () => {
: null}
<div className="appPageSection">
{/*<h2>{__('Download Documenti', 'gepafin')}</h2>*/}
<h2>{__('Partecipa', 'gepafin')}</h2>
<h2>{__('Download Documenti', 'gepafin')}</h2>
<div className="appPageSection__actions">
{/* <Button
type="button"

View File

@@ -263,7 +263,7 @@ const SoccorsoEditPreInstructor = () => {
</div>
<div className="appPageSection__hr">
<span>{__('Azioni rapide', 'gepafin')}</span>
<span>{__('Azioni', 'gepafin')}</span>
</div>
<div className="appPageSection">

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { is, isEmpty, isNil } from 'ramda';
import { head, is, isEmpty, isNil, pathOr } from 'ramda';
import { wrap } from 'object-path-immutable';
// store
@@ -26,6 +26,13 @@ import { classNames } from 'primereact/utils';
import { Dialog } from 'primereact/dialog';
import { InputText } from 'primereact/inputtext';
import { InputTextarea } from 'primereact/inputtextarea';
import { klona } from 'klona';
import { useForm } from 'react-hook-form';
import FormField from '../../components/FormField';
import uniqid from '../../helpers/uniqid';
import { Editor } from 'primereact/editor';
import { TZDate } from '@date-fns/tz';
import { InputNumber } from 'primereact/inputnumber';
const SoccorsoEditPreInstructor = () => {
const isAsyncRequest = useStore().main.isAsyncRequest();
@@ -36,10 +43,28 @@ const SoccorsoEditPreInstructor = () => {
const [isVisibleNewCommDialog, setIsVisibleNewCommDialog] = useState(false);
const [newCommData, setNewCommData] = useState({});
const [isLoadingCommunication, setIsLoadingCommunication] = useState(false);
const [isVisibleExtendTimeDialog, setIsVisibleExtendTimeDialog] = useState(false);
const [extendedTime, setExtendedTime] = useState(3);
const [isLoadingExtendingTime, setIsLoadingExtendingTime] = useState(false);
const toast = useRef(null);
const [formInitialData, setFormInitialData] = useState({});
const {
control,
handleSubmit,
formState: { errors, isValid },
setValue,
register,
trigger,
getValues,
clearErrors
} = useForm({
defaultValues: useMemo(() => {
return formInitialData;
}, [formInitialData]), mode: 'onChange'
});
const goToEvaluationPage = () => {
//navigate('/domande');
navigate(`/domande/${id}`);
}
const getCallback = (data) => {
@@ -64,7 +89,7 @@ const SoccorsoEditPreInstructor = () => {
const getCommsCallback = (data) => {
if (data.status === 'SUCCESS') {
setComms(data.data.commentsList);
setComms(data.data.commentsList.map(o => getFormattedCommsData(o)));
}
storeSet.main.unsetAsyncRequest();
}
@@ -87,31 +112,19 @@ const SoccorsoEditPreInstructor = () => {
return data;
};
const renderHeader = () => {
return (
<span className="ql-formats">
<button className="ql-bold" aria-label="Bold"></button>
<button className="ql-italic" aria-label="Italic"></button>
<button className="ql-underline" aria-label="Underline"></button>
<button className="ql-link" aria-label="Link"></button>
<button className="ql-list" value="ordered"></button>
<button className="ql-header" value="2"></button>
<button className="ql-header" value="3"></button>
<button className="ql-blockquote"></button>
<button className="ql-list" value="bullet"></button>
<button className="ql-indent" value="-1"></button>
<button className="ql-indent" value="+1"></button>
</span>
);
const getFormattedCommsData = (data) => {
data.id = isNil(data.id) ? uniqid('id') : data.id;
data.commentedDate = is(String, data.commentedDate) ? new Date(data.commentedDate) : (data.commentedDate ? data.commentedDate : '');
data.createdDate = is(String, data.createdDate) ? new Date(data.createdDate) : (data.createdDate ? data.createdDate : '');
data.updatedDate = is(String, data.updatedDate) ? new Date(data.updatedDate) : (data.updatedDate ? data.updatedDate : '');
return data;
};
const header = renderHeader();
const headerEditDialog = () => {
const headerNewComDialog = () => {
return <span>{__('Aggiungi comunicazione', 'gepafin')}</span>
}
const hideEditDialog = () => {
const hideNewComDialog = () => {
setIsVisibleNewCommDialog(false);
setNewCommData({
title: '',
@@ -119,9 +132,9 @@ const SoccorsoEditPreInstructor = () => {
});
}
const footerEditDialog = () => {
const footerNewComDialog = () => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideEditDialog} outlined/>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideNewComDialog} outlined/>
<Button
type="button"
disabled={isLoadingCommunication || isEmpty(newCommData.title) || isEmpty(newCommData.comment)}
@@ -142,11 +155,34 @@ const SoccorsoEditPreInstructor = () => {
setNewCommData(newData);
}
const renderHeader = () => {
return (
<span className="ql-formats">
<button className="ql-bold" aria-label="Bold"></button>
<button className="ql-italic" aria-label="Italic"></button>
<button className="ql-underline" aria-label="Underline"></button>
<button className="ql-link" aria-label="Link"></button>
<button className="ql-list" value="ordered"></button>
<button className="ql-header" value="2"></button>
<button className="ql-header" value="3"></button>
<button className="ql-blockquote"></button>
<button className="ql-list" value="bullet"></button>
<button className="ql-indent" value="-1"></button>
<button className="ql-indent" value="+1"></button>
</span>
);
};
const header = renderHeader();
const updateNewAmendmentData = (value, path) => {
const newData = wrap(data).set(path.split('.'), value).value();
setData(newData);
}
const createCommunication = () => {
setIsLoadingCommunication(true);
CommunicationService.createCommunication(newCommData, createCommunicationCallback, errCreateCommunicationCallback, [
['amendmentId', amendmentId]
]);
CommunicationService.createCommunication(amendmentId, newCommData, createCommunicationCallback, errCreateCommunicationCallback);
}
const createCommunicationCallback = (data) => {
@@ -158,7 +194,8 @@ const SoccorsoEditPreInstructor = () => {
detail: data.message
});
}
console.log(data.data)
setComms([...comms, getFormattedCommsData(data.data)])
setIsVisibleNewCommDialog(false);
}
setIsLoadingCommunication(false);
}
@@ -175,6 +212,150 @@ const SoccorsoEditPreInstructor = () => {
setIsLoadingCommunication(false);
}
const onSubmit = () => {
};
const doUpdateAmendment = () => {
trigger();
let formValues = klona(getValues());
const newFormValues = Object.keys(formValues)
.reduce((acc, cur) => {
let fieldVal = formValues[cur];
fieldVal = isEmpty(fieldVal) ? null : fieldVal;
fieldVal = is(Array, fieldVal) ? fieldVal.map(o => o.id).join(',') : null;
acc.push({
'fieldId': cur,
'fieldValue': fieldVal
});
return acc;
}, []);
const submitData = {
updatedFormFields: newFormValues,
//note: data.internalNote
}
storeSet.main.setAsyncRequest();
AmendmentsService.updateSoccorso(amendmentId, submitData, updateAmendmentCallback, errUpdateAmendmentCallback);
}
const updateAmendmentCallback = (data) => {
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: data.message
});
}
}
storeSet.main.unsetAsyncRequest();
}
const errUpdateAmendmentCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const doCloseAmendment = () => {
const submitData = {
internalNote: data.internalNote
}
storeSet.main.setAsyncRequest();
AmendmentsService.closeSoccorso(amendmentId, submitData, closeAmendmentCallback, errCloseAmendmentCallback);
}
const closeAmendmentCallback = (data) => {
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: data.message
});
}
if (data.data.status) {
updateNewAmendmentData(data.data.status, 'status')
}
}
storeSet.main.unsetAsyncRequest();
}
const errCloseAmendmentCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
storeSet.main.unsetAsyncRequest();
}
const headerExtendRespDialog = () => {
return <span>{__('Estendi scadenza', 'gepafin')}</span>
}
const hideExtendRespDialog = () => {
setIsVisibleExtendTimeDialog(false);
}
const footerExtendRespDialog = () => {
return <div>
<Button type="button" label={__('Anulla', 'gepafin')} onClick={hideExtendRespDialog} outlined/>
<Button
type="button"
disabled={isLoadingExtendingTime || isEmpty(extendedTime)}
label={__('Invia', 'gepafin')} onClick={doExtendTimeResponse}/>
</div>
}
const openExtendResponseTimeDialog = () => {
setIsVisibleExtendTimeDialog(true);
setExtendedTime(3);
}
const doExtendTimeResponse = () => {
setIsLoadingExtendingTime(true);
AmendmentsService.extendSoccorso(amendmentId, extendedTime, extendCallback, errExtendCallback);
}
const extendCallback = (data) => {
if (data.status === 'SUCCESS') {
if (toast.current) {
toast.current.show({
severity: 'success',
summary: '',
detail: data.message
});
}
setIsVisibleExtendTimeDialog(false);
}
setIsLoadingExtendingTime(false);
}
const errExtendCallback = (data) => {
if (toast.current && data.message) {
toast.current.show({
severity: 'error',
summary: '',
detail: data.message
});
}
set404FromErrorResponse(data);
setIsLoadingExtendingTime(false);
}
useEffect(() => {
const parsedSoccorsoId = parseInt(amendmentId);
const soccorsoEntityId = !isNaN(parsedSoccorsoId) ? parsedSoccorsoId : 0;
@@ -228,7 +409,7 @@ const SoccorsoEditPreInstructor = () => {
</p>
<p className="appPageSection__pMeta">
<span>{__('Stato', 'gepafin')}</span>
<span>{getBandoLabel(data.applicationStatus)}</span>
<span>{getBandoLabel(data.status)}</span>
</p>
</div>
@@ -245,7 +426,8 @@ const SoccorsoEditPreInstructor = () => {
</div>
<div>
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
<div className="ql-editor">
<div className="appPageSection__withBorder grey ql-editor"
style={{ minHeight: '200px' }}>
{renderHtmlContent(data.note)}
</div>
</div>
@@ -265,51 +447,121 @@ const SoccorsoEditPreInstructor = () => {
<tbody className="myTbody">
{!isNil(comms) && !isEmpty(comms)
? comms.map((o, i) => <tr key={o.id}>
<td></td>
<td></td>
</tr>) : null}
<tr>
<td>-</td>
<td>-</td>
</tr>
<td valign="top">
{getDateFromISOstring(o.commentedDate)}
</td>
<td>
<h3>{o.title}</h3>
<p>{o.comment}</p>
</td>
</tr>)
: <tr>
<td>-</td>
<td>-</td>
</tr>}
</tbody>
</table>
<Button
style={{marginTop: 30}}
style={{ marginTop: 30 }}
onClick={openNewCommDialog}
type="button"
label={__('Aggiungi Comunicazione', 'gepafin')}
icon="pi pi-plus" iconPos="right"/>
</div>
<div className="appPageSection">
<h2>{__('Documenti Ricevuti', 'gepafin')}</h2>
<form className="appForm" onSubmit={handleSubmit(onSubmit)}>
{data.formFields.map((o, i) => {
const test = {
'updatedFormFields': [
{
'fieldId': 'a5867bdceb',
'fieldValue': '136'
},
{
'fieldId': 'ab0f00219b',
'fieldValue': null
}
]
}
const thisField = head(test.updatedFormFields.filter(j => j.fieldId === o.fieldId));
const value = pathOr({}, ['fieldValue'], thisField);
console.log('value', value, o.fieldId);
return <FormField
key={o.fieldId}
type="fileupload"
setDataFn={setValue}
fieldName={o.fieldId}
label={o.label}
control={control}
errors={errors}
defaultValue={[]}
accept={[]}
doctype="document"
register={register}
sourceId={data.applicationId}
source="application"
multiple={true}
/>
})}
</form>
<Button
style={{ marginTop: 30 }}
type="button"
onClick={doUpdateAmendment}
label={__('Aggiorna', 'gepafin')}/>
</div>
<div className="appPage__spacer"></div>
<div className="appPageSection__hr">
<span>{__('Azioni rapide', 'gepafin')}</span>
<span>{__('Azioni', 'gepafin')}</span>
</div>
<div className="appPageSection">
<div className="appPageSection__actions">
<Button
type="button"
disabled={true}
outlined
label={__('Invia Sollecito', 'gepafin')}
icon="pi pi-send"
/>
<Button
type="button"
onClick={openExtendResponseTimeDialog}
outlined
label={__('Estendi Scadenza', 'gepafin')}
icon="pi pi-stopwatch"
/>
<Button
type="button"
onClick={doCloseAmendment}
label={__('Chiudi Soccorso Istruttorio', 'gepafin')}
icon="pi pi-times" iconPos="right"/>
</div>
</div>
<div className="appForm__field" style={{ marginTop: '-40px' }}>
<label>{__('Note Interne', 'gepafin')}</label>
<div>
<Editor
value={data.internalNote}
placeholder={__('Digita qui il messagio', 'gepafin')}
headerTemplate={header}
onTextChange={(e) => updateNewAmendmentData(
e.htmlValue,
'internalNote'
)}
style={{ height: 80 * 3, width: '100%' }}
/>
</div>
</div>
</div>
: <>
<Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
@@ -325,10 +577,10 @@ const SoccorsoEditPreInstructor = () => {
<Dialog
visible={isVisibleNewCommDialog}
modal
header={headerEditDialog}
footer={footerEditDialog}
header={headerNewComDialog}
footer={footerNewComDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideEditDialog}>
onHide={hideNewComDialog}>
<div className="appForm__field">
<label
className={classNames({ 'p-error': isEmpty(newCommData.title) })}>
@@ -342,9 +594,31 @@ const SoccorsoEditPreInstructor = () => {
className={classNames({ 'p-error': isEmpty(newCommData.comment) })}>
{__('Contenuto', 'gepafin')}*
</label>
<InputTextarea value={newCommData.comment}
invalid={isEmpty(newCommData.comment)}
onChange={(e) => updateNewCommData(e.target.value, 'comment')}/>
<InputTextarea
value={newCommData.comment}
rows={5} cols={30}
invalid={isEmpty(newCommData.comment)}
onChange={(e) => updateNewCommData(e.target.value, 'comment')}/>
</div>
</Dialog>
<Dialog
visible={isVisibleExtendTimeDialog}
modal
header={headerExtendRespDialog}
footer={footerExtendRespDialog}
style={{ maxWidth: '600px', width: '100%' }}
onHide={hideExtendRespDialog}>
<div className="appForm__field">
<label
className={classNames({ 'p-error': isEmpty(extendedTime) })}>
{__('Giorni', 'gepafin')}*
</label>
<InputNumber
keyfilter="int"
value={extendedTime}
showButtons
onChange={(e) => setExtendedTime(e.value)}/>
</div>
</Dialog>
</div>

View File

@@ -15,4 +15,20 @@ export default class AmendmentsService {
static createSoccorso = (body, callback, errCallback, queryParams) => {
NetworkService.post(`${API_BASE_URL}/amendments`, body, callback, errCallback, queryParams);
};
static updateSoccorso = (id, body, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/amendments/${id}`, body, callback, errCallback, queryParams);
};
static extendSoccorso = (id, days, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/amendments/${id}/extendExpiration`, {}, callback, errCallback, [
['extendedDays', days]
]);
};
static closeSoccorso = (id, body, callback, errCallback, queryParams) => {
NetworkService.put(`${API_BASE_URL}/amendments`, body, callback, errCallback, [
['id', id]
]);
};
}

View File

@@ -8,7 +8,7 @@ export default class CommunicationService {
NetworkService.get(`${API_BASE_URL}/communication/${id}`, callback, errCallback, queryParams);
};
static createCommunication = (body, callback, errCallback, queryParams) => {
NetworkService.post(`${API_BASE_URL}/communication`, body, callback, errCallback, queryParams);
static createCommunication = (id, body, callback, errCallback, queryParams) => {
NetworkService.post(`${API_BASE_URL}/communication/${id}`, body, callback, errCallback, queryParams);
};
}