286 lines
7.8 KiB
TypeScript
Executable File
286 lines
7.8 KiB
TypeScript
Executable File
import { noCase } from 'change-case';
|
|
import { useState, useEffect, useContext } from 'react';
|
|
// @mui
|
|
import {
|
|
Box,
|
|
List,
|
|
Badge,
|
|
Button,
|
|
Avatar,
|
|
Tooltip,
|
|
Divider,
|
|
Typography,
|
|
ListItemText,
|
|
ListSubheader,
|
|
ListItemAvatar,
|
|
ListItemButton,
|
|
Stack
|
|
} from '@mui/material';
|
|
// utils
|
|
import { fToNow } from '@/utils/formatTime';
|
|
// _mock_
|
|
//import { _notifications } from '@/_mock';
|
|
// components
|
|
import Iconify from '@/components/Iconify';
|
|
import Scrollbar from '@/components/Scrollbar';
|
|
import MenuPopover from '@/components/MenuPopover';
|
|
import { IconButtonAnimate } from '@/components/animate';
|
|
import axios from '@/utils/axios';
|
|
import { useSnackbar } from 'notistack';
|
|
import { LanguageContext } from '@/contexts/LanguageContext';
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
export default function NotificationsPopover() {
|
|
const { localeData }: any = useContext(LanguageContext);
|
|
const [notifications, setNotifications] = useState([]);
|
|
const {enqueueSnackbar} = useSnackbar();
|
|
const getDataNotifications = async () => {
|
|
axios
|
|
.get('notifications/1')
|
|
.then((response) => {
|
|
setNotifications(response.data.data.notifications);
|
|
})
|
|
.catch((error) => {
|
|
enqueueSnackbar(error.response.data.meta.message, {variant : "error"});
|
|
});
|
|
};
|
|
useEffect(() => {
|
|
getDataNotifications();
|
|
}, []);
|
|
|
|
const totalUnRead = notifications.filter((item) => item.isUnRead === 1).length;
|
|
|
|
const [open, setOpen] = useState<HTMLElement | null>(null);
|
|
|
|
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
|
|
setOpen(event.currentTarget);
|
|
};
|
|
|
|
const handleClose = () => {
|
|
setOpen(null);
|
|
};
|
|
|
|
const handleMarkAllAsRead = () => {
|
|
setNotifications(
|
|
notifications.map((notification) => ({
|
|
...notification,
|
|
isUnRead: 0,
|
|
}))
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<IconButtonAnimate
|
|
color={open ? 'primary' : 'default'}
|
|
onClick={handleOpen}
|
|
sx={{ width: 40, height: 40 }}
|
|
>
|
|
<Badge badgeContent={totalUnRead} color="error">
|
|
<Iconify icon="eva:bell-fill" width={20} height={20} />
|
|
</Badge>
|
|
</IconButtonAnimate>
|
|
|
|
<MenuPopover
|
|
open={Boolean(open)}
|
|
anchorEl={open}
|
|
onClose={handleClose}
|
|
sx={{ width: 360, p: 0, mt: 1.5, ml: 0.75 }}
|
|
>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', py: 2, px: 2.5 }}>
|
|
<Box sx={{ flexGrow: 1 }}>
|
|
<Typography variant="subtitle1">{localeData.txtNotifications}</Typography>
|
|
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
|
{localeData.txtYouHave} {totalUnRead} {localeData.txtUnm}
|
|
</Typography>
|
|
</Box>
|
|
|
|
{/* {totalUnRead > 0 && (
|
|
<Tooltip title=" Mark all as read">
|
|
<IconButtonAnimate color="primary" onClick={handleMarkAllAsRead}>
|
|
<Iconify icon="eva:done-all-fill" width={20} height={20} />
|
|
</IconButtonAnimate>
|
|
</Tooltip>
|
|
)} */}
|
|
</Box>
|
|
|
|
<Divider sx={{ borderStyle: 'dashed' }} />
|
|
|
|
<Scrollbar sx={{ height: { xs: 340, sm: 'auto' } }}>
|
|
{notifications && notifications.length > 0 ? (
|
|
<>
|
|
<List
|
|
disablePadding
|
|
subheader={
|
|
<ListSubheader disableSticky sx={{ py: 1, px: 2.5, typography: 'overline' }}>
|
|
{localeData.txtNew}
|
|
</ListSubheader>
|
|
}
|
|
>
|
|
{notifications.slice(0, 2).map((notification) => (
|
|
<NotificationItem key={notification.id} notification={notification} getDataNotifications={getDataNotifications}/>
|
|
))}
|
|
</List>
|
|
|
|
<List
|
|
disablePadding
|
|
subheader={
|
|
<ListSubheader disableSticky sx={{ py: 1, px: 2.5, typography: 'overline' }}>
|
|
{localeData.txtBeforeThat}
|
|
</ListSubheader>
|
|
}
|
|
>
|
|
{notifications.slice(2, 5).map((notification) => (
|
|
<NotificationItem key={notification.id} notification={notification} getDataNotifications={getDataNotifications}/>
|
|
))}
|
|
</List>
|
|
</>
|
|
): ''}
|
|
|
|
</Scrollbar>
|
|
|
|
<Divider sx={{ borderStyle: 'dashed' }} />
|
|
|
|
{/* <Box sx={{ p: 1 }}>
|
|
<Button fullWidth disableRipple>
|
|
View All
|
|
</Button>
|
|
</Box> */}
|
|
</MenuPopover>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
type NotificationItemProps = {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
avatar: string | null;
|
|
type: string;
|
|
createdAt: Date;
|
|
isUnRead: boolean;
|
|
};
|
|
|
|
function NotificationItem({ notification, getDataNotifications }: { notification: NotificationItemProps, getDataNotifications: () => void}) {
|
|
const { avatar, title } = renderContent(notification);
|
|
const {enqueueSnackbar} = useSnackbar();
|
|
const handleClick = () => {
|
|
const data = {
|
|
'user_id' : 1,
|
|
'id' : notification.id,
|
|
};
|
|
if(notification.isUnRead)
|
|
{
|
|
axios
|
|
.post('set-read-notification', data)
|
|
.then((response) => {
|
|
enqueueSnackbar(response.data.meta.message, {variant : "success"});
|
|
getDataNotifications();
|
|
})
|
|
.catch((error) => {
|
|
enqueueSnackbar(error.response.data.meta.message, {variant : "error"});
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<ListItemButton
|
|
onClick={handleClick}
|
|
sx={{
|
|
py: 1.5,
|
|
px: 2.5,
|
|
mt: '1px',
|
|
...(notification.isUnRead && {
|
|
bgcolor: 'action.selected',
|
|
}),
|
|
}}
|
|
>
|
|
<ListItemAvatar>
|
|
<Avatar sx={{ bgcolor: 'background.neutral' }}>{avatar}</Avatar>
|
|
</ListItemAvatar>
|
|
<ListItemText
|
|
primary={title}
|
|
secondary={
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
mt: 0.5,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
color: 'text.disabled',
|
|
}}
|
|
>
|
|
<Iconify icon="eva:clock-outline" sx={{ mr: 0.5, width: 16, height: 16 }} />
|
|
{fToNow(notification.createdAt)}
|
|
</Typography>
|
|
}
|
|
/>
|
|
</ListItemButton>
|
|
);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
function renderContent(notification: NotificationItemProps) {
|
|
const title = (
|
|
<Stack direction="column">
|
|
<Typography variant="subtitle2">{notification.title}</Typography>
|
|
<Typography component="span" variant="body2" sx={{ color: 'text.secondary' }}>
|
|
{notification.description}
|
|
</Typography>
|
|
</Stack>
|
|
);
|
|
|
|
if (notification.type === 'order_placed') {
|
|
return {
|
|
avatar: (
|
|
<img
|
|
alt={notification.title}
|
|
src="https://minimal-assets-api.vercel.app/assets/icons/ic_notification_package.svg"
|
|
/>
|
|
),
|
|
title,
|
|
};
|
|
}
|
|
if (notification.type === 'order_shipped') {
|
|
return {
|
|
avatar: (
|
|
<img
|
|
alt={notification.title}
|
|
src="https://minimal-assets-api.vercel.app/assets/icons/ic_notification_shipping.svg"
|
|
/>
|
|
),
|
|
title,
|
|
};
|
|
}
|
|
if (notification.type === 'mail' || notification.type === 'request_document' || notification.type === 'grab_status') {
|
|
return {
|
|
avatar: (
|
|
<img
|
|
alt={notification.title}
|
|
src="/icons/ic_mail.svg"
|
|
/>
|
|
),
|
|
title,
|
|
};
|
|
}
|
|
if (notification.type === 'chat_message') {
|
|
return {
|
|
avatar: (
|
|
<img
|
|
alt={notification.title}
|
|
src="https://minimal-assets-api.vercel.app/assets/icons/ic_notification_chat.svg"
|
|
/>
|
|
),
|
|
title,
|
|
};
|
|
}
|
|
return {
|
|
avatar: notification.avatar ? <img alt={notification.title} src={notification.avatar} /> : null,
|
|
title,
|
|
};
|
|
}
|