Files
Genarrative/src/components/platform-entry/PlatformProfileWalletLedgerModal.tsx
T
kdletters 9c9c8f468a 恢复平台个人页并阻断旧业务回流
恢复创作、项目、我的平台侧栏与现役搜索
恢复全宽个人页及资料编辑、充值兑换、社区反馈和 API Key 入口
迁移平台资料、钱包和设置客户端并移除旧创作依赖
新增 Vite 与 ESLint 退役模块门禁并补齐界面和搜索测试
同步旧创作退役方案、平台入口决策与踩坑记录
2026-07-18 17:29:06 +08:00

143 lines
4.8 KiB
TypeScript

import { Coins } from 'lucide-react';
import type { ProfileWalletLedgerResponse } from '../../../packages/shared/src/contracts/runtime';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformAsyncStatePanel } from '../common/PlatformAsyncStatePanel';
import { PlatformEmptyState } from '../common/PlatformEmptyState';
import { PlatformPillBadge } from '../common/PlatformPillBadge';
import { PlatformProfileContentRow } from '../common/PlatformProfileContentRow';
import { PlatformProfileSkeletonList } from '../common/PlatformProfileSkeletonList';
import { PlatformProfileSummaryHeader } from '../common/PlatformProfileSummaryHeader';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import {
buildPlatformWalletLedgerPresentation,
formatPlatformProfileTime,
} from './platformProfileFundsModel';
import { PlatformProfileSecondaryModalShell } from './PlatformProfileModalShell';
export type PlatformProfileWalletLedgerModalProps = {
ledger: ProfileWalletLedgerResponse | null;
fallbackBalance: number;
isLoading: boolean;
error: string | null;
onClose: () => void;
onRetry: () => void;
};
/**
* 个人中心泥点账单弹窗。
* 保持 RPG 首页里既有的展示文案、状态分支和交互,仅把实现提取为共享组件。
*/
export function PlatformProfileWalletLedgerModal({
ledger,
fallbackBalance,
isLoading,
error,
onClose,
onRetry,
}: PlatformProfileWalletLedgerModalProps) {
const walletLedgerPresentation = buildPlatformWalletLedgerPresentation(
ledger,
fallbackBalance,
);
const entries = walletLedgerPresentation.entries;
return (
<PlatformProfileSecondaryModalShell
title="泥点账单"
onClose={onClose}
closeLabel="关闭泥点账单"
closeButtonClassName="bg-white/78"
panelClassName="relative !max-h-[min(92vh,42rem)] !max-w-[30rem] bg-[linear-gradient(180deg,#fff7f8_0%,#ffffff_38%,#f8fafc_100%)] text-zinc-950 shadow-2xl !rounded-[1.35rem] sm:!rounded-[1.35rem]"
contentClassName="relative max-h-[min(92vh,42rem)] overflow-y-auto px-4 pb-5 pt-4 sm:px-5"
>
<PlatformProfileSummaryHeader
kicker="LEDGER"
title="泥点账单"
badge={
<PlatformPillBadge
tone="profile"
icon={<Coins className="h-3.5 w-3.5 text-[#ff4056]" />}
className="bg-white/70"
>
{walletLedgerPresentation.balanceLabel}
</PlatformPillBadge>
}
/>
<PlatformAsyncStatePanel
errorState={
error ? (
<PlatformStatusMessage
tone="error"
className="mt-4 rounded-xl py-3"
>
<div>{error}</div>
<PlatformActionButton
surface="profile"
shape="pill"
size="xs"
className="mt-3"
onClick={onRetry}
>
重新加载
</PlatformActionButton>
</PlatformStatusMessage>
) : null
}
isLoading={isLoading}
loadingState={
<PlatformProfileSkeletonList
count={5}
containerClassName="mt-5 space-y-3"
itemClassName="h-16"
/>
}
isEmpty={entries.length === 0}
emptyState={
<PlatformEmptyState
surface="subpanel"
size="inline"
className="mt-5 py-8"
>
暂无账单记录
</PlatformEmptyState>
}
>
<div className="mt-5 space-y-2.5">
{entries.map((entry) => (
<PlatformProfileContentRow
key={entry.id}
surface="flat"
radius="xs"
padding="none"
className="flex items-center justify-between gap-3 px-3 py-3 shadow-sm"
>
<div className="min-w-0">
<div className="truncate text-sm font-black text-zinc-900">
{entry.sourceLabel}
</div>
<div className="mt-1 text-xs font-semibold text-zinc-500">
{formatPlatformProfileTime(entry.createdAt)}
</div>
</div>
<div className="shrink-0 text-right">
<div
className={`text-base font-black ${
entry.isIncome ? 'text-emerald-600' : 'text-rose-500'
}`}
>
{entry.amountLabel}
</div>
<div className="mt-1 text-[11px] font-semibold text-zinc-400">
{entry.balanceLabel}
</div>
</div>
</PlatformProfileContentRow>
))}
</div>
</PlatformAsyncStatePanel>
</PlatformProfileSecondaryModalShell>
);
}