import { View, Platform, findNodeHandle, UIManager } from 'react-native'; import { SamsungPayButton } from './index'; import type { SamsungPayProps } from '../../models/component_models/moyasar_props'; import { debugLog, errorLog } from '../../helpers/debug_log'; import { useEffect, useRef } from 'react'; import type { ResultCallback } from '../../models/payment_result'; import { PaymentRequest } from '../../models/api/api_requests/payment_request'; import { SamsungPayRequestSource } from '../../models/api/sources/samsung_pay/samsung_pay_request_source'; import { createPayment } from '../../services/payment_service'; import { GeneralError, isMoyasarError, NetworkError, } from '../../models/errors/moyasar_errors'; import { PaymentConfig } from '../../models/payment_config'; import { toMajor } from '../../helpers/currency_util'; import { assert } from '../../helpers/assert'; export async function onSamsungPayResponse( token: string, orderNumber: string, paymentConfig: PaymentConfig, onPaymentResult: ResultCallback ) { const source = new SamsungPayRequestSource({ samsungPayToken: token, manualPayment: paymentConfig.samsungPay?.manual, }); const paymentRequest = new PaymentRequest({ givenId: paymentConfig.givenId, baseUrl: paymentConfig.baseUrl, amount: paymentConfig.amount, currency: paymentConfig.currency, description: paymentConfig.description, metadata: { ...(paymentConfig.metadata || {}), samsungpay_order_id: orderNumber, // This value must be supplied to native layer for Visa payments. Also for refund & chargebacks that's why we will send it to the backend }, source: source, applyCoupon: paymentConfig.applyCoupon, splits: paymentConfig.splits, }); debugLog('Moyasar SDK: Paying with Samsung Pay...'); try { const paymentResponse = await createPayment( paymentRequest, paymentConfig.publishableApiKey ); onPaymentResult(paymentResponse); } catch (error) { errorLog(`Moyasar SDK: Failed to pay with Samsung Pay, ${error}`); if (isMoyasarError(error)) { onPaymentResult(error); } else { onPaymentResult( new NetworkError( 'Moyasar SDK: An error occured error while processing a Samsung Pay payment' ) ); } } } // If we can't get the manufacturer, assume it's a Samsung device. Native layer will handle it. function isSamsungDevice(): boolean { if (Platform.OS !== 'android') return false; try { const manufacturer = Platform.constants.Manufacturer; if (!manufacturer) return true; const sanitized = manufacturer.toLowerCase().trim(); return sanitized === 'samsung' || sanitized.includes('samsung'); } catch (e) { debugLog(`Moyasar SDK: Error checking Samsung device: ${e}`); return true; } } const createFragment = (viewId: number | null) => UIManager.dispatchViewManagerCommand( viewId, // We are calling the 'create' command 'CreateSamsungPayButtonFragment', [viewId] ); // TODO: Support customizing the Samsung Pay button export function SamsungPay({ paymentConfig, onPaymentResult, style, }: SamsungPayProps) { assert( !!paymentConfig.samsungPay, 'Samsung Pay is not configured to use Samsung Pay, you have to configure the `samsungPay` property in the `PaymentConfig` object' ); const ref = useRef(null); useEffect(() => { if (isSamsungDevice() && paymentConfig.samsungPay) { // Samsung Pay SDK initialization code const viewId = findNodeHandle(ref.current); if (viewId === null) { errorLog('Failed to get viewId for Samsung Pay'); return; } debugLog('Moyasar SDK: Initializing Samsung Pay fragment...'); // TODO: Try catch createFragment(viewId); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Samsung Pay is in Samsung devices only, show empty view on other devices if (!isSamsungDevice() || !paymentConfig.samsungPay) { debugLog( 'Moyasar SDK: Samsung Pay is not supported on this device or the `samsungPay` property is not set, showing empty view' ); return ; } // TODO: Check why the button takes some top and bottom padding // If the below view is rendered but not visible, // it mostly mean that the Samsung device does not support Samsung Pay // or the device is not configured for it yet (There are other rare cases as well as implmented by Samsung) return ( { if (!result.nativeEvent.result) { errorLog('Moyasar SDK: Samsung Pay result is empty or null'); onPaymentResult( new GeneralError('Moyasar SDK: Samsung Pay token is null') ); return; } const payload = JSON.parse(result.nativeEvent.result ?? ''); onSamsungPayResponse( payload['3DS'].data, result.nativeEvent.orderNumber ?? '', paymentConfig, onPaymentResult ); }} ref={ref} /> ); }