@filanodev/paygate-next
v1.0.2
Published
Plugin Next.js pour l'intégration de PayGateGlobal - Support FLOOZ et T-Money
Maintainers
Readme
@filanodev/paygate-next
Plugin Next.js pour l'intégration de PayGateGlobal - Support FLOOZ et T-Money.
📝 Package communautaire développé par Filano pour aider les développeurs Next.js à intégrer plus rapidement PayGateGlobal.
Fonctionnalités
- ✅ Next.js 12-15 - Support des versions modernes
- 🔄 SSR/SSG/ISR - Compatible avec tous les modes de rendu
- ⚡ API Routes - Helpers prêts à l'emploi
- 🎯 TypeScript - Support complet avec types
- 🛠 React Hooks - Client-side moderne
- 🔧 Server Utils - Utilitaires serveur
- 🌐 App Router - Support Next.js 13+ App Directory
Installation
npm install @filanodev/paygate-next
# ou
yarn add @filanodev/paygate-next
# ou
pnpm add @filanodev/paygate-nextConfiguration
Variables d'environnement
Créez un fichier .env.local :
PAYGATE_TOKEN=your-paygate-token-hereProvider dans l'App (App Router)
// app/layout.tsx
import { PayGateProvider } from '@filanodev/paygate-next/client'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="fr">
<body>
<PayGateProvider
authToken={process.env.NEXT_PUBLIC_PAYGATE_TOKEN!}
verifySSL={false} // pour le développement uniquement
>
{children}
</PayGateProvider>
</body>
</html>
)
}Provider dans Pages Router
// pages/_app.tsx
import type { AppProps } from 'next/app'
import { PayGateProvider } from '@filanodev/paygate-next/client'
export default function App({ Component, pageProps }: AppProps) {
return (
<PayGateProvider
authToken={process.env.NEXT_PUBLIC_PAYGATE_TOKEN!}
verifySSL={false}
>
<Component {...pageProps} />
</PayGateProvider>
)
}Usage Client-side
Hook principal
// app/payment/page.tsx
'use client'
import { usePayGate } from '@filanodev/paygate-next/client'
export default function PaymentPage() {
const {
initiatePayment,
loading,
error,
lastPayment,
clearError
} = usePayGate()
const handlePayment = async () => {
const result = await initiatePayment({
phoneNumber: '+22890123456',
amount: 1000,
identifier: `ORDER_${Date.now()}`,
network: 'FLOOZ',
description: 'Test paiement Next.js'
})
if (result) {
console.log('Paiement initié:', result.txReference)
}
}
return (
<div>
<h1>Paiement PayGate</h1>
<button onClick={handlePayment} disabled={loading}>
{loading ? 'Traitement...' : 'Payer 1000 FCFA'}
</button>
{error && (
<div className="error">
{error}
<button onClick={clearError}>×</button>
</div>
)}
{lastPayment && (
<div className="success">
Paiement initié: {lastPayment.txReference}
</div>
)}
</div>
)
}Composant PaymentForm
// app/checkout/page.tsx
'use client'
import { PaymentForm } from '@filanodev/paygate-next/client'
import { useRouter } from 'next/navigation'
export default function CheckoutPage() {
const router = useRouter()
const handleSuccess = (result: any) => {
console.log('Paiement réussi:', result)
router.push(`/success?ref=${result.txReference}`)
}
const handleError = (error: string) => {
console.error('Erreur paiement:', error)
// Afficher une notification d'erreur
}
return (
<div>
<h1>Finaliser votre commande</h1>
<PaymentForm
onSuccess={handleSuccess}
onError={handleError}
submitLabel="Payer maintenant"
showReset={true}
defaultDescription="Commande e-commerce"
identifierPrefix="SHOP"
/>
</div>
)
}Hook spécialisé pour les statuts
// app/payment/[reference]/page.tsx
'use client'
import { usePaymentStatus } from '@filanodev/paygate-next/client'
import { useParams } from 'next/navigation'
export default function PaymentStatusPage() {
const params = useParams()
const reference = params.reference as string
const {
status,
loading,
error,
isPolling,
check,
startPolling,
stopPolling
} = usePaymentStatus(reference, 5000)
return (
<div>
<h1>Statut du paiement</h1>
<p>Référence: {reference}</p>
<div>
<button onClick={() => check()} disabled={loading}>
Vérifier maintenant
</button>
<button onClick={startPolling} disabled={isPolling}>
📡 Surveillance auto
</button>
<button onClick={stopPolling} disabled={!isPolling}>
⏹ Arrêter
</button>
</div>
{status && (
<div className={`status-${status.status === 0 ? 'success' : 'pending'}`}>
<h3>{status.message}</h3>
<p>Montant: {status.amount} FCFA</p>
<p>Téléphone: {status.phoneNumber}</p>
<p>Méthode: {status.paymentMethod}</p>
</div>
)}
{isPolling && (
<p>🔄 Surveillance en cours...</p>
)}
</div>
)
}API Routes
App Router - Route Handlers
// app/api/payments/initiate/route.ts
import { NextRequest } from 'next/server'
import { createInitiatePaymentHandler } from '@filanodev/paygate-next/server'
const handler = createInitiatePaymentHandler({
authToken: process.env.PAYGATE_TOKEN!
})
export async function POST(request: NextRequest) {
return handler(request)
}// app/api/payments/status/[reference]/route.ts
import { NextRequest } from 'next/server'
import { createStatusHandler } from '@filanodev/paygate-next/server'
const handler = createStatusHandler()
export async function GET(
request: NextRequest,
{ params }: { params: { reference: string } }
) {
return handler(request, { params })
}// app/api/payments/balance/route.ts
import { NextRequest } from 'next/server'
import { createBalanceHandler } from '@filanodev/paygate-next/server'
const handler = createBalanceHandler()
export async function GET(request: NextRequest) {
return handler(request)
}Pages Router - API Routes
// pages/api/payments/initiate.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { serverInitiatePayment, validatePaymentData } from '@filanodev/paygate-next/server'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Méthode non autorisée' })
}
try {
const paymentData = validatePaymentData(req.body)
const result = await serverInitiatePayment(paymentData)
res.status(200).json({
success: true,
data: result
})
} catch (error) {
res.status(400).json({
success: false,
error: error.message
})
}
}// pages/api/payments/status/[reference].ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { serverCheckPaymentStatus } from '@filanodev/paygate-next/server'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Méthode non autorisée' })
}
try {
const { reference } = req.query
const status = await serverCheckPaymentStatus(reference as string)
res.status(200).json({
success: true,
data: status
})
} catch (error) {
res.status(404).json({
success: false,
error: 'Paiement non trouvé'
})
}
}Webhook Handler
// app/api/webhooks/paygate/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { createWebhookHandler } from '@filanodev/paygate-next/server'
const webhookHandler = createWebhookHandler(
async (payload) => {
// Traiter la mise à jour du paiement
console.log('Paiement mis à jour:', payload)
// Exemple: mettre à jour la base de données
// await updatePaymentInDatabase(payload.identifier, payload.status)
// Exemple: envoyer une notification
// await sendNotification(payload)
},
process.env.PAYGATE_WEBHOOK_SECRET
)
export async function POST(request: NextRequest) {
try {
const payload = await request.json()
const success = await webhookHandler(payload)
if (success) {
return NextResponse.json({ received: true })
} else {
return NextResponse.json({ error: 'Invalid webhook' }, { status: 400 })
}
} catch (error) {
return NextResponse.json({ error: 'Webhook error' }, { status: 500 })
}
}Utilisation Server-side
Dans les Server Components
// app/orders/[id]/page.tsx
import { serverCheckPaymentStatus } from '@filanodev/paygate-next/server'
interface Props {
params: { id: string }
}
export default async function OrderPage({ params }: Props) {
let paymentStatus = null
try {
// Récupérer le statut côté serveur
paymentStatus = await serverCheckPaymentStatus(params.id)
} catch (error) {
console.error('Erreur lors de la récupération du statut:', error)
}
return (
<div>
<h1>Commande #{params.id}</h1>
{paymentStatus ? (
<div className={`status-${paymentStatus.status === 0 ? 'success' : 'pending'}`}>
<p>Statut: {paymentStatus.message}</p>
<p>Montant: {paymentStatus.amount} FCFA</p>
</div>
) : (
<p>Statut du paiement non disponible</p>
)}
</div>
)
}Dans les Server Actions
// app/payment/actions.ts
'use server'
import { serverInitiatePayment } from '@filanodev/paygate-next/server'
import { revalidatePath } from 'next/cache'
export async function processPayment(formData: FormData) {
try {
const result = await serverInitiatePayment({
phoneNumber: formData.get('phoneNumber') as string,
amount: Number(formData.get('amount')),
identifier: `ORDER_${Date.now()}`,
network: formData.get('network') as 'FLOOZ' | 'TMONEY',
description: 'Paiement via Server Action'
})
// Revalider les données de la page
revalidatePath('/payments')
return {
success: true,
data: result
}
} catch (error) {
return {
success: false,
error: error.message
}
}
}Middleware et sécurité
Middleware avec CORS
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { withCors } from '@filanodev/paygate-next/server'
const corsHandler = withCors(['https://your-domain.com'])
export function middleware(request: NextRequest) {
// Appliquer CORS aux routes API PayGate
if (request.nextUrl.pathname.startsWith('/api/payments')) {
return corsHandler((req) => NextResponse.next())(request)
}
return NextResponse.next()
}
export const config = {
matcher: '/api/payments/:path*'
}Configuration avancée
// lib/paygate.ts
import { createPayGateApiClient, ensurePayGateConfig } from '@filanodev/paygate-next/server'
// Vérifier la configuration au démarrage
ensurePayGateConfig()
// Client global pour l'application
export const paygateClient = createPayGateApiClient({
authToken: process.env.PAYGATE_TOKEN!,
verifySSL: process.env.NODE_ENV === 'production'
})Exemple d'application complète
// app/page.tsx
import { PaymentDemo } from './components/PaymentDemo'
export default function HomePage() {
return (
<main>
<h1>Demo PayGate Next.js</h1>
<PaymentDemo />
</main>
)
}// app/components/PaymentDemo.tsx
'use client'
import { useState } from 'react'
import { usePayGate, PaymentForm } from '@filanodev/paygate-next/client'
export function PaymentDemo() {
const [paymentReference, setPaymentReference] = useState<string | null>(null)
const { checkPaymentStatus, loading, lastStatus } = usePayGate()
const handlePaymentSuccess = (result: any) => {
setPaymentReference(result.txReference)
}
const checkStatus = async () => {
if (paymentReference) {
await checkPaymentStatus(paymentReference)
}
}
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<h2>Initier un paiement</h2>
<PaymentForm
onSuccess={handlePaymentSuccess}
onError={(error) => console.error(error)}
identifierPrefix="DEMO"
/>
{paymentReference && (
<div style={{ marginTop: '30px', padding: '20px', background: '#f5f5f5' }}>
<h3>Vérifier le statut</h3>
<p>Référence: {paymentReference}</p>
<button onClick={checkStatus} disabled={loading}>
{loading ? 'Vérification...' : 'Vérifier le statut'}
</button>
{lastStatus && (
<div style={{ marginTop: '10px' }}>
<strong>Statut:</strong> {lastStatus.message}<br />
<strong>Montant:</strong> {lastStatus.amount} FCFA<br />
<strong>Méthode:</strong> {lastStatus.paymentMethod}
</div>
)}
</div>
)}
</div>
)
}API
Hooks Client-side
usePayGate()- Hook principal avec toutes les fonctionnalitésusePaymentInitiation()- Spécialisé pour l'initiation de paiementsusePaymentStatus(reference?, pollInterval?)- Vérification de statut avec polling
Composants
<PayGateProvider>- Provider context pour l'application<PaymentForm>- Formulaire de paiement complet
Utilitaires Server-side
getServerPayGateClient(config?)- Obtenir le client serveurserverInitiatePayment(params, config?)- Initier un paiementserverCheckPaymentStatus(reference, config?)- Vérifier le statutcreateInitiatePaymentHandler(config?)- Handler API prêt à l'emploicreateStatusHandler(config?)- Handler de vérification de statutcreateWebhookHandler(onUpdated, secret?)- Handler de webhook
Helpers API
withPayGateErrorHandling()- Middleware de gestion d'erreursvalidatePaymentData()- Validation des données de paiementcreateApiResponse()- Créer une réponse API standardiséewithCors()- Middleware CORS
Support TypeScript
Le package inclut tous les types TypeScript :
import type {
PayGateConfig,
InitiatePaymentParams,
PaymentResponse,
PaymentStatus,
WebhookPayload
} from '@filanodev/paygate-next'Gestion des erreurs
'use client'
import { usePayGate, PayGateError } from '@filanodev/paygate-next/client'
export default function PaymentComponent() {
const { initiatePayment } = usePayGate()
const handlePayment = async () => {
try {
await initiatePayment(params)
} catch (error) {
if (error instanceof PayGateError) {
console.error('Erreur PayGate:', error.status, error.message)
} else {
console.error('Erreur générale:', error)
}
}
}
return <button onClick={handlePayment}>Payer</button>
}Support
Pour toute question sur ce package, créez une issue sur GitHub.
Pour le support PayGateGlobal officiel :
- Site : https://paygateglobal.com/
- Email : [email protected]
Licence
MIT
