feat: books fetch on SSR in book reader
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 17s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 17s
This commit is contained in:
@@ -1,13 +1,36 @@
|
|||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { ClientBookPage } from "@/components/reader/ClientBookPage";
|
import { ClientBookPage } from "@/components/reader/ClientBookPage";
|
||||||
import { BookSkeleton } from "@/components/skeletons/BookSkeleton";
|
import { BookSkeleton } from "@/components/skeletons/BookSkeleton";
|
||||||
|
import { BookService } from "@/lib/services/book.service";
|
||||||
|
import { ERROR_CODES } from "@/constants/errorCodes";
|
||||||
|
import { AppError } from "@/utils/errors";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default async function BookPage({ params }: { params: Promise<{ bookId: string }> }) {
|
export default async function BookPage({ params }: { params: Promise<{ bookId: string }> }) {
|
||||||
const { bookId } = await params;
|
const { bookId } = await params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// SSR: Fetch directly on server instead of client-side XHR
|
||||||
|
const data = await BookService.getBook(bookId);
|
||||||
|
const nextBook = await BookService.getNextBook(bookId, data.book.seriesId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<BookSkeleton />}>
|
<Suspense fallback={<BookSkeleton />}>
|
||||||
<ClientBookPage bookId={bookId} />
|
<ClientBookPage bookId={bookId} initialData={{ ...data, nextBook }} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
// If config is missing, redirect to settings
|
||||||
|
if (error instanceof AppError && error.code === ERROR_CODES.KOMGA.MISSING_CONFIG) {
|
||||||
|
redirect("/settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass error to client component
|
||||||
|
const errorCode = error instanceof AppError ? error.code : ERROR_CODES.BOOK.NOT_FOUND;
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<BookSkeleton />}>
|
||||||
|
<ClientBookPage bookId={bookId} initialError={errorCode} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,9 +10,15 @@ import logger from "@/lib/logger";
|
|||||||
|
|
||||||
interface ClientBookPageProps {
|
interface ClientBookPageProps {
|
||||||
bookId: string;
|
bookId: string;
|
||||||
|
initialData?: {
|
||||||
|
book: KomgaBook;
|
||||||
|
pages: number[];
|
||||||
|
nextBook: KomgaBook | null;
|
||||||
|
};
|
||||||
|
initialError?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ClientBookPage({ bookId }: ClientBookPageProps) {
|
export function ClientBookPage({ bookId, initialData, initialError }: ClientBookPageProps) {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [data, setData] = useState<{
|
const [data, setData] = useState<{
|
||||||
@@ -21,6 +27,22 @@ export function ClientBookPage({ bookId }: ClientBookPageProps) {
|
|||||||
nextBook: KomgaBook | null;
|
nextBook: KomgaBook | null;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
|
// Use SSR data if available
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialData) {
|
||||||
|
setData(initialData);
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (initialError) {
|
||||||
|
setError(initialError);
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetchBookData();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [bookId, initialData, initialError]);
|
||||||
|
|
||||||
const fetchBookData = async () => {
|
const fetchBookData = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -43,11 +65,6 @@ export function ClientBookPage({ bookId }: ClientBookPageProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchBookData();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [bookId]);
|
|
||||||
|
|
||||||
const handleRetry = () => {
|
const handleRetry = () => {
|
||||||
fetchBookData();
|
fetchBookData();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user