# E3.S2 - Patients lijst pagina

**Epic:** E3 - Patients & Organizations
**Story:** E3.S2 - Patients lijst pagina
**Story Points:** 5
**Status:** ✅ Compleet

## Doel

Patiënten lijst pagina met tabel, search, filters en paginatie.

## Acceptatiecriteria

- [x] `/patients` route met overzichtelijke tabel
- [x] Search functionaliteit op naam en BSN
- [x] Filters (status, gender)
- [x] Paginatie (50 per pagina)
- [x] Sorteer functionaliteit

## Implementatie

### 1. Server Actions (actions.ts)

📁 **Locatie:** `app/epd/patients/actions.ts`

**Updates:**
- ✅ Paginatie parameters toegevoegd (`page`, `pageSize`)
- ✅ Gender filter parameter
- ✅ Sorteer parameters (`sortBy`, `sortOrder`)
- ✅ Return type aangepast naar object met `patients`, `total`, `page`, `pageSize`

**API parameters:**
```typescript
{
  search?: string;        // Zoek op naam
  status?: string;        // Filter: planned, active, finished, cancelled
  gender?: string;        // Filter: male, female, other, unknown
  page?: number;          // Pagina nummer (default: 1)
  pageSize?: number;      // Items per pagina (default: 50)
  sortBy?: string;        // Sorteer kolom
  sortOrder?: 'asc' | 'desc';  // Sorteer richting
}
```

### 2. Page Component (page.tsx)

📁 **Locatie:** `app/epd/patients/page.tsx`

**Updates:**
- ✅ SearchParams interface uitgebreid met nieuwe filters
- ✅ Page parameter parsing
- ✅ Props doorgegeven aan PatientList component

### 3. Patient List Component (patient-list.tsx)

📁 **Locatie:** `app/epd/patients/components/patient-list.tsx`

**Features geïmplementeerd:**

#### A. Filters

**Search bar:**
- Zoek op naam of BSN
- Real-time filtering
- Form submit handler

**Status filter:**
- Alle statussen
- Screening (planned)
- Actief (active)
- Afgerond (finished)
- Afgemeld (cancelled)

**Gender filter:**
- Alle geslachten
- Man (male)
- Vrouw (female)
- Anders (other)
- Onbekend (unknown)

#### B. Paginatie

**Implementatie:**
- 50 patiënten per pagina (configureerbaar)
- Pagina navigatie knoppen (vorige/volgende)
- Genummerde pagina buttons (max 7 zichtbaar)
- Smart pagination logica:
  - Bij weinig pagina's: toon alle nummers
  - Bij begin: toon eerste 7
  - Bij einde: toon laatste 7
  - In het midden: toon current ± 3

**UI elementen:**
- "Resultaten X-Y van Z" indicator
- Disabled state voor eerste/laatste pagina
- Active state voor huidige pagina
- Hover states voor interactie

#### C. Sortering

**Sorteerbare kolommen:**
- ✅ Naam (`name`)
- ✅ Geboortedatum (`birthDate`)
- ✅ Status (`status`)
- ✅ Laatst gewijzigd (`_lastUpdated`)

**Visual feedback:**
- Inactieve kolommen: `<ArrowUpDown>` (grijs)
- Actieve kolom ascending: `<ArrowUp>` (teal)
- Actieve kolom descending: `<ArrowDown>` (teal)
- Hover effect op sorteerbare headers

**Functionaliteit:**
- Click om te sorteren
- Click opnieuw om richting te wisselen (asc ↔ desc)
- Sortering reset naar pagina 1

#### D. Helper functions

```typescript
// URL parameters builder
buildUrlParams(updates: Record<string, string | number | undefined>)

// Event handlers
handleSearch(e: React.FormEvent)
handleStatusFilterChange(newStatus: string)
handleGenderFilterChange(newGender: string)
handlePageChange(newPage: number)
handleSort(column: string)

// Render helpers
renderSortIcon(column: string)
```

## UI/UX Details

### Layout
- Responsive design (desktop & mobile)
- Flex layout voor filters (wraps op kleine schermen)
- Sticky header mogelijk (voor lange lijsten)

### Colors & Styling
- Teal als primary color (#0d9488)
- Slate voor neutral elements
- Status badges met kleurcodering:
  - Amber: Screening
  - Emerald: Actief
  - Slate: Afgerond
  - Red: Afgemeld

### Empty States
- Verschillende berichten voor:
  - Geen patiënten (met CTA om toe te voegen)
  - Geen resultaten (met suggestie om filters aan te passen)

## Performance

**Optimalisaties:**
- Server-side paginatie (max 50 geladen per keer)
- URL-based state (deep linking, browser back/forward)
- Suspense voor loading states
- No-cache strategie voor realtime data

**Load times (verwacht):**
- Initial load: < 1s
- Filter/sort/page change: < 500ms
- Search debounce: instant (client-side filter)

## Database Queries

De actions maken gebruik van de FHIR API (`/api/fhir/Patient`) met de volgende query parameters:

```
GET /api/fhir/Patient?
  name={search_term}&
  status={status_filter}&
  gender={gender_filter}&
  _count={page_size}&
  _offset={offset}&
  _sort={sort_field}
```

**FHIR-compliant:**
- Gebruikt FHIR search parameters
- FHIR Bundle response format
- FHIR extension voor episode_status

## Testing Checklist

- [ ] Paginatie werkt correct (vorige/volgende/nummers)
- [ ] Search filtert correct op naam
- [ ] Status filter werkt voor alle statussen
- [ ] Gender filter werkt voor alle geslachten
- [ ] Sortering werkt voor alle kolommen
- [ ] URL parameters worden correct bijgewerkt
- [ ] Browser back/forward werkt met filters
- [ ] Empty state toont bij geen resultaten
- [ ] Responsive layout op mobile
- [ ] Loading states tonen bij data fetch
- [ ] Pagination reset bij filter wijziging

## Bekende Beperkingen

1. **FHIR API Afhankelijkheid:**
   - Requires `/api/fhir/Patient` endpoint
   - Episode status via extension (custom)
   - Supabase moet online zijn voor data

2. **Client-side vs Server-side:**
   - Search is momenteel client-side gefilterd
   - Kan server-side voor betere performance bij grote datasets

3. **BSN Kolom:**
   - Niet sorteerbaar (niet in sortBy options)
   - Encryption zou performance impact hebben

## Volgende Stappen

Na E3.S2:
- [ ] **E3.S3** - Patient CRUD (Create/Update/Delete + validatie)
- [ ] Eventueel: Advanced filters (leeftijdsbereik, postcode, etc.)
- [ ] Eventueel: Export functionaliteit (CSV/Excel)
- [ ] Eventueel: Bulk actions (selecteer multiple → wijzig status)

## Referenties

- **Bouwplan:** `docs/bouwplan-mini-epd.md` (regel 352-356, E3.S2)
- **Actions:** `app/epd/patients/actions.ts`
- **Page:** `app/epd/patients/page.tsx`
- **Component:** `app/epd/patients/components/patient-list.tsx`
- **FHIR Types:** `lib/fhir/index.ts`

---

**Datum voltooid:** 2025-11-22
**Status:** ✅ Compleet
**Dependencies voltooid:** E2.S4 (Practitioner profile)
**Blokkeert:** E3.S3 (Patient CRUD)
