Skip to content

Commit c0ba2ac

Browse files
Add eight-language countertop noodle cooker selection (#183)
1 parent f406ab4 commit c0ba2ac

14 files changed

Lines changed: 240 additions & 143 deletions

‎scripts/generate-static-pages.ts‎

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ import InductionCookingContent, { type InductionLocale } from '../src/features/c
4242
import ChineseCookingContent from '../src/features/commercial-kitchen/ChineseCookingContent';
4343
import { hotCookingPath } from '../src/features/commercial-kitchen/routes.mjs';
4444
import { inductionPage, getInductionPage, inductionPageSchema, zhHotCookingPage, chineseCookingSchema } from '../src/features/commercial-kitchen/data/inductionPage.mjs';
45-
import SteamCabinetContent from '../src/features/commercial-kitchen/SteamCabinetContent';
46-
import { getSteamCabinetPage, steamCabinetSchema } from '../src/features/commercial-kitchen/data/steamCabinetPage.mjs';
47-
import { steamCabinetPath } from '../src/features/commercial-kitchen/routes.mjs';
48-
const steamCabinetRelPath = steamCabinetPath.slice(1);
45+
import CookingSelectionContent from '../src/features/commercial-kitchen/CookingSelectionContent';
46+
import { cookingSelectionGroup, getCookingSelectionPage, cookingSelectionSchema } from '../src/features/commercial-kitchen/data/cookingSelectionPages.mjs';
47+
import { steamCabinetPath, noodleCookerPath } from '../src/features/commercial-kitchen/routes.mjs';
48+
const cookingSelectionRelPaths = [steamCabinetPath, noodleCookerPath].map(path => path.slice(1));
4949
const inductionRelPath = inductionPage.path.slice(1, -1);
5050
const hotCookingRelPath = hotCookingPath.slice(1);
5151
import RefrigerationModelCatalogue from '../src/features/refrigeration/RefrigerationModelCatalogue';
@@ -1793,15 +1793,15 @@ function injectStaticRouteContent(
17931793
renderToStaticMarkup(createElement(CatalogueHeroMedia, {src:'/commercial-kitchen-media/kitchen-hero.webp',
17941794
alt:'Commercial kitchen application',scene:true,items:kitchenHeroItems})));
17951795
htmlContent = htmlContent.replace(/<script id="schema-jsonld-static-page"[^>]*>[\s\S]*?<\/script>/, `<script id="schema-jsonld-static-page" type="application/ld+json">${JSON.stringify(kitchenStructuredData(kitchenLaunch)).replace(/</g, '\\u003c')}</script>`);
1796-
} else if (relPath === inductionRelPath || relPath === hotCookingRelPath || relPath === steamCabinetRelPath) {
1796+
} else if (relPath === inductionRelPath || relPath === hotCookingRelPath || cookingSelectionRelPaths.includes(relPath)) {
17971797
const hotCooking = relPath === hotCookingRelPath;
1798-
const steamCabinet = relPath === steamCabinetRelPath;
1798+
const selectionGroup = cookingSelectionGroup('/' + relPath);
17991799
const locale = (lang === 'zh-cn' ? 'zh' : lang) as InductionLocale;
18001800
staticBody = hotCooking
18011801
? renderToStaticMarkup(createElement(ChineseCookingContent, { page: zhHotCookingPage }))
1802-
: steamCabinet ? renderToStaticMarkup(createElement(SteamCabinetContent, { locale }))
1802+
: selectionGroup ? renderToStaticMarkup(createElement(CookingSelectionContent, { group: selectionGroup, locale }))
18031803
: renderToStaticMarkup(createElement(InductionCookingContent, { locale }));
1804-
const schema = JSON.stringify(hotCooking ? chineseCookingSchema(zhHotCookingPage) : steamCabinet ? steamCabinetSchema(locale) : inductionPageSchema(locale)).replace(/</g, '\\u003c');
1804+
const schema = JSON.stringify(hotCooking ? chineseCookingSchema(zhHotCookingPage) : selectionGroup ? cookingSelectionSchema(selectionGroup, locale) : inductionPageSchema(locale)).replace(/</g, '\\u003c');
18051805
htmlContent = htmlContent.replace(/<script id="schema-jsonld-static-page"[^>]*>[\s\S]*?<\/script>/g, '');
18061806
htmlContent = htmlContent.replace('</head>', `<script id="schema-jsonld-static-page" type="application/ld+json">${schema}</script></head>`);
18071807
} else if (kitchenCategories.some(category => category.path === `/${relPath}/`)) {
@@ -1964,7 +1964,7 @@ function run() {
19641964
...mobilePages.map(page => ({path:page.path.slice(1),priority:'0.9',changefreq:'monthly',languages:[...overviewLanguages]})),
19651965
...['screen-protectors','screen-protectors/compare'].map(path => ({ path, priority: '0.8', changefreq: 'monthly', languages: overviewLanguages.filter(l=>l!=='en') })),
19661966
...buyerGuides.map(guide => ({ path: guide.path.slice(1), priority: '0.8', changefreq: 'monthly', languages: overviewLanguages })),
1967-
{ path: steamCabinetRelPath, priority: '0.8', changefreq: 'monthly', languages: overviewLanguages },
1967+
...cookingSelectionRelPaths.map(path => ({ path, priority: '0.8', changefreq: 'monthly', languages: overviewLanguages })),
19681968
{ path: inductionRelPath, priority: '0.8', changefreq: 'monthly', languages: overviewLanguages },
19691969
{ path: hotCookingRelPath, priority: '0.8', changefreq: 'monthly', languages: ['zh-cn'] },
19701970
...kitchenCategories.map(category => ({ path: category.path.replace(/^\/|\/$/g, ''), priority: '0.8', changefreq: 'monthly', languages: overviewLanguages })),
@@ -2088,8 +2088,9 @@ function run() {
20882088
const meta = buyerMeta(buyerGuide, lang);
20892089
seo = { title: meta.title, desc: meta.description, keywords: '', image: meta.image };
20902090
}
2091-
if (entry.path === inductionRelPath || entry.path === hotCookingRelPath || entry.path === steamCabinetRelPath) {
2092-
const page = entry.path === hotCookingRelPath ? zhHotCookingPage : entry.path === steamCabinetRelPath ? getSteamCabinetPage(lang) : getInductionPage(lang);
2091+
if (entry.path === inductionRelPath || entry.path === hotCookingRelPath || cookingSelectionRelPaths.includes(entry.path)) {
2092+
const selectionGroup = cookingSelectionGroup('/' + entry.path);
2093+
const page = entry.path === hotCookingRelPath ? zhHotCookingPage : selectionGroup ? getCookingSelectionPage(selectionGroup, lang) : getInductionPage(lang);
20932094
seo = { title: page.title, desc: page.description, keywords: '', image: page.image };
20942095
}
20952096
const equipmentCategory = kitchenCategories.find(category => category.path === `/${entry.path}/`);

‎scripts/kitchen-static-content.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { equipmentFilters, legacyHotGroups } from '../src/features/commercial-ki
22
import {quantityBand} from '../src/features/commercial-kitchen/data/model.mjs';
33
import { kitchenPurchasePaths, orderSupportPaths } from '../src/features/commercial-kitchen/data/purchase-paths.mjs';
44
import { kitchenFaq } from '../src/features/commercial-kitchen/data/discovery.mjs';
5-
import { steamCabinetPath } from '../src/features/commercial-kitchen/routes.mjs';
5+
import { steamCabinetPath, noodleCookerPath } from '../src/features/commercial-kitchen/routes.mjs';
66
import { kitchenModelHref } from '../src/features/commercial-kitchen/data/categories.mjs';
77
const escape = value => String(value).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
88

@@ -23,7 +23,7 @@ export function renderKitchenStaticContent(products, launch, heroMedia = '') {
2323
<h2 id="commercial-kitchen-equipment">Compare commercial kitchen equipment</h2><p>${products.length} models. Eight with indicative reference prices.</p>
2424
<span id="kitchen-induction-range"></span><span id="coffee-machine-catalogue"></span>
2525
${Object.keys(legacyHotGroups).map(id=>`<span id="${id}"></span>`).join('')}
26-
<nav aria-label="Equipment ranges">${equipmentFilters.flatMap(item=>item.links).map(item=>`<a href="${item.path}">${escape(item.label)} ↗</a>`).join(' · ')} · <a href="${steamCabinetPath}/">Commercial induction steam cabinets ↗</a></nav>
26+
<nav aria-label="Equipment ranges">${equipmentFilters.flatMap(item=>item.links).map(item=>`<a href="${item.path}">${escape(item.label)} ↗</a>`).join(' · ')} · <a href="${steamCabinetPath}/">Commercial induction steam cabinets ↗</a> · <a href="${noodleCookerPath}/">Commercial countertop noodle cookers ↗</a></nav>
2727
<div>${[...featured, ...products.filter(p => !launch.featuredProductIds.includes(p.id))].map((p,index) => `${index===8?'<details class="catalog-rest"><summary>View all models</summary>':''}<article id="model-${escape(p.id)}">${p.handbookGroup?`<span id="catalog-${escape(p.id)}"></span>`: ''}<img src="${escape(p.image)}" alt="${escape(p.model + ' ' + p.name)}" width="420" height="290" loading="lazy" />
2828
<h3>${escape(p.model)} — ${escape(p.name)}</h3><p>${escape(p.metric)} · ${escape(p.dimensions)}</p>
2929
<dl>${Object.entries(p.specs).map(([key, value]) => `<dt>${escape(key)}</dt><dd>${escape(value)}</dd>`).join('')}</dl>

‎src/App.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { steamCabinetPages } from "./features/commercial-kitchen/data/steamCabinetPage.mjs";
1+
import { cookingSelectionPages } from "./features/commercial-kitchen/data/cookingSelectionPages.mjs";
22
import { inductionPages, zhHotCookingPage } from './features/commercial-kitchen/data/inductionPage.mjs';
33
import {isNewMarket} from './features/freight/new-markets/model';
44
import './features/freight/market-preparation.css';
@@ -481,7 +481,7 @@ export default function App() {
481481
{Object.values(navigationPrefixes).filter(Boolean).flatMap(prefix=>[kitchenPackagePath,...kitchenPackageScenarioPaths].map(path=><Route key={prefix+path} path={prefix+path} element={<LocalizedPackagePage/>}/>))}
482482
<Route path={kitchenPackagePath} element={<RestaurantKitchenPackages />} />
483483
<Route path={`${kitchenPackagePath}/:scenarioSlug`} element={<RestaurantKitchenScenario />} />
484-
{[...inductionPages, ...steamCabinetPages, zhHotCookingPage].map(page => <Route key={page.path} path={page.path} element={<InductionCookingPage/>}/>)}
484+
{[...inductionPages, ...cookingSelectionPages, zhHotCookingPage].map(page => <Route key={page.path} path={page.path} element={<InductionCookingPage/>}/>)}
485485
{kitchenCategoryPaths.flatMap(path => Object.values(navigationPrefixes).map(prefix=><Route key={prefix+path} path={prefix+path} element={prefix?<LocalizedCategoryPage/>:<KitchenCategoryPage/>}/>))}
486486
{Object.values(navigationPrefixes).filter(Boolean).map(prefix=><Route key={prefix+'audio'} path={prefix+'/sourcing/audio-speakers-from-china'} element={<LocalizedAudioPage/>}/>)}
487487
{Object.values(navigationPrefixes).map(prefix=><Route key={prefix+'coffee'} path={prefix+coffeePath} element={<CoffeePage/>}/>)}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { SharedKitchenListBar } from './components/SharedKitchenList';
2+
import InductionCatalogue from './components/InductionCatalogue';
3+
import { cookingSelectionBreadcrumb, cookingSelections } from './data/cookingSelectionPages.mjs';
4+
import catalogueCopy from './locales/planning/induction-catalogue.json';
5+
import navigationCopy from './locales/planning/induction-use.json';
6+
7+
export default function CookingSelectionContent({ group, locale, onAdd, count = 0, status = '' }: {
8+
group: keyof typeof cookingSelections;
9+
locale: keyof typeof catalogueCopy;
10+
onAdd?: (id: string) => void;
11+
count?: number;
12+
status?: string;
13+
}) {
14+
const { copy, id, models } = cookingSelections[group];
15+
const text = copy[locale];
16+
const breadcrumb = cookingSelectionBreadcrumb(group, locale);
17+
const heroModel = models[1];
18+
const names = 'doors' in text ? text.doors : catalogueCopy[locale].noodleNames;
19+
const selectionId = id + '-selection';
20+
const titleId = selectionId + '-title';
21+
const installationId = id + '-installation';
22+
return <main id="main-content" className={`ddnz-kitchen kitchen-brand induction-page ${id}-page`}
23+
lang={locale === 'zh' ? 'zh-CN' : locale} dir={locale === 'ar' ? 'rtl' : 'ltr'}>
24+
<nav className="kitchen-breadcrumb wrap" aria-label={navigationCopy[locale].labels[4]}><ol>
25+
{breadcrumb.slice(0, -1).map(([name, path]) => <li key={path}><a href={path}>{name}</a></li>)}
26+
<li aria-current="page">{text.label}</li>
27+
</ol></nav>
28+
<section className="section wrap induction-intro-section">
29+
<div className="induction-intro-copy">
30+
<h1>{text.heading}</h1>
31+
<p>{text.intro}</p>
32+
<div className="induction-page-actions">
33+
<a className="button primary" href={'#' + selectionId}>{text.choose} ↓</a>
34+
{'installation' in text && <a className="text-link" href={'#' + installationId}>{text.installation} ↓</a>}
35+
</div>
36+
</div>
37+
<figure className="induction-hero-photo">
38+
<img src={heroModel.image} alt={names[1]} width="1536" height="1024" fetchPriority="high"/>
39+
<figcaption><bdi>{heroModel.model}</bdi></figcaption>
40+
</figure>
41+
</section>
42+
<SharedKitchenListBar locale={locale} count={count} status={status}/>
43+
<section className="section wrap induction-use-section" id={selectionId} aria-labelledby={titleId}>
44+
<h2 id={titleId}>{text.choose}</h2>
45+
<nav className="induction-use-nav" aria-labelledby={titleId}>
46+
{models.map((model, index) => <a key={model.id} href={'#model-' + model.id}>
47+
<img src={model.image} width="100" height="78" alt="" loading="lazy"/>
48+
<span><strong>{names[index]} <span aria-hidden="true">↓</span></strong><span><bdi>{model.model}</bdi></span></span>
49+
</a>)}
50+
</nav>
51+
{'note' in text && <p className="noodle-configuration-note">{text.note}</p>}
52+
</section>
53+
<InductionCatalogue locale={locale} group={group} expanded showTotal standaloneSelection onAdd={onAdd}/>
54+
{'checks' in text && <section className="section wrap induction-quote-checks" id={installationId}>
55+
<h2>{text.installation}</h2>
56+
<div className="induction-site-checks">
57+
{text.checks.map(([heading, body]) => <article key={heading}><h3>{heading}</h3><p>{body}</p></article>)}
58+
</div>
59+
</section>}
60+
</main>;
61+
}

‎src/features/commercial-kitchen/InductionCookingPage.tsx‎

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import SEO from '../../components/SEO';
55
import SourcingHomepageNav from '../../components/SourcingHomepageNav';
66
import Footer from '../../components/Footer';
77
import { productAlternates, productRouteParts } from '../../lib/productLocalization.mjs';
8-
import SteamCabinetContent from './SteamCabinetContent';
9-
import { getSteamCabinetPage, steamCabinetSchema } from './data/steamCabinetPage.mjs';
10-
import { steamCabinetPath } from './routes.mjs';
8+
import CookingSelectionContent from './CookingSelectionContent';
9+
import { cookingSelectionGroup, getCookingSelectionPage, cookingSelectionSchema } from './data/cookingSelectionPages.mjs';
1110
import ChineseCookingContent from './ChineseCookingContent';
1211
import InductionCookingContent, { type InductionLocale } from './InductionCookingContent';
1312
import { sharedKitchenListHref, useSharedKitchenList } from './components/SharedKitchenList';
@@ -21,20 +20,20 @@ export default function InductionCookingPage() {
2120
const normalized = pathname.replace(/\/$/, '') + '/';
2221
const hotCooking = normalized === zhHotCookingPage.path;
2322
const route = productRouteParts(pathname);
24-
const steamCabinet = route.path === steamCabinetPath;
23+
const selectionGroup = cookingSelectionGroup(route.path);
2524
const locale = route.locale as InductionLocale;
26-
const page = hotCooking ? zhHotCookingPage : steamCabinet ? getSteamCabinetPage(locale) : getInductionPage(locale);
25+
const page = hotCooking ? zhHotCookingPage : selectionGroup ? getCookingSelectionPage(selectionGroup, locale) : getInductionPage(locale);
2726
const sharedList = useSharedKitchenList(locale);
2827
const quotePath = sharedKitchenListHref(locale);
2928

3029
useEffect(() => {
3130
document.getElementById('schema-jsonld-static-page')?.remove();
3231
const schema = document.createElement('script');
3332
schema.type = 'application/ld+json';
34-
schema.textContent = JSON.stringify(hotCooking ? chineseCookingSchema(zhHotCookingPage) : steamCabinet ? steamCabinetSchema(locale) : inductionPageSchema(locale));
33+
schema.textContent = JSON.stringify(hotCooking ? chineseCookingSchema(zhHotCookingPage) : selectionGroup ? cookingSelectionSchema(selectionGroup, locale) : inductionPageSchema(locale));
3534
document.head.appendChild(schema);
3635
return () => schema.remove();
37-
}, [hotCooking, steamCabinet, locale]);
36+
}, [hotCooking, selectionGroup, locale]);
3837

3938
useEffect(() => {
4039
if (!hash) return;
@@ -49,8 +48,8 @@ export default function InductionCookingPage() {
4948
<SourcingHomepageNav quotePath={quotePath} supportedLanguages={hotCooking ? ['zh'] : undefined}/>
5049
{hotCooking
5150
? <ChineseCookingContent page={zhHotCookingPage} onAdd={sharedList.add} count={sharedList.count} status={sharedList.status}/>
52-
: steamCabinet
53-
? <SteamCabinetContent locale={locale} onAdd={sharedList.add} count={sharedList.count} status={sharedList.status}/>
51+
: selectionGroup
52+
? <CookingSelectionContent group={selectionGroup} locale={locale} onAdd={sharedList.add} count={sharedList.count} status={sharedList.status}/>
5453
: <InductionCookingContent locale={locale} onAdd={sharedList.add} count={sharedList.count} status={sharedList.status}/>}
5554
<Footer quotePath={quotePath} pageKey="commercial_kitchen" description={page.description}/>
5655
</>;

‎src/features/commercial-kitchen/SteamCabinetContent.tsx‎

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

0 commit comments

Comments
 (0)