hellth-hub/apps/admin/app/(authed)/rezepte/eier-muffins/page.tsx

193 lines
7.6 KiB
TypeScript
Raw Permalink Normal View History

"use client";
import {
ArrowPathIcon,
ClockIcon,
FireIcon,
PlusIcon,
ScaleIcon,
} from "@heroicons/react/24/outline";
import Link from "next/link";
import { useEffect, useMemo, useState } from "react";
import { useSession } from "@/lib/auth-client";
import {
RecipeRating,
loadHellthData,
recipeRatingSummary,
saveHellthData,
uid,
} from "@/lib/hellth-data";
const recipeId = "recipe-eggs";
function MacroBar() {
return (
<div className="flex h-4 overflow-hidden rounded-full bg-gray-100">
<div className="w-[22%] bg-amber-400" />
<div className="w-[33%] bg-blue-500" />
<div className="flex-1 bg-green-500" />
</div>
);
}
export default function RecipePage() {
const { data: session } = useSession();
const userKey = session?.user?.id ?? session?.user?.email ?? null;
const displayName = session?.user?.name || session?.user?.email || "Du";
const [ratings, setRatings] = useState<RecipeRating[]>([]);
const [rating, setRating] = useState(5);
const [comment, setComment] = useState("");
const summary = useMemo(() => recipeRatingSummary(recipeId, ratings), [ratings]);
useEffect(() => {
if (!userKey) return;
const data = loadHellthData(userKey);
setRatings(data.recipeRatings);
const own = data.recipeRatings.find((item) => item.recipeId === recipeId && item.userKey === userKey);
if (own) {
setRating(own.rating);
setComment(own.comment ?? "");
}
}, [userKey]);
function saveRating() {
if (!userKey) return;
const data = loadHellthData(userKey);
const nextRating: RecipeRating = {
id: data.recipeRatings.find((item) => item.recipeId === recipeId && item.userKey === userKey)?.id ?? uid("rating"),
recipeId,
userKey,
displayName,
rating,
comment: comment.trim() || undefined,
createdAt: new Date().toISOString(),
};
const nextRatings = [
nextRating,
...data.recipeRatings.filter((item) => !(item.recipeId === recipeId && item.userKey === userKey)),
];
saveHellthData({ ...data, recipeRatings: nextRatings }, userKey);
setRatings(nextRatings);
}
return (
<div className="mx-auto max-w-3xl pb-24">
<section className="rounded-[2.5rem] bg-white px-6 pb-8 pt-5 shadow-sm ring-1 ring-gray-100 sm:px-10">
<div className="mx-auto mb-10 h-2 w-14 rounded-full bg-gray-200" />
<div className="mx-auto flex h-56 w-56 items-center justify-center rounded-full bg-gradient-to-br from-amber-100 to-orange-200 text-6xl font-black text-orange-700 shadow-inner">
EM
</div>
<h1 className="mt-10 text-center text-5xl font-black leading-none tracking-normal text-gray-950">
Eier-Muffins mit Paprika
</h1>
<div className="mt-10 grid grid-cols-3 gap-4 text-center">
<div>
<FireIcon className="mx-auto h-9 w-9 text-green-500" />
<p className="mt-3 text-3xl font-black text-gray-950">523 <span className="text-xl">kcal</span></p>
<p className="text-sm font-black text-gray-400">Pro Portion</p>
</div>
<div>
<ClockIcon className="mx-auto h-9 w-9 text-orange-500" />
<p className="mt-3 text-3xl font-black text-gray-950">20<span className="text-xl"> Min</span></p>
<p className="text-sm font-black text-gray-400">Kochzeit</p>
</div>
<div>
<ScaleIcon className="mx-auto h-9 w-9 text-blue-400" />
<p className="mt-3 text-3xl font-black text-gray-950">88<span className="text-xl">/100</span></p>
<p className="text-sm font-black text-gray-400">Score</p>
</div>
</div>
<div className="mt-8 rounded-[2rem] bg-amber-50 p-5">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div>
<h2 className="text-xl font-black text-gray-950">User-Bewertung</h2>
<p className="mt-1 text-sm font-bold text-amber-800">
{summary.count ? `${summary.average}/5 aus ${summary.count} Bewertung(en)` : "Noch keine Bewertungen."}
</p>
</div>
<div className="flex gap-1">
{[1, 2, 3, 4, 5].map((value) => (
<button
key={value}
type="button"
onClick={() => setRating(value)}
className={`text-3xl ${value <= rating ? "text-amber-500" : "text-amber-200"}`}
aria-label={`${value} Sterne`}
title={`${value} Sterne`}
>
*
</button>
))}
</div>
</div>
<textarea
value={comment}
onChange={(event) => setComment(event.target.value)}
placeholder="Kurzer Kommentar: schmeckt gut, sättigt, Meal-Prep geeignet..."
className="mt-4 min-h-24 w-full rounded-3xl border border-amber-100 bg-white px-4 py-3 text-sm font-semibold"
/>
<button type="button" onClick={saveRating} className="mt-3 rounded-full bg-gray-950 px-5 py-3 text-sm font-black text-white">
Bewertung speichern
</button>
</div>
<div className="my-10 h-px bg-gray-100" />
<h2 className="text-xl font-black text-gray-400">Makros</h2>
<div className="mt-6">
<MacroBar />
<div className="mt-6 grid grid-cols-3 gap-4">
<div>
<p className="text-sm font-black text-gray-400">Kohlenhydr.</p>
<p className="mt-2 text-4xl font-black text-gray-950">20 <span className="text-gray-300">g</span></p>
</div>
<div>
<p className="text-sm font-black text-gray-400">Fett</p>
<p className="mt-2 text-4xl font-black text-gray-950">30 <span className="text-gray-300">g</span></p>
</div>
<div>
<p className="text-sm font-black text-gray-400">Proteine</p>
<p className="mt-2 text-4xl font-black text-gray-950">41 <span className="text-gray-300">g</span></p>
</div>
</div>
</div>
<div className="my-10 h-px bg-gray-100" />
<div className="flex items-center justify-between">
<h2 className="text-xl font-black text-gray-400">Zutaten</h2>
<button type="button" className="text-lg font-black text-gray-400">1 Portionen</button>
</div>
<div className="mt-6 rounded-[2rem] bg-gray-50 p-5">
{[
["Paprika", "150 g"],
["Eier", "3 Stück"],
["Hirtenkäse", "60 g"],
["Zwiebel", "1/2 Stück"],
].map(([name, amount]) => (
<div key={name} className="flex items-center justify-between border-b border-gray-200 py-4 last:border-0">
<p className="text-lg font-black text-gray-950">{name}</p>
<p className="text-lg font-black text-gray-400">{amount}</p>
</div>
))}
</div>
</section>
<div className="fixed inset-x-0 bottom-20 z-40 mx-auto grid max-w-md grid-cols-2 gap-3 px-5 lg:bottom-6">
<button type="button" className="inline-flex items-center justify-center gap-2 rounded-full border border-gray-200 bg-white px-5 py-4 text-base font-black text-gray-950 shadow-sm">
<ArrowPathIcon className="h-5 w-5" />
Tauschen
</button>
<Link href="/" className="inline-flex items-center justify-center gap-2 rounded-full bg-gray-950 px-5 py-4 text-base font-black text-white shadow-sm">
<PlusIcon className="h-5 w-5" />
Protokollieren
</Link>
</div>
</div>
);
}