feature/IO-3096-GlobalNotifications - add Dayjs, minor packages on backend

This commit is contained in:
Dave Richer
2025-02-28 11:13:08 -05:00
parent 5bd6f0453d
commit 9b871149ac
5 changed files with 251 additions and 245 deletions

View File

@@ -3,6 +3,7 @@ import { Alert, Badge, Button, Checkbox, List, Typography } from "antd";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import "./notification-center.styles.scss";
import day from "../../utils/day.js";
const { Text, Title } = Typography;
@@ -49,7 +50,7 @@ const NotificationCenterComponent = ({
>
RO #{notification.roNumber}
</Link>
<Text type="secondary">{new Date(notification.created_at).toLocaleString()}</Text>
<Text type="secondary">{day(notification.created_at).fromNow()}</Text>
</Title>
<Text strong={!notification.read}>
<ul>

View File

@@ -6,6 +6,10 @@ import { GET_NOTIFICATIONS } from "../../graphql/notifications.queries";
import { INITIAL_NOTIFICATIONS, useSocket } from "../../contexts/SocketIO/socketContext.jsx";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors.js";
import day from "../../utils/day.js";
// This will be used to poll for notifications when the socket is disconnected
const NOTIFICATION_POLL_INTERVAL_SECONDS = 60;
export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
@@ -37,12 +41,12 @@ export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
},
fetchPolicy: "cache-and-network",
notifyOnNetworkStatusChange: true,
pollInterval: isConnected ? 0 : 30000,
pollInterval: isConnected ? 0 : day.duration(NOTIFICATION_POLL_INTERVAL_SECONDS, "seconds").asMilliseconds(),
skip: !userAssociationId,
onError: (err) => {
setError(err.message);
console.error("GET_NOTIFICATIONS error:", err);
setTimeout(() => refetch(), 2000);
console.error(`Error polling Notifications in notification-center: ${err?.message || ""}`);
setTimeout(() => refetch(), day.duration(2, "seconds").asMilliseconds());
}
});
@@ -75,7 +79,7 @@ export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
__typename: notif.__typename
};
})
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
.sort((a, b) => day(b.created_at).diff(day(a.created_at)));
setNotifications(processedNotifications);
setError(null);
}
@@ -111,7 +115,7 @@ export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
const handleMarkAllRead = useCallback(() => {
markAllNotificationsRead()
.then(() => {
const timestamp = new Date().toISOString();
const timestamp = day().toISOString();
setNotifications((prev) => {
const updatedNotifications = prev.map((notif) =>
notif.read === null && notif.associationid === userAssociationId
@@ -133,7 +137,7 @@ export function NotificationCenterContainer({ visible, onClose, bodyshop }) {
variables: { id: notificationId }
})
.then(() => {
const timestamp = new Date().toISOString();
const timestamp = day().toISOString();
setNotifications((prev) => {
return prev.map((notif) =>
notif.id === notificationId && !notif.read ? { ...notif, read: timestamp } : notif

View File

@@ -12,12 +12,13 @@ import {
MARK_NOTIFICATION_READ
} from "../../graphql/notifications.queries.js";
import { gql, useMutation } from "@apollo/client";
import day from "../../utils/day.js";
const SocketContext = createContext(null);
export const INITIAL_NOTIFICATIONS = 10;
const INITIAL_NOTIFICATIONS = 10;
export const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => {
const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => {
const socketRef = useRef(null);
const [clientId, setClientId] = useState(null);
const [isConnected, setIsConnected] = useState(false);
@@ -26,7 +27,7 @@ export const SocketProvider = ({ children, bodyshop, navigate, currentUser }) =>
const [markNotificationRead] = useMutation(MARK_NOTIFICATION_READ, {
update: (cache, { data: { update_notifications } }) => {
const timestamp = new Date().toISOString();
const timestamp = day().toISOString();
const updatedNotification = update_notifications.returning[0];
cache.modify({
@@ -79,7 +80,7 @@ export const SocketProvider = ({ children, bodyshop, navigate, currentUser }) =>
const [markAllNotificationsRead] = useMutation(MARK_ALL_NOTIFICATIONS_READ, {
variables: { associationid: userAssociationId },
update: (cache) => {
const timestamp = new Date().toISOString();
const timestamp = day().toISOString();
cache.modify({
fields: {
notifications(existing = [], { readField }) {
@@ -202,7 +203,7 @@ export const SocketProvider = ({ children, bodyshop, navigate, currentUser }) =>
scenario_text: JSON.stringify(notifications.map((notif) => notif.body)),
fcm_text: notifications.map((notif) => notif.body).join(". ") + ".",
scenario_meta: JSON.stringify(notifications.map((notif) => notif.variables || {})),
created_at: new Date(notifications[0].timestamp).toISOString(),
created_at: day(notifications[0].timestamp).toISOString(),
read: null,
job: { ro_number: jobRoNumber }
};
@@ -224,8 +225,8 @@ export const SocketProvider = ({ children, bodyshop, navigate, currentUser }) =>
query: GET_NOTIFICATIONS,
variables: baseVariables,
data: {
notifications: [newNotification, ...existingNotifications].sort(
(a, b) => new Date(b.created_at) - new Date(a.created_at)
notifications: [newNotification, ...existingNotifications].sort((a, b) =>
day(b.created_at).diff(day(a.created_at))
)
},
broadcast: true
@@ -444,11 +445,11 @@ export const SocketProvider = ({ children, bodyshop, navigate, currentUser }) =>
);
};
export const useSocket = () => {
const useSocket = () => {
const context = useContext(SocketContext);
// NOTE: Not sure if we absolutely require this, does cause slipups on dev env
if (!context) throw new Error("useSocket must be used within a SocketProvider");
return context;
};
export default SocketContext;
export { SocketContext, SocketProvider, INITIAL_NOTIFICATIONS, useSocket };