102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
import { useEffect, useMemo, useState } from "react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { accessApi } from "../api/access";
|
|
import { ApiError } from "../api/client";
|
|
import { approvalsApi } from "../api/approvals";
|
|
import { dashboardApi } from "../api/dashboard";
|
|
import { heartbeatsApi } from "../api/heartbeats";
|
|
import { issuesApi } from "../api/issues";
|
|
import { queryKeys } from "../lib/queryKeys";
|
|
import {
|
|
computeInboxBadgeData,
|
|
loadDismissedInboxItems,
|
|
saveDismissedInboxItems,
|
|
} from "../lib/inbox";
|
|
|
|
const TOUCHED_ISSUE_STATUSES = "backlog,todo,in_progress,in_review,blocked,done";
|
|
|
|
export function useDismissedInboxItems() {
|
|
const [dismissed, setDismissed] = useState<Set<string>>(loadDismissedInboxItems);
|
|
|
|
useEffect(() => {
|
|
const handleStorage = (event: StorageEvent) => {
|
|
if (event.key !== "paperclip:inbox:dismissed") return;
|
|
setDismissed(loadDismissedInboxItems());
|
|
};
|
|
window.addEventListener("storage", handleStorage);
|
|
return () => window.removeEventListener("storage", handleStorage);
|
|
}, []);
|
|
|
|
const dismiss = (id: string) => {
|
|
setDismissed((prev) => {
|
|
const next = new Set(prev);
|
|
next.add(id);
|
|
saveDismissedInboxItems(next);
|
|
return next;
|
|
});
|
|
};
|
|
|
|
return { dismissed, dismiss };
|
|
}
|
|
|
|
export function useInboxBadge(companyId: string | null | undefined) {
|
|
const { dismissed } = useDismissedInboxItems();
|
|
|
|
const { data: approvals = [] } = useQuery({
|
|
queryKey: queryKeys.approvals.list(companyId!),
|
|
queryFn: () => approvalsApi.list(companyId!),
|
|
enabled: !!companyId,
|
|
});
|
|
|
|
const { data: joinRequests = [] } = useQuery({
|
|
queryKey: queryKeys.access.joinRequests(companyId!),
|
|
queryFn: async () => {
|
|
try {
|
|
return await accessApi.listJoinRequests(companyId!, "pending_approval");
|
|
} catch (err) {
|
|
if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {
|
|
return [];
|
|
}
|
|
throw err;
|
|
}
|
|
},
|
|
enabled: !!companyId,
|
|
retry: false,
|
|
});
|
|
|
|
const { data: dashboard } = useQuery({
|
|
queryKey: queryKeys.dashboard(companyId!),
|
|
queryFn: () => dashboardApi.summary(companyId!),
|
|
enabled: !!companyId,
|
|
});
|
|
|
|
const { data: touchedIssues = [] } = useQuery({
|
|
queryKey: queryKeys.issues.listTouchedByMe(companyId!),
|
|
queryFn: () =>
|
|
issuesApi.list(companyId!, {
|
|
touchedByUserId: "me",
|
|
status: TOUCHED_ISSUE_STATUSES,
|
|
}),
|
|
enabled: !!companyId,
|
|
});
|
|
|
|
const { data: heartbeatRuns = [] } = useQuery({
|
|
queryKey: queryKeys.heartbeats(companyId!),
|
|
queryFn: () => heartbeatsApi.list(companyId!),
|
|
enabled: !!companyId,
|
|
});
|
|
|
|
return useMemo(
|
|
() =>
|
|
computeInboxBadgeData({
|
|
approvals,
|
|
joinRequests,
|
|
dashboard,
|
|
heartbeatRuns,
|
|
touchedIssues,
|
|
dismissed,
|
|
}),
|
|
[approvals, joinRequests, dashboard, heartbeatRuns, touchedIssues, dismissed],
|
|
);
|
|
}
|