Rezepte: listanje po 12 in oglasi med karticami
This commit is contained in:
parent
a039cf48da
commit
8bf90c6942
@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState, Fragment } from "react";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { ChefHat, X, Calendar } from "lucide-react";
|
import { ChefHat, X, Calendar } from "lucide-react";
|
||||||
import { usePageMeta } from "@/hooks/use-page-meta";
|
import { usePageMeta } from "@/hooks/use-page-meta";
|
||||||
@ -43,6 +43,8 @@ export default function RecipesPage() {
|
|||||||
"Das Rezept des Tages und alle bisherigen Rezepte aus der Alpenküche bei FOLX TV — österreichische, bayerische und schweizer Hausmannskost."
|
"Das Rezept des Tages und alle bisherigen Rezepte aus der Alpenküche bei FOLX TV — österreichische, bayerische und schweizer Hausmannskost."
|
||||||
);
|
);
|
||||||
const [selected, setSelected] = useState<DailyRecipe | null>(null);
|
const [selected, setSelected] = useState<DailyRecipe | null>(null);
|
||||||
|
const [page, setPage] = useState(0);
|
||||||
|
const PAGE_SIZE = 12;
|
||||||
|
|
||||||
const { data = [], isLoading } = useQuery<DailyRecipe[]>({
|
const { data = [], isLoading } = useQuery<DailyRecipe[]>({
|
||||||
queryKey: ["/api/recipes"],
|
queryKey: ["/api/recipes"],
|
||||||
@ -51,6 +53,13 @@ export default function RecipesPage() {
|
|||||||
|
|
||||||
const today = data[0];
|
const today = data[0];
|
||||||
const rest = data.slice(1);
|
const rest = data.slice(1);
|
||||||
|
const totalPages = Math.max(1, Math.ceil(rest.length / PAGE_SIZE));
|
||||||
|
const pageItems = rest.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);
|
||||||
|
|
||||||
|
const goPage = (p: number) => {
|
||||||
|
setPage(Math.max(0, Math.min(totalPages - 1, p)));
|
||||||
|
document.getElementById("rezept-archiv")?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
@ -96,16 +105,24 @@ export default function RecipesPage() {
|
|||||||
<InArticleAd />
|
<InArticleAd />
|
||||||
|
|
||||||
{rest.length > 0 && (
|
{rest.length > 0 && (
|
||||||
<section data-testid="section-recipe-archive">
|
<section data-testid="section-recipe-archive" id="rezept-archiv">
|
||||||
<div className="flex items-center gap-3 mb-4 mt-8">
|
<div className="flex items-center gap-3 mb-4 mt-8">
|
||||||
<div className="h-px flex-1 bg-card-border" />
|
<div className="h-px flex-1 bg-card-border" />
|
||||||
<h2 className="text-lg font-bold text-foreground px-3">Alle Rezepte</h2>
|
<h2 className="text-lg font-bold text-foreground px-3">Alle Rezepte</h2>
|
||||||
<div className="h-px flex-1 bg-card-border" />
|
<div className="h-px flex-1 bg-card-border" />
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground mb-4">
|
||||||
|
{rest.length} Rezepte · Seite {page + 1} von {totalPages}
|
||||||
|
</p>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
||||||
{rest.map((r) => (
|
{pageItems.map((r, idx) => (
|
||||||
|
<Fragment key={r.id}>
|
||||||
|
{idx > 0 && idx % 4 === 0 && (
|
||||||
|
<div key={`ad-${idx}`} className="sm:col-span-2 lg:col-span-3 xl:col-span-4">
|
||||||
|
<InArticleAd />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
key={r.id}
|
|
||||||
onClick={() => setSelected(r)}
|
onClick={() => setSelected(r)}
|
||||||
className="bg-card rounded-xl border border-card-border overflow-hidden text-left group hover:border-primary/50 transition-all hover:shadow-lg hover:shadow-primary/5"
|
className="bg-card rounded-xl border border-card-border overflow-hidden text-left group hover:border-primary/50 transition-all hover:shadow-lg hover:shadow-primary/5"
|
||||||
data-testid={`card-recipe-${r.id}`}
|
data-testid={`card-recipe-${r.id}`}
|
||||||
@ -128,8 +145,41 @@ export default function RecipesPage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex flex-wrap items-center justify-center gap-2 mt-8" data-testid="recipe-pagination">
|
||||||
|
<button
|
||||||
|
onClick={() => goPage(page - 1)}
|
||||||
|
disabled={page === 0}
|
||||||
|
className="px-3 py-2 text-sm rounded-lg border border-card-border bg-card text-foreground disabled:opacity-40 hover:border-primary/50 transition-colors"
|
||||||
|
>
|
||||||
|
Zurück
|
||||||
|
</button>
|
||||||
|
{Array.from({ length: totalPages }).map((_, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => goPage(i)}
|
||||||
|
className={`w-9 h-9 text-sm rounded-lg border transition-colors ${
|
||||||
|
i === page
|
||||||
|
? "bg-primary text-white border-primary"
|
||||||
|
: "bg-card text-foreground border-card-border hover:border-primary/50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{i + 1}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
<button
|
||||||
|
onClick={() => goPage(page + 1)}
|
||||||
|
disabled={page === totalPages - 1}
|
||||||
|
className="px-3 py-2 text-sm rounded-lg border border-card-border bg-card text-foreground disabled:opacity-40 hover:border-primary/50 transition-colors"
|
||||||
|
>
|
||||||
|
Weiter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user