All files / react-app/src/api useGetSystemNotifs.ts

74.62% Statements 50/67
51.61% Branches 16/31
77.77% Functions 14/18
77.04% Lines 47/61

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,
  };
};