- added sidebar container for notifications;

- styles and interactions for notifications;
This commit is contained in:
Vitalii Kiiko
2024-12-24 14:50:20 +01:00
parent 1296348b6f
commit bb983feb12
6 changed files with 224 additions and 20 deletions

View File

@@ -0,0 +1,55 @@
.notificationsIcon {
&:hover {
cursor: pointer;
}
}
.notificationsSidebar {
max-width: 360px;
width: 100%;
}
.notificationsSidebar__loading {
padding: 30px 0;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
gap: 10px;
}
.notificationsSidebar__list {
display: flex;
flex-direction: column;
gap: 5px;
list-style: none;
padding: 0;
}
.notificationsSidebar__listItem {
display: flex;
justify-content: space-between;
align-items: center;
gap: 5px;
padding: 15px 0;
border-bottom: 1px solid #e7e7e7;
&:hover {
cursor: pointer;
color: var(--primary-text);
}
}
.notificationsSidebar__listItemContent {
display: flex;
flex-direction: column;
gap: 5px;
font-size: 14px;
}
.notificationsSidebar__listItemChosen {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 5px;
}

View File

@@ -45,3 +45,4 @@
@import "./components/myTable.scss"; @import "./components/myTable.scss";
@import "./components/evaluation.scss"; @import "./components/evaluation.scss";
@import "./components/fieldsRepeater.scss"; @import "./components/fieldsRepeater.scss";
@import "./components/notificationsSidebar.scss";

View File

@@ -0,0 +1,19 @@
import React from 'react';
const NotificationItem = ({ item, clickFn }) => {
const handleClick = () => {
clickFn(item.id);
}
return (
<li className="notificationsSidebar__listItem" onClick={handleClick}>
<div className="notificationsSidebar__listItemContent">
<strong>{item.title}</strong>
<span>{item.createdDate}</span>
</div>
<i className="pi pi-angle-right"></i>
</li>
)
}
export default NotificationItem;

View File

@@ -0,0 +1,22 @@
import React from 'react';
import { __ } from '@wordpress/i18n';
import { Button } from 'primereact/button';
const NotificationItemChosen = ({ item, closeFn }) => {
return (
<div className="notificationsSidebar__listItemChosen">
<Button
style={{marginBottom: '20px'}}
type="button"
outlined
onClick={closeFn}
label={__('Indietro', 'gepafin')}
icon="pi pi-arrow-left" iconPos="left"/>
<strong>{item.title}</strong>
<span>{item.createdDate}</span>
{item.message}
</div>
)
}
export default NotificationItemChosen;

View File

@@ -0,0 +1,121 @@
import React, { useEffect, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { head, isEmpty } from 'ramda';
// components
import { Badge } from 'primereact/badge';
import { Sidebar } from 'primereact/sidebar';
import { TabPanel, TabView } from 'primereact/tabview';
import NotificationItem from './components/NotificationItem';
import NotificationItemChosen from './components/NotificationItemChosen';
const NotificationsSidebar = () => {
const [activeIndex, setActiveIndex] = useState(0);
const [loading, setLoading] = useState(false);
const [notificationsVisible, setNotificationsVisible] = useState(false);
const [notifications, setNotifications] = useState([]);
const [notificationsRead, setNotificationsRead] = useState([]);
const [chosenMsg, setChosenMsg] = useState({});
// Handle tab change
const handleTabChange = (e) => {
setActiveIndex(e.index);
fetchTabData(e.index);
};
const fetchTabData = (index) => {
setChosenMsg({});
console.log('fetchTabData', index);
setLoading(true);
setTimeout(() => {
setLoading(false);
}, 7000)
}
const chooseNotification = (id) => {
const properItems = activeIndex === 0 ? notifications : notificationsRead;
const chosen = head(properItems.filter(o => o.id === id));
if (chosen) {
setChosenMsg(chosen);
}
}
const closeChosenMsg = () => {
setChosenMsg({});
}
useEffect(() => {
setNotifications(() => {
const msg = {
'id': 35,
'createdDate': '2024-12-23T14:55:27.278103',
'updatedDate': '2024-12-23T14:55:27.278103',
'userId': 30,
'title': 'Il Risultato della Valutazione per la Richiesta È Disponibile',
'message': 'Il risultato della valutazione per la richiesta ai sensi del protocollo n. 10000015 è ora disponibile.',
'status': 'UNREAD',
'companyId': 103,
'redirectUrl': 'EVALUATION_RESULT',
'notificationType': 'EVALUATION_RESULT'
};
return Array.from({ length: 33 }, (_, index) => ({
...msg,
id: msg.id + index
}));
})
}, []);
return (
<>
<i className="pi pi-bell p-overlay-badge topBar__icon notificationsIcon"
onClick={() => setNotificationsVisible(true)}>
<Badge value={notifications.length}></Badge>
</i>
<Sidebar
className="notificationsSidebar"
position="left"
visible={notificationsVisible}
onHide={() => setNotificationsVisible(false)}>
<TabView activeIndex={activeIndex} onTabChange={handleTabChange}>
<TabPanel header={__('Da leggere', 'gepafin')}>
{loading
? <div className="notificationsSidebar__loading">
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
</div>
: !isEmpty(chosenMsg)
? <NotificationItemChosen item={chosenMsg} closeFn={closeChosenMsg}/>
: (notifications.length > 0
? <ul className="notificationsSidebar__list">
{notifications.map(o => <NotificationItem key={o.id} item={o}
clickFn={chooseNotification}/>)}
</ul>
: <div className="notificationsSidebar__loading">
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
{__('Vuoto', 'gepafin')}
</div>)}
</TabPanel>
<TabPanel header={__('Letti', 'gepafin')}>
{loading
? <div className="notificationsSidebar__loading">
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }}></i>
</div>
: !isEmpty(chosenMsg)
? <NotificationItemChosen item={chosenMsg} closeFn={closeChosenMsg}/>
: (notificationsRead.length > 0
? <ul className="notificationsSidebar__list">
{notificationsRead.map(o => <NotificationItem key={o.id} item={o}
clickFn={chooseNotification}/>)}
</ul>
:
<div className="notificationsSidebar__loading">
<i className="pi pi-megaphone" style={{ fontSize: '2rem' }}></i>
{__('Vuoto', 'gepafin')}
</div>)}
</TabPanel>
</TabView>
</Sidebar>
</>
)
}
export default NotificationsSidebar;

