Ga naar inhoud

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-picker de crop en wordt de afbeelding daarna door expo-image-manipulator op 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 in pendingTogglePatchRef zodat 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-manipulator naar 512 bij 512 gezet; op web levert AvatarCropModal een Blob. De backend slaat de afbeelding synchroon op in S3 als WebP en geeft direct een signed avatar_url terug. 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: MyDataScreen gebruikt erasureApi. De export gaat via requestDataExport; het verwijderverzoek loopt in stappen (start levert of TOTP nodig is en of er een e-mailcode is verstuurd, daarna bevestigt confirm met 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 via authApi.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
  • /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.tsx en AvatarCropModal.web.tsx: native- en webvariant van de croptool. Op native een lichte wrapper omdat expo-image-picker de 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.tsx
  • frontend/src/features/profile/screens/MyDataScreen.tsx
  • frontend/src/features/profile/screens/GekoppeldeAccountsScreen.tsx
  • frontend/src/features/profile/api/profileApi.ts
  • frontend/src/features/profile/api/erasureApi.ts
  • frontend/app/profiel/_layout.tsx