@mostajs/pay-panel-ui
v0.2.0
Published
Panneau de paiement headless + Web Component : sélecteur de plan × sélecteur de fournisseur × récurrence → checkout. Compose @mostajs/payment.
Maintainers
Readme
@mostajs/pay-panel-ui
Panneau de paiement headless + Web Component : grille de plans × sélecteur de fournisseur × récurrence → checkout. Compose
@mostajs/payment; consomme plans/providers par injection (app-agnostique). i18n fr / en / ar + RTL.
Auteur : Dr Hamid MADANI [email protected]
Pourquoi
@mostajs/payment encaisse (11 providers) ; @mostajs/subscriptions-plan gère plans & abonnements —
mais aucun ne fournit l'UI « choisir une offre + un mode de paiement + payer ». Ce module
comble ce gap de présentation, sans dupliquer la logique : il compose payment et reçoit les
données par injection. Voir docs/02-AUDIT-EXISTANT-PAYPANELUI.md.
Architecture
- Cœur headless (
.) — état + logique + i18n/RTL, sans dépendance framework. - Web Component (
./web) —<pay-panel>, marche en HTML pur et dans tout framework. - React (
./react, à venir 0.2) —<PayPanel/>composant qui embarquepayment.PaymentPage.
Utilisation — HTML pur (cas RaceVision)
<pay-panel locale="fr" theme="dark"></pay-panel>
<script type="module">
import '@mostajs/pay-panel-ui/web' // auto-enregistre <pay-panel>
const el = document.querySelector('pay-panel')
el.config = {
plans: () => fetch('/sponsor/plans').then(r => r.json()),
providers: () => fetch('/sponsor/providers').then(r => r.json()).then(j => j.providers),
scope: { type: 'course', id: 'cyclisme-alger-2026' },
onCheckout: (sel) => fetch('/sponsor/checkout', {
method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify({ advertiserId: 'adv-1', planSlug: sel.planSlug, provider: sel.provider, courseSlug: 'cyclisme-alger-2026' }),
}).then(r => r.json()).then(j => ({ checkoutUrl: j.checkoutUrl })),
}
el.addEventListener('checkout', (e) => console.log(e.detail))
</script>Utilisation — cœur headless (n'importe quel rendu)
import { createPayPanel } from '@mostajs/pay-panel-ui'
const panel = createPayPanel({ plans, providers, onCheckout, locale: 'ar' /* ⇒ RTL */ })
panel.subscribe((state) => render(state)) // votre rendu
await panel.load()
panel.select({ planSlug: 'gold', provider: 'stripe' })
await panel.checkout()Utilisation — React (./react)
import { PayPanel } from '@mostajs/pay-panel-ui/react'
<PayPanel config={{ plans, providers, onCheckout, scope, locale: 'fr' }} />
// Checkout EMBARQUÉ (compose @mostajs/payment) via le slot renderCheckout :
import { PaymentPage } from '@mostajs/payment'
<PayPanel
config={cfg}
renderCheckout={({ selection }) => (
<PaymentPage orderId={oid} orderSummary={{ title: selection!.planSlug, amount, currency }}
config={paymentConfig} checkoutApiPath="/sponsor/checkout" />
)}
/>Hook bas niveau : const { state, select, checkout, t } = usePayPanel(config).
Thème via variables CSS --pp-card / --pp-bd / --pp-accent / --pp-ok / --pp-danger / --pp-fg / --pp-mut.
react est un peer optionnel (cœur . et ./web n'en dépendent pas).
i18n & RTL
locale: 'fr' | 'en' | 'ar' (défaut fr). 'ar' applique dir="rtl". Libellés surchargeables via
config.messages. Helpers exportés : PAYPANEL_I18N, isRTL, makeTranslator, formatPrice, intervalLabel.
Attributs (<pay-panel>)
locale—fr|en|artheme—light|dark- propriété
config(JS) —{ plans, providers, onCheckout, scope?, messages?, autoRedirect? } - évènement
checkout—{ detail: { selection, result } }
Licence
AGPL-3.0-or-later — Dr Hamid MADANI [email protected]
