# TechTitans POS — IPTV Account Page Legacy-Layout Parity

**Date:** 2026-11-11 · **Branch:** `techtitans/integration` · Local commits only (no push/deploy). NH POS / legacy portal untouched. **Frontend-only UI/UX redesign** — no backend, calculation, billing, renewal, credit or expiry logic changed.

Reorganizes the IPTV account detail page (`/iptv/:id`) into the old TechTitans portal's compact two-column operational layout, with modern Cacart styling, so staff can renew/credit/pay/adjust without scrolling through many stacked sections.

## 1. Before → after

| | Before | After |
|---|---|---|
| Structure | **8 stacked full-width sections** (header, summary cards, Package & pricing, Credit & Renewal, Expiry, Account status, History, Notifications) | **Compact header + two equal columns + history tabs** |
| Full-page height @1440 | **3,268 px** (~3.6 screens) | **1,759 px** (~46% shorter) |
| Above the fold | header + 4 summary cards + top of one card | header + **both column titles** + the whole left summary |
| Rarely-used forms | inline, full-width | right-side **drawers** |

Screenshots in `docs/techtitans/screenshots/iptv-legacy-layout/`: `before-desktop.png`, `before-desktop-fold.png`, `before-mobile.png` and `after-desktop.png`, `after-desktop-fold.png`, `after-tablet.png`, `after-mobile.png`, `after-zoom.png`, plus operation shots (`after-credit.png`, `after-expiry-drawer.png`, `after-advanced.png`, `after-pending.png`).

## 2. New layout (matches the legacy screen)

- **Compact account header** — Customer · MC ID · Provider/Portal · MAC id · status badge, with right-aligned actions: **Edit connection**, **Enable/Disable** (confirmed), **Notes** (→ Notes tab), **Advanced settings** (drawer).
- **Two equal columns** (`1fr 1fr` desktop → stack ≤900px):
  - **LEFT — Connection summary & expiry:** Unit price, Monthly charge, **Payment finished date** (= service expiry) + Active/Expired + days-left, **Connection outstanding** + a "Customer account balance … across all orders" line, and compact **Change monthly charge…** / **Change expiry date…** buttons that open drawers.
  - **RIGHT — Credit & Renewal (stays on-page):** Package, **Free Credit 0–12**, **Pay Credit 0–18**, Discount (authorized), Pay now / Pay later + partial + Authorize-before-payment (+reason), Comment, email/SMS, **backend-calculated tax + Charge/Tax/Total**, one **Review & apply**.
- **Pending connections** render the Activation panel prominently (columns hidden) above the tabs.
- **Account history** — compact tabs: Invoices / Payments / Renewals-Credits / Notes / Activity.

### Drawers (shared `FormDrawer` — right-side, portaled, mobile full-width, preserve page state, confirm + reason)
Edit Connection · **Change Monthly Charge** (reason + "future charges only") · **Manual Expiry Adjustment** (± days/months + Bring-to-current, preview + required reason) · **Advanced settings** (notifications + credential reveal + enable/disable). Common operations (Free/Pay Credit, Pay Now/Later) stay directly on the page.

### Tax (Task 6)
No independent HST checkbox — the Credit & Renewal panel shows the configured rate/total from the existing POS-backed `quote`; totals are backend-calculated and match the issued invoice.

## 3. Functional preservation (all verified working after the move)

Paid renewals · free extensions · **combined free + paid** · discounts · taxes (POS engine) · Pay Now · Pay Later · partial payments · grant policy · authorize-unpaid override · expiry ± days/months · Bring to Current Date · monthly charge change · enable/disable · notes + audit/activity · invoice PDF · **connection vs customer outstanding** · credential reveal · activation of pending · tenant isolation. No calc changes, no duplicate ledgers/invoices — every `iptvApi` call, ConfirmDialog, permission gate, quote/preview and idempotency (`newRequestId`) is preserved, only relocated.

**Incidental fix:** mutation handlers now re-hydrate the full subscription via the existing `refresh()` (which re-fetches `getSubscription` + billing + notes) instead of trusting the partial mutation response — so the Renewals/Activity tabs never momentarily blank after an action (a glitch spotted in live testing).

## 4. Changed files
- `frontend/src/pages/iptv/IptvDetailPage.tsx` — the layout restructure + drawers + the refresh fix.
- `frontend/src/pages/iptv/iptv.css` — compact header / two-column / summary-row styles.
- `frontend/src/pages/iptv/IptvPages.test.tsx` — selectors updated for the drawer-moved controls (same API bodies asserted).

## 5. Testing
- **Frontend:** `vitest run src/pages/iptv src/components/ui` → **72 passed**; `tsc -b`, eslint, `npm run build` clean.
- **Live E2E (billing enabled) — 13/13 PASS**, 0 console/page errors (fresh test connection IPTV-2026-0032): page height **1759px vs 3268px**; header + both columns above the fold; columns side-by-side desktop, stacked tablet/mobile (0px overflow), 150% zoom clean; combined Pay 1 + Free 1 → one CA$16.95 invoice + "1 paid + 1 free" row + expiry +2mo; 10% discount total CA$15.26 matching the invoice; pay-later granted + outstanding then settled; Change-expiry drawer ±2mo + bring-to-current (reason-gated); Change-charge drawer $15→$18.50 ("future charges only"); Advanced drawer (notifications + credential + enable/disable); Edit-Connection MAC update; 5 history tabs; pending state shows the Activation panel with columns hidden.
- No real customer records modified; no live SMS/email or card charges (offline cash only).

## 6. Known notes / limitations
- The Credit & Renewal panel is inherently tall, so its **Review & apply** button sits just below a 900px fold on a maxed-out form; the panel header and the entire left column are above the fold. Still a ~46% height reduction overall.
- Backend behaviour, calculations and the two-page create/activate workflow are unchanged (see [IPTV-TWO-PAGE-WORKFLOW-REPORT.md](IPTV-TWO-PAGE-WORKFLOW-REPORT.md) and [IPTV-CREDIT-EXPIRY-PAYMENT-PARITY.md](IPTV-CREDIT-EXPIRY-PAYMENT-PARITY.md)).

## 7. Local commits (on `techtitans/integration`, no push)
- **Frontend:** `cf4ef0c` — IPTV account page redesign + drawers + refresh fix + test selector updates.
- **Backend (docs):** this report + before/after screenshots (committed below).
