expo-duooomi-app/app/pointList.native.tsx

239 lines
9.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Ionicons } from '@expo/vector-icons'
import { root } from '@repo/core'
import { AlipayController } from '@repo/sdk'
import { LinearGradient } from 'expo-linear-gradient'
import Alipay from 'expo-native-alipay'
import { Stack, useRouter } from 'expo-router'
import ExpoWeChat from 'expo-wechat'
import React, { useEffect, useState } from 'react'
import { Dimensions, ScrollView } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { Block, Img, Text } from '@/@share/components'
import { IOS_UNIVERSAL_LINK, SCHEME } from '@/app.constants'
import { useUserBalance } from '@/hooks/core'
import { useError } from '@/hooks/data/use-error'
import { cn } from '@/utils/cn'
const { width: SCREEN_WIDTH } = Dimensions.get('window')
const OPTION_WIDTH = (SCREEN_WIDTH - 32 - 15) / 2 // 32px padding, 15px gap
const RECHARGE_OPTIONS = [
{ id: 1, points: '500', price: '$10.00' },
{ id: 2, points: '1,000', price: '$20.00' },
{ id: 3, points: '2,500', price: '$50.00' },
{ id: 4, points: '5,000', price: '$100.00' },
]
const PAYMENT_METHODS = [
{ id: 'alipay', label: '支付宝' },
{ id: 'wechat', label: '微信' },
] as const
export default function ChargePage() {
const router = useRouter()
const insets = useSafeAreaInsets()
const [selectedOption, setSelectedOption] = useState(RECHARGE_OPTIONS[0].id)
const [paymentMethod, setPaymentMethod] = useState<'alipay' | 'wechat'>('alipay')
const balanceRes = useUserBalance()
console.log('balanceRes-------', balanceRes)
const selectedRecharge = RECHARGE_OPTIONS.find((option) => option.id === selectedOption)
const initPay = async () => {
// 设置支付宝回调 URL Scheme使用 App 的统一 scheme
Alipay.setAlipayScheme(SCHEME)
Alipay.setAlipaySandbox(true) // 开启沙箱模式,测试环境使用
console.log('-------alipay version:', await Alipay.getVersion())
const wechatAppId = 'wx940e1ed91a5c303c'
const result = await ExpoWeChat.registerApp(wechatAppId, IOS_UNIVERSAL_LINK)
console.log('-------wechat', result)
}
const handlePay = async () => {
// 支付宝端支付
// payInfo 是后台拼接好的支付参数
// return_url=
// const payInfo =
// 'alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=2021001172656340&biz_content=%7B%22out_trade_no%22%3A%221111112222222%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%221234%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay&notify_url=http%3A%2F%2Fane.boshu.ltd%2Fowner%2Fpay%2Fapi%2FownerPay%2Fcallback&sign=oUQmGtkv8mrhJ0YwHl9%2FfxMcoLACWuSFKiMTC4Id8nc%2FZVvDQ6MLQq5hhtEN03Qn1%2BAtzTAaofE8nNixdroxOek2l5YtOAcYcXVYlJIyogN%2B22erN2NpDTWJ7tQTKgYFDJLRiG0DZJaxfADhUUF6UR9kdA8omoXKLDlP17ZPUs5Jr4aKv5HJtH5C53ui7PbmyWYg934L4UDC2F%2F9pPQlRwwDeE1SAaV3HW9Dt83kK52o8%2FlChXdotbFdAvH0d4qYGhpEYU5sepj9xiOMyL9aC4pMXW9INYLLGbvtqtlRchZTAfH5yji6nqqQm9KKMmcVrWdBDLyjFVNpejq1UjbJBw%3D%3D&sign_type=RSA2&timestamp=2020-07-09+12%3A16%3A16&version=1.0'
if (paymentMethod === 'alipay') {
console.log('handlePay-----------alipay')
const alipay = root.get(AlipayController)
const { data, error } = await useError(
async () =>
await alipay.appPay({
subject: '2',
totalAmount: selectedRecharge ? selectedRecharge.price.replace('$', '') : '0.01',
body: '',
outTradeNo: '2' + Date.now(),
credits: 1,
}),
)
console.log('error----------', error)
console.log('data-----------', data)
// const payInfo =
// 'alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=9021000158673972&biz_content=%7B%22out_trade_no%22%3A%221111112222222%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%221234%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay&notify_url=http%3A%2F%2Fane.boshu.ltd%2Fowner%2Fpay%2Fapi%2FownerPay%2Fcallback&sign=oUQmGtkv8mrhJ0YwHl9%2FfxMcoLACWuSFKiMTC4Id8nc%2FZVvDQ6MLQq5hhtEN03Qn1%2BAtzTAaofE8nNixdroxOek2l5YtOAcYcXVYlJIyogN%2B22erN2NpDTWJ7tQTKgYFDJLRiG0DZJaxfADhUUF6UR9kdA8omoXKLDlP17ZPUs5Jr4aKv5HJtH5C53ui7PbmyWYg934L4UDC2F%2F9pPQlRwwDeE1SAaV3HW9Dt83kK52o8%2FlChXdotbFdAvH0d4qYGhpEYU5sepj9xiOMyL9aC4pMXW9INYLLGbvtqtlRchZTAfH5yji6nqqQm9KKMmcVrWdBDLyjFVNpejq1UjbJBw%3D%3D&sign_type=RSA2&timestamp=2020-07-09+12%3A16%3A16&version=1.0'
const resule = await Alipay.pay(data.orderStr)
console.log('alipay:resule-->>>', resule)
balanceRes.load()
} else if (paymentMethod === 'wechat') {
}
}
useEffect(() => {
balanceRes.load()
initPay()
}, [])
const renderHeader = () => (
<Block className="flex-row items-center justify-between px-[16px]" style={{ paddingTop: 12, paddingBottom: 12 }}>
<Block className="ml-[-8px] size-[40px] items-center justify-center" opacity={0.7} onClick={() => router.back()}>
<Ionicons color="white" name="chevron-back" size={24} />
</Block>
<Text className="text-[16px] font-[700] text-white"></Text>
<Block className="w-[32px]" />
</Block>
)
const renderMyPoints = () => (
<Block className="mt-[12px] items-center justify-center py-[24px]">
<Text className="text-[14px] font-[400] text-[#B0B0B0]"></Text>
<Text className="mt-[4px] text-[40px] font-[900] italic tracking-tighter text-fg">{balanceRes?.balance}</Text>
</Block>
)
const renderOptions = () => (
<Block className="mt-[16px] px-[16px]">
<Text className="mb-[16px] text-[14px] font-[700] text-white"></Text>
<Block className="flex-row flex-wrap justify-between gap-y-[16px]">
{RECHARGE_OPTIONS.map((item) => {
const isSelected = selectedOption === item.id
return (
<Block
key={item.id}
opacity={0.9}
style={{ width: OPTION_WIDTH }}
className={cn(
'relative items-center justify-center overflow-hidden rounded-[16px] border-[2px] bg-[#FFFFFF33] py-[12px]',
isSelected ? 'border-[#FFE500]' : 'border-transparent',
)}
onClick={() => setSelectedOption(item.id)}
>
<Img
className="absolute inset-0"
source={require('@/assets/images/itemBg.png')}
style={{ resizeMode: 'cover' }}
/>
{/* Flash Icon */}
<Block className="mb-[8px]">
<Ionicons color="#FFD700" name="flash" size={24} />
</Block>
{/* Points */}
<Text className="mb-[16px] text-[24px] font-[700] text-white">{item.points}</Text>
{/* Price Button */}
<Block className="border-[#000000]">
<LinearGradient
colors={['#393939', '#060606']}
end={{ x: 0, y: 1 }}
start={{ x: 0, y: 0 }}
style={{
borderRadius: 100,
width: 120,
height: 32,
alignItems: 'center',
justifyContent: 'center',
borderColor: '#000000',
overflow: 'hidden',
borderWidth: 1,
}}
>
<Text className="text-[12px] font-[600] text-white"> {item.price}</Text>
</LinearGradient>
</Block>
</Block>
)
})}
</Block>
</Block>
)
const renderPaymentMethods = () => (
<Block className="mt-[32px] px-[16px]">
<Text className="font-700 mb-[16px] text-[14px] text-white">:</Text>
<Block className="gap-[12px]">
{PAYMENT_METHODS.map((method) => {
const isSelected = paymentMethod === method.id
return (
<Block
key={method.id}
opacity={0.8}
className={cn(
'flex-row items-center gap-[12px] rounded-full px-[20px] py-[16px]',
isSelected ? 'bg-white' : 'bg-[#FFFFFF33]',
)}
onClick={() => setPaymentMethod(method.id)}
>
<Block
className={cn(
'h-[20px] w-[20px] items-center justify-center rounded-full',
isSelected ? 'bg-black' : 'border-[2px] border-white/50',
)}
>
{isSelected && <Ionicons color="white" name="checkmark" size={14} />}
</Block>
<Text className={cn('font-700 text-[16px]', isSelected ? 'text-black' : 'text-white')}>
{method.label}
</Text>
</Block>
)
})}
</Block>
</Block>
)
const renderBottomBar = () => (
<Block
className="absolute inset-x-0 bottom-0 border-t border-white/5 bg-[#1C1E22]/95 px-[16px]"
style={{ paddingBottom: insets.bottom + 12, paddingTop: 16 }}
>
<Block
className="h-[52px] items-center justify-center rounded-full bg-accent shadow-lg shadow-[#FFE500]/20"
opacity={0.8}
onClick={handlePay}
>
<Text className="text-[16px] font-[900] italic text-black"></Text>
</Block>
<Block className="mt-[12px] flex-row justify-center">
<Text className="text-[11px] text-[#888888]"> </Text>
<Block opacity={0.6} onClick={() => console.log('Open agreement')}>
<Text className="text-[11px] text-accent underline"></Text>
</Block>
</Block>
</Block>
)
return (
<Block className="flex-1 bg-[#21221D]">
<Stack.Screen options={{ headerShown: false }} />
{renderHeader()}
<ScrollView contentContainerStyle={{ flexGrow: 1, paddingBottom: 200 }} showsVerticalScrollIndicator={false}>
{renderMyPoints()}
{renderOptions()}
{renderPaymentMethods()}
</ScrollView>
{renderBottomBar()}
</Block>
)
}