Ga naar inhoud

Billing (Frontend)

UI-Architectuur & Design

De Billing-UI leeft binnen het Beheer-scherm en is opgebouwd rond een tabbed SectionCard. Activatie van een abonnement gebeurt op een eigen scherm, omdat die flow een Stripe Payment Element en een terugkomstroute via SetupIntent vereist.

  • BeheerScreen rendert BillingSection als hoofdsectie. Hierin zitten de plan-status, pool-overzicht, betaalmethoden, factuurlijst en het tab-paneel.
  • BillingTabsCard toont vijf tabs: Atlas, Uitnodigingen, Reviews, Gebruik en Limiet. De tabs zijn lazy-mounted: visitedTabs voorkomt dat ongeziene tabs hun fetches starten.
  • ActiverenScreen is een eigen route en rendert het Stripe Payment Element. Op web direct via @stripe/stripe-js; op native via een WebView die dezelfde HTML laadt en het resultaat via postMessage terugstuurt naar de app.
  • LimietTabPanel combineert de SpendingLimitSettings, ReviewCapModal en ChannelCapModal voor het beheren van EUR-plafond, review-caps en notificatiedrempels.
  • UsageBarChart toont per kalendermaand een gestapelde balk met platformfee, individuele reviews, ward-reviews, SMS-overage en briefoverage. De jaartabbladen worden gevuld vanuit usage_years in de summary.
graph TD
    A[BeheerScreen] --> B[BillingSection]
    B --> C[ReadOnlyBanner]
    B --> D[PoolUsageCard]
    B --> E[PaymentMethodManager]
    B --> F[InvoiceList]
    B --> G[BillingTabsCard]
    G --> G1[Atlas tab]
    G --> G2[ChannelsTabPanel]
    G --> G3[Reviews tab]
    G --> G4[UsageBarChart]
    G --> G5[LimietTabPanel]
    G5 --> G5a[SpendingLimitSettings]
    G5 --> G5b[ReviewCapModal]
    G5 --> G5c[ChannelCapModal]
    H[ActiverenScreen] --> H1[Stripe PaymentElement / WebView]

State & Data Flow

Billing-state is bewust niet globaal: elke tab haalt zijn eigen data via billingApi. De brondata is GET /api/billing/summary/, die in een enkele response de plan-status, pool, factuurperiode, channel-usage en jaaroverzicht bevat. Aanvullende endpoints leveren detaildata (atlas, usage per jaar, spending-limit, payment methods, invoices).

  • Initial load: BillingSection haalt summary op. De Atlas-, Uitnodigingen- en Limiet-tabs lazy-laden hun extra data zodra de gebruiker erheen klikt.
  • Activatie: ActiverenScreen vraagt eerst een SetupIntent op via POST /api/billing/payment-methods/setup-intent/, toont het Stripe Payment Element met dat client_secret, en submit het resultaat naar POST /api/billing/activate/ (samen met terms_accepted en payment_method_id of setup_intent_id).
  • Polling vervalt: na een succesvolle activate-call leest de frontend opnieuw /summary/ voor de bijgewerkte plan_status. Stripe-webhooks updaten ondertussen BillingProfile/BillingPeriod op de backend zonder dat de UI hoeft te pollen.
  • Notice acknowledgements: useBillingNoticeAcknowledgements haalt de huidige acks op via GET /api/billing/acknowledgements/ en bevestigt een soort overschrijding via POST met ack_type. Daarmee worden de in-app popups voor de huidige factuurperiode onderdrukt.
