Files
mylegal-stage-law/src/lib/use-bubble-counts.ts
T
2026-04-17 03:05:59 +00:00

80 lines
2.8 KiB
TypeScript

import { useEffect, useState, useCallback } from "react";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/lib/auth";
interface Counts {
messages: number;
tasks: number;
notifications: number;
}
export function useBubbleCounts(): Counts {
const { user } = useAuth();
const [counts, setCounts] = useState<Counts>({ messages: 0, tasks: 0, notifications: 0 });
const load = useCallback(async () => {
if (!user) {
setCounts({ messages: 0, tasks: 0, notifications: 0 });
return;
}
const [memberRes, msgRes, taskRes, notifRes] = await Promise.all([
supabase.from("conversation_members").select("conversation_id, last_read_at").eq("user_id", user.id),
// unread messages: query per-convo handled below
Promise.resolve(null),
supabase
.from("task_assignees")
.select("task_id, tasks!inner(status, due_date)")
.eq("user_id", user.id)
.eq("tasks.status", "incomplete"),
supabase
.from("notifications")
.select("id", { count: "exact", head: true })
.eq("user_id", user.id)
.is("read_at", null),
]);
let unreadMessages = 0;
const memberRows = memberRes.data ?? [];
if (memberRows.length) {
// For each conversation, count messages newer than last_read_at and not from self
const results = await Promise.all(
memberRows.map(async (m) => {
const { count } = await supabase
.from("messages")
.select("id", { count: "exact", head: true })
.eq("conversation_id", m.conversation_id)
.gt("created_at", m.last_read_at)
.neq("sender_id", user.id);
return count ?? 0;
}),
);
unreadMessages = results.reduce((a, b) => a + b, 0);
}
const taskCount = (taskRes.data ?? []).length;
setCounts({
messages: unreadMessages,
tasks: taskCount,
notifications: notifRes.count ?? 0,
});
}, [user]);
useEffect(() => {
if (!user) return;
load();
const ch = supabase
.channel(`bubbles-${user.id}-${Math.random().toString(36).slice(2)}`)
.on("postgres_changes", { event: "*", schema: "public", table: "messages" }, () => load())
.on("postgres_changes", { event: "*", schema: "public", table: "task_assignees" }, () => load())
.on("postgres_changes", { event: "*", schema: "public", table: "tasks" }, () => load())
.on("postgres_changes", { event: "*", schema: "public", table: "notifications", filter: `user_id=eq.${user.id}` }, () => load())
.on("postgres_changes", { event: "*", schema: "public", table: "conversation_members", filter: `user_id=eq.${user.id}` }, () => load())
.subscribe();
return () => {
supabase.removeChannel(ch);
};
}, [user, load]);
return counts;
}