M46 Error Page
Read the following context files first:
- docs/PRD/07_Modules_and_Templates.md
- docs/dev-frontend-guides/03_MODULE_DEVELOPMENT_LIFECYCLE.md
- docs/dev-frontend-guides/05_BEM_SASS_THEMING.md
- docs/dev-frontend-guides/01_FIGMA_TO_CODE_WORKFLOW.md
- docs/dev-frontend-guides/04_STORYBOOK_FIRST_DEVELOPMENT.md
- packages/modules/src/m06-hero-simple/ (all files in this directory)
- packages/modules/src/registry.ts
- packages/ui/src/ (scan for available UI components)
Now create a new module with the following details:
Module ID: M46 Module Name: Error Page Figma Desktop 404: https://www.figma.com/design/VFdCObxYyZjSRFdK5pU1df/01_Savoy_library?node-id=1513-242605&m=dev Figma Desktop 500: https://www.figma.com/design/VFdCObxYyZjSRFdK5pU1df/01_Savoy_library?node-id=1513-242642&m=dev Figma Mobile: N/A (responsive by design — no separate mobile Figma) Component Type: STATIC
Description: Error page module used exclusively on 404 (Not Found) and 500 (Internal Server Error) pages. Content is managed via a dedicated “Error Pages” tab on the siteRoot Document Type in Umbraco. For 404 pages, content is fetched from CMS at runtime. For 500 pages, content is pre-rendered as static fallback (no API dependency when server/DB is down).
Props:
label?: HtmlHeading— Error type label (e.g., “ERROR”, “INTERNAL SERVER ERROR”). Uses htmlHeading for semantic control.errorCode: string— The error number displayed large (“404” or “500”). Hardcoded per usage, not from CMS.body?: string— Descriptive text explaining the error.cta?: CtaLinkWithElement— CTA button linking back to homepage or other page.siteKey: string— Site identifier for theming.locale: string— Current language.moduleId?: string— Module ID for data attributes.
UI Components to Use:
CtaLinkfrom@savoy/ui— For the CTA pill buttonHtmlHeadingpattern from@savoy/cms-client— For label rendering
Layout:
- Full-width section with background color
var(--color-bg-alt) - Content centered horizontally, max-width ~889px
- Vertical padding: 80px
- Stacked vertically: label → error code → body text → CTA button
- Gap between text elements: 14px
- Gap between text group and CTA: 34px
- All text centered
- Responsive: max-width adapts fluidly, padding reduces on mobile
CMS Integration (Special — NOT a Block List module)
Section titled “CMS Integration (Special — NOT a Block List module)”This module does NOT follow the standard Block List pattern. Instead:
- siteRoot gets a new “Error Pages” tab (sortOrder 15) via migration
- Fields on siteRoot:
error404Label— Single Html Heading Block List (invariant BL, culture-variant text inside)error404Body— Textarea (culture-variant)error404Cta— Single URL Picker (culture-variant)error500Label— Single Html Heading Block List (invariant BL, culture-variant text inside)error500Body— Textarea (culture-variant)error500Cta— Single URL Picker (culture-variant)
- Error code (404/500) is hardcoded in the frontend, not a CMS field
- The module is NOT registered in the Page Modules Block List — it’s used directly by Next.js error boundary files
Next.js Integration
Section titled “Next.js Integration”not-found.tsx— Fetches siteRoot content from CMS API, extracts error404* fields, renders<ErrorPage>error.tsx('use client') — Uses pre-rendered static content. On CMS publish (webhook), a build step regenerates static error content per site. Fallback: embed default text if static content unavailable.
Development Process
Section titled “Development Process”Follow a frontend-first approach, in this exact order:
Phase A — Storybook
Section titled “Phase A — Storybook”- Define types in
.types.tsfirst, aligned with expected content structure - Scaffold test file — create
.test.tsxwith describe blocks for mapper + rendering → Static: write full mapper tests + rendering tests NOW (TDD — before implementation) - Write Storybook stories with realistic mock data BEFORE implementing the component
- Create these story variants: Default, MinimalContent, EmptyState, LongContent, AllOptions, FigmaFidelity → FigmaFidelity must mirror Figma content exactly (Lorem Ipsum OK if Figma uses it) → All other variants use realistic hotel context data — never Lorem Ipsum
- Stories must include
tags: ['autodocs', 'vitest'], full EN autodocs documentation with Figma desktop + mobile links, User Story link, and feature bullet list
Phase B — React/Next.js
Section titled “Phase B — React/Next.js”- Implement the component —
.tsx+.scss(BEM + CSS custom properties) → Static: Server Component (no ‘use client’) - Write mapper —
.mapper.tstransforming siteRoot properties → ErrorPage props → Two mapper functions:mapError404(siteRoot)andmapError500(siteRoot) - Run unit tests —
pnpm --filter modules test— all must pass before continuing - Register in
packages/modules/src/registry.tswith{ component, mapper, moduleId } - Export via
index.tswith named exports - Pre-gate checks —
pnpm typecheck+pnpm lint— both must pass before visual testing
Phase B7 — Pixel Perfect Visual Testing (HARD GATE)
Section titled “Phase B7 — Pixel Perfect Visual Testing (HARD GATE)”This phase is MANDATORY. Phase C cannot begin until both thresholds are met (or the fallback limit is reached).
Thresholds (both viewports must pass):
- Desktop (1440×900): diff ≤ 5%
- Mobile (375×812): diff ≤ 10%
Fallback: If after 10 fix iterations or 30 minutes thresholds are still not met, stop and notify the user explicitly with current diff values, then proceed to Phase C. Manual visual review is required before merge.
Phase C — Umbraco
Section titled “Phase C — Umbraco”- Add “Error Pages” tab to siteRoot via migration — NOT a new Element Type
- No SVG thumbnail needed (not a Block List module)
- No Block List registration needed
- Create test content on siteRoot error fields
- Validate mapper against real API response
- Test in at least 2 sites
- Update
not-found.tsxanderror.tsxto use the module
Files to Create
Section titled “Files to Create”- packages/modules/src/m46-error-page/index.ts
- packages/modules/src/m46-error-page/ErrorPage.tsx
- packages/modules/src/m46-error-page/ErrorPage.scss
- packages/modules/src/m46-error-page/ErrorPage.types.ts
- packages/modules/src/m46-error-page/ErrorPage.mapper.ts
- packages/modules/src/m46-error-page/ErrorPage.stories.tsx
- packages/modules/src/m46-error-page/ErrorPage.test.tsx
- apps/cms/Savoy.Cms/Migrations/AddErrorPagesMigration.cs (adds tab to siteRoot)
Conventions
Section titled “Conventions”- BEM class names with SASS (no CSS Modules, no Tailwind)
- All colors, fonts, spacing via CSS custom properties (var(—token-name))
- SCSS uses BEM nesting with
&__element,&--modifier(max 3 levels) - Root element:
<section data-module="errorPage" data-module-id={moduleId}> - Semantic HTML (section, h2-h4)
- Responsive: mobile-first with min-width breakpoints
- Fluid layout — no fixed pixel widths
- Storybook stories use realistic hotel context data (FigmaFidelity is the only exception)
- Stories include
tags: ['autodocs', 'vitest'], Figma link in parameters.design - This module extends ModuleLayoutProps but layout spacing may not be used (error pages don’t go through Block List)