import React from 'react'; import { NativeEventEmitter, NativeModules, requireNativeComponent, StyleSheet } from 'react-native'; import { MFLanguage } from './MFEnums'; import { MFGetPaymentStatusResponse, MFExecutePaymentRequest, MFGooglePayRequest, MFError } from './MFModels'; import { modelParser } from './MFUtils'; //#region GooglePay V2 (MFGPayModule - Recommended) const MFGPayConstants = { MFGPayModuleNAME: 'MFGPayModule', MFGooglePayButtonModuleNAME: 'MFGooglePayButton', GPayReceivedTokenEventName: 'onGPayReceivedToken', GPaySessionUpdatedEventName: 'onGPaySessionUpdated', GPayExecutePaymentSuccessEventName: 'onGPayExecutePaymentSuccess', GPayInvoiceCreatedEventName: 'onGPayInvoiceCreated', GPayErrorEventName: 'onGPayError', }; interface IGooglePayButtonProps { style?: any; type?: number; theme?: number; radius?: number; } const styles = StyleSheet.create({ googlePay: { width: '90%', height: 70, margin: 10, }, }); // Google Pay is Android-only; on iOS MFGPayModule is not registered. Fall back to a // no-op so `new NativeEventEmitter(...)` doesn't throw at import on iOS (it would // otherwise crash the whole JS bundle). The emitter is never used on iOS. const MFGPayNative = NativeModules.MFGPayModule ?? { addListener: () => {}, removeListeners: () => {} }; const MFEventEmitter = new NativeEventEmitter(MFGPayNative); const GooglePayButton = requireNativeComponent('MFGooglePayButton'); const { GooglePayButtonConstants } = NativeModules; type Listener = ((value: T) => void) | undefined; interface IMFGPayButton { setupWithAutoExecute(sessionId: string, googlePayRequest: MFGooglePayRequest): Promise<{ isReady: boolean }>; setupWithManualExecute(sessionId: string, googlePayRequest: MFGooglePayRequest): Promise<{ isReady: boolean }>; setupTokenOnly(googlePayRequest: MFGooglePayRequest): Promise<{ isReady: boolean }>; isGooglePayAvailable(): Promise; updateRequestAmount(amount: string): Promise<{ isUpdated: boolean }>; openSheet(): Promise<{ isInvoked: boolean }>; executePayment(executePaymentRequest: MFExecutePaymentRequest, lang: MFLanguage): Promise; } class MFGPayButton extends React.Component implements IMFGPayButton { constructor(props: any) { super(props); } async setupWithAutoExecute( sessionId: string, googlePayRequest: MFGooglePayRequest, onInvoiceCreated?: (invoiceId: string) => void, onExecutePaymentSuccess?: (response: MFGetPaymentStatusResponse) => void, onError?: (error: MFError) => void ): Promise<{ isReady: boolean }> { this.registerListener(MFGPayConstants.GPayInvoiceCreatedEventName, onInvoiceCreated); this.registerListener(MFGPayConstants.GPayExecutePaymentSuccessEventName, onExecutePaymentSuccess); this.registerListener(MFGPayConstants.GPayErrorEventName, onError); const jsonResponse = await MFGPayNative.setupWithAutoExecute(sessionId, googlePayRequest); return modelParser<{ isReady: boolean }>(jsonResponse); } async setupWithManualExecute( sessionId: string, googlePayRequest: MFGooglePayRequest, onSessionUpdated?: (updatedSessionId: string) => void, onError?: (error: MFError) => void ): Promise<{ isReady: boolean }> { this.registerListener(MFGPayConstants.GPaySessionUpdatedEventName, onSessionUpdated); this.registerListener(MFGPayConstants.GPayErrorEventName, onError); const jsonResponse = await MFGPayNative.setupWithManualExecute(sessionId, googlePayRequest); return modelParser<{ isReady: boolean }>(jsonResponse); } async setupTokenOnly( googlePayRequest: MFGooglePayRequest, onReceivedToken?: (token: string) => void, onError?: (error: MFError) => void ): Promise<{ isReady: boolean }> { this.registerListener(MFGPayConstants.GPayReceivedTokenEventName, onReceivedToken); this.registerListener(MFGPayConstants.GPayErrorEventName, onError); const jsonResponse = await MFGPayNative.setupTokenOnly(googlePayRequest); return modelParser<{ isReady: boolean }>(jsonResponse); } async isGooglePayAvailable(): Promise { return await MFGPayNative.isGooglePayAvailable(); } async updateRequestAmount(amount: string): Promise<{ isUpdated: boolean }> { const jsonResponse = await MFGPayNative.updateRequestAmount(amount); return modelParser<{ isUpdated: boolean }>(jsonResponse); } async openSheet(): Promise<{ isInvoked: boolean }> { const jsonResponse = await MFGPayNative.openSheet(); return modelParser<{ isInvoked: boolean }>(jsonResponse); } async executePayment( executePaymentRequest: MFExecutePaymentRequest, lang: MFLanguage, onInvoiceCreated?: (invoiceId: string) => void ): Promise { this.registerListener(MFGPayConstants.GPayInvoiceCreatedEventName, onInvoiceCreated); const jsonResponse = await MFGPayNative.executePayment(executePaymentRequest, lang); return modelParser(jsonResponse); } private registerListener(eventName: string, listener?: Listener) { MFEventEmitter.removeAllListeners(eventName); if (typeof listener === 'function') { MFEventEmitter.addListener(eventName, (data: T | string) => { let parsedData: T; try { if ( eventName === MFGPayConstants.GPayReceivedTokenEventName || eventName === MFGPayConstants.GPayInvoiceCreatedEventName ) { parsedData = data as T; // keep token as-is } else { parsedData = typeof data === 'string' ? modelParser(data) : data; } } catch { parsedData = data as T; } listener(parsedData); }); } } render() { return ; } } export { MFGPayButton, GooglePayButtonConstants, IGooglePayButtonProps }; //#endregion