Profiel (Frontend)
UI-Architectuur & Design
De profielmodule bestaat uit een hoofdscherm en acht losse subschermen voor specifieke acties. Het hoofdscherm gebruikt SectionCard plus RowItem voor een consistente lijststructuur. Privacy- en haptics-toggles werken optimistisch: de schakelaar gaat direct om en de PATCH wordt op de achtergrond verstuurd. Bij een fout wordt de waarde teruggedraaid en verschijnt een toast.
- ProfileScreen: bovenste avatar-blok, persoonsgegevens met inline bewerken, privacy-toggles, haptics, een biometrie-schakelaar per apparaat (native), het wisselen tussen apotheken bij meerdere lidmaatschappen, en snelkoppelingen naar pushmeldingen, e-mailmeldingen, beveiliging, sessies, mijn gegevens en gekoppelde accounts.
- AvatarCropModal (web variant): web-only croptool die een blob teruggeeft. Op native verzorgt
expo-image-pickerde crop en wordt de afbeelding daarna doorexpo-image-manipulatorop 512 bij 512 gezet voordat de upload start. - PushNotificationsScreen: master-schakelaar plus categoriegroepen. Vraagt browser- of OS-pushtoestemming pas op het moment dat de gebruiker de master-schakelaar zelf aanzet, en registreert dan een pushtoken via
registerForPushToken. - EmailNotificationsScreen: identieke opbouw, zonder toestemmingsvraag.
- PasswordChangeScreen, TwoFAResetScreen, SessionsScreen, TrustedDevicesScreen: aparte routes die deels via
/api/auth/...werken (wachtwoord, 2FA, sessies, devices) en hier in de profielmodule gegroepeerd staan voor UX-eenheid. - MyDataScreen: zelf-service AVG-acties. De gebruiker vraagt een gegevensexport aan en kan een verwijderverzoek voor het eigen account starten, bevestigen of annuleren.
- GekoppeldeAccountsScreen: toont de eigen OIDC-koppelingen (ZORG-ID, Google, Apple), start een koppeling via de authenticatiemodule en laat de gebruiker een koppeling ontkoppelen.
graph TD
A[app/profiel/index.tsx] --> B[ProfileScreen]
A2[app/profiel/pushmeldingen.tsx] --> C[PushNotificationsScreen]
A3[app/profiel/emailmeldingen.tsx] --> D[EmailNotificationsScreen]
A4[app/profiel/wachtwoord-reset.tsx] --> E[PasswordChangeScreen]
A5[app/profiel/2fa-reset.tsx] --> F[TwoFAResetScreen]
A6[app/profiel/sessies.tsx] --> G[SessionsScreen]
A7[app/profiel/apparaten.tsx] --> H[TrustedDevicesScreen]
A8[app/profiel/mijn-data.tsx] --> I[MyDataScreen]
A9[app/profiel/gekoppelde-accounts.tsx] --> J[GekoppeldeAccountsScreen]
B --> B1[ProfileAvatarBlock]
B --> B2[AvatarCropModal]
B --> B3[LogoutFloatingRow]
State & Data Flow
De profielmodule houdt geen eigen globale store bij. Per scherm wordt bij mount via profileApi data opgehaald, in lokale useState gezet en met PATCH-calls bijgewerkt. De ingelogde gebruiker (naam, e-mail, telefoon, avatar) wordt centraal beheerd door AuthContext. Na een avatar-upload of e-mailwijziging roept ProfileScreen setUser aan zodat header, sidebar en chat direct de nieuwe waarden tonen.
- Toggles: optimistic update via
patchToggle. Patches worden gequeued inpendingTogglePatchRefzodat snel opeenvolgende clicks samen in een PATCH worden geflusht. Bij een fout draait de queue terug. - Avatar upload: foto wordt op native door
expo-image-manipulatornaar 512 bij 512 gezet; op web levertAvatarCropModaleen Blob. De backend slaat de afbeelding synchroon op in S3 als WebP en geeft direct een signedavatar_urlterug. Er is geen polling. - Push permission: het scherm vraagt toestemming alleen na een expliciete actie van de gebruiker (master-toggle aan). Wordt toestemming geweigerd, dan opent een toast met een link naar de instellingen van het apparaat.
- Gegevensexport en verwijderverzoek:
MyDataScreengebruikterasureApi. De export gaat viarequestDataExport; het verwijderverzoek loopt in stappen (startlevert of TOTP nodig is en of er een e-mailcode is verstuurd, daarna bevestigtconfirmmet wachtwoord en een tweede factor). Een lopend verzoek toont de geplande datum en een annuleerknop. - Gekoppelde accounts: koppelen verloopt via de authenticatiemodule (op native deels via
expo-apple-authentication, anders via een browser-round-trip die terugkeert op/oauth-return). Ontkoppelen gaat viaauthApi.oauthUnlink.
sequenceDiagram
participant UI as ProfileScreen
participant API as profileApi.ts
participant Auth as AuthContext
participant BE as Backend
UI->>API: GET /api/profile/settings/
BE-->>API: 200 ProfileSettings
UI->>API: PATCH /api/profile/settings/ {share_phone:false}
BE-->>API: 200 ProfileSettings
UI->>API: POST /api/profile/avatar/ (multipart)
BE-->>API: 200 {avatar_url}
API-->>Auth: setUser({...user, avatarUrl})
Auth-->>UI: re-render header/sidebar
Navigatie & Routing
/profiel: hoofdscherm (ProfileScreen)./profiel/pushmeldingen: PushNotificationsScreen./profiel/emailmeldingen: EmailNotificationsScreen./profiel/wachtwoord-reset: PasswordChangeScreen./profiel/2fa-reset: TwoFAResetScreen./profiel/sessies: SessionsScreen./profiel/apparaten: TrustedDevicesScreen./profiel/mijn-data: MyDataScreen./profiel/gekoppelde-accounts: GekoppeldeAccountsScreen.
Alle routes zijn gegroepeerd onder app/profiel/_layout.tsx met een Stack zonder header. Elke route checkt eerst of de gebruiker is ingelogd en redirect anders naar /login. Er is geen aanvullende RBAC: een gebruiker kan altijd zijn eigen profiel en instellingen beheren.
Bestandsstructuur & Verantwoordelijkheden
src/features/profile/screens/ProfileScreen.tsx: hoofdscherm met avatar, persoonsgegevens, privacy-toggles, haptics, biometrie en apotheek-wissel.src/features/profile/screens/PushNotificationsScreen.tsx: master-schakelaar plus per-categorie pushvoorkeuren; vraagt toestemming en registreert pushtoken.src/features/profile/screens/EmailNotificationsScreen.tsx: per-categorie e-mailvoorkeuren.src/features/profile/screens/PasswordChangeScreen.tsx: wachtwoord wijzigen via/api/auth/security/password/change/.src/features/profile/screens/TwoFAResetScreen.tsx: TOTP opnieuw instellen via/api/auth/security/2fa/reset/.src/features/profile/screens/SessionsScreen.tsx: actieve sessies tonen en intrekken.src/features/profile/screens/TrustedDevicesScreen.tsx: vertrouwde apparaten beheren via/api/auth/devices/.src/features/profile/screens/MyDataScreen.tsx: gegevensexport en het verwijderverzoek voor het eigen account.src/features/profile/screens/GekoppeldeAccountsScreen.tsx: OIDC-koppelingen (ZORG-ID, Google, Apple) bekijken, koppelen en ontkoppelen.src/features/profile/components/ProfileAvatarBlock.tsx: render van de avatar plus knop voor foto wijzigen of verwijderen.src/features/profile/components/AvatarCropModal.tsxenAvatarCropModal.web.tsx: native- en webvariant van de croptool. Op native een lichte wrapper omdatexpo-image-pickerde crop afhandelt; op web rendert de modal een echte cropper.src/features/profile/components/LogoutFloatingRow.tsx: rij voor uitloggen onder aan het scherm.src/features/profile/components/skeletons/: skeletons (ProfileSkeleton,PushNotificationsSkeleton,SessionsSkeleton,MyDataSkeleton,_shared) die de definitieve layout nabootsen om layout-jumps te voorkomen.src/features/profile/api/profileApi.ts: API-calls voor settings, avatar, push, e-mail, devices, wachtwoord en 2FA-reset.src/features/profile/api/erasureApi.ts: API-calls voor gegevensexport en het verwijderverzoek.
Belangrijke bestanden
frontend/src/features/profile/screens/ProfileScreen.tsxfrontend/src/features/profile/screens/MyDataScreen.tsxfrontend/src/features/profile/screens/GekoppeldeAccountsScreen.tsxfrontend/src/features/profile/api/profileApi.tsfrontend/src/features/profile/api/erasureApi.tsfrontend/app/profiel/_layout.tsx