Replace entire repo content with updated code from /root/shahikitchen-website/
This commit is contained in:
@@ -55,6 +55,11 @@
|
||||
scroll-margin-top: var(--header-height);
|
||||
}
|
||||
|
||||
/* Prevent horizontal scroll from overflowing children */
|
||||
html {
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
/* Base */
|
||||
body,
|
||||
.shahi-body {
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ export default function RootLayout({
|
||||
{children}
|
||||
<CartDrawer />
|
||||
<WishlistDrawer />
|
||||
<Toaster position="top-center" richColors closeButton />
|
||||
<Toaster position="top-center" richColors closeButton offset={124} />
|
||||
</WishlistProvider>
|
||||
</CartProvider>
|
||||
</LanguageProvider>
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function LocationsPage() {
|
||||
{/* Branch 1: Askim */}
|
||||
<div className="bg-white border border-[#EDE6D9] rounded-2xl p-8">
|
||||
<div className="uppercase text-[#B38B4D] text-xs tracking-[2px] mb-2">RESTAURANT & BUFFET</div>
|
||||
<h2 className="text-4xl tracking-[-1.5px] mb-4">Shahi Kitchen – Askim (Sisjön)</h2>
|
||||
<h2 className="text-2xl sm:text-3xl md:text-4xl tracking-[-1.5px] mb-4 break-words">Shahi Kitchen – Askim (Sisjön)</h2>
|
||||
|
||||
<div className="space-y-5 text-[15px]">
|
||||
<div>
|
||||
@@ -95,7 +95,7 @@ export default function LocationsPage() {
|
||||
{/* Branch 2: Backaplan */}
|
||||
<div className="bg-white border border-[#EDE6D9] rounded-2xl p-8">
|
||||
<div className="uppercase text-[#B38B4D] text-xs tracking-[2px] mb-2">SWEETS, SNACKS & CAFÉ</div>
|
||||
<h2 className="text-4xl tracking-[-1.5px] mb-4">Shahi Sweets – Backaplan</h2>
|
||||
<h2 className="text-2xl sm:text-3xl md:text-4xl tracking-[-1.5px] mb-4 break-words">Shahi Sweets – Backaplan</h2>
|
||||
|
||||
<div className="space-y-5 text-[15px]">
|
||||
<div>
|
||||
|
||||
+7
-7
@@ -137,7 +137,7 @@ export default function LoginPage() {
|
||||
{t.auth.usernameLabel}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<User className="absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<User className="absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="username"
|
||||
name="username"
|
||||
@@ -146,7 +146,7 @@ export default function LoginPage() {
|
||||
onChange={handleChange}
|
||||
placeholder={t.auth.usernamePlaceholder}
|
||||
required
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -157,7 +157,7 @@ export default function LoginPage() {
|
||||
{t.auth.passwordLabel}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<Lock className="absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Lock className="absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
@@ -166,7 +166,7 @@ export default function LoginPage() {
|
||||
onChange={handleChange}
|
||||
placeholder={t.auth.passwordPlaceholder}
|
||||
required
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -177,21 +177,21 @@ export default function LoginPage() {
|
||||
{t.auth.siteLabel}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<MapPin className="pointer-events-none absolute left-4 top-4 z-10 h-5 w-5 text-[#B38B4D]" />
|
||||
<MapPin className="pointer-events-none absolute start-4 top-4 z-10 h-5 w-5 text-[#B38B4D]" />
|
||||
<select
|
||||
id="site"
|
||||
name="site"
|
||||
value={formData.site}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="w-full cursor-pointer appearance-none rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-10 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full cursor-pointer appearance-none rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-10 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
>
|
||||
<option value="">{t.auth.sitePlaceholder}</option>
|
||||
<option value="askim">{t.auth.askim}</option>
|
||||
<option value="backaplan">{t.auth.backaplan}</option>
|
||||
</select>
|
||||
{/* Custom dropdown arrow for polish */}
|
||||
<div className="pointer-events-none absolute right-4 top-4 text-[#B38B4D]">▾</div>
|
||||
<div className="pointer-events-none absolute end-4 top-4 text-[#B38B4D]">▾</div>
|
||||
</div>
|
||||
<p className="mt-1.5 text-[11px] text-[#8A8478]">Select the location you are working at today.</p>
|
||||
</div>
|
||||
|
||||
+33
-18
@@ -18,6 +18,11 @@ import { useCart } from "@/components/CartContext";
|
||||
import WishlistButton from "@/components/WishlistButton";
|
||||
import { useLanguage } from "@/lib/language-context";
|
||||
import { getTranslation } from "@/lib/translations";
|
||||
import {
|
||||
getCategoryName,
|
||||
getMenuItemDescription,
|
||||
getMenuItemName,
|
||||
} from "@/application/i18n/menu-localization";
|
||||
import {
|
||||
dishImageUrl,
|
||||
getMenuPosterSrc,
|
||||
@@ -45,7 +50,10 @@ export default function MenuPage() {
|
||||
// Sidebar categories
|
||||
const sidebarCategories = [
|
||||
{ id: "All", name: t.menu.allDishes || "All Dishes" },
|
||||
...menuCategories.map((cat) => ({ id: cat.id, name: cat.name })),
|
||||
...menuCategories.map((cat) => ({
|
||||
id: cat.id,
|
||||
name: getCategoryName(language, cat.id, cat.name),
|
||||
})),
|
||||
];
|
||||
|
||||
// Filtering logic
|
||||
@@ -62,11 +70,15 @@ export default function MenuPage() {
|
||||
// Search
|
||||
if (searchQuery.trim()) {
|
||||
const q = searchQuery.toLowerCase().trim();
|
||||
items = items.filter(
|
||||
(item) =>
|
||||
item.name.toLowerCase().includes(q) ||
|
||||
(item.description && item.description.toLowerCase().includes(q))
|
||||
);
|
||||
items = items.filter((item) => {
|
||||
const localizedName = getMenuItemName(language, item).toLowerCase();
|
||||
const localizedDescription = getMenuItemDescription(language, t, item).toLowerCase();
|
||||
return (
|
||||
localizedName.includes(q) ||
|
||||
localizedDescription.includes(q) ||
|
||||
item.name.toLowerCase().includes(q)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Vegetarian
|
||||
@@ -77,7 +89,7 @@ export default function MenuPage() {
|
||||
return { ...category, items };
|
||||
})
|
||||
.filter((category) => category.items.length > 0);
|
||||
}, [searchQuery, showVegetarianOnly, activeCategory]);
|
||||
}, [searchQuery, showVegetarianOnly, activeCategory, language, t]);
|
||||
|
||||
const handleCategorySelect = (id: string) => {
|
||||
setActiveCategory(id);
|
||||
@@ -85,9 +97,9 @@ export default function MenuPage() {
|
||||
};
|
||||
|
||||
const getItemDescription = (item: MenuItem) =>
|
||||
(t as { menuDescriptions?: Record<string, string> }).menuDescriptions?.[item.id] ||
|
||||
item.description ||
|
||||
"";
|
||||
getMenuItemDescription(language, t, item);
|
||||
|
||||
const getItemName = (item: MenuItem) => getMenuItemName(language, item);
|
||||
|
||||
const openDishDetails = (item: MenuItem) => {
|
||||
setDetailItem(item);
|
||||
@@ -173,7 +185,7 @@ export default function MenuPage() {
|
||||
<div className="sticky top-[116px]">
|
||||
<div className="mb-6">
|
||||
<div className="text-xs tracking-[3px] text-[#c99a2e] mb-2">EXPLORE OUR</div>
|
||||
<h3 className="font-serif text-3xl tracking-tight">Signature Categories</h3>
|
||||
<h3 className="font-serif text-2xl sm:text-3xl tracking-tight">Signature Categories</h3>
|
||||
</div>
|
||||
|
||||
{/* Smooth scroll: horizontal on mobile, vertical on desktop when list exceeds viewport */}
|
||||
@@ -265,7 +277,9 @@ export default function MenuPage() {
|
||||
filteredCategories.map((category) => (
|
||||
<div key={category.id} className="mb-16">
|
||||
<div className="flex items-center gap-4 mb-7">
|
||||
<div className="text-3xl tracking-[-1px] text-[#101724]">{category.name}</div>
|
||||
<div className="text-xl sm:text-2xl md:text-3xl tracking-[-1px] text-[#101724] min-w-0 break-words">
|
||||
{getCategoryName(language, category.id, category.name)}
|
||||
</div>
|
||||
<div className="flex-1 h-px bg-gradient-to-r from-[#e5e1d7] to-transparent" />
|
||||
<div className="text-sm font-medium text-[#68717f] tracking-widest">
|
||||
{category.items.length} {t.menu.dishes}
|
||||
@@ -314,7 +328,7 @@ export default function MenuPage() {
|
||||
>
|
||||
<motion.img
|
||||
src={getCardImageSrc(item, category.id)}
|
||||
alt={item.name}
|
||||
alt={getItemName(item)}
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
loading="lazy"
|
||||
whileHover={!isMobile ? {
|
||||
@@ -337,18 +351,18 @@ export default function MenuPage() {
|
||||
)}
|
||||
<div className="absolute top-3 right-3 z-10">
|
||||
<WishlistButton
|
||||
item={{ id: item.id, name: item.name, price: item.price, image: item.image }}
|
||||
item={{ id: item.id, name: getItemName(item), price: item.price, image: item.image }}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6 flex flex-col flex-1">
|
||||
<div className="flex justify-between items-start gap-4 mb-4">
|
||||
<h3 className="text-[22px] leading-tight tracking-[-0.4px] text-[#2C2A26]">
|
||||
{item.name}
|
||||
<div className="flex justify-between items-start gap-3 mb-4 min-w-0">
|
||||
<h3 className="min-w-0 flex-1 text-lg sm:text-[22px] leading-tight tracking-[-0.4px] text-[#2C2A26] break-words">
|
||||
{getItemName(item)}
|
||||
</h3>
|
||||
{renderMenuPrice(item)}
|
||||
<div className="shrink-0">{renderMenuPrice(item)}</div>
|
||||
</div>
|
||||
|
||||
{usesDetailModal ? (
|
||||
@@ -404,6 +418,7 @@ export default function MenuPage() {
|
||||
{detailItem && (
|
||||
<DishDetailsModal
|
||||
item={detailItem}
|
||||
displayName={getItemName(detailItem)}
|
||||
description={getItemDescription(detailItem)}
|
||||
isOpen={!!detailItem}
|
||||
onClose={() => setDetailItem(null)}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { filterMenuItems } from '@/application/menu/filter-menu';
|
||||
|
||||
import { getMenuPosterSrc, logoUrl, SITE_ASSETS } from '@/lib/assets';
|
||||
import { buildTableOrderPayload } from '@/application/table-order/table-order-use-cases';
|
||||
import { parseTableId } from '@/domain/table/table-id';
|
||||
@@ -34,6 +34,11 @@ import type { MenuItem } from '@/domain/menu/entities';
|
||||
import { playAddSound, playSuccessSound } from '@/infrastructure/audio/web-audio-sound-adapter';
|
||||
import { useLanguage } from '@/presentation/providers/language-provider';
|
||||
import { getTranslation } from '@/presentation/i18n/translations';
|
||||
import {
|
||||
getMenuItemDescription,
|
||||
getMenuItemName,
|
||||
localizeOrderLineName,
|
||||
} from '@/application/i18n/menu-localization';
|
||||
import Navbar from '@/components/Navbar';
|
||||
|
||||
import Footer from '@/components/Footer';
|
||||
@@ -66,14 +71,20 @@ export default function OrderFromTablePage() {
|
||||
const tableDisplay = isValid ? parsed.tableNumber : '';
|
||||
|
||||
// Filtered dishes for the selector grid (same data source as everywhere else)
|
||||
const filteredDishes = useMemo(
|
||||
() =>
|
||||
filterMenuItems(allMenuItems, {
|
||||
searchQuery: search,
|
||||
vegetarianOnly: vegOnly,
|
||||
}),
|
||||
[allMenuItems, search, vegOnly]
|
||||
);
|
||||
const filteredDishes = useMemo(() => {
|
||||
const query = search.toLowerCase().trim();
|
||||
return allMenuItems.filter((item) => {
|
||||
if (vegOnly && !item.isVegetarian) return false;
|
||||
if (!query) return true;
|
||||
const localizedName = getMenuItemName(language, item).toLowerCase();
|
||||
const localizedDescription = getMenuItemDescription(language, t, item).toLowerCase();
|
||||
return (
|
||||
localizedName.includes(query) ||
|
||||
localizedDescription.includes(query) ||
|
||||
item.name.toLowerCase().includes(query)
|
||||
);
|
||||
});
|
||||
}, [allMenuItems, search, vegOnly, language, t]);
|
||||
|
||||
const selectedTotal = calculateOrderTotal(selected);
|
||||
|
||||
@@ -231,7 +242,7 @@ export default function OrderFromTablePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto px-6 pt-8 pb-24">
|
||||
<div className={`max-w-6xl mx-auto px-6 pt-8 ${selected.length > 0 ? 'pb-36 lg:pb-24' : 'pb-24'}`}>
|
||||
{/* Intro */}
|
||||
<div className="mb-8">
|
||||
<div className="text-[#B38B4D] text-xs tracking-[3.5px] mb-2 font-medium">{to.tableLabel.toUpperCase()} {tableDisplay}</div>
|
||||
@@ -240,18 +251,18 @@ export default function OrderFromTablePage() {
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-12 gap-8">
|
||||
{/* DISH SELECTOR */}
|
||||
<div className="lg:col-span-7">
|
||||
{/* DISH SELECTOR — below summary on mobile for faster checkout */}
|
||||
<div className="order-2 lg:order-1 lg:col-span-7">
|
||||
{/* Filters */}
|
||||
<div className="mb-5 flex flex-col sm:flex-row gap-3 items-stretch sm:items-center">
|
||||
<div className="relative flex-1">
|
||||
<Search className="pointer-events-none absolute left-4 top-3.5 h-4 w-4 text-[#B38B4D]" />
|
||||
<Search className="pointer-events-none absolute start-4 top-3.5 h-4 w-4 text-[#B38B4D]" />
|
||||
<input
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={to.searchPlaceholder}
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-white py-3 pl-11 pr-4 text-sm placeholder:text-[#8A8478] focus:border-[#B38B4D] focus:ring-1 focus:ring-[#B38B4D]/20 outline-none"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-white py-3 ps-11 pe-4 text-sm placeholder:text-[#8A8478] focus:border-[#B38B4D] focus:ring-1 focus:ring-[#B38B4D]/20 outline-none"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
@@ -273,6 +284,8 @@ export default function OrderFromTablePage() {
|
||||
filteredDishes.map((dish) => {
|
||||
const inOrder = selected.some((s) => s.id === dish.id);
|
||||
const poster = getMenuPosterSrc(dish, 'optimized');
|
||||
const dishName = getMenuItemName(language, dish);
|
||||
const dishDescription = getMenuItemDescription(language, t, dish);
|
||||
return (
|
||||
<motion.button
|
||||
key={dish.id}
|
||||
@@ -283,7 +296,7 @@ export default function OrderFromTablePage() {
|
||||
<div className="relative h-20 w-20 flex-shrink-0 overflow-hidden rounded-xl bg-[#F2EDE4]">
|
||||
<img
|
||||
src={poster}
|
||||
alt={dish.name}
|
||||
alt={dishName}
|
||||
className="absolute inset-0 h-full w-full object-cover group-active:scale-105 transition"
|
||||
onError={(e) => {
|
||||
const target = e.currentTarget as HTMLImageElement;
|
||||
@@ -296,7 +309,7 @@ export default function OrderFromTablePage() {
|
||||
<div className="flex min-w-0 flex-1 flex-col py-0.5">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="font-medium tracking-[-0.2px] text-[15px] leading-tight line-clamp-2 pr-1">
|
||||
{dish.name}
|
||||
{dishName}
|
||||
</div>
|
||||
<div className="shrink-0 text-right font-semibold text-[#B38B4D] tabular-nums text-sm leading-tight">
|
||||
{dish.pricing === 'weight' ? (
|
||||
@@ -313,9 +326,9 @@ export default function OrderFromTablePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{dish.description && (
|
||||
{dishDescription && (
|
||||
<div className="mt-1 text-xs text-[#6B665F] line-clamp-2">
|
||||
{dish.description}
|
||||
{dishDescription}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -338,9 +351,9 @@ export default function OrderFromTablePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ORDER SUMMARY (sticky on desktop) */}
|
||||
<div className="lg:col-span-5">
|
||||
<div className="lg:sticky lg:top-24">
|
||||
{/* ORDER SUMMARY (first on mobile, sticky on desktop) */}
|
||||
<div className="order-1 lg:order-2 lg:col-span-5">
|
||||
<div className="lg:sticky lg:top-[calc(var(--header-height)+5.5rem)]">
|
||||
<div className="rounded-3xl border border-[#EDE6D9] bg-white p-6 shadow-sm">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="font-semibold tracking-tight text-lg">{to.yourOrder}</div>
|
||||
@@ -364,7 +377,7 @@ export default function OrderFromTablePage() {
|
||||
{selected.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-3 rounded-2xl bg-[#F8F5F0] px-4 py-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="font-medium text-[15px] tracking-[-0.2px]">{item.name}</div>
|
||||
<div className="font-medium text-[15px] tracking-[-0.2px]">{localizeOrderLineName(language, item)}</div>
|
||||
<div className="text-xs text-[#6B665F] tabular-nums">
|
||||
{item.pricingMode === 'weight'
|
||||
? `${item.pricePerHalfKg ?? item.price} kr / ½ kg · ${formatLineQuantityLabel(item)}`
|
||||
@@ -376,7 +389,7 @@ export default function OrderFromTablePage() {
|
||||
<div className="flex items-center gap-1.5">
|
||||
<button
|
||||
onClick={() => updateQty(item.id, item.quantity - 1)}
|
||||
className="h-8 w-8 flex items-center justify-center rounded-full border border-[#EDE6D9] bg-white active:bg-white text-lg leading-none active:scale-95"
|
||||
className="h-11 w-11 flex items-center justify-center rounded-full border border-[#EDE6D9] bg-white active:bg-white text-lg leading-none active:scale-95 touch-manipulation"
|
||||
aria-label="Decrease"
|
||||
>
|
||||
−
|
||||
@@ -386,7 +399,7 @@ export default function OrderFromTablePage() {
|
||||
</span>
|
||||
<button
|
||||
onClick={() => updateQty(item.id, item.quantity + 1)}
|
||||
className="h-8 w-8 flex items-center justify-center rounded-full border border-[#EDE6D9] bg-white active:bg-white text-lg leading-none active:scale-95"
|
||||
className="h-11 w-11 flex items-center justify-center rounded-full border border-[#EDE6D9] bg-white active:bg-white text-lg leading-none active:scale-95 touch-manipulation"
|
||||
aria-label="Increase"
|
||||
>
|
||||
+
|
||||
@@ -418,8 +431,8 @@ export default function OrderFromTablePage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Total + Send */}
|
||||
<div className="mt-5 border-t border-[#EDE6D9] pt-5">
|
||||
{/* Total + Send — desktop only; mobile uses sticky bottom bar */}
|
||||
<div className="hidden lg:block mt-5 border-t border-[#EDE6D9] pt-5">
|
||||
<div className="flex items-baseline justify-between text-lg mb-4">
|
||||
<span className="text-[#6B665F]">{to.total}</span>
|
||||
<span className="font-semibold tabular-nums">{selectedTotal} kr</span>
|
||||
@@ -437,6 +450,14 @@ export default function OrderFromTablePage() {
|
||||
Staff will come to your table to confirm.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Mobile: show total inline in summary card */}
|
||||
<div className="lg:hidden mt-5 border-t border-[#EDE6D9] pt-4">
|
||||
<div className="flex items-baseline justify-between text-lg">
|
||||
<span className="text-[#6B665F]">{to.total}</span>
|
||||
<span className="font-semibold tabular-nums">{selectedTotal} kr</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Small context line */}
|
||||
@@ -448,6 +469,27 @@ export default function OrderFromTablePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile sticky order bar */}
|
||||
{selected.length > 0 && (
|
||||
<div className="lg:hidden fixed inset-x-0 bottom-0 z-50 border-t border-[#EDE6D9] bg-white/95 backdrop-blur-xl shadow-[0_-4px_24px_-4px_rgba(16,23,36,0.12)] px-4 py-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]">
|
||||
<div className="mx-auto flex max-w-6xl items-center gap-4">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-xs text-[#6B665F]">
|
||||
{selected.length} {selected.length === 1 ? 'item' : 'items'}
|
||||
</div>
|
||||
<div className="font-semibold tabular-nums text-[#101724]">{selectedTotal} kr</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleSendOrder}
|
||||
disabled={isSending}
|
||||
className="shrink-0 rounded-2xl bg-gradient-to-r from-[#B38B4D] via-[#c99a2e] to-[#B38B4D] px-6 py-3.5 text-sm font-semibold tracking-[0.5px] text-white shadow-lg active:brightness-95 disabled:opacity-60 touch-manipulation"
|
||||
>
|
||||
{isSending ? 'Sending...' : to.sendOrder}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
+10
-5
@@ -17,6 +17,10 @@ import { menuCategories } from "@/lib/menu-data";
|
||||
import { buildCartLineFromMenuItem } from "@/application/cart/cart-line-builder";
|
||||
import type { MenuItem } from "@/domain/menu/entities";
|
||||
import { getTranslation } from "@/lib/translations";
|
||||
import {
|
||||
getMenuItemDescription,
|
||||
getMenuItemName,
|
||||
} from "@/application/i18n/menu-localization";
|
||||
import SignatureMenuMarquee, { type SignatureDish } from "@/components/SignatureMenuMarquee";
|
||||
|
||||
type SignatureFilter = "All" | "Rice" | "Curry" | "Meat" | "Street" | "Roll" | "Sweets";
|
||||
@@ -55,11 +59,12 @@ export default function ShahiKitchenHomepage() {
|
||||
menuCategories.flatMap((category) =>
|
||||
category.items.map((item) => ({
|
||||
...item,
|
||||
desc: item.description ?? "",
|
||||
name: getMenuItemName(language, item),
|
||||
desc: getMenuItemDescription(language, t, item),
|
||||
filterTag: getDishFilterTag(item, category.id),
|
||||
}))
|
||||
),
|
||||
[]
|
||||
[language, t]
|
||||
);
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
@@ -175,9 +180,9 @@ export default function ShahiKitchenHomepage() {
|
||||
{ title: "Shahi Sweets", desc: "Homemade mithai made daily. From fresh Jalebi to Rasmalai — the perfect sweet ending." },
|
||||
{ title: "Warm Hospitality", desc: "Whether you're here for a quick lunch or a family celebration, you will always be treated like Shahi." },
|
||||
]).map((item, index) => (
|
||||
<div key={index} className="experience-card group relative border border-[#EDE6D9] p-9 rounded-2xl bg-[#F8F5F0] overflow-hidden">
|
||||
<div className="text-[#B38B4D] text-6xl font-light mb-9 tracking-[-2px]">0{index + 1}</div>
|
||||
<h4 className="text-[29px] tracking-[-0.8px] mb-5 text-[#2C2A26] leading-tight">{item.title}</h4>
|
||||
<div key={index} className="experience-card group relative border border-[#EDE6D9] p-6 sm:p-9 rounded-2xl bg-[#F8F5F0] overflow-hidden">
|
||||
<div className="text-[#B38B4D] text-4xl sm:text-6xl font-light mb-6 sm:mb-9 tracking-[-2px]">0{index + 1}</div>
|
||||
<h4 className="text-xl sm:text-2xl md:text-[29px] tracking-[-0.8px] mb-4 sm:mb-5 text-[#2C2A26] leading-tight break-words">{item.title}</h4>
|
||||
<p className="text-[#6B665F] text-[15.5px] leading-relaxed">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
|
||||
+48
-33
@@ -26,6 +26,11 @@ import {
|
||||
import { container } from '@/infrastructure/di/container';
|
||||
import { useLanguage } from '@/presentation/providers/language-provider';
|
||||
import { getTranslation } from '@/presentation/i18n/translations';
|
||||
import {
|
||||
getMenuItemDescription,
|
||||
getMenuItemName,
|
||||
localizeOrderLineName,
|
||||
} from '@/application/i18n/menu-localization';
|
||||
import { useState } from 'react';
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { MapPin, Calendar, Clock, Users, User, Phone, Mail, MessageCircle, Plus, Minus, X, ArrowRight, Search, CheckCircle } from "lucide-react";
|
||||
@@ -93,10 +98,16 @@ export default function ReservePage() {
|
||||
// Flatten menu for selector (with search)
|
||||
const allDishes = menuCategories.flatMap((cat) => cat.items);
|
||||
|
||||
const filteredDishes = allDishes.filter((dish) =>
|
||||
dish.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||
(dish.description && dish.description.toLowerCase().includes(search.toLowerCase()))
|
||||
);
|
||||
const filteredDishes = allDishes.filter((dish) => {
|
||||
const q = search.toLowerCase();
|
||||
const localizedName = getMenuItemName(language, dish).toLowerCase();
|
||||
const localizedDescription = getMenuItemDescription(language, t, dish).toLowerCase();
|
||||
return (
|
||||
localizedName.includes(q) ||
|
||||
localizedDescription.includes(q) ||
|
||||
dish.name.toLowerCase().includes(q)
|
||||
);
|
||||
});
|
||||
|
||||
const addToPreOrder = (dish: MenuItem) => {
|
||||
setPreOrder((prev) => addOrderLine(prev, buildCartLineFromMenuItem(dish)));
|
||||
@@ -173,7 +184,7 @@ export default function ReservePage() {
|
||||
<div className="mb-6 inline-flex h-16 w-16 items-center justify-center rounded-2xl border border-[#c99a2e]/30 bg-white/5 p-3 backdrop-blur mx-auto">
|
||||
<img src={logoUrl()} alt="Shahi Kitchen" className="h-full w-full object-contain" />
|
||||
</div>
|
||||
<div className="font-serif text-4xl tracking-[-1.5px] mb-1">Shahi Kitchen</div>
|
||||
<div className="font-serif text-2xl sm:text-3xl md:text-4xl tracking-[-1.5px] mb-1">Shahi Kitchen</div>
|
||||
<div className="text-sm font-medium tracking-[2.5px] text-[#c99a2e] mb-4">TABLE RESERVATIONS</div>
|
||||
<p className="text-sm leading-relaxed text-white/70 max-w-xs mx-auto mb-4">
|
||||
Two locations. Unforgettable evenings. Pre-order your favorites for a perfect arrival.
|
||||
@@ -187,7 +198,7 @@ export default function ReservePage() {
|
||||
<div className="max-w-4xl mx-auto space-y-8">
|
||||
{/* Booking Form Card - now wider (full in max-w-4xl) */}
|
||||
<div className="rounded-3xl border border-[#EDE6D9] bg-white p-6 sm:p-8 shadow-xl md:p-10">
|
||||
<h2 className="text-3xl tracking-tight font-serif mb-2">{t.booking.formTitle}</h2>
|
||||
<h2 className="text-2xl sm:text-3xl tracking-tight font-serif mb-2">{t.booking.formTitle}</h2>
|
||||
<p className="text-[#6B665F] mb-8">Fill in your details to secure your table.</p>
|
||||
|
||||
<form onSubmit={handleContinue} className="space-y-6">
|
||||
@@ -195,21 +206,21 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="location" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.locationLabel}</label>
|
||||
<div className="relative">
|
||||
<MapPin className="pointer-events-none absolute left-4 top-4 z-10 h-5 w-5 text-[#B38B4D]" />
|
||||
<MapPin className="pointer-events-none absolute start-4 top-4 z-10 h-5 w-5 text-[#B38B4D]" />
|
||||
<select
|
||||
id="location"
|
||||
name="location"
|
||||
value={booking.location}
|
||||
onChange={handleBookingChange}
|
||||
required
|
||||
className="w-full cursor-pointer appearance-none rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-10 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full cursor-pointer appearance-none rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-10 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
>
|
||||
<option value="">{t.booking.locationPlaceholder}</option>
|
||||
{locationOptions.map((opt) => (
|
||||
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="pointer-events-none absolute right-4 top-4 text-[#B38B4D]">▾</div>
|
||||
<div className="pointer-events-none absolute end-4 top-4 text-[#B38B4D]">▾</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -218,7 +229,7 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="date" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.dateLabel}</label>
|
||||
<div className="relative">
|
||||
<Calendar className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Calendar className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="date"
|
||||
name="date"
|
||||
@@ -227,7 +238,7 @@ export default function ReservePage() {
|
||||
onChange={handleBookingChange}
|
||||
min={new Date().toISOString().split('T')[0]}
|
||||
required
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -236,7 +247,7 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="time" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.timeLabel}</label>
|
||||
<div className="relative">
|
||||
<Clock className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Clock className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="time"
|
||||
name="time"
|
||||
@@ -244,7 +255,7 @@ export default function ReservePage() {
|
||||
value={booking.time}
|
||||
onChange={handleBookingChange}
|
||||
required
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -254,19 +265,19 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="guests" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.guestsLabel}</label>
|
||||
<div className="relative">
|
||||
<Users className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Users className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<select
|
||||
id="guests"
|
||||
name="guests"
|
||||
value={booking.guests}
|
||||
onChange={handleBookingChange}
|
||||
required
|
||||
className="w-full cursor-pointer appearance-none rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-10 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full cursor-pointer appearance-none rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-10 text-[17px] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
>
|
||||
<option value="">Select</option>
|
||||
{[1,2,3,4,5,6,7,8,9,10].map(n => <option key={n} value={n}>{n}</option>)}
|
||||
</select>
|
||||
<div className="pointer-events-none absolute right-4 top-4 text-[#B38B4D]">▾</div>
|
||||
<div className="pointer-events-none absolute end-4 top-4 text-[#B38B4D]">▾</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -274,7 +285,7 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="name" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.nameLabel}</label>
|
||||
<div className="relative">
|
||||
<User className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<User className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
@@ -283,7 +294,7 @@ export default function ReservePage() {
|
||||
onChange={handleBookingChange}
|
||||
placeholder={t.booking.namePlaceholder}
|
||||
required
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,7 +303,7 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="phone" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.phoneLabel}</label>
|
||||
<div className="relative">
|
||||
<Phone className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Phone className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="phone"
|
||||
name="phone"
|
||||
@@ -301,7 +312,7 @@ export default function ReservePage() {
|
||||
onChange={handleBookingChange}
|
||||
placeholder={t.booking.phonePlaceholder}
|
||||
required
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -310,7 +321,7 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="email" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.emailLabel}</label>
|
||||
<div className="relative">
|
||||
<Mail className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Mail className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
@@ -318,7 +329,7 @@ export default function ReservePage() {
|
||||
value={booking.email}
|
||||
onChange={handleBookingChange}
|
||||
placeholder={t.booking.emailPlaceholder}
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -327,7 +338,7 @@ export default function ReservePage() {
|
||||
<div>
|
||||
<label htmlFor="notes" className="mb-2 block text-sm font-semibold tracking-wide text-[#6B665F]">{t.booking.notesLabel}</label>
|
||||
<div className="relative">
|
||||
<MessageCircle className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<MessageCircle className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<textarea
|
||||
id="notes"
|
||||
name="notes"
|
||||
@@ -335,7 +346,7 @@ export default function ReservePage() {
|
||||
onChange={handleBookingChange}
|
||||
placeholder={t.booking.notesPlaceholder}
|
||||
rows={3}
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20 resize-y"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20 resize-y"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -360,18 +371,18 @@ export default function ReservePage() {
|
||||
exit={{ opacity: 0 }}
|
||||
className="rounded-3xl border border-[#EDE6D9] bg-white p-6 sm:p-8 shadow-xl md:p-10"
|
||||
>
|
||||
<h2 className="text-3xl tracking-tight font-serif mb-2">{t.booking.menuTitle}</h2>
|
||||
<h2 className="text-2xl sm:text-3xl tracking-tight font-serif mb-2">{t.booking.menuTitle}</h2>
|
||||
<p className="text-[#6B665F] mb-6">{t.booking.menuSubtitle}</p>
|
||||
|
||||
{/* Search */}
|
||||
<div className="relative mb-6">
|
||||
<Search className="pointer-events-none absolute left-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<Search className="pointer-events-none absolute start-4 top-4 h-5 w-5 text-[#B38B4D]" />
|
||||
<input
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={t.booking.searchPlaceholder}
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 pl-12 pr-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
className="w-full rounded-2xl border border-[#EDE6D9] bg-[#F8F5F0] py-4 ps-12 pe-4 text-[17px] placeholder:text-[#8A8478] transition-all outline-none focus:border-[#B38B4D] focus:bg-white focus:ring-1 focus:ring-[#B38B4D]/20"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -380,7 +391,11 @@ export default function ReservePage() {
|
||||
{filteredDishes.length > 0 ? (
|
||||
filteredDishes.map((dish) => {
|
||||
const posterSrc = getMenuPosterSrc(dish);
|
||||
const shortDesc = dish.description ? (dish.description.length > 80 ? dish.description.slice(0, 80) + '...' : dish.description) : '';
|
||||
const dishName = getMenuItemName(language, dish);
|
||||
const dishDescription = getMenuItemDescription(language, t, dish);
|
||||
const shortDesc = dishDescription
|
||||
? (dishDescription.length > 80 ? dishDescription.slice(0, 80) + '...' : dishDescription)
|
||||
: '';
|
||||
const isAdded = preOrder.some((p) => p.id === dish.id);
|
||||
return (
|
||||
<motion.div
|
||||
@@ -390,13 +405,13 @@ export default function ReservePage() {
|
||||
onMouseEnter={() => playHoverSound()}
|
||||
>
|
||||
{/* Item Name */}
|
||||
<div className="font-semibold tracking-[-0.3px] text-base mb-1 text-[#2C2A26] line-clamp-1">{dish.name}</div>
|
||||
<div className="font-semibold tracking-[-0.3px] text-base mb-1 text-[#2C2A26] line-clamp-1">{dishName}</div>
|
||||
|
||||
{/* Poster under name */}
|
||||
<div className="relative w-full h-24 sm:h-28 md:h-32 rounded-xl overflow-hidden border border-[#EDE6D9] mb-2 bg-[#F8F5F0]">
|
||||
<img
|
||||
src={posterSrc}
|
||||
alt={dish.name}
|
||||
alt={dishName}
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
loading="lazy"
|
||||
onError={(e) => {
|
||||
@@ -464,11 +479,11 @@ export default function ReservePage() {
|
||||
{/* Small poster thumbnail in summary for better visualization */}
|
||||
<img
|
||||
src={thumb}
|
||||
alt={item.name}
|
||||
alt={localizeOrderLineName(language, item)}
|
||||
className="w-10 h-10 object-cover rounded-lg border border-[#EDE6D9] flex-shrink-0"
|
||||
/>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-sm truncate">{item.name}</div>
|
||||
<div className="font-medium text-sm truncate">{localizeOrderLineName(language, item)}</div>
|
||||
<div className="text-[10px] text-[#6B665F]">
|
||||
{item.pricingMode === 'weight'
|
||||
? `${item.pricePerHalfKg ?? item.price} kr / ½ kg · ${formatLineQuantityLabel(item)}`
|
||||
@@ -520,7 +535,7 @@ export default function ReservePage() {
|
||||
<div className="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-[#B38B4D]/10">
|
||||
<CheckCircle className="h-10 w-10 text-[#B38B4D]" />
|
||||
</div>
|
||||
<h2 className="text-4xl tracking-tight font-serif mb-4">{t.booking.successTitle}</h2>
|
||||
<h2 className="text-2xl sm:text-3xl md:text-4xl tracking-tight font-serif mb-4 break-words">{t.booking.successTitle}</h2>
|
||||
<p className="text-[#6B665F] mb-8 leading-relaxed">{t.booking.successMessage}</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
||||
|
||||
Reference in New Issue
Block a user