/* eslint-disable valtio/state-snapshot-rule */ import { useSnapshot } from 'valtio'; import { useRef, useState, useMemo, useEffect } from 'react'; import { FlatList, StyleSheet, View, Modal } from 'react-native'; import { FlexView, IconLink, Spacing, Text, useTheme, Separator, BorderRadius, useCustomDimensions } from '@reown/appkit-ui-react-native'; import { OnRampController } from '@reown/appkit-core-react-native'; import { Quote, ITEM_HEIGHT as QUOTE_ITEM_HEIGHT } from './Quote'; import { PaymentMethod } from './PaymentMethod'; import { type OnRampPaymentMethod, type OnRampQuote } from '@reown/appkit-common-react-native'; interface SelectPaymentModalProps { title?: string; visible: boolean; onClose: () => void; } const SEPARATOR_HEIGHT = Spacing.s; export function SelectPaymentModal({ title, visible, onClose }: SelectPaymentModalProps) { const Theme = useTheme(); const { maxHeight } = useCustomDimensions(); const { selectedQuote, quotes, selectedPaymentMethod } = useSnapshot(OnRampController.state); const paymentMethodsRef = useRef(null); const [paymentMethods, setPaymentMethods] = useState( OnRampController.state.paymentMethods ); const [activePaymentMethod, setActivePaymentMethod] = useState( OnRampController.state.selectedPaymentMethod ); const availablePaymentMethods = useMemo(() => { return paymentMethods.filter( paymentMethod => quotes?.some(quote => quote.paymentMethodType === paymentMethod.paymentMethod) ); }, [paymentMethods, quotes]); const availableQuotes = useMemo(() => { return quotes?.filter(quote => activePaymentMethod?.paymentMethod === quote.paymentMethodType); }, [quotes, activePaymentMethod]); const sortedQuotes = useMemo(() => { if (!selectedQuote || selectedQuote.paymentMethodType !== activePaymentMethod?.paymentMethod) { return availableQuotes; } return [ selectedQuote, ...(availableQuotes?.filter( quote => quote.serviceProvider !== selectedQuote.serviceProvider ) ?? []) ]; }, [availableQuotes, selectedQuote, activePaymentMethod]); const renderSeparator = () => { return ; }; const handleQuotePress = (quote: OnRampQuote) => { if (activePaymentMethod) { OnRampController.clearError(); OnRampController.setSelectedQuote(quote); OnRampController.setSelectedPaymentMethod(activePaymentMethod); } onClose(); }; const handlePaymentMethodPress = (paymentMethod: OnRampPaymentMethod) => { setActivePaymentMethod(paymentMethod); }; const renderQuote = ({ item, index }: { item: OnRampQuote; index: number }) => { const logoURL = OnRampController.getServiceProviderImage(item.serviceProvider); const isSelected = item.serviceProvider === OnRampController.state.selectedQuote?.serviceProvider && item.paymentMethodType === OnRampController.state.selectedQuote?.paymentMethodType; const isRecommended = availableQuotes?.findIndex(quote => quote.serviceProvider === item.serviceProvider) === 0 && availableQuotes?.length > 1; const tagText = isRecommended ? 'Recommended' : item.lowKyc ? 'Low KYC' : undefined; return ( handleQuotePress(item)} tagText={tagText} testID={`quote-item-${index}`} /> ); }; const renderPaymentMethod = ({ item }: { item: OnRampPaymentMethod }) => { const parsedItem = item as OnRampPaymentMethod; const isSelected = parsedItem.paymentMethod === activePaymentMethod?.paymentMethod; return ( handlePaymentMethodPress(parsedItem)} selected={isSelected} testID={`payment-method-item-${parsedItem.paymentMethod}`} /> ); }; useEffect(() => { if (visible && OnRampController.state.selectedPaymentMethod) { const methods = [ OnRampController.state.selectedPaymentMethod, ...OnRampController.state.paymentMethods.filter( m => m.paymentMethod !== OnRampController.state.selectedPaymentMethod?.paymentMethod ) ]; //Update payment methods order setPaymentMethods(methods); setActivePaymentMethod(OnRampController.state.selectedPaymentMethod); } }, [visible]); return ( {!!title && {title}} Pay with item.paymentMethod} horizontal showsHorizontalScrollIndicator={false} /> Providers `${item.serviceProvider}-${item.paymentMethodType}`} getItemLayout={(_, index) => ({ length: QUOTE_ITEM_HEIGHT + SEPARATOR_HEIGHT, offset: (QUOTE_ITEM_HEIGHT + SEPARATOR_HEIGHT) * index, index })} /> ); } const styles = StyleSheet.create({ modalContent: { margin: 0, flex: 1, justifyContent: 'flex-end' }, header: { marginBottom: Spacing.l, paddingHorizontal: Spacing.m, paddingTop: Spacing.m }, container: { borderTopLeftRadius: BorderRadius.l, borderTopRightRadius: BorderRadius.l }, separator: { width: undefined, marginVertical: Spacing.m, marginHorizontal: Spacing.m }, listContent: { paddingTop: Spacing['3xs'], paddingBottom: Spacing['4xl'], paddingHorizontal: Spacing.m }, iconPlaceholder: { height: 32, width: 32 }, subtitle: { marginBottom: Spacing.xs, marginHorizontal: Spacing.m }, emptyContainer: { height: 150 }, paymentMethodsContainer: { paddingHorizontal: Spacing['3xs'] }, paymentMethodsContent: { paddingLeft: Spacing.xs } });