Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
f524dc8fd1
commit
ca5b7ea01a
@@ -0,0 +1,36 @@
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import type { Database } from "@/integrations/supabase/types";
|
||||
|
||||
export type NotificationKind = Database["public"]["Enums"]["notification_kind"];
|
||||
|
||||
export interface CreateNotificationInput {
|
||||
user_id: string;
|
||||
kind: NotificationKind;
|
||||
title: string;
|
||||
body?: string | null;
|
||||
link?: string | null;
|
||||
task_id?: string | null;
|
||||
case_id?: string | null;
|
||||
conversation_id?: string | null;
|
||||
created_by?: string | null;
|
||||
}
|
||||
|
||||
export async function createNotifications(rows: CreateNotificationInput[]) {
|
||||
if (!rows.length) return;
|
||||
await supabase.from("notifications").insert(rows);
|
||||
}
|
||||
|
||||
const MENTION_RE = /@\[([^\]]+)\]\(user:([0-9a-f-]{36})\)/g;
|
||||
|
||||
export function extractMentions(body: string): string[] {
|
||||
const ids = new Set<string>();
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = MENTION_RE.exec(body)) !== null) {
|
||||
ids.add(m[2]);
|
||||
}
|
||||
return Array.from(ids);
|
||||
}
|
||||
|
||||
export function renderMentionsToText(body: string): string {
|
||||
return body.replace(MENTION_RE, "@$1");
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
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}`)
|
||||
.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;
|
||||
}
|
||||
Reference in New Issue
Block a user