feat(auth): 更新用户认证类型定义并优化提款功能
- 添加 AuthCoinAmount 类型和 AuthWithdrawAccount 接口 - 在 AuthUser 和相关 DTO 中增加余额和提款账户字段 - 将获取用户资料的请求方法从 POST 改为 GET - 实现提款账户信息的默认值设置和状态管理 - 添加 JackpotPoolTicker 组件并在状态栏中显示 - 更新多语言文件中的游戏规则说明 - 实现提款表单的预填充和状态重置功能
This commit is contained in:
@@ -67,7 +67,7 @@ function logAuthSessionExpiry(action: string, session: AuthSessionInput) {
|
||||
}
|
||||
|
||||
async function getCurrentUserProfileByToken(userToken: string) {
|
||||
const response = await api.post<AuthUserProfileDto>(AUTH_ENDPOINTS.profile, {
|
||||
const response = await api.get<AuthUserProfileDto>(AUTH_ENDPOINTS.profile, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${userToken}`,
|
||||
'user-token': userToken,
|
||||
@@ -195,7 +195,7 @@ export async function sendSmsCode(
|
||||
}
|
||||
|
||||
export async function getCurrentUserProfile() {
|
||||
const response = await api.post<AuthUserProfileDto>(AUTH_ENDPOINTS.profile)
|
||||
const response = await api.get<AuthUserProfileDto>(AUTH_ENDPOINTS.profile)
|
||||
|
||||
return normalizeAuthUserProfile(
|
||||
unwrapEnvelope(
|
||||
|
||||
@@ -21,9 +21,13 @@ function formatWinAmount(value: string) {
|
||||
|
||||
type MessageBroadcastProps = {
|
||||
className?: string
|
||||
showJackpotPool?: boolean
|
||||
}
|
||||
|
||||
export function MessageBroadcast({ className }: MessageBroadcastProps) {
|
||||
export function MessageBroadcast({
|
||||
className,
|
||||
showJackpotPool = true,
|
||||
}: MessageBroadcastProps) {
|
||||
const { t } = useTranslation()
|
||||
const prefersReducedMotion = useReducedMotion()
|
||||
const jackpotBroadcasts = useGameSessionStore(
|
||||
@@ -165,10 +169,12 @@ export function MessageBroadcast({ className }: MessageBroadcastProps) {
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
<JackpotPoolTicker
|
||||
variant="inline"
|
||||
className="!w-fit max-w-[54%] shrink-0 md:max-w-[calc(var(--design-unit)*320)]"
|
||||
/>
|
||||
{showJackpotPool ? (
|
||||
<JackpotPoolTicker
|
||||
variant="inline"
|
||||
className="!w-fit max-w-[54%] shrink-0 md:max-w-[calc(var(--design-unit)*320)]"
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import fire from '@/assets/system/fire.webp'
|
||||
import lock from '@/assets/system/lock.webp'
|
||||
import statusCenter from '@/assets/system/status-center.webp'
|
||||
import statusLine from '@/assets/system/status-line.webp'
|
||||
import { JackpotPoolTicker } from '@/components/jackpot-pool-ticker.tsx'
|
||||
import { LottiePlayer } from '@/components/lottie-player.tsx'
|
||||
import { MessageBroadcast } from '@/components/message-broadcast.tsx'
|
||||
import { SmartBackground } from '@/components/smart-background.tsx'
|
||||
@@ -43,7 +44,7 @@ export function DesktopStatusLine() {
|
||||
return (
|
||||
<div className={'relative w-full flex flex-col text-design-22'}>
|
||||
<div className={'w-full px-design-16 mb-design-10'}>
|
||||
<MessageBroadcast />
|
||||
<MessageBroadcast showJackpotPool={false} />
|
||||
</div>
|
||||
<SmartBackground
|
||||
src={statusLine}
|
||||
@@ -157,8 +158,8 @@ export function DesktopStatusLine() {
|
||||
className={countdownClassName}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-1 items-center justify-center gap-design-88">
|
||||
<div className="flex items-center gap-design-9">
|
||||
<div className="grid min-w-0 flex-1 grid-cols-[repeat(3,minmax(0,1fr))] items-center justify-items-stretch pl-design-6 pr-design-16">
|
||||
<div className="flex min-w-0 items-center justify-center gap-design-6">
|
||||
<span className="relative flex h-design-24 w-design-24 items-center justify-center">
|
||||
<motion.span
|
||||
aria-hidden="true"
|
||||
@@ -207,14 +208,26 @@ export function DesktopStatusLine() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-baseline gap-design-7 font-bold leading-none">
|
||||
<div className="flex min-w-0 items-baseline justify-center gap-design-5 font-bold leading-none">
|
||||
<span className="text-design-20 tracking-[0.06em] text-[#9FBAC0]">
|
||||
{t('gameDesktop.status.roundId')}:
|
||||
</span>
|
||||
<span className="text-design-24 font-black tracking-[0.06em] text-[#E7FFFF] [text-shadow:0_0_calc(var(--design-unit)*9)_rgba(75,255,254,0.38)]">
|
||||
<span className="min-w-0 truncate text-design-24 font-black tracking-[0.06em] text-[#E7FFFF] [text-shadow:0_0_calc(var(--design-unit)*9)_rgba(75,255,254,0.38)]">
|
||||
{roundId}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex min-w-0 items-center justify-center">
|
||||
<JackpotPoolTicker
|
||||
variant="inline"
|
||||
className={cn(
|
||||
'!h-design-52 !w-full max-w-full justify-center !px-design-5 md:!px-design-6',
|
||||
'[&>div:first-child]:md:!mr-design-5 [&>div:first-child]:md:!h-design-20 [&>div:first-child]:md:!w-design-20',
|
||||
'[&>span:first-of-type]:md:!mr-[20px] [&>span:first-of-type]:md:!text-design-10',
|
||||
'[&>span:last-child]:!shrink-0 [&>span:last-child]:!text-design-9 md:[&>span:last-child]:!text-design-20',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SmartBackground>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
DEFAULT_WITHDRAW_CONFIG,
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '@/constants'
|
||||
import { useDepositWithdrawConfig } from '@/hooks/use-deposit-withdraw-config'
|
||||
import { useAuthStore } from '@/store'
|
||||
import type { DepositWithdrawConfig } from '@/type'
|
||||
import type { AuthWithdrawAccount, DepositWithdrawConfig } from '@/type'
|
||||
|
||||
const QUICK_WITHDRAW_OPTION_COUNT = 6
|
||||
|
||||
@@ -16,6 +16,24 @@ interface WithdrawDiamondBounds {
|
||||
minimumDiamonds: number
|
||||
}
|
||||
|
||||
interface WithdrawAccountDefaults {
|
||||
bankAccount: string
|
||||
holderName: string
|
||||
receiverEmail: string
|
||||
receiverPhone: string
|
||||
}
|
||||
|
||||
function getWithdrawAccountDefaults(
|
||||
withdraw: AuthWithdrawAccount | null | undefined,
|
||||
): WithdrawAccountDefaults {
|
||||
return {
|
||||
bankAccount: withdraw?.receiveAccount ?? '',
|
||||
holderName: withdraw?.receiverName ?? '',
|
||||
receiverEmail: withdraw?.receiverEmail ?? '',
|
||||
receiverPhone: withdraw?.receiverMobile ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
function formatNumber(locale: string, value: number) {
|
||||
return new Intl.NumberFormat(locale).format(value)
|
||||
}
|
||||
@@ -200,6 +218,11 @@ export function useWithdrawVm() {
|
||||
const { i18n, t } = useTranslation()
|
||||
const currentUser = useAuthStore((state) => state.currentUser)
|
||||
const withdrawConfigQuery = useDepositWithdrawConfig()
|
||||
const withdrawAccountDefaults = useMemo(
|
||||
() => getWithdrawAccountDefaults(currentUser?.withdraw),
|
||||
[currentUser?.withdraw],
|
||||
)
|
||||
const hasEditedWithdrawAccountRef = useRef(false)
|
||||
const config = useMemo(() => {
|
||||
const baseConfig = getNormalizedConfig(
|
||||
withdrawConfigQuery.data,
|
||||
@@ -228,10 +251,18 @@ export function useWithdrawVm() {
|
||||
const [paymentChannelCode, setPaymentChannelCode] = useState('')
|
||||
const [paymentType, setPaymentType] = useState('')
|
||||
const [bankCode, setBankCode] = useState('')
|
||||
const [holderName, setHolderName] = useState('')
|
||||
const [bankAccount, setBankAccount] = useState('')
|
||||
const [receiverEmail, setReceiverEmail] = useState('')
|
||||
const [receiverPhone, setReceiverPhone] = useState('')
|
||||
const [holderName, setHolderNameState] = useState(
|
||||
() => withdrawAccountDefaults.holderName,
|
||||
)
|
||||
const [bankAccount, setBankAccountState] = useState(
|
||||
() => withdrawAccountDefaults.bankAccount,
|
||||
)
|
||||
const [receiverEmail, setReceiverEmailState] = useState(
|
||||
() => withdrawAccountDefaults.receiverEmail,
|
||||
)
|
||||
const [receiverPhone, setReceiverPhoneState] = useState(
|
||||
() => withdrawAccountDefaults.receiverPhone,
|
||||
)
|
||||
|
||||
const sortedPayChannels = useMemo(
|
||||
() =>
|
||||
@@ -318,6 +349,28 @@ export function useWithdrawVm() {
|
||||
},
|
||||
[maxWithdrawAmount],
|
||||
)
|
||||
const applyWithdrawAccountDefaults = useCallback(() => {
|
||||
setHolderNameState(withdrawAccountDefaults.holderName)
|
||||
setBankAccountState(withdrawAccountDefaults.bankAccount)
|
||||
setReceiverEmailState(withdrawAccountDefaults.receiverEmail)
|
||||
setReceiverPhoneState(withdrawAccountDefaults.receiverPhone)
|
||||
}, [withdrawAccountDefaults])
|
||||
const setHolderName = useCallback((nextHolderName: string) => {
|
||||
hasEditedWithdrawAccountRef.current = true
|
||||
setHolderNameState(nextHolderName)
|
||||
}, [])
|
||||
const setBankAccount = useCallback((nextBankAccount: string) => {
|
||||
hasEditedWithdrawAccountRef.current = true
|
||||
setBankAccountState(nextBankAccount)
|
||||
}, [])
|
||||
const setReceiverEmail = useCallback((nextReceiverEmail: string) => {
|
||||
hasEditedWithdrawAccountRef.current = true
|
||||
setReceiverEmailState(nextReceiverEmail)
|
||||
}, [])
|
||||
const setReceiverPhone = useCallback((nextReceiverPhone: string) => {
|
||||
hasEditedWithdrawAccountRef.current = true
|
||||
setReceiverPhoneState(nextReceiverPhone)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const firstAvailablePayChannel = sortedPayChannels[0]
|
||||
@@ -406,6 +459,14 @@ export function useWithdrawVm() {
|
||||
}
|
||||
}, [amount, maxWithdrawAmount, setAmount])
|
||||
|
||||
useEffect(() => {
|
||||
if (hasEditedWithdrawAccountRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
applyWithdrawAccountDefaults()
|
||||
}, [applyWithdrawAccountDefaults])
|
||||
|
||||
const quickAmounts = useMemo(() => {
|
||||
if (!selectedCurrency || !withdrawDiamondBounds) {
|
||||
return []
|
||||
@@ -474,11 +535,14 @@ export function useWithdrawVm() {
|
||||
setPaymentChannelCode(nextPaymentChannelCode)
|
||||
setPaymentType(nextPaymentMethod?.code ?? '')
|
||||
setBankCode('')
|
||||
setHolderName('')
|
||||
setBankAccount('')
|
||||
setReceiverEmail('')
|
||||
setReceiverPhone('')
|
||||
}, [config, maxWithdrawAmount, sortedPayChannels])
|
||||
hasEditedWithdrawAccountRef.current = false
|
||||
applyWithdrawAccountDefaults()
|
||||
}, [
|
||||
applyWithdrawAccountDefaults,
|
||||
config,
|
||||
maxWithdrawAmount,
|
||||
sortedPayChannels,
|
||||
])
|
||||
|
||||
const selectedCurrencyPreview = useMemo(() => {
|
||||
const previewCurrencyCode = selectedCurrency?.code ?? '--'
|
||||
|
||||
@@ -24,9 +24,11 @@ export function normalizeAuthUserProfile(dto: AuthUserProfileDto): AuthUser {
|
||||
return {
|
||||
channelId: dto.channel_id,
|
||||
coin: dto.coin,
|
||||
coinBalance: dto.coin_balance,
|
||||
createTime: dto.create_time,
|
||||
currentStreak: dto.current_streak,
|
||||
email: dto.email,
|
||||
frozenBalance: dto.frozen_balance,
|
||||
headImage: dto.head_image,
|
||||
id: dto.uuid,
|
||||
lastBetPeriodNo: dto.last_bet_period_no,
|
||||
@@ -34,8 +36,18 @@ export function normalizeAuthUserProfile(dto: AuthUserProfileDto): AuthUser {
|
||||
phone: dto.phone,
|
||||
registerInviteCode: dto.register_invite_code,
|
||||
riskFlags: dto.risk_flags,
|
||||
totalDepositCoin: dto.total_deposit_coin,
|
||||
totalWithdrawCoin: dto.total_withdraw_coin,
|
||||
username: dto.username,
|
||||
uuid: dto.uuid,
|
||||
withdraw: dto.withdraw
|
||||
? {
|
||||
receiveAccount: dto.withdraw.receive_account,
|
||||
receiverEmail: dto.withdraw.receiver_email,
|
||||
receiverMobile: dto.withdraw.receiver_mobile,
|
||||
receiverName: dto.withdraw.receiver_name,
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,8 @@ export default {
|
||||
'',
|
||||
'1. Only **1 winning number** is drawn in each round.',
|
||||
'2. If the player’s selected numbers **include the winning number**, the bet is considered a win.',
|
||||
'3. If a player selects multiple numbers and the bet amount is the same for each number, then:',
|
||||
'3. Each round, a player may bet on **1–5 numbers only**, and must not select more than **5**.',
|
||||
'4. If a player selects multiple numbers and the bet amount is the same for each number, then:',
|
||||
'',
|
||||
'```text',
|
||||
'Winning Number Stake = Total Bet Amount ÷ Number of Selected Numbers',
|
||||
|
||||
@@ -250,7 +250,8 @@ export default {
|
||||
'',
|
||||
'1. Hanya **1 nomor pemenang** yang akan dikeluarkan di setiap putaran.',
|
||||
'2. Jika nomor yang dipilih pemain **mencakup nomor pemenang**, maka taruhan tersebut dianggap menang.',
|
||||
'3. Jika pemain memilih beberapa nomor dan jumlah taruhan untuk setiap nomor sama, maka:',
|
||||
'3. Dalam setiap putaran, pemain hanya boleh bertaruh pada **1–5 nomor**, dan tidak boleh melebihi **5 nomor**.',
|
||||
'4. Jika pemain memilih beberapa nomor dan jumlah taruhan untuk setiap nomor sama, maka:',
|
||||
'',
|
||||
'```text',
|
||||
'Nilai Taruhan Nomor Menang = Total Taruhan ÷ Jumlah Nomor yang Dipilih',
|
||||
|
||||
@@ -253,7 +253,8 @@ export default {
|
||||
'',
|
||||
'1. Hanya **1 nombor kemenangan** akan dikeluarkan dalam setiap pusingan.',
|
||||
'2. Jika nombor yang dipilih oleh pemain **mengandungi nombor kemenangan**, pertaruhan tersebut dianggap menang.',
|
||||
'3. Jika pemain memilih beberapa nombor dan jumlah pertaruhan bagi setiap nombor adalah sama, maka:',
|
||||
'3. Dalam setiap pusingan, pemain hanya boleh bertaruh pada **1–5 nombor**, dan tidak boleh melebihi **5 nombor**.',
|
||||
'4. Jika pemain memilih beberapa nombor dan jumlah pertaruhan bagi setiap nombor adalah sama, maka:',
|
||||
'',
|
||||
'```text',
|
||||
'Nilai Pertaruhan Nombor Menang = Jumlah Pertaruhan ÷ Bilangan Nombor yang Dipilih',
|
||||
|
||||
@@ -243,10 +243,11 @@ export default {
|
||||
'',
|
||||
'1. 每期只开出 **1 个中奖号码**。',
|
||||
'2. 如果玩家押注的号码中 **包含开奖号码**,则视为中奖。',
|
||||
'3. 如果玩家选择了多个号码,且每个号码押注金额相同,则:',
|
||||
'3. 每场玩家最多只能下注 **1~5 个号码**,不能超过 **5 个**。',
|
||||
'4. 如果玩家选择了多个号码,且每个号码押注金额相同,则:',
|
||||
'',
|
||||
'```text',
|
||||
'压中号码面额 = 本笔压注总额 ÷ 所选号码个数',
|
||||
'压中号码面额 = 本笔投注总额 ÷ 所选号码个数',
|
||||
'```',
|
||||
'',
|
||||
'**示例:**',
|
||||
|
||||
@@ -4,12 +4,23 @@ export type AuthStatus = 'anonymous' | 'authenticated' | 'restoring'
|
||||
|
||||
export type AuthSubmitContext = 'login' | 'register'
|
||||
|
||||
export type AuthCoinAmount = number | string
|
||||
|
||||
export interface AuthWithdrawAccount {
|
||||
receiveAccount?: string
|
||||
receiverEmail?: string
|
||||
receiverMobile?: string
|
||||
receiverName?: string
|
||||
}
|
||||
|
||||
export interface AuthUser {
|
||||
createTime?: number
|
||||
channelId?: number
|
||||
coin?: string
|
||||
coin?: AuthCoinAmount
|
||||
coinBalance?: number
|
||||
currentStreak?: number
|
||||
email?: string
|
||||
frozenBalance?: number
|
||||
headImage?: string
|
||||
id: string
|
||||
isJackpot?: boolean
|
||||
@@ -21,8 +32,11 @@ export interface AuthUser {
|
||||
riskFlags?: number
|
||||
roles?: string[]
|
||||
streakLevel?: number
|
||||
totalDepositCoin?: number
|
||||
totalWithdrawCoin?: number
|
||||
username?: string
|
||||
uuid?: string
|
||||
withdraw?: AuthWithdrawAccount
|
||||
}
|
||||
|
||||
export interface AuthSessionInput {
|
||||
@@ -47,7 +61,7 @@ export interface AuthTokenDto {
|
||||
|
||||
export interface AuthUserDto {
|
||||
channel_id: number
|
||||
coin: string
|
||||
coin: AuthCoinAmount
|
||||
phone?: string
|
||||
risk_flags: number
|
||||
username: string
|
||||
@@ -69,17 +83,27 @@ export interface RefreshTokenDto {
|
||||
|
||||
export interface AuthUserProfileDto {
|
||||
channel_id: number
|
||||
coin: string
|
||||
coin: number
|
||||
coin_balance: number
|
||||
create_time: number
|
||||
current_streak: number
|
||||
email: string
|
||||
frozen_balance: number
|
||||
head_image: string
|
||||
last_bet_period_no: string
|
||||
phone: string
|
||||
register_invite_code: string
|
||||
risk_flags: number
|
||||
total_deposit_coin: number
|
||||
total_withdraw_coin: number
|
||||
username: string
|
||||
uuid: string
|
||||
withdraw?: {
|
||||
receive_account: string
|
||||
receiver_email: string
|
||||
receiver_mobile: string
|
||||
receiver_name: string
|
||||
} | null
|
||||
}
|
||||
|
||||
export interface LoginRequestDto {
|
||||
|
||||
Reference in New Issue
Block a user