expria-frontend/src/features/billing/hooks/useCustomerPortal.ts
Hermann_Kitio de16deede3 feat(billing): Customer Portal + page Paramètres + Standard→Premium via portal
- useCustomerPortal hook (mutation + redirect full-page)
- AccountBillingSection: badge plan + bouton Gérer mon abonnement (Standard/Premium)
- ParametresPage: page conteneur /parametres avec section billing
- PricingPage: Standard→Premium redirige vers Customer Portal (prorata natif Stripe)
- Tests: 212 → 219 verts (+7)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 05:43:06 +03:00

55 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 douvrir lespace abonnement. Réessayez dans quelques instants.'
export function useCustomerPortal(): UseCustomerPortalResult {
const [error, setError] = useState<string | null>(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,
}
}