134 lines
4.6 KiB
JavaScript
134 lines
4.6 KiB
JavaScript
import { Virtuoso } from "react-virtuoso";
|
|
import { Alert, Badge, Button, Space, Spin, Switch, Tooltip, Typography } from "antd";
|
|
import { CheckCircleFilled, CheckCircleOutlined, EyeFilled, EyeOutlined } from "@ant-design/icons";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useNavigate } from "react-router-dom";
|
|
import "./notification-center.styles.scss";
|
|
import day from "../../utils/day.js";
|
|
import { useEffect, useRef } from "react";
|
|
import { DateTimeFormat } from "../../utils/DateFormatter.jsx";
|
|
|
|
const { Text, Title } = Typography;
|
|
|
|
/**
|
|
* Notification Center Component
|
|
*/
|
|
const NotificationCenterComponent = ({
|
|
visible,
|
|
notifications,
|
|
loading,
|
|
showUnreadOnly,
|
|
toggleUnreadOnly,
|
|
markAllRead,
|
|
loadMore,
|
|
onNotificationClick,
|
|
unreadCount,
|
|
isEmployee,
|
|
isDarkMode,
|
|
ref
|
|
}) => {
|
|
const { t } = useTranslation();
|
|
const navigate = useNavigate();
|
|
const virtuosoRef = useRef(null);
|
|
|
|
// Scroll to top when showUnreadOnly changes
|
|
useEffect(() => {
|
|
if (virtuosoRef.current) {
|
|
virtuosoRef.current.scrollToIndex({ index: 0, behavior: "smooth" });
|
|
}
|
|
}, [showUnreadOnly]);
|
|
|
|
const renderNotification = (index, notification) => {
|
|
const handleClick = () => {
|
|
if (!notification.read) {
|
|
onNotificationClick(notification.id);
|
|
}
|
|
navigate(`/manage/jobs/${notification.jobid}`);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
key={`${notification.id}-${index}`}
|
|
className={`notification-item ${notification.read ? "notification-read" : "notification-unread"}`}
|
|
onClick={handleClick}
|
|
>
|
|
<Badge dot={!notification.read}>
|
|
<div className="notification-content">
|
|
<Title level={5} className="notification-title">
|
|
<span className="ro-number">
|
|
{t("notifications.labels.ro-number", { ro_number: notification.roNumber || t("general.labels.na") })}
|
|
</span>
|
|
<Text type="secondary" className="relative-time" title={DateTimeFormat(notification.created_at)}>
|
|
{day(notification.created_at).fromNow()}
|
|
</Text>
|
|
</Title>
|
|
<Text strong={!notification.read} className="notification-body">
|
|
<ul>
|
|
{notification.scenarioText.map((text, idx) => (
|
|
<li key={`${notification.id}-${idx}`}>{text}</li>
|
|
))}
|
|
</ul>
|
|
</Text>
|
|
</div>
|
|
</Badge>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className={`notification-center ${visible ? "visible" : ""}`} ref={ref}>
|
|
<div className="notification-header">
|
|
<Space orientation="horizontal">
|
|
<h3>{t("notifications.labels.notification-center")}</h3>
|
|
{loading && <Spin spinning={loading} size="small"></Spin>}
|
|
</Space>
|
|
<div className="notification-controls">
|
|
<Tooltip title={t("notifications.labels.show-unread-only")}>
|
|
<Space size={4} align="center" className="notification-toggle">
|
|
{showUnreadOnly ? (
|
|
<EyeFilled className="notification-toggle-icon" />
|
|
) : (
|
|
<EyeOutlined className="notification-toggle-icon" />
|
|
)}
|
|
<Switch
|
|
checked={showUnreadOnly}
|
|
onChange={(checked) => toggleUnreadOnly(checked)}
|
|
size="small"
|
|
disabled={!isEmployee}
|
|
/>
|
|
</Space>
|
|
</Tooltip>
|
|
<Tooltip title={t("notifications.labels.mark-all-read")}>
|
|
<Button
|
|
type="link"
|
|
icon={!unreadCount ? <CheckCircleFilled /> : <CheckCircleOutlined />}
|
|
onClick={markAllRead}
|
|
disabled={!unreadCount}
|
|
/>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
{!isEmployee ? (
|
|
<div style={{ padding: 10 }}>
|
|
<Alert title={t("notifications.labels.employee-notification")} type="warning" />
|
|
</div>
|
|
) : (
|
|
<div className={isDarkMode ? "notification-center--dark" : "notification-center--light"} style={{ height: "400px", width: "100%" }}>
|
|
<Virtuoso
|
|
ref={virtuosoRef}
|
|
style={{ height: "100%", width: "100%" }}
|
|
data={notifications}
|
|
totalCount={notifications.length}
|
|
endReached={loadMore}
|
|
itemContent={renderNotification}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
NotificationCenterComponent.displayName = "NotificationCenterComponent";
|
|
|
|
export default NotificationCenterComponent;
|