Merge improvement/inbox-nav-links: navigation links on watched + scheduler notices

This commit is contained in:
npeter83 2026-06-19 03:07:35 +02:00
commit 795f21a1e1
6 changed files with 38 additions and 7 deletions

View file

@ -174,7 +174,13 @@ export default function Feed({
? i18n.t("feed.markedWatchedNamed", { title: v.title })
: i18n.t("feed.markedWatched"),
action: { label: i18n.t("feed.unwatch"), onClick: () => onState(id, "new") },
meta: { kind: "video-watched", videoId: id, title: v?.title ?? "this video" },
meta: {
kind: "video-watched",
videoId: id,
title: v?.title ?? "this video",
channelId: v?.channel_id ?? "",
channelName: v?.channel_title ?? "",
},
});
} else if (status === "new") {
// Unhide / unwatch (from a card, the toast's Undo, or the center): quietly resolve

View file

@ -1,7 +1,7 @@
import { useEffect, useSyncExternalStore } from "react";
import { useTranslation } from "react-i18next";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { Bell, Check, CheckCheck, ExternalLink, Eye, RotateCcw, Search, Trash2, Tv, X } from "lucide-react";
import { Activity, Bell, Check, CheckCheck, ExternalLink, Eye, RotateCcw, Search, Trash2, Tv, X } from "lucide-react";
import { api, type AppNotification, type FeedFilters } from "../lib/api";
import { useLiveQuery } from "../lib/useLiveQuery";
import {
@ -94,11 +94,12 @@ export default function NotificationsPanel({
clearMut.mutate();
}
// "Find in feed" / undo, ported from the old bell.
function locateHidden(meta: VideoHiddenMeta) {
// "Find in feed" / undo, ported from the old bell. Works for both hidden and watched
// notices — jump to the feed filtered to that state and the video's channel.
function locate(meta: VideoHiddenMeta | VideoWatchedMeta) {
setFilters({
...filters,
show: "hidden",
show: meta.kind === "video-hidden" ? "hidden" : "watched",
channelId: meta.channelId || undefined,
channelName: meta.channelName || undefined,
});
@ -168,6 +169,7 @@ export default function NotificationsPanel({
t={t}
onRead={() => readMut.mutate(n.id)}
onDismiss={() => dismissMut.mutate(n.id)}
onOpenScheduler={() => setPage("scheduler")}
/>
))}
</div>
@ -184,7 +186,7 @@ export default function NotificationsPanel({
key={n.id}
n={n}
t={t}
onFind={locateHidden}
onFind={locate}
onRevert={revertState}
onFocusChannel={onFocusChannel}
onRemove={() => removeClient(n.id)}
@ -204,11 +206,13 @@ function NotificationRow({
t,
onRead,
onDismiss,
onOpenScheduler,
}: {
n: AppNotification;
t: (k: string, o?: any) => string;
onRead: () => void;
onDismiss: () => void;
onOpenScheduler: () => void;
}) {
// The maintenance producer ships the affected videos in `data.videos`; list a few titles.
const videos: { id: string; title: string | null }[] = Array.isArray(n.data?.videos)
@ -261,6 +265,15 @@ function NotificationRow({
)}
</ul>
)}
{isScheduler && (
<button
onClick={onOpenScheduler}
className="flex items-center gap-1 text-accent text-sm font-semibold hover:underline mt-1.5"
>
<Activity className="w-3.5 h-3.5" />
{t("inbox.openScheduler")}
</button>
)}
</div>
<div className="flex items-center gap-1 shrink-0">
{!n.read && (
@ -296,7 +309,7 @@ function ClientActivityRow({
}: {
n: ClientNotif;
t: (k: string, o?: any) => string;
onFind: (meta: VideoHiddenMeta) => void;
onFind: (meta: VideoHiddenMeta | VideoWatchedMeta) => void;
onRevert: (meta: VideoHiddenMeta | VideoWatchedMeta) => void;
onFocusChannel: (name: string) => void;
onRemove: () => void;
@ -342,6 +355,13 @@ function ClientActivityRow({
</div>
) : watched ? (
<div className="flex items-center gap-3 mt-1">
<button
onClick={() => onFind(watched)}
className="flex items-center gap-1 text-accent text-sm font-semibold hover:underline"
>
<Search className="w-3.5 h-3.5" />
{t("notifications.findInFeed")}
</button>
<button
onClick={() => onRevert(watched)}
className="flex items-center gap-1 text-accent text-sm font-semibold hover:underline"

View file

@ -10,6 +10,7 @@
"sectionSystem": "System",
"sectionActivity": "Aktivität",
"andMore": "und {{count}} weitere",
"openScheduler": "Zeitplaner öffnen",
"maintenance": {
"title": "Videos entfernt",
"body_one": "{{count}} gespeichertes oder in einer Playlist befindliches Video wurde entfernt, weil es auf YouTube nicht mehr verfügbar ist.",

View file

@ -10,6 +10,7 @@
"sectionSystem": "System",
"sectionActivity": "Activity",
"andMore": "and {{count}} more",
"openScheduler": "Open Scheduler",
"maintenance": {
"title": "Videos removed",
"body_one": "{{count}} saved or playlisted video was removed because it's no longer available on YouTube.",

View file

@ -10,6 +10,7 @@
"sectionSystem": "Rendszer",
"sectionActivity": "Tevékenység",
"andMore": "és még {{count}}",
"openScheduler": "Ütemező megnyitása",
"maintenance": {
"title": "Videók eltávolítva",
"body_one": "{{count}} mentett vagy lejátszási listás videó eltávolítva, mert már nem elérhető a YouTube-on.",

View file

@ -23,6 +23,8 @@ export type VideoWatchedMeta = {
kind: "video-watched";
videoId: string;
title: string;
channelId: string;
channelName: string;
};
export type ChannelSubscribedMeta = {
kind: "channel-subscribed";