This commit is contained in:
root
2026-01-03 06:06:54 +00:00
parent d138dae2ca
commit eeaa9a66bb
16 changed files with 728 additions and 348 deletions

View File

@@ -1,8 +1,8 @@
'use client'
import { useState, useEffect } from 'react'
import Image from 'next/image'
import { useI18n } from '@/lib/i18n'
import { ALLOWED_PAYMENT_CURRENCIES } from '@/lib/payment-currencies'
interface RedeemPointsModalProps {
isOpen: boolean
@@ -19,7 +19,7 @@ export default function RedeemPointsModal({
}: RedeemPointsModalProps) {
const { t } = useI18n()
const [pointsToRedeem, setPointsToRedeem] = useState<string>('')
const [cryptoCurrency, setCryptoCurrency] = useState<string>('btc')
const [cryptoCurrency] = useState<string>('usdtsol') // Fixed to USDT (SOL) only
const [walletAddress, setWalletAddress] = useState<string>('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string>('')
@@ -35,7 +35,6 @@ export default function RedeemPointsModal({
// Reset form
setPointsToRedeem('')
setWalletAddress('')
setCryptoCurrency('btc')
setError('')
setSuccess(false)
setRedemptionDetails(null)
@@ -58,25 +57,17 @@ export default function RedeemPointsModal({
}
useEffect(() => {
// Calculate estimated crypto amount when points or currency changes
// Calculate estimated crypto amount when points changes
// USDT (SOL) rate is approximately 0.9 CHF per USDT
if (pointsToRedeem && !isNaN(parseFloat(pointsToRedeem))) {
const points = parseFloat(pointsToRedeem)
const chfValue = points / pointsToCryptoChf
// Mock exchange rates (should match API)
const mockRates: Record<string, number> = {
'btc': 85000,
'eth': 2500,
'sol': 100,
'xrp': 0.6,
'bnbbsc': 300,
'usdterc20': 0.9,
}
const rate = mockRates[cryptoCurrency.toLowerCase()] || 1
setEstimatedCrypto(chfValue / rate)
const usdtRate = 0.9 // CHF per USDT (SOL)
setEstimatedCrypto(chfValue / usdtRate)
} else {
setEstimatedCrypto(0)
}
}, [pointsToRedeem, cryptoCurrency, pointsToCryptoChf])
}, [pointsToRedeem, pointsToCryptoChf])
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
@@ -216,7 +207,7 @@ export default function RedeemPointsModal({
<div style={{ marginBottom: '24px' }}>
<p><strong>{t('redeemPoints.redemptionId')}:</strong> #{redemptionDetails.redemption_id}</p>
<p><strong>{t('redeemPoints.pointsRedeemed')}:</strong> {redemptionDetails.points_redeemed.toFixed(2)}</p>
<p><strong>{t('redeemPoints.cryptoAmount')}:</strong> {redemptionDetails.crypto_amount.toFixed(8)} {redemptionDetails.crypto_currency.toUpperCase()}</p>
<p><strong>{t('redeemPoints.cryptoAmount')}:</strong> {redemptionDetails.crypto_amount.toFixed(8)} USDT</p>
<p><strong>{t('redeemPoints.newBalance')}:</strong> {redemptionDetails.new_balance.toFixed(2)} {t('redeemPoints.points')}</p>
<p style={{ marginTop: '16px', fontSize: '14px', color: 'var(--muted)' }}>
{redemptionDetails.message}
@@ -252,18 +243,23 @@ export default function RedeemPointsModal({
<div style={{ fontSize: '14px', color: 'var(--muted)', marginBottom: '4px' }}>
{t('redeemPoints.currentBalance')}
</div>
<div style={{ fontSize: '24px', fontWeight: 600, color: '#0a7931' }}>
{currentPoints.toFixed(2)} {t('redeemPoints.points')}
<div style={{ fontSize: '24px', fontWeight: 600, color: '#0a7931', display: 'flex', alignItems: 'center', gap: '8px' }}>
<Image
src="/icon_ref_points.png"
alt="Referral Points"
width={24}
height={24}
style={{ display: 'inline-block', verticalAlign: 'middle' }}
/>
{currentPoints.toFixed(2)} {t('redeemPoints.points')}
</div>
</div>
<label style={{ display: 'block', marginBottom: '8px', fontSize: '14px', fontWeight: 500 }}>
{t('redeemPoints.selectCrypto')} *
</label>
<select
value={cryptoCurrency}
onChange={(e) => setCryptoCurrency(e.target.value)}
style={{
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', marginBottom: '8px', fontSize: '14px', fontWeight: 500 }}>
{t('redeemPoints.cryptoCurrency')}
</label>
<div style={{
width: '100%',
padding: '12px',
background: 'var(--bg-soft)',
@@ -271,16 +267,10 @@ export default function RedeemPointsModal({
borderRadius: '8px',
fontSize: '14px',
color: 'var(--text)',
marginBottom: '16px',
}}
required
>
{ALLOWED_PAYMENT_CURRENCIES.map((currency) => (
<option key={currency} value={currency}>
{currency.toUpperCase()}
</option>
))}
</select>
}}>
USDT (SOL)
</div>
</div>
<label style={{ display: 'block', marginBottom: '8px', fontSize: '14px', fontWeight: 500 }}>
{t('redeemPoints.walletAddress')} *
@@ -310,26 +300,44 @@ export default function RedeemPointsModal({
({t('redeemPoints.min')}: {minRedemptionPoints})
</span>
</label>
<input
type="number"
value={pointsToRedeem}
onChange={(e) => setPointsToRedeem(e.target.value)}
min={minRedemptionPoints}
max={currentPoints}
step="1"
placeholder={minRedemptionPoints.toString()}
style={{
width: '100%',
padding: '12px',
background: 'var(--bg-soft)',
border: '1px solid var(--border)',
borderRadius: '8px',
fontSize: '14px',
color: 'var(--text)',
marginBottom: '16px',
}}
required
/>
<div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
<input
type="number"
value={pointsToRedeem}
onChange={(e) => setPointsToRedeem(e.target.value)}
min={minRedemptionPoints}
max={currentPoints}
step="1"
placeholder={minRedemptionPoints.toString()}
style={{
flex: 1,
padding: '12px',
background: 'var(--bg-soft)',
border: '1px solid var(--border)',
borderRadius: '8px',
fontSize: '14px',
color: 'var(--text)',
}}
required
/>
<button
type="button"
onClick={() => setPointsToRedeem(currentPoints.toString())}
style={{
padding: '12px 20px',
background: 'var(--bg-soft)',
border: '1px solid var(--border)',
borderRadius: '8px',
fontSize: '14px',
color: 'var(--text)',
cursor: 'pointer',
fontWeight: 500,
whiteSpace: 'nowrap',
}}
>
{t('drop.max')}
</button>
</div>
{pointsNum > 0 && (
<div style={{
@@ -343,7 +351,7 @@ export default function RedeemPointsModal({
<strong>{t('redeemPoints.estimatedValue')}:</strong>
</div>
<div style={{ color: 'var(--muted)' }}>
{chfValue.toFixed(2)} CHF {estimatedCrypto.toFixed(8)} {cryptoCurrency.toUpperCase()}
{chfValue.toFixed(2)} CHF {estimatedCrypto.toFixed(8)} USDT
</div>
</div>
)}