Fix MindSpace preview crash and simplify balance ring popover.
Wrap preview mode in ChatProvider so useChat works, and drop recharge ledger from the balance dropdown to keep it compact. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+12
-10
@@ -157,16 +157,18 @@ export function App() {
|
|||||||
|
|
||||||
if (mindSpacePreview) {
|
if (mindSpacePreview) {
|
||||||
return (
|
return (
|
||||||
<MindSpaceView
|
<ChatProvider user={PREVIEW_USER}>
|
||||||
previewMode
|
<MindSpaceView
|
||||||
user={PREVIEW_USER}
|
previewMode
|
||||||
onBack={() => {
|
user={PREVIEW_USER}
|
||||||
window.location.href = '/';
|
onBack={() => {
|
||||||
}}
|
window.location.href = '/';
|
||||||
onLogout={() => {
|
}}
|
||||||
window.location.href = '/';
|
onLogout={() => {
|
||||||
}}
|
window.location.href = '/';
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</ChatProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { useEffect, useRef, useState, type CSSProperties } from 'react';
|
import { useEffect, useRef, useState, type CSSProperties } from 'react';
|
||||||
import { getMyBillingLedger, getMyUsage } from '../api/client';
|
import { getMyUsage } from '../api/client';
|
||||||
import type { LedgerEntry, UsageRecord } from '../types';
|
import type { UsageRecord } from '../types';
|
||||||
|
|
||||||
const RING_R = 16;
|
const RING_R = 16;
|
||||||
const CIRC = 2 * Math.PI * RING_R;
|
const CIRC = 2 * Math.PI * RING_R;
|
||||||
const POPOVER_WIDTH = 260;
|
const POPOVER_WIDTH = 260;
|
||||||
const RECENT_USAGE_LIMIT = 5;
|
const RECENT_USAGE_LIMIT = 5;
|
||||||
const RECENT_LEDGER_LIMIT = 8;
|
|
||||||
|
|
||||||
function formatYuan(cents: number) {
|
function formatYuan(cents: number) {
|
||||||
return `¥${(cents / 100).toFixed(2)}`;
|
return `¥${(cents / 100).toFixed(2)}`;
|
||||||
@@ -49,16 +48,6 @@ function formatUsageTime(ts: number) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatLedgerLabel(entry: LedgerEntry) {
|
|
||||||
if (entry.note === '新用户赠送') return '新用户赠送';
|
|
||||||
if (entry.note?.startsWith('order:')) return '微信支付充值';
|
|
||||||
if (entry.note === '用户自助充值') return '微信支付充值';
|
|
||||||
if (entry.note === '管理员充值') return '管理员充值';
|
|
||||||
if (entry.type === 'refund') return '退款';
|
|
||||||
if (entry.type === 'adjust') return entry.note?.trim() || '账户调整';
|
|
||||||
return entry.note?.trim() || '账户充值';
|
|
||||||
}
|
|
||||||
|
|
||||||
type BalanceRingProps = {
|
type BalanceRingProps = {
|
||||||
balanceCents: number;
|
balanceCents: number;
|
||||||
totalCreditCents?: number;
|
totalCreditCents?: number;
|
||||||
@@ -77,9 +66,6 @@ export function BalanceRing({
|
|||||||
const [usageRecords, setUsageRecords] = useState<UsageRecord[] | null>(null);
|
const [usageRecords, setUsageRecords] = useState<UsageRecord[] | null>(null);
|
||||||
const [usageLoading, setUsageLoading] = useState(false);
|
const [usageLoading, setUsageLoading] = useState(false);
|
||||||
const [usageError, setUsageError] = useState<string | null>(null);
|
const [usageError, setUsageError] = useState<string | null>(null);
|
||||||
const [ledgerEntries, setLedgerEntries] = useState<LedgerEntry[] | null>(null);
|
|
||||||
const [ledgerLoading, setLedgerLoading] = useState(false);
|
|
||||||
const [ledgerError, setLedgerError] = useState<string | null>(null);
|
|
||||||
const wrapRef = useRef<HTMLDivElement>(null);
|
const wrapRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const total = Math.max(totalCreditCents ?? balanceCents, balanceCents, 0);
|
const total = Math.max(totalCreditCents ?? balanceCents, balanceCents, 0);
|
||||||
@@ -137,8 +123,6 @@ export function BalanceRing({
|
|||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
setUsageLoading(true);
|
setUsageLoading(true);
|
||||||
setUsageError(null);
|
setUsageError(null);
|
||||||
setLedgerLoading(true);
|
|
||||||
setLedgerError(null);
|
|
||||||
void getMyUsage()
|
void getMyUsage()
|
||||||
.then((records) => {
|
.then((records) => {
|
||||||
if (!cancelled) setUsageRecords(records);
|
if (!cancelled) setUsageRecords(records);
|
||||||
@@ -151,18 +135,6 @@ export function BalanceRing({
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (!cancelled) setUsageLoading(false);
|
if (!cancelled) setUsageLoading(false);
|
||||||
});
|
});
|
||||||
void getMyBillingLedger(RECENT_LEDGER_LIMIT)
|
|
||||||
.then((entries) => {
|
|
||||||
if (!cancelled) setLedgerEntries(entries);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (!cancelled) {
|
|
||||||
setLedgerError(err instanceof Error ? err.message : '加载失败');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
if (!cancelled) setLedgerLoading(false);
|
|
||||||
});
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
@@ -173,13 +145,9 @@ export function BalanceRing({
|
|||||||
setUsageRecords(null);
|
setUsageRecords(null);
|
||||||
setUsageError(null);
|
setUsageError(null);
|
||||||
setUsageLoading(false);
|
setUsageLoading(false);
|
||||||
setLedgerEntries(null);
|
|
||||||
setLedgerError(null);
|
|
||||||
setLedgerLoading(false);
|
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
const recentUsage = (usageRecords ?? []).slice(0, RECENT_USAGE_LIMIT);
|
const recentUsage = (usageRecords ?? []).slice(0, RECENT_USAGE_LIMIT);
|
||||||
const recentLedger = (ledgerEntries ?? []).slice(0, RECENT_LEDGER_LIMIT);
|
|
||||||
const centerLabel = total <= 0 ? '—' : empty ? '0%' : `${pct}%`;
|
const centerLabel = total <= 0 ? '—' : empty ? '0%' : `${pct}%`;
|
||||||
const ariaLabel = total > 0 ? `账户额度,剩余 ${pct}%` : '账户额度';
|
const ariaLabel = total > 0 ? `账户额度,剩余 ${pct}%` : '账户额度';
|
||||||
|
|
||||||
@@ -251,29 +219,6 @@ export function BalanceRing({
|
|||||||
<p className="balance-popover-hint">按人民币结算,每次对话按实际用量扣费</p>
|
<p className="balance-popover-hint">按人民币结算,每次对话按实际用量扣费</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="balance-popover-section">
|
|
||||||
<h5>充值明细</h5>
|
|
||||||
{ledgerLoading ? (
|
|
||||||
<p className="balance-popover-muted">加载中…</p>
|
|
||||||
) : ledgerError ? (
|
|
||||||
<p className="balance-popover-muted">{ledgerError}</p>
|
|
||||||
) : recentLedger.length === 0 ? (
|
|
||||||
<p className="balance-popover-muted">暂无充值记录</p>
|
|
||||||
) : (
|
|
||||||
<ul className="balance-usage-list">
|
|
||||||
{recentLedger.map((row) => (
|
|
||||||
<li key={row.id} className="balance-usage-item">
|
|
||||||
<span className="balance-usage-time">{formatUsageTime(row.createdAt)}</span>
|
|
||||||
<span className="balance-usage-tokens">{formatLedgerLabel(row)}</span>
|
|
||||||
<strong className="balance-usage-credit">
|
|
||||||
+{formatYuan(Math.abs(row.amountCents))}
|
|
||||||
</strong>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`balance-popover-section balance-popover-usage${showRecentUsage ? ' expanded' : ''}`}
|
className={`balance-popover-section balance-popover-usage${showRecentUsage ? ' expanded' : ''}`}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user