View File

@@ -1,4 +1,4 @@
import React, { useRef, useState } from 'react'; import React, { useRef } from 'react';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
// components // components
@@ -8,14 +8,12 @@ import LogoIcon from '../../../../icons/LogoIcon';
import { IconField } from 'primereact/iconfield'; import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon'; import { InputIcon } from 'primereact/inputicon';
import { InputText } from 'primereact/inputtext'; import { InputText } from 'primereact/inputtext';
import { Badge } from 'primereact/badge';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import TopBarProfileMenu from '../../../../components/TopBarProfileMenu'; import TopBarProfileMenu from '../../../../components/TopBarProfileMenu';
import { Sidebar } from 'primereact/sidebar'; import NotificationsSidebar from '../../../../components/NotificationsSidebar';
const AppTopbar = () => { const AppTopbar = () => {
const menuLeft = useRef(null); const menuLeft = useRef(null);
const [notificationsVisible, setNotificationsVisible] = useState(false);
const startContent = <Link to="/"> const startContent = <Link to="/">
<LogoIcon/> <LogoIcon/>
@@ -26,14 +24,13 @@ const AppTopbar = () => {
<InputIcon className="pi pi-search"> </InputIcon> <InputIcon className="pi pi-search"> </InputIcon>
<InputText v-model="value1" placeholder={__('Cerca', 'gepafin')} disabled={true}/> <InputText v-model="value1" placeholder={__('Cerca', 'gepafin')} disabled={true}/>
</IconField> </IconField>
<i className="pi pi-bell p-overlay-badge topBar__icon"> <NotificationsSidebar/>
<Badge value="0"></Badge>
</i>
<i className="pi pi-envelope topBar__icon"></i> <i className="pi pi-envelope topBar__icon"></i>
{/*<i className="pi pi-envelope p-overlay-badge topBar__icon"> {/*<i className="pi pi-envelope p-overlay-badge topBar__icon">
<Badge severity="danger"></Badge> <Badge severity="danger"></Badge>
</i>*/} </i>*/}
<Button <Button
type="button"
className="topBar__profileBtn" className="topBar__profileBtn"
outlined outlined
onClick={(event) => menuLeft.current.toggle(event)} aria-controls="topBar_profileMenu" aria-haspopup> onClick={(event) => menuLeft.current.toggle(event)} aria-controls="topBar_profileMenu" aria-haspopup>
@@ -44,18 +41,7 @@ const AppTopbar = () => {
</div> </div>
return ( return (
<> <Toolbar start={startContent} end={endContent} className="topBar"/>
<Toolbar start={startContent} end={endContent} className="topBar"/>
<Sidebar visible={notificationsVisible} onHide={() => setNotificationsVisible(false)} fullScreen>
<h2>Sidebar</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</Sidebar>
</>
) )
} }