1
+ import React , { createContext , useCallback , useMemo , useState } from 'react' ;
2
+ import { Modal , View , ActivityIndicator , } from 'react-native' ;
3
+ import { WebView , WebViewMessageEvent } from 'react-native-webview' ;
4
+ import {
5
+ PaystackParams ,
6
+ PaystackProviderProps ,
7
+ } from './types' ;
8
+ import { validateParams , paystackHtmlContent , generatePaystackParams , handlePaystackMessage } from './utils' ;
9
+ import { styles } from './styles' ;
10
+
11
+ export const PaystackContext = createContext < {
12
+ popup : {
13
+ checkout : ( params : PaystackParams ) => void ;
14
+ newTransaction : ( params : PaystackParams ) => void ;
15
+ } ;
16
+ } | null > ( null ) ;
17
+
18
+ export const PaystackProvider : React . FC < PaystackProviderProps > = ( {
19
+ publicKey,
20
+ currency = 'NGN' ,
21
+ defaultChannels = [ 'card' ] ,
22
+ debug = false ,
23
+ children,
24
+ onGlobalSuccess,
25
+ onGlobalCancel,
26
+ } ) => {
27
+ const [ visible , setVisible ] = useState ( false ) ;
28
+ const [ params , setParams ] = useState < PaystackParams | null > ( null ) ;
29
+ const [ method , setMethod ] = useState < 'checkout' | 'newTransaction' > ( 'checkout' ) ;
30
+
31
+ const fallbackRef = useMemo ( ( ) => `ref_${ Date . now ( ) } ` , [ ] ) ;
32
+
33
+ const open = useCallback (
34
+ ( params : PaystackParams , selectedMethod : 'checkout' | 'newTransaction' ) => {
35
+ if ( debug ) console . log ( `[Paystack] Opening modal with method: ${ selectedMethod } ` ) ;
36
+ if ( ! validateParams ( params , debug ) ) return ;
37
+ setParams ( params ) ;
38
+ setMethod ( selectedMethod ) ;
39
+ setVisible ( true ) ;
40
+ } ,
41
+ [ debug ]
42
+ ) ;
43
+
44
+ const checkout = ( params : PaystackParams ) => open ( params , 'checkout' ) ;
45
+ const newTransaction = ( params : PaystackParams ) => open ( params , 'newTransaction' ) ;
46
+
47
+ const close = ( ) => {
48
+ setVisible ( false ) ;
49
+ setParams ( null ) ;
50
+ }
51
+
52
+ const handleMessage = ( event : WebViewMessageEvent ) => {
53
+ handlePaystackMessage ( {
54
+ event,
55
+ debug,
56
+ params,
57
+ onGlobalSuccess,
58
+ onGlobalCancel,
59
+ close,
60
+ } ) ;
61
+ } ;
62
+
63
+ const paystackHTML = useMemo ( ( ) => {
64
+ if ( ! params ) return '' ;
65
+ return paystackHtmlContent (
66
+ generatePaystackParams ( {
67
+ publicKey,
68
+ email : params . email ,
69
+ amount : params . amount ,
70
+ reference : params . reference || fallbackRef ,
71
+ metadata : params . metadata ,
72
+ currency,
73
+ channels : defaultChannels ,
74
+ } ) ,
75
+ method
76
+ ) ;
77
+ } , [ params , method ] ) ;
78
+
79
+ if ( debug && visible ) {
80
+ console . log ( '[Paystack] HTML Injected:' , paystackHTML ) ;
81
+ }
82
+
83
+ return (
84
+ < PaystackContext . Provider value = { { popup : { checkout, newTransaction } } } >
85
+ { children }
86
+ < Modal visible = { visible } transparent animationType = "slide" >
87
+ < View style = { styles . container } >
88
+ < WebView
89
+ originWhitelist = { [ "*" ] }
90
+ source = { { html : paystackHTML } }
91
+ onMessage = { handleMessage }
92
+ javaScriptEnabled
93
+ domStorageEnabled
94
+ startInLoadingState
95
+ onLoadStart = { ( ) => debug && console . log ( '[Paystack] WebView Load Start' ) }
96
+ onLoadEnd = { ( ) => debug && console . log ( '[Paystack] WebView Load End' ) }
97
+ renderLoading = { ( ) => < ActivityIndicator size = "large" /> }
98
+ />
99
+ </ View >
100
+ </ Modal >
101
+ </ PaystackContext . Provider >
102
+ ) ;
103
+ } ;
0 commit comments