mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 01:35:39 -04:00
Add /dashboard route, mark-all-watched on complete, keyboard fixes
- Move dashboard page to app/(pages)/dashboard, redirect / to /dashboard for authenticated users, update all nav/breadcrumb/auth hrefs - Mark all episodes watched when a TV show status is set to "completed" (markAllEpisodesWatched skips already-watched episodes) - Refactor KeyboardProvider to store shortcuts in a ref instead of state, eliminating unnecessary re-renders; use react-hotkeys-hook for Cmd+K so it works reliably in form inputs - Fix useRegisterShortcut: re-register on every render (stable ref read) with a separate cleanup effect, removing brittle key memoization - Search page: silently navigate to title detail on import instead of showing "Added to library" toast
This commit is contained in:
@@ -35,11 +35,7 @@ export default function SearchPage() {
|
||||
if (l) setSearched(true);
|
||||
}, []);
|
||||
|
||||
async function handleImport(
|
||||
tmdbId: number,
|
||||
type: "movie" | "tv",
|
||||
title: string,
|
||||
) {
|
||||
async function handleOpen(tmdbId: number, type: "movie" | "tv") {
|
||||
setImporting(tmdbId);
|
||||
try {
|
||||
const res = await fetch("/api/titles/import", {
|
||||
@@ -49,11 +45,10 @@ export default function SearchPage() {
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.id) {
|
||||
toast.success(`Added "${title}" to library`);
|
||||
router.push(`/titles/${data.id}`);
|
||||
}
|
||||
} catch {
|
||||
toast.error("Failed to import title");
|
||||
toast.error("Failed to load title");
|
||||
} finally {
|
||||
setImporting(null);
|
||||
}
|
||||
@@ -64,7 +59,7 @@ export default function SearchPage() {
|
||||
<div className="space-y-2">
|
||||
<h1 className="font-display text-3xl tracking-tight">Search</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Find movies and TV shows to add to your library
|
||||
Find movies and TV shows to track
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -91,14 +86,14 @@ export default function SearchPage() {
|
||||
posterPath={r.posterPath}
|
||||
releaseDate={r.releaseDate}
|
||||
voteAverage={r.voteAverage}
|
||||
onImport={() => handleImport(r.tmdbId, r.type, r.title)}
|
||||
onImport={() => handleOpen(r.tmdbId, r.type)}
|
||||
/>
|
||||
{importing === r.tmdbId && (
|
||||
<div className="absolute inset-0 flex items-center justify-center rounded-xl bg-background/80 backdrop-blur-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||
<span className="text-sm font-medium text-primary">
|
||||
Importing
|
||||
Loading
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -380,7 +380,9 @@ export default function TitleDetailPage() {
|
||||
<Breadcrumb className="relative z-20">
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink render={<Link href="/" />}>Home</BreadcrumbLink>
|
||||
<BreadcrumbLink render={<Link href="/dashboard" />}>
|
||||
Home
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
|
||||
@@ -2,8 +2,22 @@
|
||||
|
||||
import { motion } from "motion/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { useSession } from "@/lib/auth/client";
|
||||
|
||||
export default function Home() {
|
||||
const { data: session, isPending } = useSession();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPending && session?.user) {
|
||||
router.replace("/dashboard");
|
||||
}
|
||||
}, [session, isPending, router]);
|
||||
|
||||
if (isPending) return null;
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden">
|
||||
{/* Background grain texture */}
|
||||
|
||||
Reference in New Issue
Block a user