- implemneted API for notifications;
- added styles for notifications; - added email template to amendment page;
This commit is contained in:
@@ -434,6 +434,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.appPageSection__emailTemplate {
|
||||||
|
> div {
|
||||||
|
max-width: 100%!important;
|
||||||
|
> div {
|
||||||
|
max-width: 100%!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 700px) {
|
||||||
.appPageSection {
|
.appPageSection {
|
||||||
&.columns {
|
&.columns {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
|
||||||
|
|
||||||
const NotificationItem = ({ item, clickFn }) => {
|
const NotificationItem = ({ item, clickFn }) => {
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@@ -8,8 +9,10 @@ const NotificationItem = ({ item, clickFn }) => {
|
|||||||
return (
|
return (
|
||||||
<li className="notificationsSidebar__listItem" onClick={handleClick}>
|
<li className="notificationsSidebar__listItem" onClick={handleClick}>
|
||||||
<div className="notificationsSidebar__listItemContent">
|
<div className="notificationsSidebar__listItemContent">
|
||||||
<strong>{item.title}</strong>
|
{item.status === 'READ'
|
||||||
<span>{item.createdDate}</span>
|
? <p>{item.title}</p>
|
||||||
|
: <strong>{item.title}</strong>}
|
||||||
|
<span>{getDateFromISOstring(item.createdDate)}</span>
|
||||||
</div>
|
</div>
|
||||||
<i className="pi pi-angle-right"></i>
|
<i className="pi pi-angle-right"></i>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
|
import getDateFromISOstring from '../../../../helpers/getDateFromISOstring';
|
||||||
|
|
||||||
const NotificationItemChosen = ({ item, closeFn }) => {
|
const NotificationItemChosen = ({ item, closeFn, markReadFn }) => {
|
||||||
return (
|
return (
|
||||||
<div className="notificationsSidebar__listItemChosen">
|
<div className="notificationsSidebar__listItemChosen">
|
||||||
<Button
|
<Button
|
||||||
@@ -13,8 +14,15 @@ const NotificationItemChosen = ({ item, closeFn }) => {
|
|||||||
label={__('Indietro', 'gepafin')}
|
label={__('Indietro', 'gepafin')}
|
||||||
icon="pi pi-arrow-left" iconPos="left"/>
|
icon="pi pi-arrow-left" iconPos="left"/>
|
||||||
<strong>{item.title}</strong>
|
<strong>{item.title}</strong>
|
||||||
<span>{item.createdDate}</span>
|
<span>{getDateFromISOstring(item.createdDate)}</span>
|
||||||
{item.message}
|
{item.message}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style={{marginTop: '20px'}}
|
||||||
|
type="button"
|
||||||
|
outlined
|
||||||
|
onClick={() => markReadFn(item.id)}
|
||||||
|
label={__('Letto', 'gepafin')}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import { storeGet, useStore } from '../../store';
|
|||||||
// api
|
// api
|
||||||
import NotificationService from '../../service/notification-service';
|
import NotificationService from '../../service/notification-service';
|
||||||
|
|
||||||
|
// tools
|
||||||
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { Badge } from 'primereact/badge';
|
import { Badge } from 'primereact/badge';
|
||||||
import { Sidebar } from 'primereact/sidebar';
|
import { Sidebar } from 'primereact/sidebar';
|
||||||
@@ -33,11 +36,12 @@ const NotificationsSidebar = () => {
|
|||||||
|
|
||||||
const fetchTabData = (index) => {
|
const fetchTabData = (index) => {
|
||||||
setChosenMsg({});
|
setChosenMsg({});
|
||||||
console.log('fetchTabData', index);
|
|
||||||
setLoading(true);
|
if (0 === index) {
|
||||||
setTimeout(() => {
|
fetchMessages();
|
||||||
setLoading(false);
|
} else {
|
||||||
}, 7000)
|
fetchMessages('READ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const chooseNotification = (id) => {
|
const chooseNotification = (id) => {
|
||||||
@@ -52,28 +56,79 @@ const NotificationsSidebar = () => {
|
|||||||
setChosenMsg({});
|
setChosenMsg({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetchMessages = (status = 'UNREAD') => {
|
||||||
|
const chosenCompanyId = storeGet.main.chosenCompanyId();
|
||||||
|
const userData = storeGet.main.userData();
|
||||||
|
const role = pathOr('', ['role', 'roleType'], userData);
|
||||||
|
|
||||||
|
if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') {
|
||||||
|
setLoading(true);
|
||||||
|
NotificationService.getNotifications(
|
||||||
|
userData.id,
|
||||||
|
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
||||||
|
errGetNotifications,
|
||||||
|
[
|
||||||
|
['status', status],
|
||||||
|
['companyId', chosenCompanyId]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else if (userData.id && role !== 'ROLE_BENEFICIARY') {
|
||||||
|
setLoading(true);
|
||||||
|
NotificationService.getNotifications(
|
||||||
|
userData.id,
|
||||||
|
status === 'UNREAD' ? getNotifications : getNotificationsRead,
|
||||||
|
errGetNotifications,
|
||||||
|
[
|
||||||
|
['status', status]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getNotifications = (resp) => {
|
const getNotifications = (resp) => {
|
||||||
console.log('resp', resp);
|
if (resp.status === 'SUCCESS') {
|
||||||
|
setNotifications(resp.data);
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNotificationsRead = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
setNotificationsRead(resp.data);
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const errGetNotifications = (resp) => {
|
const errGetNotifications = (resp) => {
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeNotificationRead = (id) => {
|
||||||
|
NotificationService.notificationMakeRead(id, makeReadCallback, makeReadErrorCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeReadCallback = (resp) => {
|
||||||
|
if (resp.status === 'SUCCESS') {
|
||||||
|
if (0 === activeIndex) {
|
||||||
|
const msgs = notifications.map(o => o.id === resp.data.id ? resp.data : o);
|
||||||
|
setNotifications(msgs);
|
||||||
|
} else {
|
||||||
|
const msgs = notificationsRead.map(o => o.id === resp.data.id ? resp.data : o);
|
||||||
|
setNotificationsRead(msgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeReadErrorCallback = (resp) => {
|
||||||
|
set404FromErrorResponse(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const role = pathOr('', ['role', 'roleType'], userData);
|
fetchMessages();
|
||||||
|
|
||||||
console.log('chosenCompanyId', chosenCompanyId, role)
|
|
||||||
if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') {
|
|
||||||
NotificationService.getNotifications(userData.id, getNotifications, errGetNotifications, [
|
|
||||||
['status', 'UNREAD'],
|
|
||||||
['companyId', chosenCompanyId]
|
|
||||||
]);
|
|
||||||
} else if (userData.id && role !== 'ROLE_BENEFICIARY') {
|
|
||||||
NotificationService.getNotifications(userData.id, getNotifications, errGetNotifications, [
|
|
||||||
['status', 'UNREAD']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}, [chosenCompanyId, userData.id]);
|
}, [chosenCompanyId, userData.id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -94,10 +149,15 @@ const NotificationsSidebar = () => {
|
|||||||
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
|
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
|
||||||
</div>
|
</div>
|
||||||
: !isEmpty(chosenMsg)
|
: !isEmpty(chosenMsg)
|
||||||
? <NotificationItemChosen item={chosenMsg} closeFn={closeChosenMsg}/>
|
? <NotificationItemChosen
|
||||||
|
item={chosenMsg}
|
||||||
|
closeFn={closeChosenMsg}
|
||||||
|
markReadFn={makeNotificationRead}/>
|
||||||
: (notifications.length > 0
|
: (notifications.length > 0
|
||||||
? <ul className="notificationsSidebar__list">
|
? <ul className="notificationsSidebar__list">
|
||||||
{notifications.map(o => <NotificationItem key={o.id} item={o}
|
{notifications.map(o => <NotificationItem
|
||||||
|
key={o.id}
|
||||||
|
item={o}
|
||||||
clickFn={chooseNotification}/>)}
|
clickFn={chooseNotification}/>)}
|
||||||
</ul>
|
</ul>
|
||||||
: <div className="notificationsSidebar__loading">
|
: <div className="notificationsSidebar__loading">
|
||||||
@@ -111,10 +171,15 @@ const NotificationsSidebar = () => {
|
|||||||
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
|
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
|
||||||
</div>
|
</div>
|
||||||
: !isEmpty(chosenMsg)
|
: !isEmpty(chosenMsg)
|
||||||
? <NotificationItemChosen item={chosenMsg} closeFn={closeChosenMsg}/>
|
? <NotificationItemChosen
|
||||||
|
item={chosenMsg}
|
||||||
|
closeFn={closeChosenMsg}
|
||||||
|
markReadFn={makeNotificationRead}/>
|
||||||
: (notificationsRead.length > 0
|
: (notificationsRead.length > 0
|
||||||
? <ul className="notificationsSidebar__list">
|
? <ul className="notificationsSidebar__list">
|
||||||
{notificationsRead.map(o => <NotificationItem key={o.id} item={o}
|
{notificationsRead.map(o => <NotificationItem
|
||||||
|
key={o.id}
|
||||||
|
item={o}
|
||||||
clickFn={chooseNotification}/>)}
|
clickFn={chooseNotification}/>)}
|
||||||
</ul>
|
</ul>
|
||||||
:
|
:
|
||||||
|
|||||||
28
src/helpers/getStrippedHtmlBodyTags.js
Normal file
28
src/helpers/getStrippedHtmlBodyTags.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import parse from 'html-react-parser';
|
||||||
|
import DOMPurify from 'dompurify';
|
||||||
|
|
||||||
|
const getEmailTemplateForSoccorso = (content = '', fallback = '') => {
|
||||||
|
const config = {
|
||||||
|
FORBID_TAGS: ['html', 'body'],
|
||||||
|
WHOLE_DOCUMENT: false,
|
||||||
|
RETURN_DOM: false,
|
||||||
|
RETURN_DOM_FRAGMENT: false,
|
||||||
|
RETURN_DOM_IMPORT: false,
|
||||||
|
FORCE_BODY: false,
|
||||||
|
ADD_TAGS: ['*'],
|
||||||
|
ADD_ATTR: ['*']
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const wrappedHtml = `<div>${content}</div>`;
|
||||||
|
const cleaned = DOMPurify.sanitize(wrappedHtml, config);
|
||||||
|
|
||||||
|
const tempDiv = document.createElement('div');
|
||||||
|
tempDiv.innerHTML = cleaned;
|
||||||
|
return parse(tempDiv.innerHTML);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('DOMPurify cleaning error:', error);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getEmailTemplateForSoccorso;
|
||||||
@@ -138,7 +138,7 @@ const RepeaterFields = ({
|
|||||||
className="fieldsRepeater__addNew"
|
className="fieldsRepeater__addNew"
|
||||||
outlined
|
outlined
|
||||||
type="button"
|
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}
|
onClick={addNew}
|
||||||
label={__('Aggiungi nuovo file', 'gepafin')}
|
label={__('Aggiungi nuovo file', 'gepafin')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { Dialog } from 'primereact/dialog';
|
|||||||
import FormField from '../../components/FormField';
|
import FormField from '../../components/FormField';
|
||||||
import SoccorsoComunications from '../SoccorsoEditPreInstructor/components/SoccorsoComunications';
|
import SoccorsoComunications from '../SoccorsoEditPreInstructor/components/SoccorsoComunications';
|
||||||
import { Editor } from 'primereact/editor';
|
import { Editor } from 'primereact/editor';
|
||||||
|
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
|
||||||
|
|
||||||
const SoccorsoEditBeneficiario = () => {
|
const SoccorsoEditBeneficiario = () => {
|
||||||
const isAsyncRequest = useStore().main.isAsyncRequest();
|
const isAsyncRequest = useStore().main.isAsyncRequest();
|
||||||
@@ -327,10 +328,7 @@ const SoccorsoEditBeneficiario = () => {
|
|||||||
? <div className="appPageSection">
|
? <div className="appPageSection">
|
||||||
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
|
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
|
||||||
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
||||||
<div className="appPageSection__withBorder grey ql-editor"
|
<div>{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}</div>
|
||||||
style={{ minHeight: '100px' }}>
|
|
||||||
{renderHtmlContent(data.note)}
|
|
||||||
</div>
|
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|
||||||
{data.id
|
{data.id
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import AmendmentsService from '../../service/amendments-service';
|
|||||||
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
|
||||||
import getBandoLabel from '../../helpers/getBandoLabel';
|
import getBandoLabel from '../../helpers/getBandoLabel';
|
||||||
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
import getDateFromISOstring from '../../helpers/getDateFromISOstring';
|
||||||
import renderHtmlContent from '../../helpers/renderHtmlContent';
|
import getEmailTemplateForSoccorso from '../../helpers/getStrippedHtmlBodyTags';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
@@ -411,8 +411,11 @@ const SoccorsoEditPreInstructor = () => {
|
|||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
|
<h2>{__('Dettagli Richiesta', 'gepafin')}</h2>
|
||||||
<div className="appPageSection columns">
|
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
||||||
<div>
|
<div
|
||||||
|
className="appPageSection__emailTemplate">{getEmailTemplateForSoccorso(data.emailTemplate, data.note)}</div>
|
||||||
|
</div>
|
||||||
|
<div className="appPageSection">
|
||||||
<h3>{__('Documenti Richiesti', 'gepafin')}</h3>
|
<h3>{__('Documenti Richiesti', 'gepafin')}</h3>
|
||||||
<ol className="appPageSection__list">
|
<ol className="appPageSection__list">
|
||||||
{data.formFields
|
{data.formFields
|
||||||
@@ -422,16 +425,6 @@ const SoccorsoEditPreInstructor = () => {
|
|||||||
</li>) : null}
|
</li>) : null}
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<h3>{__('Note e spiegazioni', 'gepafin')}</h3>
|
|
||||||
<div className="appPageSection__withBorder grey ql-editor"
|
|
||||||
style={{ minHeight: '200px' }}>
|
|
||||||
{renderHtmlContent(data.note)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="appPageSection">
|
<div className="appPageSection">
|
||||||
<h2>{__('Comunicazioni', 'gepafin')}</h2>
|
<h2>{__('Comunicazioni', 'gepafin')}</h2>
|
||||||
|
|||||||
@@ -7,4 +7,16 @@ export default class NotificationService {
|
|||||||
static getNotifications = (id, callback, errCallback, queryParams) => {
|
static getNotifications = (id, callback, errCallback, queryParams) => {
|
||||||
NetworkService.get(`${API_BASE_URL}/notification/user/${id}`, callback, errCallback, queryParams);
|
NetworkService.get(`${API_BASE_URL}/notification/user/${id}`, callback, errCallback, queryParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static notificationMakeRead = (id, callback, errCallback) => {
|
||||||
|
NetworkService.put(`${API_BASE_URL}/notification/${id}`, {}, callback, errCallback, [
|
||||||
|
['status', 'READ']
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
static notificationMakeUnread = (id, callback, errCallback) => {
|
||||||
|
NetworkService.put(`${API_BASE_URL}/notification/${id}`, {}, callback, errCallback, [
|
||||||
|
['status', 'UNREAD']
|
||||||
|
]);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user