Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | 104x 13x 13x 26x 13x 104x 120x 120x 120x 104x 18x 18x 18x 104x 42x 42x 42x 104x 15x 104x 15x 2x 2x 2x 104x 14x 14x 13x 1x 1x 104x 48x 48x 48x 48x 15x 15x 15x 48x 12x 48x 48x 48x 48x 48x 48x 48x | import { useQuery } from "@tanstack/react-query";
import { API } from "aws-amplify";
import { useEffect, useState } from "react";
import {
BannerNotificationSchema,
ReactQueryApiError,
ValidBannerNotification,
} from "shared-types";
import { useGetUser } from "@/api";
const mapValidNotifications = (notifications: unknown[]): ValidBannerNotification[] => {
Iif (!Array.isArray(notifications)) return [];
return notifications
.filter((notification) => BannerNotificationSchema.safeParse(notification).success)
.map((notification) => BannerNotificationSchema.parse(notification));
};
const getTime = (value?: string) => {
Iif (!value) return null;
const time = new Date(value).getTime();
return Number.isNaN(time) ? null : time;
};
const sortByPublishedDateDesc = (a: ValidBannerNotification, b: ValidBannerNotification) => {
const aTime = getTime(a.pubDate) ?? Number.NEGATIVE_INFINITY;
const bTime = getTime(b.pubDate) ?? Number.NEGATIVE_INFINITY;
return bTime - aTime;
};
const isActiveNotification = (notification: ValidBannerNotification, now: number) => {
const pubDate = getTime(notification.pubDate);
const expDate = getTime(notification.expDate);
return pubDate !== null && expDate !== null && pubDate <= now && expDate > now;
};
const getNotificationStorageKey = (username?: string) =>
username ? `notifs.${username}` : undefined;
const parseDismissedNotifications = (value: string | null): string[] => {
if (!value) return [];
try {
const parsed = JSON.parse(value);
return Array.isArray(parsed)
? parsed.filter((item): item is string => typeof item === "string")
: [];
} catch {
return [];
}
};
export const getSystemNotifs = async (): Promise<ValidBannerNotification[]> => {
try {
const notifications = await API.get("os", "/systemNotifs", {});
return mapValidNotifications(notifications);
} catch (error) {
console.error("Error fetching notifications:", error);
return [];
}
};
export const useGetSystemNotifs = () => {
const userQuery = useGetUser();
const [dismissed, setDismissed] = useState<string[]>([]);
const username = userQuery?.data?.user?.username;
useEffect(() => {
const storageKey = getNotificationStorageKey(username);
Iif (!storageKey) {
setDismissed([]);
return;
}
setDismissed(parseDismissedNotifications(localStorage.getItem(storageKey)));
}, [username]);
const result = useQuery<ValidBannerNotification[], ReactQueryApiError>(
["systemBannerNotifs"],
() => getSystemNotifs(),
);
const now = Date.now();
const allNotifications = [...(result.data ?? [])].sort(sortByPublishedDateDesc);
const notDismissed = allNotifications.filter((i) => !dismissed.includes(i.notifId));
const currentNotifs = notDismissed.filter((i) => isActiveNotification(i, now));
const clearNotif = (id?: string) => {
const toBeRemoved = id ?? currentNotifs?.[0]?.notifId ?? "";
const cleared = [...dismissed, toBeRemoved].filter((v, i, a) => a.indexOf(v) === i);
setDismissed(cleared);
const storageKey = getNotificationStorageKey(username);
if (storageKey) {
localStorage.setItem(storageKey, JSON.stringify(cleared));
}
};
const resetNotifs = () => {
setDismissed([]);
const storageKey = getNotificationStorageKey(username);
if (storageKey) {
localStorage.setItem(storageKey, JSON.stringify([]));
}
};
return {
notifications: currentNotifs,
dismissed: dismissed,
allNotifications,
clearNotif: clearNotif,
resetNotifs: resetNotifs,
};
};
|