From baec54814dbeb2536220d0bbd9e038f4ed5edf43 Mon Sep 17 00:00:00 2001 From: Alex Polo Date: Fri, 31 Oct 2025 22:23:59 +0100 Subject: [PATCH] Implement booking cancellation feature and refactor booking fetching logic --- logs/out-0.log | 12 + src/app/admin/bookings/bookings-client.tsx | 63 ++- src/app/api/bookings/route.ts | 21 + src/components/marketing/featured-menus.tsx | 16 +- src/config/sample-data.js | 464 -------------------- src/config/sample-data.ts | 62 ++- 6 files changed, 139 insertions(+), 499 deletions(-) delete mode 100644 src/config/sample-data.js diff --git a/logs/out-0.log b/logs/out-0.log index 23051c4..cb1eba8 100644 --- a/logs/out-0.log +++ b/logs/out-0.log @@ -17,3 +17,15 @@ 2025-10-31T20:54:03: > Ready on http://localhost:3000 2025-10-31T21:04:52: > Ready on http://localhost:3000 2025-10-31T21:07:41: > Ready on http://localhost:3000 +2025-10-31T21:31:48: > Ready on http://localhost:3000 +2025-10-31T21:34:11: > Ready on http://localhost:3000 +2025-10-31T21:39:45: > Ready on http://localhost:3000 +2025-10-31T21:40:36: > Ready on http://localhost:3000 +2025-10-31T21:45:41: > Ready on http://localhost:3000 +2025-10-31T21:47:51: > Ready on http://localhost:3000 +2025-10-31T21:50:59: > Ready on http://localhost:3000 +2025-10-31T21:58:30: > Ready on http://localhost:3000 +2025-10-31T22:14:18: > Ready on http://localhost:3000 +2025-10-31T22:17:17: > Ready on http://localhost:3000 +2025-10-31T22:21:03: > Ready on http://localhost:3000 +2025-10-31T22:22:22: > Ready on http://localhost:3000 diff --git a/src/app/admin/bookings/bookings-client.tsx b/src/app/admin/bookings/bookings-client.tsx index dda1a29..5a218b6 100644 --- a/src/app/admin/bookings/bookings-client.tsx +++ b/src/app/admin/bookings/bookings-client.tsx @@ -14,22 +14,54 @@ type Booking = { menu_id?: string package_id?: string message?: string + status?: string } export default function BookingsClient() { const [bookings, setBookings] = useState([]) const [loading, setLoading] = useState(true) + const [cancelling, setCancelling] = useState(null) + + async function fetchBookings() { + try { + const r = await fetch('/api/bookings') + const data = await r.ok ? await r.json() : [] + setBookings(Array.isArray(data) ? data : []) + } catch (err) { + console.error(err) + } finally { + setLoading(false) + } + } useEffect(() => { - let mounted = true - fetch('/api/bookings') - .then(r => r.ok ? r.json() : []) - .then(data => { if (mounted) setBookings(Array.isArray(data) ? data : []) }) - .catch(err => console.error(err)) - .finally(() => { if (mounted) setLoading(false) }) - return () => { mounted = false } + fetchBookings() }, []) + async function cancelBooking(id: string, name: string) { + if (!confirm(`Annuller booking for ${name}?\n\nDette kan ikke fortrydes.`)) return + + setCancelling(id) + try { + const res = await fetch('/api/bookings', { + method: 'DELETE', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id }) + }) + + if (res.ok) { + setBookings(prev => prev.filter(b => b.id !== id)) + alert(`Booking for ${name} er annulleret`) + } else { + alert('Kunne ikke annullere booking — prøv igen') + } + } catch (err) { + alert('Fejl ved annullering — prøv igen') + } finally { + setCancelling(null) + } + } + if (loading) return
Indlæser bookinger...
if (bookings.length === 0) return
Ingen bookinger fundet.
@@ -44,17 +76,30 @@ export default function BookingsClient() { Kuverter Menu Note + Handling {bookings.map(b => ( - + {b.booking_date} {b.start_time.slice(0,5)} - {b.end_time.slice(0,5)} - {b.name}
{b.email}{b.phone ? ` · ${b.phone}` : ''}
+ +
{b.name}
+
{b.email}{b.phone ? ` · ${b.phone}` : ''}
+ {b.party_size || '-'} {b.menu_id || b.package_id || '-'} {b.message || '-'} + + + ))} diff --git a/src/app/api/bookings/route.ts b/src/app/api/bookings/route.ts index 3779b8a..c211239 100644 --- a/src/app/api/bookings/route.ts +++ b/src/app/api/bookings/route.ts @@ -75,3 +75,24 @@ export async function POST(req: Request) { return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }) } } + +export async function DELETE(req: Request) { + try { + const body = await req.json() + const { id } = body + if (!id) { + return NextResponse.json({ error: 'Missing booking id' }, { status: 400 }) + } + + const [result] = await pool.query('DELETE FROM bookings WHERE id = ?', [id]) + // @ts-ignore + if (result.affectedRows === 0) { + return NextResponse.json({ error: 'Booking not found' }, { status: 404 }) + } + + return NextResponse.json({ ok: true }) + } catch (error) { + console.error('Error deleting booking', error) + return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }) + } +} diff --git a/src/components/marketing/featured-menus.tsx b/src/components/marketing/featured-menus.tsx index 397e258..c6ee94a 100644 --- a/src/components/marketing/featured-menus.tsx +++ b/src/components/marketing/featured-menus.tsx @@ -1,16 +1,25 @@ +'use client' + import { sampleData } from '@/config/sample-data' -import { Menu } from '@/types/models' +import { Menu, Package } from '@/types/models' import { ImagePlaceholder } from '@/components/ui/image-placeholder' import { cn } from '@/lib/utils' import { ArrowRight } from 'lucide-react' export function FeaturedMenus() { const { packages, menus } = sampleData - // Prefer menus explicitly marked as featured. Fall back to first 4 if none set. + + // Force rebuild - Prefer menus explicitly marked as featured const featuredMenus = (menus.filter((m: Menu) => (m as any).featured) as Menu[]) .slice(0, 4) .length > 0 ? (menus.filter((m: Menu) => (m as any).featured) as Menu[]).slice(0, 4) : menus.slice(0, 4) + console.log('=== FeaturedMenus Debug v2 ===') + console.log('Total menus:', menus.length) + console.log('Featured menus:', featuredMenus.map(m => m.id)) + console.log('Total packages:', packages.length) + console.log('Package menuIds:', packages.map((p: Package) => p.menuId)) + return (
@@ -24,7 +33,8 @@ export function FeaturedMenus() {
{featuredMenus.map((menu: Menu) => { - const basePackage = packages.find((p: { menuId: string }) => p.menuId === menu.id) + const basePackage = packages.find((p: Package) => p.menuId === menu.id) + console.log(`Menu: ${menu.id}, Package found: ${basePackage?.id}, Price: ${basePackage?.pricePerCover}`) return (