# WP1 — Shared shell (header · footer · nav · language switcher)

**Repo:** FE only — `/home/moonui4/public_html/moon-erp` (branch `hazemdev4`)
**Depends on:** WP0 ✅ (`41e14035`, `9a04a6e8`) · **Review:** code-reviewer · **[FIN]:** no · **Migration:** no

## Goal

Turn the theme's copy-pasted shell into real Angular components wrapping a router outlet, so every later WP just fills `<router-outlet>`. Pixel-identical to the theme, but with the four things the theme never had: **a real language switcher**, **an authenticated header state**, **a live cart badge**, and **a category menu fed by the API**.

## Source of truth for markup

Theme (already extracted, read-only):
`/tmp/claude-0/-home-moonui4-public-html/714ac5d7-2ce4-45d7-bc22-9a935e3e9336/scratchpad/theme/theme/`

In `index.html` — **verified line numbers**:

| Piece | Lines |
|---|---|
| `<header>` incl. top bar + search + cart badge | **108–295** (the desktop category `<nav>` is 198–294, inside it) |
| `<footer>` | **1520–1632** |
| Mobile bottom nav | **1635–1660** |
| Mobile menu drawer | **~1662–1740** |

**T1 (verified): lines 1–295 are byte-identical across all 29 theme pages** (`md5 ae36a323`), and the tail from `<footer>` onward is byte-identical too (`md5 ef28ee10`). So extraction is mechanical and zero-risk — you are not choosing between variants. Port the markup **verbatim**, changing only what this brief tells you to change.

## Components to build

Under `projects/storefront/src/app/layout/`:

- `shell.component` — the layout route wrapper: header + `<router-outlet>` + footer + bottom nav + drawer
- `top-bar.component` · `header.component` · `category-nav.component` · `footer.component` · `mobile-bottom-nav.component` · `mobile-menu-drawer.component`

Plus `core/services/toast.service.ts` + a `toast-container.component` (the theme's toast markup lives in `app.js`; port its visual style, drive it from a signal).

Standalone components, `.scss`, no NgModules. Match WP0's existing structure and naming.

## The four things the theme did NOT have — build them properly

**1) Real language switcher (T11).** The theme's switchers (top bar + mobile drawer) are inert `href="#"` and `app.js`'s handler targets classes that exist nowhere. Wire both to WP0's `LanguageService`: switch `ar`↔`en`, set `<html lang>` **and** `<html dir>`, persist the choice, and make the whole shell re-render correctly in both directions.

**2) Authenticated header state (T8).** The theme header always renders login/register anchors — there is no logged-in variant at all. Design one in the theme's own visual language (same spacing, same `primary` orange, same Material Icons ligature style): show the customer's name + a small menu with logout. Drive it from WP0's `auth.state` signals. **Logout is a client-side token drop (A7) — there is no logout endpoint.**

**3) Live cart badge.** The theme hardcodes `"5"` in **two** places (`.cart-badge`, line 162 desktop and line 1648 mobile). Bind both to `cartState.itemCount`. **Hide the badge entirely when the count is 0** — do not render a `0`. Note **T7: the wishlist counter has no class or id at all** — add a hook for it but leave it inert (wishlist is out of MVP scope).

**4) Category menu from the API.** The desktop nav (198–294) hardcodes categories. Fetch them via WP0's API client. Mind the contract:
- Categories come from an **unpaginated** `{ data: [...] }` endpoint (`categories/tree`) — **not** the paginated envelope (A15: `per_page` is ignored there anyway).
- **A14: the `category_id` product filter is NON-RECURSIVE.** A parent category link can therefore return zero products. Link to whatever level the seeded data actually hangs products off; if you must link parents, note it for WP2 rather than papering over it.
- The API returns **no nulls** (A9) — `category_id === 0` means "none". Use falsy checks, never `=== null`.
- Loading/failure must not collapse the header layout. A failed category fetch degrades to an empty menu, never a broken page or a blank screen.

## i18n — the discipline starts here

**Every user-facing string is a translation key, from the first component.** The theme has zero `data-i18n` and hardcoded Arabic everywhere; if discipline slips now, WP6 becomes a rewrite. Add keys to **both** `ar.json` and `en.json` — English is a day-one requirement (owner decision D5), not a later pass.

**Bump `I18N_VERSION`** in the storefront's config on any i18n JSON edit. The JSONs are not fingerprinted; without the bump, clients see raw keys like `SHELL.CART` after deploy.

**Branding (T10/OPEN-2):** the theme is inconsistent — header says `صيدليتي`, auth pages say `الصيدلاني`/`صيدليات`. Use **`صيدليتي`**, and put it in an **i18n key** so it stays swappable per client. That keeps the still-open owner decision reversible for the cost of one key.

## Traps

🔴 **T2 — do NOT port `style-ar.css` / `style-en.css`.** Every rule in them is keyed on `body[dir=...]` while the theme sets `dir` on `<html>` — so ~380 lines of RTL/LTR CSS **never applied in the theme**. Porting them faithfully would make them apply **for the first time** and silently change the rendering. Handle direction with Tailwind logical utilities instead. The audit of those files is WP6's job.

⚠️ **T3 — Tailwind is now compiled, not the CDN.** Any class assembled dynamically (`` `bg-${color}-500` ``) **silently does not exist** in a compiled build. Use complete literal class names, always.

⚠️ **T5** — `index.html` ships two conflicting hero sliders. Both are WP2's problem; ignore them here.

⚠️ **Icons** are Material Icons used as **ligature text** in three distinct families (`Material Icons`, `Material Icons Outlined`, `Material Icons Round`). Preserve the exact family per icon or the metrics shift.

## Acceptance criteria

- [ ] `npx ng build storefront` green **and** `npx ng build` (admin app) still green — zero regression. `angular.json`'s `moon-erp` project block untouched.
- [ ] Header, footer, bottom nav and drawer render **visually identical** to the theme at desktop and mobile widths. State the method you used to check (screenshot diff vs the static theme page is ideal; if you compare by eye, say so plainly rather than implying more rigor than you had).
- [ ] Language switcher actually flips `ar`↔`en`: `<html lang>` and `<html dir>` both change, the choice survives reload, and the layout is correct in **both** directions.
- [ ] Header shows the logged-out variant by default and the account variant when `auth.state` has a token; logout clears the token and returns to the logged-out variant.
- [ ] Both cart badges track `cartState.itemCount` live and disappear at 0.
- [ ] Category menu is populated from the real moonui4 API. **A demo seeder is landing in the backend in parallel** — if the catalog is still empty when you test, say so and verify against the empty state instead of inventing mock data.
- [ ] Zero hardcoded user-facing strings — grep your own diff and report the result.
- [ ] `I18N_VERSION` bumped.

## Out of scope

Do not build any page body — no home, catalog, product detail, cart, auth, or checkout (those are WP2–WP5). Do not implement cart merge-on-login (WP3). Do not touch the backend, `src/` (the admin app), or `angular.json`'s `moon-erp` block. **Do not run `/fullpush`, do not deploy, do not push, do not merge to `main`.**

## Commit

Conventional commit on `hazemdev4` with `[skip-changelog]` (the shell alone is not a user-visible capability; the CHANGELOG bullet lands with WP2's catalog). Commit only.

## Report back

If any fact in this brief contradicts what you find in the code or the theme, **say so** — the brief is a best current understanding, not gospel. Report what you verified versus what you assumed.
