Files
Genarrative/src/components/platform-entry/PlatformProfileTaskCenterModal.tsx
T
kdletters 387a1c26e3 完成全量检查整改
清理已跟踪原始日志与个人本地配置
修复前后端有效门禁、测试和构建问题
补齐生产 Jenkins、SpacetimeDB 本地命令与文档约束
收紧图片编辑器状态、附件与媒体引用测试
排除已下线旧创作入口测试并清理 warning
2026-07-17 16:56:46 +08:00

149 lines
5.0 KiB
TypeScript

import type { ProfileTaskCenterResponse } from '../../../packages/shared/src/contracts/runtime';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformAsyncStatePanel } from '../common/PlatformAsyncStatePanel';
import { PlatformEmptyState } from '../common/PlatformEmptyState';
import { PlatformProfileContentRow } from '../common/PlatformProfileContentRow';
import { PlatformProfileSkeletonList } from '../common/PlatformProfileSkeletonList';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import {
buildProfileTaskProgressLabel,
getProfileTaskClaimButtonLabel,
getProfileTaskStatusLabel,
selectProfileTaskCenterTasks,
} from '../rpg-entry/rpgEntryProfileTaskViewModel';
import { PlatformProfileModalShell } from './PlatformProfileModalShell';
export type PlatformProfileTaskCenterModalProps = {
center: ProfileTaskCenterResponse | null;
isLoading: boolean;
error: string | null;
success: string | null;
claimingTaskId: string | null;
fallbackBalance: number;
onClose: () => void;
onRetry: () => void;
onClaim: (taskId: string) => void;
};
/**
* 个人中心每日任务弹窗。
* 复用任务中心 view model,保持原有任务筛选、状态文案和领取交互不变。
*/
export function PlatformProfileTaskCenterModal({
center,
isLoading,
error,
success,
claimingTaskId,
fallbackBalance,
onClose,
onRetry,
onClaim,
}: PlatformProfileTaskCenterModalProps) {
const tasks = selectProfileTaskCenterTasks(center?.tasks ?? []);
const walletBalance = center?.walletBalance ?? fallbackBalance;
return (
<PlatformProfileModalShell
title="每日任务"
description={`${walletBalance}泥点`}
onClose={onClose}
closeLabel="关闭每日任务"
panelClassName="platform-recharge-modal !max-w-md rounded-[1.4rem]"
bodyClassName="space-y-3 px-5 py-5"
>
{success ? (
<PlatformStatusMessage
tone="success"
surface="profile"
size="xs"
className="rounded-2xl font-semibold"
>
{success}
</PlatformStatusMessage>
) : null}
<PlatformAsyncStatePanel
errorState={
error ? (
<PlatformStatusMessage
tone="error"
surface="profile"
size="xs"
className="rounded-2xl font-semibold"
>
<div>{error}</div>
<PlatformActionButton
surface="profile"
size="xs"
className="mt-3"
onClick={onRetry}
>
重新加载
</PlatformActionButton>
</PlatformStatusMessage>
) : null
}
isLoading={isLoading}
loadingState={
<PlatformProfileSkeletonList
count={2}
containerClassName="space-y-3"
itemClassName="h-20 rounded-2xl bg-white/10"
/>
}
isEmpty={tasks.length === 0}
emptyState={
<PlatformEmptyState surface="subpanel" size="inline">
暂无任务
</PlatformEmptyState>
}
>
<div className="space-y-3">
{tasks.map((task) => {
const isClaimable = task.status === 'claimable';
const isClaiming = claimingTaskId === task.taskId;
const progressLabel = buildProfileTaskProgressLabel(task);
return (
<PlatformProfileContentRow
key={task.taskId}
radius="sm"
padding="md"
>
<div className="flex min-w-0 items-start justify-between gap-3">
<div className="min-w-0">
<div className="text-base font-black text-[var(--platform-text-strong)]">
{task.title}
</div>
<div className="mt-1 text-xs font-semibold text-[var(--platform-text-soft)]">
{progressLabel}
</div>
</div>
<div className="shrink-0 text-right">
<div className="text-sm font-black text-[var(--platform-text-strong)]">
+{task.rewardPoints}
</div>
<div className="mt-1 text-[11px] font-semibold text-[var(--platform-text-soft)]">
{getProfileTaskStatusLabel(task.status)}
</div>
</div>
</div>
<PlatformActionButton
surface="profile"
fullWidth
size="sm"
className="mt-3 disabled:opacity-50"
disabled={!isClaimable || Boolean(claimingTaskId)}
onClick={() => onClaim(task.taskId)}
>
{getProfileTaskClaimButtonLabel(task, isClaiming)}
</PlatformActionButton>
</PlatformProfileContentRow>
);
})}
</div>
</PlatformAsyncStatePanel>
</PlatformProfileModalShell>
);
}