sequenceDiagram
    participant UI as ActiverenScreen
    participant BE as Backend
    participant Stripe as Stripe API
    participant WH as Stripe Webhook

    UI->>BE: POST /api/billing/payment-methods/setup-intent/
    BE->>Stripe: SetupIntent.create
    Stripe-->>BE: client_secret
    BE-->>UI: client_secret + publishable_key + billing_details
    UI->>Stripe: Confirm SetupIntent (PaymentElement)
    Stripe-->>UI: setup_intent.status=succeeded
    UI->>BE: POST /api/billing/activate/ {setup_intent_id, terms_accepted}
    BE->>Stripe: PaymentMethod.attach + Subscription.create
    Stripe-->>BE: subscription_id (status active|trialing)
    BE-->>UI: 200 OK {subscription_id}
    Stripe-->>WH: customer.subscription.updated
    WH->>BE: upsert BillingPeriod, plan_status=active
  • /beheer: hoofdscherm met Billing-sectie. De tab-keuze wordt overgenomen uit de query-parameter tab (atlas, uitnodigingen, reviews, gebruik, limiet).
  • /beheer/billing/activeren: Stripe-activatie. Bouwt een WebView op native, of laadt het Payment Element direct op web. Returnt naar de app via een sentinel-URL die parseBillingReturnUrl interpreteert.
  • /beheer/billing/done: post-activatie scherm voor de native return-flow.
  • Permission gating: alle billing-routes vereisen settings.manage_billing. PermissionGate schermt UI af; backend dwingt het via HasPermissionCode af.
  • Modals: bevestiging van plan-cancel, EUR-cap aanpassen, review-caps aanpassen en betaalmethode-acties gebruiken AppModal (geen Alert.alert). Server-feedback gaat via useToast().

Bestandsstructuur & Verantwoordelijkheden

  • app/beheer/billing/activeren.tsx: Expo Router-route die ActiverenScreen mount.
  • app/beheer/billing/done.tsx: post-activatie redirect-route voor de native return-flow.
  • src/features/beheer/components/BillingSection.tsx: hoofdcomponent dat plan-status, pool, betaalmethoden, facturen en het tabpaneel orkestreert.
  • src/features/billing/screens/ActiverenScreen.tsx: Stripe-activatie scherm met Payment Element (web direct, native via WebView).
  • src/features/billing/api/billingApi.ts: REST-client voor alle /api/billing/-endpoints.
  • src/features/billing/types/billing.ts: TypeScript-types voor summary, status, spending-limit, atlas, payment methods en acknowledgements.
  • src/features/billing/constants.ts: prijs- en bundleconstanten (PLATFORM_PRICE, PLATFORM_INCLUDED_PATIENTS, INDIVIDUAL_PRICE, WARD_PRICE, BTW_RATE, ATLAS_ENTERPRISE_PRICE).
  • src/features/billing/components/AddPaymentMethodModal.tsx: modal voor het toevoegen van een betaalmethode via SetupIntent.
  • src/features/billing/components/PaymentMethodManager.tsx, PaymentMethodCard.tsx: lijst en kaartweergave van betaalmethoden.
  • src/features/billing/components/InvoiceList.tsx: facturenlijst met PDF-link naar Stripe.
  • src/features/billing/components/SpendingLimitSettings.tsx, LimietTabPanel.tsx, ReviewCapModal.tsx, ChannelCapModal.tsx: beheer van EUR-plafond, review-caps en notificatiedrempels.
  • src/features/billing/components/PoolUsageCard.tsx: visualisatie van inbegrepen vs verbruikte patienten in de huidige factuurperiode.
  • src/features/billing/components/ChannelsTabPanel.tsx: SMS- en briefverbruik plus overage-prognose.
  • src/features/billing/components/TrialStatusCard.tsx: trial-overzicht met resterende dagen.
  • src/features/billing/components/UsageBarChart.tsx: gestapelde maandgrafiek voor verbruik en kosten.
  • src/features/billing/components/EditBillingInfoModal.tsx, EditBedrijfsgegevensModal.tsx: bewerken van factuur-e-mail, adres, KVK en bedrijfsgegevens.
  • src/features/billing/components/AdresAutocomplete.tsx, KvkAutocomplete.tsx: zoekvelden voor adres (PDOK) en KVK-validatie.
  • src/features/billing/components/ReadOnlyBanner.tsx: melding bij trial-expired, cancelled of readonly plan.
  • src/features/billing/components/skeletons/: lokale skeletons voor de billing-secties.
  • src/features/billing/hooks/useBillingNoticeAcknowledgements.ts: hook die acks ophaalt en muteert.
  • src/features/billing/lib/handleBillingReturn.ts: parse- en saveroutines voor de Stripe return-URL op web en native.

Belangrijke bestanden

  • src/features/beheer/components/BillingSection.tsx
  • src/features/billing/screens/ActiverenScreen.tsx
  • src/features/billing/api/billingApi.ts
  • src/features/billing/components/LimietTabPanel.tsx
  • src/features/billing/components/SpendingLimitSettings.tsx
  • src/features/billing/types/billing.ts
  • src/features/billing/constants.ts