89fd333702
Add client-logging SDK, expanded event taxonomy, API observability, admin domain events UI, and move SENTRY_DSN to HQ system settings with @sentry/node bootstrap after config preload. Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.9 KiB
TypeScript
46 lines
1.9 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { REDEEM_TOKEN_TTL_SECONDS } from '@dukang/shared-types';
|
|
import PageHeader from '@dukang/shared-ui/PageHeader';
|
|
import { usePageView } from '../lib/usePageView';
|
|
|
|
export default function RedeemCodePage() {
|
|
usePageView('redeem_code_view');
|
|
const navigate = useNavigate();
|
|
const token = sessionStorage.getItem('redeemToken') || '';
|
|
const amount = sessionStorage.getItem('redeemAmount') || '0';
|
|
const [secondsLeft, setSecondsLeft] = useState(REDEEM_TOKEN_TTL_SECONDS);
|
|
|
|
useEffect(() => {
|
|
const expireAt = sessionStorage.getItem('redeemExpireAt');
|
|
if (!expireAt) return;
|
|
const tick = () => {
|
|
const left = Math.max(0, Math.floor((new Date(expireAt).getTime() - Date.now()) / 1000));
|
|
setSecondsLeft(left);
|
|
};
|
|
tick();
|
|
const id = window.setInterval(tick, 1000);
|
|
return () => window.clearInterval(id);
|
|
}, []);
|
|
|
|
return (
|
|
<div className="page-no-tab" style={{ textAlign: 'center' }}>
|
|
<PageHeader title="核销码展示" onBack={() => navigate(-1)} />
|
|
<p className="text-variant body-md page-actions" style={{ marginBottom: 0, paddingBottom: 0 }}>请向门店出示以下核销码</p>
|
|
<div className="card" style={{ padding: 32 }}>
|
|
<div className="label-md text-muted">核销金额</div>
|
|
<div className="amount-xl" style={{ margin: '8px 0 24px' }}>¥{amount}</div>
|
|
<div className="code-box">{token}</div>
|
|
<p className="label-md text-muted" style={{ marginTop: 16 }}>
|
|
{secondsLeft > 0 ? `${secondsLeft} 秒后过期` : '已过期,请重新生成'}
|
|
</p>
|
|
</div>
|
|
<div className="page-actions">
|
|
<button type="button" className="btn btn-outline btn-block" onClick={() => navigate('/benefit')}>
|
|
返回权益页
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|