263 lines
7.2 KiB
TypeScript
263 lines
7.2 KiB
TypeScript
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 { useTranslation } from 'react-i18next'
|
|
import BottomSheet, { BottomSheetView, BottomSheetBackdrop } from '@gorhom/bottom-sheet'
|
|
import { CloseIcon } from '@/components/icon'
|
|
import TopUpDrawer, { TopUpOption } from '@/components/drawer/TopUpDrawer'
|
|
|
|
export interface PointsDrawerProps {
|
|
/**
|
|
* 是否显示抽屉
|
|
*/
|
|
visible: boolean
|
|
/**
|
|
* 关闭回调
|
|
*/
|
|
onClose: () => void
|
|
/**
|
|
* 当前积分总额
|
|
*/
|
|
totalPoints?: number
|
|
/**
|
|
* 订阅积分
|
|
*/
|
|
subscriptionPoints?: number
|
|
/**
|
|
* 额外充值积分
|
|
*/
|
|
topUpPoints?: number
|
|
/**
|
|
* 充值回调
|
|
*/
|
|
onRecharge?: (amount: any) => void
|
|
}
|
|
|
|
export default function PointsDrawer({
|
|
visible,
|
|
onClose,
|
|
totalPoints = 0,
|
|
subscriptionPoints = 0,
|
|
topUpPoints = 0,
|
|
onRecharge,
|
|
}: PointsDrawerProps) {
|
|
const { t } = useTranslation()
|
|
const insets = useSafeAreaInsets()
|
|
const bottomSheetRef = useRef<BottomSheet>(null)
|
|
const [topUpDrawerVisible, setTopUpDrawerVisible] = useState(false)
|
|
|
|
const snapPoints = useMemo(() => [380], [])
|
|
|
|
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) => (
|
|
<BottomSheetBackdrop
|
|
{...props}
|
|
disappearsOnIndex={-1}
|
|
appearsOnIndex={0}
|
|
opacity={0.5}
|
|
/>
|
|
),
|
|
[]
|
|
)
|
|
|
|
return (
|
|
<BottomSheet
|
|
ref={bottomSheetRef}
|
|
index={visible ? 0 : -1}
|
|
snapPoints={snapPoints}
|
|
onChange={handleSheetChanges}
|
|
enablePanDownToClose
|
|
backgroundStyle={styles.bottomSheetBackground}
|
|
handleComponent={null}
|
|
backdropComponent={renderBackdrop}
|
|
>
|
|
<BottomSheetView style={styles.container}>
|
|
{/* 顶部标题栏 */}
|
|
<View style={styles.header}>
|
|
<Text></Text>
|
|
<Pressable
|
|
style={styles.closeButton}
|
|
onPress={onClose}
|
|
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
>
|
|
<CloseIcon />
|
|
</Pressable>
|
|
</View>
|
|
<View style={styles.titleContainer}>
|
|
<Text style={styles.title}>{t('pointsDrawer.title')}</Text>
|
|
{/* 积分总额 */}
|
|
<View style={styles.balance}>
|
|
<Text style={styles.balanceValue}>{totalPoints}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* 底部按钮 */}
|
|
<View style={[styles.footer, { paddingBottom: Math.max(insets.bottom, 16) }]}>
|
|
<Pressable
|
|
style={styles.subscribeButton}
|
|
onPress={() => {
|
|
onClose()
|
|
}}
|
|
>
|
|
<LinearGradient
|
|
colors={['#FF9966', '#FF6699', '#9966FF']}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 0 }}
|
|
style={styles.subscribeButtonGradient}
|
|
>
|
|
<Text style={styles.subscribeButtonText}>{t('pointsDrawer.subscribeForPoints')}</Text>
|
|
</LinearGradient>
|
|
</Pressable>
|
|
<Pressable
|
|
style={styles.topUpButton}
|
|
onPress={() => {
|
|
setTopUpDrawerVisible(true)
|
|
}}
|
|
>
|
|
<Text style={styles.topUpButtonText}>{t('pointsDrawer.topUpPointsButton')}</Text>
|
|
</Pressable>
|
|
</View>
|
|
</BottomSheetView>
|
|
|
|
{/* 充值抽屉 */}
|
|
<TopUpDrawer
|
|
visible={topUpDrawerVisible}
|
|
onClose={() => setTopUpDrawerVisible(false)}
|
|
onNavigate={() => {
|
|
setTopUpDrawerVisible(false)
|
|
onClose()
|
|
}}
|
|
requiredPoints={100}
|
|
remainingPoints={totalPoints}
|
|
topUpTitle={t('topUp.title')}
|
|
onConfirm={(option: TopUpOption) => {
|
|
// 处理充值确认逻辑
|
|
console.log('确认充值:', option)
|
|
setTopUpDrawerVisible(false)
|
|
}}
|
|
/>
|
|
</BottomSheet>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
bottomSheetBackground: {
|
|
backgroundColor: '#090A0B',
|
|
borderTopLeftRadius: 24,
|
|
borderTopRightRadius: 24,
|
|
},
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: '#090A0B',
|
|
borderTopLeftRadius: 20,
|
|
borderTopRightRadius: 20,
|
|
overflow: 'hidden',
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
paddingTop: 12,
|
|
marginRight: 12,
|
|
},
|
|
titleContainer: {
|
|
paddingLeft: 20,
|
|
marginTop: -4,
|
|
},
|
|
title: {
|
|
color: '#F5F5F5',
|
|
fontSize: 12,
|
|
fontWeight: '500',
|
|
},
|
|
closeButton: {
|
|
width: 24,
|
|
height: 24,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
balance: {
|
|
marginBottom: 13,
|
|
},
|
|
balanceValue: {
|
|
color: '#F5F5F5',
|
|
fontSize: 40,
|
|
fontWeight: '500',
|
|
},
|
|
breakdown: {
|
|
flexDirection: 'row',
|
|
gap: 16,
|
|
marginBottom: 24,
|
|
},
|
|
breakdownText: {
|
|
color: '#ABABAB',
|
|
fontSize: 12,
|
|
fontWeight: '400',
|
|
},
|
|
breakdownTextValue: {
|
|
color: '#F5F5F5',
|
|
fontSize: 12,
|
|
fontWeight: '500',
|
|
marginLeft: 6,
|
|
},
|
|
breakdownTextSeparator: {
|
|
width: 1,
|
|
height: 14,
|
|
backgroundColor: '#3A3A3A',
|
|
marginTop: 2,
|
|
},
|
|
footer: {
|
|
paddingTop: 20,
|
|
paddingHorizontal: 16,
|
|
gap: 4,
|
|
},
|
|
subscribeButton: {
|
|
width: '100%',
|
|
height: 48,
|
|
borderRadius: 12,
|
|
overflow: 'hidden',
|
|
},
|
|
subscribeButtonGradient: {
|
|
width: '100%',
|
|
height: 48,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
borderRadius: 12,
|
|
},
|
|
subscribeButtonText: {
|
|
color: '#F5F5F5',
|
|
fontSize: 16,
|
|
fontWeight: '500',
|
|
},
|
|
topUpButton: {
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingVertical: 12,
|
|
},
|
|
topUpButtonText: {
|
|
color: '#F5F5F5',
|
|
fontSize: 12,
|
|
fontWeight: '400',
|
|
},
|
|
})
|