fix(demo): graceful UX when YouTube actions are unavailable

The shared demo account no longer hits YouTube affordances: the onboarding
wizard never opens (or renders) for it, the empty-feed prompt nudges into
the shared library instead of the connect wizard, and the browser-facing
/auth/upgrade redirects the demo home instead of returning a raw 403 JSON.
This commit is contained in:
npeter83 2026-06-16 09:27:34 +02:00
parent 5b6d898d31
commit 484c6364e6
6 changed files with 50 additions and 18 deletions

View file

@ -68,12 +68,14 @@ export default function Feed({
setFilters,
view,
canRead,
isDemo = false,
onOpenWizard,
}: {
filters: FeedFilters;
setFilters: (f: FeedFilters) => void;
view: "grid" | "list";
canRead: boolean;
isDemo?: boolean;
onOpenWizard: () => void;
}) {
const { t } = useTranslation();
@ -204,26 +206,42 @@ export default function Feed({
if (query.isLoading) return <div className="p-8 text-muted">{t("feed.loading")}</div>;
if (query.isError) return <div className="p-8 text-muted">{t("feed.loadError")}</div>;
// Onboarding empty state (no YouTube + own subscriptions): a dedicated full-page prompt,
// with no toolbar (content-type/sort would be meaningless here).
// Empty "my" feed with no YouTube access. The shared demo account can never connect
// YouTube, so it gets a gentle nudge into the shared library instead of the connect
// wizard; real users get the onboarding prompt. No toolbar (sort/type are meaningless).
if (items.length === 0 && !canRead && filters.scope === "my")
return (
<div className="p-8 grid place-items-center text-center">
<div className="max-w-sm">
<h2 className="text-lg font-semibold">{t("feed.emptyTitle")}</h2>
<p className="text-sm text-muted mt-2 mb-4">{t("feed.emptyBody")}</p>
<button
onClick={onOpenWizard}
className="inline-flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl font-semibold bg-accent text-accent-fg hover:opacity-90 transition"
>
{t("feed.setUp")}
</button>
<button
onClick={() => setFilters({ ...filters, scope: "all" })}
className="block mx-auto mt-3 text-sm text-muted hover:text-accent transition"
>
{t("feed.browseShared")}
</button>
<h2 className="text-lg font-semibold">
{isDemo ? t("feed.demoEmptyTitle") : t("feed.emptyTitle")}
</h2>
<p className="text-sm text-muted mt-2 mb-4">
{isDemo ? t("feed.demoEmptyBody") : t("feed.emptyBody")}
</p>
{isDemo ? (
<button
onClick={() => setFilters({ ...filters, scope: "all" })}
className="inline-flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl font-semibold bg-accent text-accent-fg hover:opacity-90 transition"
>
{t("feed.browseLibrary")}
</button>
) : (
<>
<button
onClick={onOpenWizard}
className="inline-flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl font-semibold bg-accent text-accent-fg hover:opacity-90 transition"
>
{t("feed.setUp")}
</button>
<button
onClick={() => setFilters({ ...filters, scope: "all" })}
className="block mx-auto mt-3 text-sm text-muted hover:text-accent transition"
>
{t("feed.browseShared")}
</button>
</>
)}
</div>
</div>
);