# WP7 — The conditional «دواء» tab in the product dialog

**Repo:** FE · **Branch:** `hazemdev2` · **Migration:** none · **Depends:** WP6

## Goal

Add a fifth tab, **دواء / Drug**, to the product create/edit dialog. It appears **only** when the product is flagged as a drug, and carries: active ingredients (multi-select, one or more, each with its own strength), dosage form, overall strength + unit, Rx/OTC, controlled flag, storage temperature, ATC code, manufacturer.

## Where everything is

- Dialog lives inside the list component: `src/app/features/products/products.component.ts` (~2119 lines) and `products.component.html` (~1292 lines). There is **no** `/products/new` route — `products/:id` is a read-only detail view.
- Dialog wrapper: `products.component.html:289-296` `<app-form-dialog [width]="'850px'">`; form element opens `:297`, closes `:884-885`.
- Tabs: PrimeNG v21 `p-tabs`, declared at `products.component.html:298-305`, panels close at `:882-883`.
  | Tab | value | panel lines |
  |---|---|---|
  | Basic Info | `"0"` | 307-407 |
  | Details | `"1"` | 410-543 |
  | Variants & More | `"2"` | 546-834 |
  | Attachments | `"3"` | 837-881 |
- Form: hand-written reactive `FormBuilder`; `initForm()` at `products.component.ts:474-501` (28 flat controls). Entry points `openNew()` `:429`, `editProduct()` `:514`.
- Field idiom: `<div class="form-row">` → N × `<div class="form-field">` → `<label>` + control, with an `@if (...touched && ...hasError('required'))` error line. Controls in use: `pInputText`, `p-select`, `p-inputNumber`, `p-toggleSwitch`, `p-multiSelect`.

## The two things that are new ground here

**1. There is no conditional tab anywhere in this codebase yet.** All four existing `<p-tab>` and `<p-tabpanel>` are unconditional. Conditionality exists only *inside* panels — copy that idiom: `products.component.html:518` uses `@if (productForm.get('track_inventory')?.value)`. So: wrap both the `<p-tab>` (in the tablist) and its `<p-tabpanel>` in `@if (productForm.get('is_drug')?.value)`.

**2. `p-tabs value="0"` is a STATIC string binding.** If the user is sitting on the drug tab and unticks the flag, the panel vanishes and **no tab is active**. You must make the active tab a bound signal and reset it to `"0"` when `is_drug` goes false. Verify the two-way binding API for the PrimeNG v21 build actually in `package.json` before assuming `[(value)]` works — if it does not, drive it from the component with an explicit reset.

## Fields

- **`is_drug` toggle** — put it in the **Basic Info** tab (it is what reveals the drug tab, so it must be visible without the drug tab existing). Add to `initForm()`.
- **Active ingredients** — `p-multiSelect` bound with `formControlName`. Copy the working pattern from `src/app/features/bank-accounts/bank-accounts.component.html:83-93` (`[options]`, `optionLabel="name"`, `optionValue="id"`, `display="chip"`, `appendTo="body"`). Per-ingredient strength: render a small row per selected ingredient with a number input + unit input, since the pivot carries `strength_value`/`strength_unit`.
- **Dosage form** — `p-select` from the `dosage_forms` list (WP5).
- **Strength value + unit**, **storage temperature**, **ATC code** — plain inputs.
- **`is_prescription`**, **`is_controlled`** — `p-toggleSwitch`, each with a one-line hint under it explaining the consequence.
- **Manufacturer** — `p-select`; WP6 exposed `manufacturer_id` through Core. If no manufacturers endpoint is reachable from Core, say so in your report and leave the control out rather than inventing an endpoint.

## Load / save

- `editProduct()` (`:514`) must patch `is_drug`, the drug details and the ingredient array (with pivot strengths) into the form. Follow how it currently loads product units (`loadProductUnits(id)` called at `:549`).
- The save payload builder must send `is_drug`, a `drug_details` object and `active_ingredients: [{id, strength_value, strength_unit}]` — exactly the contract WP6 declared on `StoreProductRequest`/`UpdateProductRequest`. **Read those two request classes and match them key-for-key**; a mismatch is silently dropped by `validated()`.
- `openNew()` (`:429`) must reset the drug fields.

## i18n

Add `PRODUCTS.TAB_DRUG`, `PRODUCTS.ACTIVE_INGREDIENTS`, `PRODUCTS.DOSAGE_FORM`, `PRODUCTS.STRENGTH`, `PRODUCTS.STRENGTH_UNIT`, `PRODUCTS.IS_PRESCRIPTION`, `PRODUCTS.IS_CONTROLLED`, `PRODUCTS.STORAGE_TEMPERATURE`, `PRODUCTS.ATC_CODE`, `PRODUCTS.IS_DRUG`, `PRODUCTS.MANUFACTURER` (+ hint keys) to **both** `src/assets/i18n/en.json` and `ar.json`. The `PRODUCTS` block is at **lines 2257-2445** in both files and they are **line-aligned** — insert at matching positions.
**Edit additively. NEVER run `git checkout`, `git restore`, or `git stash` on either file** — they were destroyed once that way and had to be recovered.

## Acceptance criteria

1. Unticking/ticking `is_drug` shows/hides the tab live, and unticking while ON the drug tab leaves a valid active tab (no blank dialog).
2. Creating a drug with 2 ingredients (different strengths) + dosage form + flags persists and reloads correctly on edit.
3. Editing a drug to remove one ingredient actually removes it.
4. A non-drug product's dialog is **visually and behaviourally unchanged** — no new tab, no new required field, saving still works.
5. RTL renders correctly (Arabic is the primary direction).
6. `ng build` green.

## Out of scope

- BE changes — WP6 delivered the contract. If you find the contract insufficient, **report it, do not patch the BE**.
- The units/composition table — **WP8**.
- WebStore's admin product screen.

## Environment

- Build: `cd /home/moonui2/public_html/moon-erp && npx ng build --base-href /app/` — pre-authorized, run it.
- `chown moonui2:moonui2` after each edit; **moonui2 only — never `/home/moonui`**.
- Working tree is dirty by design — never revert/stash/commit what you did not write; do not commit at all.
