import { useState, useRef, useMemo, useCallback, useEffect } from 'react' import { View, Text, StyleSheet, Pressable, useWindowDimensions, } from 'react-native' import { LinearGradient } from 'expo-linear-gradient' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { useRouter } from 'expo-router' import { useTranslation } from 'react-i18next' import BottomSheet, { BottomSheetView, BottomSheetBackdrop } from '@gorhom/bottom-sheet' import { CloseIcon, CheckIcon, UncheckedIcon, PointsIcon } from '@/components/icon' export interface TopUpOption { id: string points: number price: number } export interface TopUpDrawerProps { /** * 是否显示抽屉 */ visible: boolean /** * 关闭回调 */ onClose: () => void /** * 需要消耗的积分 */ requiredPoints?: number /** * 当前剩余积分 */ remainingPoints?: number /** * 充值选项列表 */ options?: TopUpOption[] /** * 确认充值回调 */ onConfirm?: (option: TopUpOption) => void /** * 充值标题 */ topUpTitle?: string /** * 充值描述 */ topUpDescription?: string /** * 导航回调,用于在导航时关闭父级抽屉(如 PointsDrawer) */ onNavigate?: () => void } const defaultOptions: TopUpOption[] = [ { id: '1', points: 1000, price: 20 }, { id: '2', points: 2500, price: 20 }, { id: '3', points: 5000, price: 20 }, { id: '4', points: 10000, price: 20 }, ] export default function TopUpDrawer({ visible, onClose, options = defaultOptions, onConfirm, topUpTitle, topUpDescription, onNavigate, }: TopUpDrawerProps) { const { t } = useTranslation() const router = useRouter() const insets = useSafeAreaInsets() const bottomSheetRef = useRef(null) const [selectedOption, setSelectedOption] = useState( options[0] || null ) const [agreed, setAgreed] = useState(false) const snapPoints = useMemo(() => [420], []) useEffect(() => { if (visible) { bottomSheetRef.current?.expand() } else { bottomSheetRef.current?.close() } }, [visible]) const handleSheetChanges = useCallback((index: number) => { if (index === -1) { onClose() } }, [onClose]) const renderBackdrop = useCallback( (props: any) => ( ), [] ) const handleClose = useCallback(() => { bottomSheetRef.current?.close() onClose() }, [onClose]) // 如果没有传入标题,使用默认翻译 const displayTitle = topUpTitle || t('topUp.title') const handleConfirm = () => { if (selectedOption && agreed) { onConfirm?.(selectedOption) } } return ( {displayTitle && ( // 这个绝对定位的标题层会盖在右上角关闭按钮上,必须允许触摸事件“穿透” {/* 主文字层 */} {displayTitle} )} {topUpDescription && ( {topUpDescription} )} {/* 充值选项网格 */} {options.map((option) => { const isSelected = selectedOption?.id === option.id return ( setSelectedOption(option)} > {isSelected ? ( {option.points.toLocaleString()} ${option.price} ) : ( {option.points.toLocaleString()} ${option.price} )} ) })} {/* 底部按钮和协议 */} {t('topUp.confirm')} setAgreed(!agreed)} > {agreed ? : } setAgreed(!agreed)} > {t('topUp.agreementText')}{' '} { e.stopPropagation() onClose() onNavigate?.() router.push('/terms') }} > {t('topUp.terms')} {t('topUp.agreementAnd')} { e.stopPropagation() onClose() onNavigate?.() router.push('/privacy') }} > {t('topUp.privacy')} ) } const styles = StyleSheet.create({ bottomSheetBackground: { backgroundColor: '#090A0B', }, handleIndicator: { backgroundColor: '#666666', }, container: { backgroundColor: '#090A0B', paddingHorizontal: 12, overflow: 'visible', }, titleContainer: { position: 'absolute', top:10, left: 0, right: 0, alignItems: 'center', justifyContent: 'center', zIndex: 10, height: 40, overflow: 'visible', }, strokeTextWrapper: { position: 'absolute', alignItems: 'center', justifyContent: 'center', }, titleText: { fontSize: 24, fontWeight: '600', textAlign: 'center', zIndex: 1, includeFontPadding: false, textAlignVertical: 'center', lineHeight: 28, }, titleStroke: { color: '#000000', }, titleFill: { color: '#F5F5F5', position: 'relative', }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingTop: 12, marginTop: 20, }, closeButton: { width: 24, height: 24, alignItems: 'center', justifyContent: 'center', }, infoSection: { marginBottom: 24, }, infoText: { color: '#F5F5F5', fontSize: 14, fontWeight: '400', marginBottom: 8, }, subtitle: { color: '#ABABAB', fontSize: 12, fontWeight: '400', }, optionsGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 8, marginTop: 12, }, optionCardWrapper: { width: '47%', aspectRatio: 2.3, }, optionCardGradient: { width: '100%', height: '100%', borderRadius: 12, padding: 2, }, optionCard: { flex: 1, alignItems: 'center', justifyContent: 'center', borderRadius: 12, backgroundColor: '#16181B', overflow: 'hidden', gap: 4, }, optionContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 2, }, optionPoints: { color: '#F5F5F5', fontSize: 20, fontWeight: '500', }, optionPrice: { color: '#ABABAB', fontSize: 12, fontWeight: '400', }, footer: { paddingTop: 20, gap: 16, }, confirmButton: { width: '100%', height: 48, borderRadius: 12, overflow: 'hidden', }, confirmButtonGradient: { width: '100%', height: 48, alignItems: 'center', justifyContent: 'center', borderRadius: 12, }, confirmButtonDisabled: { opacity: 0.5, }, confirmButtonText: { color: '#F5F5F5', fontSize: 16, fontWeight: '600', }, agreementContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, checkbox: { width: 12, height: 12, alignItems: 'center', justifyContent: 'center', marginRight: 4, }, agreementText: { color: '#8A8A8A', fontSize: 10, fontWeight: '400', }, agreementLink: { color: '#ABABAB', textDecorationLine: 'underline', }, })