diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index ccfe17a..037cc89 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -252,8 +252,6 @@ export default function App() {
onOpenAbout={() => setAboutOpen(true)}
onChangeLanguage={changeLanguage}
language={i18n.language as LangCode}
- filters={filters}
- setFilters={setFilters}
/>
) : page === "notifications" ? (
-
+
) : page === "settings" ? (
onState(id, "new") },
meta: { kind: "video-watched", videoId: id, title: v?.title ?? "this video" },
});
+ } else if (status === "new") {
+ // Unhide / unwatch (from a card, the toast's Undo, or the center): quietly resolve any
+ // stale hide/watch notice for this video so it doesn't linger with a dead action.
+ resolveVideo(id);
}
},
[qc]
diff --git a/frontend/src/components/NavSidebar.tsx b/frontend/src/components/NavSidebar.tsx
index f862adb..cef12ec 100644
--- a/frontend/src/components/NavSidebar.tsx
+++ b/frontend/src/components/NavSidebar.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useRef, useState, useSyncExternalStore } from "react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { useQuery } from "@tanstack/react-query";
@@ -17,13 +17,13 @@ import {
Tv,
UserPlus,
} from "lucide-react";
-import { api, type FeedFilters, type Me } from "../lib/api";
+import { api, type Me } from "../lib/api";
import { useLiveQuery } from "../lib/useLiveQuery";
+import { getUnreadCount, subscribe } from "../lib/notifications";
import type { Page } from "../lib/urlState";
import { type LangCode } from "../i18n";
import AvatarImg from "./Avatar";
import LanguageSwitcher from "./LanguageSwitcher";
-import NotificationCenter from "./NotificationCenter";
// Primary app navigation: a collapsible left rail with icon+label entries (Design C). The
// modules used to hide under the avatar dropdown; they now live here. Collapsed, it becomes
@@ -35,8 +35,6 @@ export default function NavSidebar({
onOpenAbout,
onChangeLanguage,
language,
- filters,
- setFilters,
}: {
me: Me;
page: Page;
@@ -44,8 +42,6 @@ export default function NavSidebar({
onOpenAbout: () => void;
onChangeLanguage: (code: LangCode) => void;
language: LangCode;
- filters: FeedFilters;
- setFilters: (f: FeedFilters) => void;
}) {
const { t } = useTranslation();
const [collapsed, setCollapsed] = useState(
@@ -125,7 +121,10 @@ export default function NavSidebar({
api.notificationUnreadCount,
{ intervalMs: 30000 }
);
- const unread = unreadQuery.data?.count ?? 0;
+ // One indicator for both layers: durable server notifications + the client-side transient
+ // events (the former separate bell is now folded into the inbox page).
+ const clientUnread = useSyncExternalStore(subscribe, getUnreadCount, getUnreadCount);
+ const unread = (unreadQuery.data?.count ?? 0) + clientUnread;
type NavItem = { page: Page; icon: typeof Home; label: string; badge?: number };
// User-facing content modules vs. admin/system modules, separated by a divider in the rail.
@@ -243,7 +242,6 @@ export default function NavSidebar({
>
-