Replace entire repo content with updated code from /root/shahikitchen-website/
This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user