import { useEffect, useState } from 'react'; import { View, TextInput, Text, StyleSheet, KeyboardAvoidingView, ScrollView, TouchableOpacity, Platform, useColorScheme, ActivityIndicator, } from 'react-native'; import { debugLog } from '../../helpers/debug_log'; import { isArabicLang, getConfiguredLocalizations, } from '../../localizations/i18n'; import type { StcPayProps } from '../../models/component_models/moyasar_props'; import { StcPayService } from '../../services/stc_pay_service'; import { formatAmount, toMajor } from '../../helpers/currency_util'; import { mapArabicNumbers } from '../../helpers/arabic_numbers_mapper'; import { formatMobileNumber } from '../../helpers/formatters'; import { StcPayOtp } from './stc_pay_otp'; import { SaudiRiyal } from '../../assets/saudi_riyal'; import { readexMedium, readexRegular } from '../../helpers/fonts'; // TODO: Modify to a better approach rather than global variable const stcPayService = new StcPayService(); let formattedAmount: string | null; // TODO: Move this to a helper function to be reusable with CC function getFormattedAmount(amount: number, currency: string): string { if (!formattedAmount) { return (formattedAmount = formatAmount(amount, currency)); } return formattedAmount; } export function StcPay({ paymentConfig, onPaymentResult, style: customStyle, }: StcPayProps) { useEffect(() => { debugLog('Moyasar SDK: stc pay view mounted'); return () => { debugLog('Moyasar SDK: stc pay view unmounted'); }; }, []); const { t } = getConfiguredLocalizations(); const isLightMode = useColorScheme() === 'light'; const [mobileNumber, setMobileNumber] = useState(''); const [mobileNumberError, setMobileNumberError] = useState( null ); const [isOtpVisible, setIsOtpVisible] = useState(false); const [isPaymentInProgress, setIsPaymentInProgress] = useState(false); const [isButtonDisabled, setIsButtonDisabled] = useState(true); useEffect(() => { setIsButtonDisabled( !!stcPayService.phoneNumberValidator.validate(mobileNumber) || isPaymentInProgress ); }, [mobileNumber, isPaymentInProgress]); return ( {isOtpVisible ? ( ) : ( {t('moyasarTranslation:phoneNumberTitle')} { const cleanNumber = value .replace(/\s/g, '') .replace(/[^\d٠-٩]/gi, ''); const mappedCleanNumbers = mapArabicNumbers(cleanNumber); setMobileNumber(mappedCleanNumbers); setMobileNumberError( stcPayService.phoneNumberValidator.visualValidate( mappedCleanNumbers ) ); }} placeholder={'05X XXX XXXX'} placeholderTextColor={customStyle?.textInputsPlaceholderColor} keyboardType="numeric" editable={!isPaymentInProgress} maxLength={12} /> {mobileNumberError} { setIsPaymentInProgress(true); const showOtp = await stcPayService.beginStcPayment( paymentConfig, mobileNumber, onPaymentResult ); setIsPaymentInProgress(false); setIsOtpVisible(showOtp); }} disabled={isButtonDisabled} > {isPaymentInProgress ? ( ) : paymentConfig.currency === 'SAR' ? ( // TODO: Remove this temp solution when the new symbol is supported by RN dependencies {`${t('moyasarTranslation:pay')}`} {`${toMajor(paymentConfig.amount, 'SAR')}`} ) : ( {t('moyasarTranslation:pay')}{' '} {getFormattedAmount( paymentConfig.amount, paymentConfig.currency )} )} )} ); } const defaultStyle = StyleSheet.create({ scrollView: { maxWidth: '100%', flexGrow: 1, justifyContent: 'space-between', flexDirection: 'column', }, container: { flex: 1, paddingHorizontal: 25, paddingVertical: 8, }, title: { fontSize: 18, marginStart: 4, marginTop: 4, textAlign: 'left', direction: isArabicLang() ? 'rtl' : 'ltr', lineHeight: Platform.OS === 'ios' ? 26 : undefined, // Text gets cutoff in the custom font in AR ...readexRegular, }, inputSubContainer: { flexDirection: 'row', justifyContent: 'center', direction: isArabicLang() ? 'rtl' : 'ltr', }, buttonContainer: { flex: 1, justifyContent: 'flex-end', marginTop: 10, }, input: { width: '100%', fontSize: 18, direction: 'ltr', textAlign: isArabicLang() ? 'right' : 'left', borderWidth: 1.25, borderColor: '#DCDCDC', borderRadius: 7, marginTop: 10, marginBottom: 2, padding: 10, ...readexRegular, }, button: { minWidth: '100%', justifyContent: 'center', backgroundColor: '#4F008C', borderRadius: 9, padding: 10, height: 50, }, buttonText: { color: 'white', fontSize: 16, fontWeight: '500', textAlign: 'center', lineHeight: Platform.OS === 'ios' ? 26 : undefined, // Text gets cutoff in the custom font in AR ...readexMedium, }, errorText: { color: 'red', fontSize: 12, textAlign: 'left', direction: isArabicLang() ? 'rtl' : 'ltr', lineHeight: Platform.OS === 'ios' ? 26 : undefined, // Text gets cutoff in the custom font in AR ...readexRegular, }, });