/** * Sprint 5d — Hook Stripe Customer Portal. * * Wrap la mutation `createCustomerPortalSession` + redirect full-page vers * la session Customer Portal Stripe. Utilisé par : * - `AccountBillingSection` (page Paramètres) : bouton « Gérer mon abonnement ». * - `PricingPage` (Standard→Premium) : redirige vers le portal qui gère * nativement l'upgrade prorata + confirmation du montant. * * Erreur 400 `NO_ACTIVE_SUBSCRIPTION` propagée telle quelle (le backend * fournit déjà un message FR exploitable directement). */ import { useState } from 'react' import { useMutation } from '@tanstack/react-query' import { createCustomerPortalSession } from '../api' export interface UseCustomerPortalResult { openPortal: () => void isLoading: boolean error: string | null } const FALLBACK_ERROR_MESSAGE = 'Impossible d’ouvrir l’espace abonnement. Réessayez dans quelques instants.' export function useCustomerPortal(): UseCustomerPortalResult { const [error, setError] = useState(null) const mutation = useMutation({ mutationFn: createCustomerPortalSession, onSuccess: (data) => { // Redirect full-page : l'utilisateur reviendra sur ${APP_URL}/dashboard // (cf. backend `return_url`). Le query param `?upgrade=success` n'est PAS // ajouté par le portal — pas de banner de bienvenue dans ce flow, // seulement une éventuelle invalidation au refresh manuel. window.location.href = data.url }, onError: (err: unknown) => { const message = err instanceof Error && err.message ? err.message : FALLBACK_ERROR_MESSAGE setError(message) }, }) function openPortal(): void { setError(null) mutation.mutate() } return { openPortal, isLoading: mutation.isPending, error, } }