Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
5158d11791
commit
a723c5eecd
@@ -46,10 +46,60 @@ const NAV: NavItem[] = [
|
||||
{ to: "/settings", label: "Settings", icon: Settings, adminOnly: true },
|
||||
];
|
||||
|
||||
function useUnreadMessagesCount() {
|
||||
const { user } = useAuth();
|
||||
const uid = user?.id;
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
if (!uid) {
|
||||
setCount(0);
|
||||
return;
|
||||
}
|
||||
const { data: mems } = await supabase
|
||||
.from("conversation_members")
|
||||
.select("conversation_id, last_read_at")
|
||||
.eq("user_id", uid);
|
||||
if (!mems || mems.length === 0) {
|
||||
setCount(0);
|
||||
return;
|
||||
}
|
||||
let total = 0;
|
||||
await Promise.all(
|
||||
mems.map(async (m) => {
|
||||
const { count: c } = 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", uid);
|
||||
total += c ?? 0;
|
||||
}),
|
||||
);
|
||||
setCount(total);
|
||||
}, [uid]);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
if (!uid) return;
|
||||
const ch = supabase
|
||||
.channel("sidebar-unread")
|
||||
.on("postgres_changes", { event: "*", schema: "public", table: "messages" }, () => refresh())
|
||||
.on("postgres_changes", { event: "UPDATE", schema: "public", table: "conversation_members", filter: `user_id=eq.${uid}` }, () => refresh())
|
||||
.subscribe();
|
||||
return () => {
|
||||
supabase.removeChannel(ch);
|
||||
};
|
||||
}, [uid, refresh]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
export function AppShell({ children }: { children: ReactNode }) {
|
||||
const { user, signOut, isAdmin, roles } = useAuth();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const unreadMessages = useUnreadMessagesCount();
|
||||
|
||||
const handleSignOut = async () => {
|
||||
await signOut();
|
||||
@@ -79,6 +129,7 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
? location.pathname === "/"
|
||||
: location.pathname.startsWith(item.to);
|
||||
const Icon = item.icon;
|
||||
const showBadge = item.to === "/messages" && unreadMessages > 0;
|
||||
return (
|
||||
<Link
|
||||
key={item.to}
|
||||
@@ -91,7 +142,12 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
)}
|
||||
>
|
||||
<Icon className="h-4 w-4" />
|
||||
{item.label}
|
||||
<span className="flex-1">{item.label}</span>
|
||||
{showBadge && (
|
||||
<Badge variant="destructive" className="h-5 px-1.5 text-[10px]">
|
||||
{unreadMessages}
|
||||
</Badge>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user