# Plan 16 — Patient portal on the website (account, medical file, full patient journey)

Status: **built 2026-09-30** (branch `Clinic`), tasks 1-13. Decisions in §5 answered by the user 2026-09-30.

Build progress:
- Task 1 — folded into the others: the `web_site/clinic/*` views already use lang keys; only `auth/signin` and
  `auth/register` had hard-coded English, and task 3 rewrites them. Each task adds the keys its pages need
  (`site.account.*` for the account area).
- Task 2 — done: `web_site.account.layout` (+ `partials/menu`, `partials/avatar`), `assets_web/css/account.css`
  (logical properties, one file for LTR and RTL), header sign-in link / user dropdown
  (`web_site.partials.account-menu`), `App\View\Composers\PatientAccountComposer` (unread counters). Menu links
  appear only once their route exists (`Route::has`). Notifications page moved onto the layout.
- Task 3 — done: sign-in by email or phone (+20/0020 normalised to the stored local form), sign-up through
  `PatientService::create` (profile with DOB/gender), required unique Egyptian mobile, terms, throttling.
  **Booking gate changed** from "profile row exists" to `PatientProfile::hasMedicalFile()` (medical_history
  set) on the website; the app API's 428 gate still checks the row only.
- Task 4 — done: `Site\PasswordResetController`, `/forgot-password`, `/reset-password?token&email` (the same
  link the API mails, now with the patient's locale prefix), tokens revoked on reset, ar.json mail strings.
- Task 5 — done: wizard + summary; chips are scoped CSS because the template's global
  `input[type=checkbox] ~ label` rules would otherwise tick every later chip.
- Task 6 — done: `/account` (`account.dashboard`), sign-in lands there; shared `account.partials.booking-card`.
- Task 7 — done: tabs with counts, details page (template `member-table`), cancel / review modals, reschedule
  slot chips. `BookingService::patientCanCancel/patientCanReschedule` + window helpers; the web never shows the
  service's 422 page any more (redirect with a translated message), and cancel/reschedule now refuse
  completed or cancelled bookings (API too). Task 12's online note is on the details page.
- Task 8 — done: one-page booking (priced type cards, 14-day strip with days off greyed, time chips, sticky
  summary, "nearest free day" link when the chosen day is empty); store checks medical file + price and never
  shows a 422 page; payment step only for pending bookings.
- Task 9 — done: reports list/detail (print view), `/account/files` (doctor report files, clinic
  `PatientAttachment`, own booking uploads).
- Task 10 — done: `/clinic/chat` inbox (`ChatService::conversationsForPatient`), chat-card thread.
- Task 11 — done: `/account/settings` (photo, details + preferred language, password change that revokes app
  tokens); notifications grouped by day.
- Task 12 — done in task 7 (D1: no video; online bookings show the "clinic will contact you" note).
- Task 13 — done: 48 new feature tests in `tests/Feature/Site/Patient*Test.php`; ar/en and phone-width
  screenshots checked with headless Edge. Remaining known failures are the 11 old storefront tests (routes removed
  in the site rebuild).

Known, not changed here: the placeholder payment gateway's return URL (`clinic.payments.return`) marks a payment
paid from the query string and has no ownership check — fine for the simulated gateway, must be replaced when a
real gateway is connected. The app API's booking gate (428) still only checks that a profile row exists.

Goal: everything a patient can do (brief list below) works on the website in the same visual language as the
bst-final marketing pages, in Arabic and English, with a proper sign-in / sign-up and a "My account" area.

Brief (what the patient can do):
1. Create an account from the website or the app.
2. Search clinics and doctors by specialty and clinic.
3. See doctor details, reviews and available times.
4. Book an appointment.
5. Choose an in-clinic visit or an online video consultation.
6. Pay online.
7. Follow all bookings, visits and online consultations.
8. See reports and prescriptions uploaded by the doctor.
9. Send written questions to the doctor and get answers (chat).
10. Rate the doctor and write a review after the visit or consultation.

Design reference: the original template at `E:\omnia\work\projectes\المركز الطبي\bst-final` (already synced
into `public/assets_web`) + the Figma app screens in `plan_Clinics/design/figma/` (Auth, Patient-details,
reservations, profile) for the flows and the content of each screen. The template has **no** account, sign-in
or dashboard pages (its pages: index, about, service(+details), doctors, doctor-details, appointment,
offers-subscribe, contact, blog(+details), faqs, before-after, privacy, terms), so the new pages are built only
from the template's own components, adapted to desktop:

| Need | Template component to reuse (source page) |
|---|---|
| Page header | `breadcumb-wrapper` + `breadcumb-title` (every inner page) |
| Form card (auth, wizard, settings, booking) | `appointment-wrapper` → `form-wrap1 bg-white` → `form-title-box bg-title` → `form-box`, fields `col-xl-6 form-group` with `form-control style2` / `form-select style2`, date field `dateTime-pick` (appointment.html, offers-subscribe.html) |
| Message / contact style form (chat reply, review) | `form-wrap3` + `form-control style3` (contact.html) |
| Details table (booking details, record details) | `member-table` (doctor-details.html) |
| Time slots / schedule | `team-schedule-table` (doctor-details.html) |
| Buttons | `vs-btn`, `vs-btn style2` (header / hero) |
| Doctor cards in lists | `web_site.partials.doctor-card` (already built from doctors.html) |

No new CSS framework; only a small `account.css` for what the template lacks (side menu, tabs, status badges,
chat bubbles, stepper), using the template's colour variables.

---

## 1. What exists today (checked in the code, 2026-09-30)

| Brief item | Backend | Website page | State of the page |
|---|---|---|---|
| 1 Account | `Site\AuthController` (email + password; register: name, email, phone, address, password) | `auth/signin`, `auth/register` | Bare Bootstrap form, English hard-coded, **no link in the header** (guests can't find it; logged-in users have only the bell) |
| — Forgot password | `Password::broker('users')` used by the API only | none | **missing on the website** |
| — Medical file | `PatientProfileController` edit/update, options from `MedicalHistoryOption` | `clinic/profile/medical` (one long form) | Works; not the 4-step wizard from Figma; booking already redirects here when no profile |
| — Personal data / password | none on the website (API has profile update) | none | **missing** |
| 2 Search | `Site\Clinic\SearchController` | `clinic/search` | Rebuilt in plan 11 — OK |
| 3 Doctor details, reviews, times | `DoctorProfileController` | `clinic/doctor-profile` | Rebuilt — OK; times are picked on the booking page |
| 4 Book | `BookingController` create/store, `BookingService::availableSlots()` | `clinic/booking/create` | Works, plain form |
| 5 Visit / online | `type in:visit,online` on the booking | radio on the booking form | Online booking exists, **no video call** (no link, no room) |
| 6 Pay | `BookingPaymentService` (placeholder gateway) | `booking/payment`, `booking/hosted` | Works, plain pages |
| 7 Follow bookings | `MyBookingController` index/show/cancel/reschedule | `my-bookings/*` | Plain table, **no tabs** (upcoming / completed / cancelled), English strings |
| 8 Reports & prescriptions | `MedicalRecordController` (published records + doctor attachment) | `medical-records/*` | Plain list |
| — Patient uploads | booking-level upload (`BookingAttachmentController`) | form on booking show | Works; no page listing the patient's own files |
| 9 Chat | `ChatController` (one thread per doctor, live via Pusher/Reverb) | `clinic/chat/index` | Works per doctor, **no inbox** (list of my conversations) |
| 10 Review | `ReviewController` create/store | `clinic/review/create` | Works, plain form |
| — Notifications | `NotificationController` | `clinic/notifications/index` | Works, plain list |

Conclusion: the business logic is done. The work is (a) a consistent account area and redesign of ~15 pages,
(b) a few real gaps: header account menu, forgot/reset password, account settings, bookings tabs,
chat inbox, "my files" page, the video consultation, and all hard-coded English strings.

---

## 2. Design

### 2.1 Account area layout

New `web_site.account.layout` (extends `web_site.layouts.master`):
- Breadcrumb header like the other pages (`breadcumb-wrapper`, page title).
- Two columns on desktop: side menu (avatar, name, phone; links: Dashboard, My bookings, Medical file,
  Reports & prescriptions, My files, Messages [unread badge], Notifications [unread badge], Account settings,
  Sign out) + content. On mobile the menu becomes a horizontal scroll bar of pills above the content.
- New CSS in `public/assets_web/css/account.css` (+ RTL rules in the same file, `[dir=rtl]`), only template
  colours/variables — no new framework.
- Status badges use the Figma colours: upcoming = blue, completed = green, cancelled = red, pending = amber.

### 2.2 Header

- Guest: "Sign in" icon/link next to the search button.
- Signed in: avatar dropdown (Dashboard, My bookings, Messages, Sign out) + the existing bell.

### 2.3 Auth pages (Figma "Auth")

- Template `form-wrap1` card (title box + form box) with the BST logo, centred in an `appointment-wrapper`
  section under the normal breadcrumb; Figma texts and field order (no mobile phone frame).
- **Sign in** with email *or* phone + password, show/hide password, remember me, "Forgot password?", "Create account".
- **Sign up**: full name, phone, email, password + confirm, date of birth, gender (the two last go to
  `clinic_patient_profiles`, which already has `date_of_birth`/`gender`), accept terms (link to `/privacy-terms`).
  After sign-up → the medical-file wizard (skippable, "complete later").
- **Forgot password** → email reset link via the existing `users` broker → "check your email" page →
  **reset password** page → "password changed" confirmation (Figma screens 1–4). See decision D2 for OTP.

### 2.4 Medical file wizard (Figma "Patient-details")

Same data as today's `profile/medical` form, split into 4 steps with a progress bar:
1. Chronic conditions (chips from `MedicalHistoryOption` type condition + "other").
2. Surgical history (yes/no → type, date, hospital, notes).
3. Medications (yes/no → chips from medication options + "other").
4. Allergies (type, substance, severity, notes).
One form, steps switched client-side (no save per step), submitted once to the existing
`profile.medical.update`; validation errors jump back to the step that holds the field. Success screen
"Your file is complete" → Dashboard (or back to the booking the patient came from, via `url.intended`).
The same page in "view" mode shows a read-only summary with an "Edit" button.

### 2.5 Pages in the account area

| Page | Content |
|---|---|
| Dashboard (new) | Greeting; next appointment card (doctor, date, clinic or online); counters (upcoming, completed, unread messages); "complete your medical file" banner when missing; latest report; quick links |
| My bookings | Tabs All / Upcoming / Completed / Cancelled (query `?status=`), cards like Figma (doctor photo, specialty, date, time, status badge, "Details") |
| Booking details | Doctor card, details list (type, date, time, clinic, payment method, total), follow-up note if any, actions by state: pay, cancel (confirm modal), reschedule, add review, view report, upload files |
| Book appointment | Redesign: steps doctor/clinic → type (visit / online, with price per `ServicePrice`) → day + slot grid → notes → confirm & pay |
| Payment pages | Redesign of payment choice + result (success / failed) |
| Reports & prescriptions | Card list (title, doctor, date, type icon) → details page (diagnosis, prescription, report, doctor file download) — Figma "reports" |
| My files (new) | Files the patient uploaded to bookings + files the clinic uploaded (`PatientAttachment`, read-only) |
| Messages (new inbox) | List of doctors I talked to (last message, time, unread dot), search; thread page redesigned as chat bubbles; empty state from Figma |
| Review | Star rating (doctor + clinic) + comment, in a modal on booking details (form page kept as fallback) |
| Notifications | Grouped Today / Yesterday / earlier, empty state |
| Account settings (new) | Name, phone, email, avatar, preferred language; change password (current + new) |

---

## 3. Tasks (one commit each)

1. **Translations & shared pieces** — `lang/{ar,en}/site.php` `account.*`/`auth.*` keys; move every hard-coded
   English string in `web_site/auth/*` and `web_site/clinic/*` to lang keys.
2. **Account layout + CSS + header menu** — `web_site.account.layout`, `account.css` (LTR + RTL), header
   guest link / user dropdown, unread counts via a view composer.
3. **Sign in / sign up redesign** — login by email or phone (`LoginRequest` + controller lookup), register adds
   DOB/gender/terms, redirect to the wizard after sign-up.
4. **Forgot / reset password** — routes `password.request|email|reset|update` on the `web` guard, 4 pages, mail
   notification in both languages (reuse the broker the API uses).
5. **Medical file wizard + view mode** — replace `profile/medical` view; controller unchanged except the
   `intended` redirect.
6. **Dashboard** — `Site\Account\DashboardController` (next booking, counters, latest report).
7. **My bookings tabs + booking details redesign** — status filter in `MyBookingController::index`, cancel
   modal, review modal.
8. **Booking flow redesign** — type choice with price, slot grid, confirm step; payment pages restyle.
9. **Reports & prescriptions + My files** — restyle records; new `Site\Clinic\PatientFileController@index`.
10. **Chat inbox + thread restyle** — `ChatService::conversationsForPatient()`; route `clinic.chat.inbox`.
11. **Notifications + account settings** — restyle list; new `Site\Account\SettingsController` (profile,
    avatar via `ImageUploadTrait`, password change).
12. **Online consultation note** (D1 = video deferred) — online bookings stay as today; booking details and the
    confirmation show "the clinic will contact you at the appointment time" instead of a join button.
13. **Tests + QA** — feature tests for each new route (auth, reset, tabs, inbox, settings, video access rules);
    render every page in ar/en; browser check of RTL and mobile width.

---

## 4. Out of scope

- Mobile app screens (the API already serves them).
- Favourites (in the Figma app, not in the brief) — can be added later in one task.
- Real payment gateway credentials (the placeholder gateway stays until go-live).
- Doctor-side changes.
- Video calls (D1: deferred to a later round, together with the mobile video).

---

## 5. Decisions (answered 2026-09-30)

Answers: **D1 = (c) video deferred**, **D2 = (a) email link**, **D3 = email or phone**, **D4 = skippable wizard,
required before the first booking**. Note for D3: before making `users.phone` unique, check existing rows for
duplicate / empty phones (normalise like `Lead::normalizePhone`) and report them instead of deleting anything.

- **D1 — Video consultation.** (a) Jitsi Meet room per online booking (free, no account, opens in the browser,
  room link shown to patient and doctor from X minutes before the time) — *recommended for now*;
  (b) Agora in-page video (needs an Agora account + token service, same as the future mobile video);
  (c) leave video for later, online booking stays "the clinic contacts you".
- **D2 — Forgot password channel.** (a) Email reset link (works today, no cost) — *recommended*;
  (b) SMS OTP like the Figma screens (uses the existing SMS integrations, costs per message, needs a working
  SMS provider).
- **D3 — Sign in with phone.** Allow email *or* phone at sign-in (Figma) — *recommended*; phone becomes
  required and unique at sign-up.
- **D4 — Medical file at sign-up.** Wizard right after sign-up but skippable, required before the first
  booking (today's rule) — *recommended*; or force it before entering the account.
