146 lines
5.4 KiB
TypeScript
146 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { MangaGrid } from "@/components/manga-grid";
|
|
import { MangaPagination } from "@/components/manga-pagination";
|
|
import { FilterSidebar } from "@/components/filter-sidebar";
|
|
import { BookOpen, Search } from "lucide-react";
|
|
import { Input } from "@/components/ui/input";
|
|
import { ThemeToggle } from "@/components/theme-toggle";
|
|
import { useGetMangas } from "@/api/mangamochi";
|
|
import { AuthHeader } from "@/components/auth-header";
|
|
import { ImportDropdown } from "@/components/import-dropdown";
|
|
import { SortOption, SortOptions } from "@/components/sort-options";
|
|
|
|
const ITEMS_PER_PAGE = 12;
|
|
|
|
export default function HomePage() {
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
const [searchQuery, setSearchQuery] = useState("");
|
|
const [selectedGenres, setSelectedGenres] = useState<number[]>([]);
|
|
const [selectedStatus, setSelectedStatus] = useState<string[]>([]);
|
|
const [minRating, setMinRating] = useState(0);
|
|
const [userFavorites, setUserFavorites] = useState(false);
|
|
const [showAdultContent, setShowAdultContent] = useState(false);
|
|
const [sortOption, setSortOption] = useState<SortOption>("title-asc");
|
|
|
|
const { data: mangas, queryKey } = useGetMangas({
|
|
page: currentPage - 1,
|
|
size: ITEMS_PER_PAGE,
|
|
sort: ["id"],
|
|
searchQuery: searchQuery,
|
|
statuses: selectedStatus,
|
|
genreIds: selectedGenres,
|
|
userFavorites,
|
|
score: minRating,
|
|
});
|
|
|
|
const totalPages = mangas?.data?.totalPages;
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-background">
|
|
<FilterSidebar
|
|
selectedGenres={selectedGenres}
|
|
selectedStatus={selectedStatus}
|
|
minRating={minRating}
|
|
userFavorites={userFavorites}
|
|
showAdultContent={showAdultContent}
|
|
onGenresChange={setSelectedGenres}
|
|
onStatusChange={setSelectedStatus}
|
|
onRatingChange={setMinRating}
|
|
onUserFavoritesChange={setUserFavorites}
|
|
onShowAdultContentChange={setShowAdultContent}
|
|
/>
|
|
|
|
{/* Main Content */}
|
|
<div className="flex-1">
|
|
{/* Header */}
|
|
<header className="border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
<div className="px-8 py-6">
|
|
<div className="flex flex-col gap-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-start gap-3">
|
|
<BookOpen className="h-8 w-8 text-primary mt-1" />
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight text-foreground">
|
|
MangaMochi
|
|
</h1>
|
|
<p className="mt-1 text-sm text-muted-foreground">
|
|
{mangas?.data?.totalElements} titles available
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-4">
|
|
<ImportDropdown />
|
|
<ThemeToggle />
|
|
<AuthHeader />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Search */}
|
|
<div className="relative max-w-md">
|
|
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
|
<Input
|
|
type="search"
|
|
placeholder="Search manga or author..."
|
|
value={searchQuery}
|
|
onChange={(e) => {
|
|
setSearchQuery(e.target.value);
|
|
setCurrentPage(1);
|
|
}}
|
|
className="pl-10 bg-card border-border"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main className="px-8 py-8">
|
|
{mangas?.data?.content && mangas.data.content.length > 0 ? (
|
|
<>
|
|
{mangas?.data?.totalElements && (
|
|
<div className="mb-6 flex items-center justify-between">
|
|
<p className="text-sm text-muted-foreground">
|
|
Showing {(currentPage - 1) * ITEMS_PER_PAGE + 1} to{" "}
|
|
{Math.min(
|
|
currentPage * ITEMS_PER_PAGE,
|
|
mangas.data.totalElements,
|
|
)}{" "}
|
|
of {mangas.data.totalElements}
|
|
</p>
|
|
<SortOptions
|
|
currentSort={sortOption}
|
|
onSortChange={setSortOption}
|
|
/>
|
|
</div>
|
|
)}
|
|
<MangaGrid manga={mangas?.data?.content} queryKey={queryKey} />
|
|
|
|
{totalPages && totalPages > 1 && (
|
|
<div className="mt-12">
|
|
<MangaPagination
|
|
currentPage={currentPage}
|
|
totalPages={totalPages}
|
|
onPageChange={setCurrentPage}
|
|
/>
|
|
</div>
|
|
)}
|
|
</>
|
|
) : (
|
|
<div className="flex min-h-[400px] items-center justify-center">
|
|
<div className="text-center">
|
|
<p className="text-lg text-muted-foreground">
|
|
No manga found matching your filters.
|
|
</p>
|
|
<p className="mt-2 text-sm text-muted-foreground">
|
|
Try adjusting your search or filter criteria.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|