feat: v1.1 - random re-roll, shopping summary, offline PWA, auth prep, profile page

This commit is contained in:
clawd
2026-02-18 10:32:12 +00:00
parent de567f93db
commit c222c880a3
13 changed files with 290 additions and 6 deletions

View File

@@ -1,10 +1,11 @@
import { useState } from 'react'
import { useParams, useNavigate, Link } from 'react-router'
import { useState, useCallback } from 'react'
import { useParams, useNavigate, useSearchParams, Link } from 'react-router'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { motion } from 'framer-motion'
import toast from 'react-hot-toast'
import { ArrowLeft, Heart, Clock, Users, ChefHat, ShoppingCart, Pencil, Minus, Plus, Send, Trash2 } from 'lucide-react'
import { fetchRecipe, toggleFavorite } from '../api/recipes'
import { Dices } from 'lucide-react'
import { fetchRecipe, toggleFavorite, fetchRandomRecipe } from '../api/recipes'
import { addFromRecipe } from '../api/shopping'
import { createNote, deleteNote } from '../api/notes'
import { Badge } from '../components/ui/Badge'
@@ -15,9 +16,21 @@ const gradients = ['from-primary/40 to-secondary/40', 'from-secondary/40 to-sage
export function RecipePage() {
const { slug } = useParams<{ slug: string }>()
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const fromRandom = searchParams.get('from') === 'random'
const qc = useQueryClient()
const [servingScale, setServingScale] = useState<number | null>(null)
const [noteText, setNoteText] = useState('')
const [rerolling, setRerolling] = useState(false)
const handleReroll = useCallback(async () => {
setRerolling(true)
try {
const r = await fetchRandomRecipe()
if (r?.slug) navigate(`/recipe/${r.slug}?from=random`, { replace: true })
} catch { /* ignore */ }
setRerolling(false)
}, [navigate])
const { data: recipe, isLoading } = useQuery({
queryKey: ['recipe', slug],
@@ -298,6 +311,18 @@ export function RecipePage() {
</div>
</div>
</div>
{/* Floating Re-Roll Button */}
{fromRandom && (
<button
onClick={handleReroll}
disabled={rerolling}
className="fixed bottom-20 right-4 z-50 w-12 h-12 rounded-full bg-gradient-to-r from-primary to-secondary text-white shadow-lg flex items-center justify-center active:scale-95 transition-transform disabled:opacity-50"
title="Nochmal würfeln"
>
<Dices size={20} className={rerolling ? 'animate-spin' : ''} />
</button>
)}
</motion.div>
)
}