import React, { useEffect, useRef, useState, useCallback } from 'react'; import { ActivityIndicator, StyleSheet, View, Text, Alert, Modal, Animated, Easing, TouchableWithoutFeedback, Platform, Dimensions, } from 'react-native'; import type { CryptoWalletProps } from './types/crypto_wallet_props'; import WebView, { type WebViewNavigation } from 'react-native-webview'; import CryptoWalletInit from './CryptoWalletInit'; import { colors } from './configs'; const borderRadiusDimension = 24 / 896; const windowHeight = Dimensions.get('window').height; const CryptoWallet: React.FC = ({ apiKey, customerEmail, callbackUrl, businessName, bussinessLogo, activityIndicatorColor = colors.primary, }) => { const [_, setLoading] = useState(true); const [error, setError] = useState(''); const [url, setUrl] = useState(null); const [showModal, setshowModal] = useState(false); const webViewRef = useRef(null); const animation = useRef(new Animated.Value(0)); const animateIn = React.useCallback(() => { setshowModal(true); Animated.timing(animation.current, { toValue: 1, duration: 700, easing: Easing.in(Easing.elastic(0.72)), useNativeDriver: false, }).start(); }, []); const animateOut = React.useCallback((): Promise => { return new Promise((resolve) => { Animated.timing(animation.current, { toValue: 0, duration: 400, useNativeDriver: false, }).start(() => { setshowModal(false); resolve(); }); }); }, []); const onReload = React.useCallback(() => { if (webViewRef.current) { webViewRef.current.reload(); } }, []); const onCancel = useCallback( (confirmed: boolean = false) => { if (!confirmed) { Alert.alert('', 'Are you sure you want to cancel this payment?', [ { text: 'No' }, { text: 'Yes, Cancel', style: 'destructive', onPress: () => onCancel(true), }, ]); return; } // remove tx_ref and dismiss animateOut(); }, [animateOut] ); useEffect(() => { setLoading(true); animateIn(); CryptoWalletInit({ apiKey: apiKey, customer_email: customerEmail, business_name: businessName, business_logo: bussinessLogo, callback_url: callbackUrl, }) .then((response) => { console.log(response); setLoading(false); setUrl(response); setError(''); }) .catch((error) => { console.log(error); setLoading(false); setError((error as Error).message); }); }, [false]); const marginTop = animation.current.interpolate({ inputRange: [0, 1], outputRange: [windowHeight, 0], }); const opacity = animation.current.interpolate({ inputRange: [0, 0.3, 1], outputRange: [0, 1, 1], }); return ( onCancel()} animation={animation.current} /> {error && ( onReload()} /> )} ( )} renderError={() => ( onReload()} /> )} onNavigationStateChange={(state: WebViewNavigation) => { console.log(state); }} /> ); }; interface CryptoWalletBackdropProps { animation: Animated.Value; onPress?: () => void; } const CryptoWalletBackdrop: React.FC = ({ animation, onPress, }) => { // Interpolation backdrop animation const backgroundColor = animation.interpolate({ inputRange: [0, 0.3, 1], outputRange: [colors.transparent, colors.transparent, 'rgba(0,0,0,0.5)'], }); return ( ); }; type CryptoWalletErrorProps = { error?: string; onTryAgain: () => void; }; const CryptoWalletError: React.FC = ({}) => { return ( An error occur, Please close the dialog and try again ); }; const styles = StyleSheet.create({ container: { top: Platform.select({ ios: 96, android: 64 }), flex: 1, backgroundColor: '#efefef', paddingBottom: Platform.select({ ios: 96, android: 64 }), overflow: 'hidden', borderTopLeftRadius: windowHeight * borderRadiusDimension, borderTopRightRadius: windowHeight * borderRadiusDimension, }, progressBar: { flex: 1, justifyContent: 'center', alignItems: 'center', }, webView: { flex: 1, backgroundColor: 'rgba(0,0,0,0)', }, error: { flex: 1, justifyContent: 'center', }, errorText: { textAlign: 'center', fontSize: 20, margin: 40, paddingHorizontal: 50, }, errorButton: { padding: 12, backgroundColor: 'blue', marginHorizontal: 40, borderRadius: 50, }, errorButtonText: { textAlign: 'center', fontSize: 18, color: 'white', }, backdrop: { position: 'absolute', left: 0, right: 0, bottom: 0, top: 0, }, }); export default CryptoWallet;