# Displays ## Definition A **Display** encapsulates **reusable, UI-only display logic**. In this codebase, a Display is a **Frontend Value Object**: - class-based - immutable - deterministic - side-effect free It answers the question: > “How should this specific piece of information be shown?” Displays are **not screen-specific**. They exist to avoid duplicating presentation logic across View Models. **Naming Convention:** - Displays MUST end with `Display` suffix - Displays MUST be reusable across multiple screens - Valid examples: `PriceDisplay`, `EmailDisplay`, `RatingDisplay` - Invalid examples: `DashboardRatingDisplay`, `UserProfileDisplay` --- ## Responsibilities A Display MAY: - format values (money, dates, durations) - handle localization only when localization inputs are deterministic (for example: mapping stable codes to stable labels) - map codes to labels - encapsulate UI display conventions - be reused across multiple View Models In addition, a Display MAY: - normalize presentation inputs (for example trimming/casing) - expose multiple explicit display variants (for example `shortLabel`, `longLabel`) A Display MUST: - be deterministic - be side-effect free - operate only on presentation data A Display MUST: - be implemented as a **class** with a small, explicit API - accept only primitives/plain data in its constructor (or static factory) - expose only primitive outputs (strings/numbers/booleans) --- ## Restrictions A Display MUST NOT: - contain business logic - enforce domain invariants - perform validation - influence system behavior - be sent back to the server - depend on backend or infrastructure concerns In this repository, a Display MUST NOT: - call `Intl.*` - call `Date.toLocaleString()` / `Date.toLocaleDateString()` / `Date.toLocaleTimeString()` Reason: these are runtime-locale/timezone dependent and cause SSR/hydration mismatches. ## Localization rule (strict) Localization MUST NOT depend on runtime locale APIs. Allowed approaches: - API returns the exact labels/strings for the current user context. - Website maps stable codes to stable labels using a deterministic table. Forbidden approaches: - any usage of `Intl.*` - any usage of `toLocale*` If a rule affects system correctness or persistence, it does not belong in a Display. --- ## Ownership & Placement - Displays belong to the **presentation layer** - They are frontend-only - They are not shared with the backend or core Placement rule (strict): - Displays live under `apps/website/lib/display-objects/*`. - Filenames MUST match the class name with `.tsx` extension (e.g., `RatingDisplay.tsx` contains `class RatingDisplay`) --- ## Relationship to View Models - View Models MAY use Displays - Displays MUST NOT depend on View Models - Displays represent **parts** - View Models represent **screens** Additional strict rules: - View Models SHOULD compose Displays. - Displays MUST NOT be serialized or passed across boundaries. - They must not appear in server-to-client DTOs. - Templates should receive primitive display outputs, not Display instances. --- ## Testing Displays SHOULD be tested because they often contain: - locale-specific behavior - formatting rules - edge cases visible to users Additionally: - test determinism by running the same inputs under Node and browser contexts (where applicable) - test boundary rules (no `Intl.*`, no `toLocale*`) --- ## Summary - Displays encapsulate **how something looks** - View Models encapsulate **what a screen needs** - Both are presentation concerns - Neither contains business truth In one sentence: Displays are **Value Objects for UI display**, not utility functions.