Skip to content

Commit 09a4079

Browse files
committed
Fix CI: route menus via ?type=<code>, not a dynamic [code] segment
`next.config.ts` sets `output: "export"` for production, which forbids runtime-discovered dynamic route params — `generateStaticParams()` must enumerate every path at build time and menu codes are defined in the database. The `/[locale]/menu/[code]/page.tsx` route I added in Phase 5 broke `next build`: Error: Page "/[locale]/menu/[code]" is missing "generateStaticParams()" so it cannot be used with "output: export" config. Reverts to the existing query-param routing pattern: the menu code is read from `?type=<code>`, generalising the legacy `?type=drinks` value that existing QR codes already use. The home page links to `/menu?type=<code>` per published menu. Drops the `[code]/page.tsx` route entirely, the redirect side-effect, and the `useRouter` mock in the test fixture. Backwards compat: `?type=drinks` still resolves to the menu coded `drinks` if present, falling back to `takeaway` for the legacy seed.
1 parent 9c20376 commit 09a4079

4 files changed

Lines changed: 17 additions & 41 deletions

File tree

web/src/app/[locale]/menu/MenuPageClient.test.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ import { render, screen, fireEvent } from '@testing-library/react';
66
const loadRestaurantMock = vi.fn();
77
const chatPanelMock = vi.fn(() => <div data-testid="chat-panel" />);
88

9-
const routerReplaceMock = vi.fn();
10-
119
vi.mock('next/navigation', () => ({
12-
useParams: () => ({ locale: 'it', code: 'food' }),
10+
useParams: () => ({ locale: 'it' }),
1311
useSearchParams: () => new URLSearchParams(''),
14-
useRouter: () => ({ replace: routerReplaceMock, push: vi.fn(), prefetch: vi.fn(), back: vi.fn(), forward: vi.fn(), refresh: vi.fn() }),
1512
}));
1613

1714
vi.mock('@/lib/i18n', () => ({

web/src/app/[locale]/menu/MenuPageClient.tsx

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useEffect, useState, useRef, useMemo } from "react";
44
import { useTranslations } from "@/lib/i18n";
55
import Image from "next/image";
6-
import { useParams, useRouter, useSearchParams } from "next/navigation";
6+
import { useParams, useSearchParams } from "next/navigation";
77
import { useRestaurantStore, useCategories } from "@/stores/restaurantStore";
88
import { MenuItemDetail } from "@/components/menu/MenuItemDetail";
99
import { RestaurantInfoModal } from "@/components/menu/RestaurantInfoModal";
@@ -26,10 +26,12 @@ type MenuEntryWithDetails = MenuEntry & { description?: string; image?: string;
2626
export default function MenuPageClient() {
2727
const t = useTranslations();
2828
const params = useParams();
29-
const router = useRouter();
3029
const searchParams = useSearchParams();
3130
const locale = params.locale as string;
32-
const menuCodeParam = (params.code as string | undefined) ?? undefined;
31+
// Menu code lives in the query string (?type=<code>) because `output: "export"`
32+
// forbids runtime-discovered dynamic route params. The legacy `?type=drinks`
33+
// value is honored as an alias for any 'drinks'- or 'takeaway'-coded menu.
34+
const typeParam = searchParams.get("type") ?? undefined;
3335
const aiChatDevOverride = process.env.NODE_ENV !== 'production' && searchParams.get('aiChat') === '1';
3436
const hasChatWorker = Boolean(process.env.NEXT_PUBLIC_CHAT_WORKER_URL);
3537
const { data, isLoading, error, loadRestaurant } = useRestaurantStore();
@@ -86,31 +88,24 @@ export default function MenuPageClient() {
8688
sessionStorage.setItem('promo_seen', '1');
8789
};
8890

89-
// Resolve the current menu from the route param. Falls back to the first published menu
90-
// when the user lands on /menu without a code (handled below by a redirect).
91+
// Resolve the current menu from `?type=<code>`. Falls back to the first published menu
92+
// when no `type` is in the query string. The legacy value `drinks` aliases to any menu
93+
// coded `drinks` (or `takeaway` for old QR codes from before the rename).
9194
const publishedMenus = useMemo(
9295
() => (data?.menus ?? []).filter((m) => m.published),
9396
[data?.menus],
9497
);
9598
const currentMenu = useMemo(() => {
9699
if (!data) return undefined;
97-
if (menuCodeParam) {
98-
return data.menus.find((m) => m.code === menuCodeParam);
99-
}
100-
// Legacy /menu?type=drinks shim: pick a 'drinks' or 'takeaway'-coded menu if present.
101-
const legacyType = searchParams.get("type");
102-
if (legacyType === "drinks") {
103-
return publishedMenus.find((m) => m.code === "drinks") || publishedMenus.find((m) => m.code === "takeaway");
100+
if (typeParam) {
101+
const direct = data.menus.find((m) => m.code === typeParam);
102+
if (direct) return direct;
103+
if (typeParam === "drinks") {
104+
return publishedMenus.find((m) => m.code === "takeaway");
105+
}
104106
}
105107
return publishedMenus[0];
106-
}, [data, menuCodeParam, publishedMenus, searchParams]);
107-
108-
// If we're on /menu (no code) and the data is loaded, redirect to the resolved menu's URL.
109-
useEffect(() => {
110-
if (!data || menuCodeParam) return;
111-
if (!currentMenu) return;
112-
router.replace(`/${locale}/menu/${currentMenu.code}`);
113-
}, [data, menuCodeParam, currentMenu, locale, router]);
108+
}, [data, typeParam, publishedMenus]);
114109

115110
const isVisible = (entry: MenuEntry) => {
116111
if (!currentMenu) return false;

web/src/app/[locale]/menu/[code]/page.tsx

Lines changed: 0 additions & 16 deletions
This file was deleted.

web/src/app/[locale]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export default function HomePage() {
179179
return (
180180
<Link
181181
key={menu.id}
182-
href={`/${locale}/menu/${menu.code}`}
182+
href={`/${locale}/menu?type=${menu.code}`}
183183
data-locale-anchor={`home:menu-${menu.code}`}
184184
className="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center justify-center aspect-square hover:shadow-xl transition-shadow"
185185
>

0 commit comments

Comments
 (0)