diff --git a/app/globals.css b/app/globals.css index 00e4b31..56ad480 100644 --- a/app/globals.css +++ b/app/globals.css @@ -55,6 +55,11 @@ scroll-margin-top: var(--header-height); } +/* Prevent horizontal scroll from overflowing children */ +html { + overflow-x: clip; +} + /* Base */ body, .shahi-body { diff --git a/app/layout.tsx b/app/layout.tsx index 2fd67c1..9e838be 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -113,7 +113,7 @@ export default function RootLayout({ {children} - + diff --git a/app/locations/page.tsx b/app/locations/page.tsx index edfd503..95e024c 100644 --- a/app/locations/page.tsx +++ b/app/locations/page.tsx @@ -55,7 +55,7 @@ export default function LocationsPage() { {/* Branch 1: Askim */}
RESTAURANT & BUFFET
-

Shahi Kitchen – Askim (Sisjön)

+

Shahi Kitchen – Askim (Sisjön)

@@ -95,7 +95,7 @@ export default function LocationsPage() { {/* Branch 2: Backaplan */}
SWEETS, SNACKS & CAFÉ
-

Shahi Sweets – Backaplan

+

Shahi Sweets – Backaplan

diff --git a/app/login/page.tsx b/app/login/page.tsx index fce4154..737631c 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -137,7 +137,7 @@ export default function LoginPage() { {t.auth.usernameLabel}
- +
@@ -157,7 +157,7 @@ export default function LoginPage() { {t.auth.passwordLabel}
- +
@@ -177,21 +177,21 @@ export default function LoginPage() { {t.auth.siteLabel}
- + {/* Custom dropdown arrow for polish */} -
+

Select the location you are working at today.

diff --git a/app/menu/page.tsx b/app/menu/page.tsx index 52b441a..5565399 100644 --- a/app/menu/page.tsx +++ b/app/menu/page.tsx @@ -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 }).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() {
EXPLORE OUR
-

Signature Categories

+

Signature Categories

{/* Smooth scroll: horizontal on mobile, vertical on desktop when list exceeds viewport */} @@ -265,7 +277,9 @@ export default function MenuPage() { filteredCategories.map((category) => (
-
{category.name}
+
+ {getCategoryName(language, category.id, category.name)} +
{category.items.length} {t.menu.dishes} @@ -314,7 +328,7 @@ export default function MenuPage() { >
-
-

- {item.name} +
+

+ {getItemName(item)}

- {renderMenuPrice(item)} +
{renderMenuPrice(item)}
{usesDetailModal ? ( @@ -404,6 +418,7 @@ export default function MenuPage() { {detailItem && ( setDetailItem(null)} diff --git a/app/orderfromtable/OrderFromTableClient.tsx b/app/orderfromtable/OrderFromTableClient.tsx index 7590ad0..8e4f2bb 100644 --- a/app/orderfromtable/OrderFromTableClient.tsx +++ b/app/orderfromtable/OrderFromTableClient.tsx @@ -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() {

-
+
0 ? 'pb-36 lg:pb-24' : 'pb-24'}`}> {/* Intro */}
{to.tableLabel.toUpperCase()} {tableDisplay}
@@ -240,18 +251,18 @@ export default function OrderFromTablePage() {
- {/* DISH SELECTOR */} -
+ {/* DISH SELECTOR — below summary on mobile for faster checkout */} +
{/* Filters */}
- + 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" />
- {/* ORDER SUMMARY (sticky on desktop) */} -
-
+ {/* ORDER SUMMARY (first on mobile, sticky on desktop) */} +
+
{to.yourOrder}
@@ -364,7 +377,7 @@ export default function OrderFromTablePage() { {selected.map((item) => (
-
{item.name}
+
{localizeOrderLineName(language, item)}
{item.pricingMode === 'weight' ? `${item.pricePerHalfKg ?? item.price} kr / ½ kg · ${formatLineQuantityLabel(item)}` @@ -376,7 +389,7 @@ export default function OrderFromTablePage() {
- {/* Total + Send */} -
+ {/* Total + Send — desktop only; mobile uses sticky bottom bar */} +
{to.total} {selectedTotal} kr @@ -437,6 +450,14 @@ export default function OrderFromTablePage() { Staff will come to your table to confirm.

+ + {/* Mobile: show total inline in summary card */} +
+
+ {to.total} + {selectedTotal} kr +
+
{/* Small context line */} @@ -448,6 +469,27 @@ export default function OrderFromTablePage() {
+ {/* Mobile sticky order bar */} + {selected.length > 0 && ( +
+
+
+
+ {selected.length} {selected.length === 1 ? 'item' : 'items'} +
+
{selectedTotal} kr
+
+ +
+
+ )} +
); diff --git a/app/page.tsx b/app/page.tsx index cb73200..5e7d16a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -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) => ( -
-
0{index + 1}
-

{item.title}

+
+
0{index + 1}
+

{item.title}

{item.desc}

))} diff --git a/app/reserve/page.tsx b/app/reserve/page.tsx index 6dd07a4..8a79a23 100644 --- a/app/reserve/page.tsx +++ b/app/reserve/page.tsx @@ -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() {
Shahi Kitchen
-
Shahi Kitchen
+
Shahi Kitchen
TABLE RESERVATIONS

Two locations. Unforgettable evenings. Pre-order your favorites for a perfect arrival. @@ -187,7 +198,7 @@ export default function ReservePage() {

{/* Booking Form Card - now wider (full in max-w-4xl) */}
-

{t.booking.formTitle}

+

{t.booking.formTitle}

Fill in your details to secure your table.

@@ -195,21 +206,21 @@ export default function ReservePage() {
- + -
+
@@ -218,7 +229,7 @@ export default function ReservePage() {
- +
@@ -236,7 +247,7 @@ export default function ReservePage() {
- +
@@ -254,19 +265,19 @@ export default function ReservePage() {
- + -
+
@@ -274,7 +285,7 @@ export default function ReservePage() {
- +
@@ -292,7 +303,7 @@ export default function ReservePage() {
- +
@@ -310,7 +321,7 @@ export default function ReservePage() {
- +
@@ -327,7 +338,7 @@ export default function ReservePage() {
- +