拆出个人中心剩余弹层组件
- 新增充值账单任务兑换码共享组件并补齐组件级测试 - 让 RpgEntryHomeView 改为复用新的 profile 弹层组件并删除内联实现 - 更新 PlatformUiKit 收口文档与团队共享记忆记录新的组件沉淀
This commit is contained in:
@@ -30,7 +30,6 @@ import {
|
||||
UserRound,
|
||||
XCircle,
|
||||
} from 'lucide-react';
|
||||
import QRCode from 'qrcode';
|
||||
import {
|
||||
type ComponentType,
|
||||
type CSSProperties,
|
||||
@@ -62,11 +61,7 @@ import type {
|
||||
ProfileDashboardSummary,
|
||||
ProfilePlayedWorkSummary,
|
||||
ProfilePlayStatsResponse,
|
||||
ProfileRechargeCenterResponse,
|
||||
ProfileRechargeProduct,
|
||||
ProfileSaveArchiveSummary,
|
||||
ProfileTaskCenterResponse,
|
||||
ProfileWalletLedgerResponse,
|
||||
} from '../../../packages/shared/src/contracts/runtime';
|
||||
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
|
||||
import {
|
||||
@@ -125,17 +120,16 @@ import {
|
||||
ProfileStatCard,
|
||||
ProfileStatCardSkeleton,
|
||||
} from '../platform-entry/PlatformProfilePrimitives';
|
||||
import {
|
||||
PlatformProfileModalShell,
|
||||
PlatformProfileSecondaryModalShell,
|
||||
} from '../platform-entry/PlatformProfileModalShell';
|
||||
import { PlatformProfileModalShell } from '../platform-entry/PlatformProfileModalShell';
|
||||
import { PlatformProfilePlayedWorksModal } from '../platform-entry/PlatformProfilePlayedWorksModal';
|
||||
import { PlatformProfileRechargeModal } from '../platform-entry/PlatformProfileRechargeModal';
|
||||
import { PlatformProfileReferralModal } from '../platform-entry/PlatformProfileReferralModal';
|
||||
import { PlatformProfileRewardCodeRedeemModal } from '../platform-entry/PlatformProfileRewardCodeRedeemModal';
|
||||
import { PlatformProfileTaskCenterModal } from '../platform-entry/PlatformProfileTaskCenterModal';
|
||||
import { PlatformProfileWalletLedgerModal } from '../platform-entry/PlatformProfileWalletLedgerModal';
|
||||
import { getInitialPlatformDesktopLayout } from '../platform-entry/platformEntryResponsive';
|
||||
import {
|
||||
type NativeWechatPaymentState,
|
||||
type RechargePaymentResult,
|
||||
type RechargeTab,
|
||||
usePlatformProfileCenterController,
|
||||
} from '../platform-entry/usePlatformProfileCenterController';
|
||||
import { ResolvedAssetImage } from '../ResolvedAssetImage';
|
||||
@@ -144,19 +138,7 @@ import {
|
||||
buildProfileDashboardPresentation,
|
||||
formatSnapshotTime,
|
||||
} from './rpgEntryProfileDashboardPresentation';
|
||||
import {
|
||||
buildMembershipLabel,
|
||||
buildRechargeProductValueLabel,
|
||||
buildWalletLedgerPresentation,
|
||||
formatRechargePrice,
|
||||
} from './rpgEntryProfileFundsViewModel';
|
||||
import {
|
||||
buildProfileTaskCardSummary,
|
||||
buildProfileTaskProgressLabel,
|
||||
getProfileTaskClaimButtonLabel,
|
||||
getProfileTaskStatusLabel,
|
||||
selectProfileTaskCenterTasks,
|
||||
} from './rpgEntryProfileTaskViewModel';
|
||||
import { buildProfileTaskCardSummary } from './rpgEntryProfileTaskViewModel';
|
||||
import {
|
||||
buildPlatformRankingEntries,
|
||||
buildPlatformRecommendFeedEntries,
|
||||
@@ -884,7 +866,6 @@ function readyRecommendRuntime(
|
||||
scanResources();
|
||||
});
|
||||
}
|
||||
const WECHAT_NATIVE_PAY_QR_IMAGE_SIZE = 180;
|
||||
const PROFILE_QR_SCAN_INTERVAL_MS = 360;
|
||||
type BarcodeDetectorLike = {
|
||||
detect: (source: CanvasImageSource) => Promise<Array<{ rawValue?: string }>>;
|
||||
@@ -2496,239 +2477,6 @@ function ProfileNicknameModal({
|
||||
);
|
||||
}
|
||||
|
||||
function useWechatNativeQrCode(codeUrl: string | null) {
|
||||
const [qrImageUrl, setQrImageUrl] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setQrImageUrl(null);
|
||||
if (!codeUrl) {
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}
|
||||
|
||||
void QRCode.toDataURL(codeUrl, {
|
||||
errorCorrectionLevel: 'M',
|
||||
margin: 1,
|
||||
width: WECHAT_NATIVE_PAY_QR_IMAGE_SIZE,
|
||||
}).then((dataUrl) => {
|
||||
if (!cancelled) {
|
||||
setQrImageUrl(dataUrl);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [codeUrl]);
|
||||
|
||||
return qrImageUrl;
|
||||
}
|
||||
|
||||
function RechargeProductCard({
|
||||
product,
|
||||
submittingProductId,
|
||||
onBuy,
|
||||
}: {
|
||||
product: ProfileRechargeProduct;
|
||||
submittingProductId: string | null;
|
||||
onBuy: (product: ProfileRechargeProduct) => void;
|
||||
}) {
|
||||
const submitting = submittingProductId === product.productId;
|
||||
const badgeLabel = product.badgeLabel;
|
||||
const value = buildRechargeProductValueLabel(product);
|
||||
|
||||
return (
|
||||
<PlatformSubpanel
|
||||
as="button"
|
||||
type="button"
|
||||
surface="platform"
|
||||
onClick={() => onBuy(product)}
|
||||
disabled={Boolean(submittingProductId)}
|
||||
interactive
|
||||
radius="sm"
|
||||
padding="none"
|
||||
className="platform-interactive-card relative min-h-[7.25rem] px-3.5 py-3.5 text-left"
|
||||
>
|
||||
{badgeLabel ? (
|
||||
<PlatformPillBadge
|
||||
tone="warning"
|
||||
size="xxs"
|
||||
className="absolute right-3 top-3 max-w-[7rem] truncate px-2 py-0.5 tracking-[0.18em]"
|
||||
>
|
||||
{badgeLabel}
|
||||
</PlatformPillBadge>
|
||||
) : null}
|
||||
<div className="pr-20 text-sm font-black text-[var(--platform-text-strong)]">
|
||||
{product.title}
|
||||
</div>
|
||||
<div className="mt-3 text-2xl font-black text-[var(--platform-text-strong)]">
|
||||
{value}
|
||||
</div>
|
||||
<div className="mt-2 flex items-center justify-between gap-3">
|
||||
<span className="text-sm font-bold text-[var(--platform-text-soft)]">
|
||||
{formatRechargePrice(product.priceCents)}
|
||||
</span>
|
||||
<span className="platform-primary-button rounded-full px-3 py-1.5 text-xs font-black">
|
||||
{submitting ? '处理中' : '购买'}
|
||||
</span>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
);
|
||||
}
|
||||
|
||||
function ProfileRechargeModal({
|
||||
center,
|
||||
isLoading,
|
||||
error,
|
||||
submittingProductId,
|
||||
nativePayment,
|
||||
activeTab,
|
||||
onTabChange,
|
||||
onClose,
|
||||
onRetry,
|
||||
onBuy,
|
||||
onConfirmNativePayment,
|
||||
}: {
|
||||
center: ProfileRechargeCenterResponse | null;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
submittingProductId: string | null;
|
||||
nativePayment: NativeWechatPaymentState | null;
|
||||
activeTab: RechargeTab;
|
||||
onTabChange: (tab: RechargeTab) => void;
|
||||
onClose: () => void;
|
||||
onRetry: () => void;
|
||||
onBuy: (product: ProfileRechargeProduct) => void;
|
||||
onConfirmNativePayment: () => void;
|
||||
}) {
|
||||
const nativeQrImageUrl = useWechatNativeQrCode(
|
||||
nativePayment?.codeUrl ?? null,
|
||||
);
|
||||
const products =
|
||||
activeTab === 'points'
|
||||
? (center?.pointProducts ?? [])
|
||||
: (center?.membershipProducts ?? []);
|
||||
const memberLabel = buildMembershipLabel(
|
||||
center?.membership,
|
||||
formatSnapshotTime,
|
||||
);
|
||||
|
||||
return (
|
||||
<PlatformProfileModalShell
|
||||
title="账户充值"
|
||||
description={
|
||||
center ? `${center.walletBalance}泥点 · ${memberLabel}` : '读取中'
|
||||
}
|
||||
onClose={onClose}
|
||||
closeLabel="关闭账户充值"
|
||||
size="md"
|
||||
panelClassName="platform-recharge-modal !max-w-[34rem] rounded-[1.4rem]"
|
||||
bodyClassName="max-h-[min(76vh,36rem)] overflow-y-auto px-5 py-5"
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onTabChange('points')}
|
||||
className={`platform-category-chip justify-center ${activeTab === 'points' ? 'platform-category-chip--active' : ''}`}
|
||||
>
|
||||
泥点充值
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onTabChange('membership')}
|
||||
className={`platform-category-chip justify-center ${activeTab === 'membership' ? 'platform-category-chip--active' : ''}`}
|
||||
>
|
||||
会员卡
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error ? (
|
||||
<PlatformStatusMessage
|
||||
tone="error"
|
||||
surface="profile"
|
||||
size="xs"
|
||||
className="mt-4 rounded-2xl font-semibold"
|
||||
>
|
||||
<div>{error}</div>
|
||||
<PlatformActionButton
|
||||
surface="profile"
|
||||
size="xs"
|
||||
className="mt-3"
|
||||
onClick={onRetry}
|
||||
>
|
||||
重新加载
|
||||
</PlatformActionButton>
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
|
||||
{isLoading ? (
|
||||
<div className="mt-4 grid gap-3 sm:grid-cols-2">
|
||||
{Array.from({ length: 4 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="h-28 animate-pulse rounded-[1.15rem] bg-white/10"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : products.length > 0 ? (
|
||||
<div className="mt-4 grid gap-3 sm:grid-cols-2">
|
||||
{products.map((product) => (
|
||||
<RechargeProductCard
|
||||
key={product.productId}
|
||||
product={product}
|
||||
submittingProductId={submittingProductId}
|
||||
onBuy={onBuy}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState
|
||||
surface="subpanel"
|
||||
size="inline"
|
||||
className="mt-4"
|
||||
>
|
||||
暂无可购买套餐
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
|
||||
{nativePayment ? (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
radius="sm"
|
||||
padding="md"
|
||||
className="mt-4 text-center"
|
||||
>
|
||||
<div className="text-sm font-black">微信扫码支付</div>
|
||||
<div className="mx-auto mt-3 flex h-[180px] w-[180px] items-center justify-center rounded-xl bg-white p-2">
|
||||
{nativeQrImageUrl ? (
|
||||
<img
|
||||
src={nativeQrImageUrl}
|
||||
alt="微信 Native 支付二维码"
|
||||
className="h-full w-full"
|
||||
/>
|
||||
) : (
|
||||
<span className="text-xs font-semibold text-slate-500">
|
||||
生成中
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<PlatformActionButton
|
||||
surface="profile"
|
||||
size="xs"
|
||||
className="mt-4 disabled:cursor-wait"
|
||||
onClick={onConfirmNativePayment}
|
||||
disabled={nativePayment.isConfirming}
|
||||
>
|
||||
{nativePayment.isConfirming ? '确认中' : '我已支付'}
|
||||
</PlatformActionButton>
|
||||
</PlatformSubpanel>
|
||||
) : null}
|
||||
</PlatformProfileModalShell>
|
||||
);
|
||||
}
|
||||
|
||||
function RechargePaymentResultModal({
|
||||
result,
|
||||
onClose,
|
||||
@@ -2823,317 +2571,6 @@ function RechargePaymentConfirmationMask({ orderId }: { orderId: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
function WalletLedgerModal({
|
||||
ledger,
|
||||
fallbackBalance,
|
||||
isLoading,
|
||||
error,
|
||||
onClose,
|
||||
onRetry,
|
||||
}: {
|
||||
ledger: ProfileWalletLedgerResponse | null;
|
||||
fallbackBalance: number;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
onClose: () => void;
|
||||
onRetry: () => void;
|
||||
}) {
|
||||
const walletLedgerPresentation = buildWalletLedgerPresentation(
|
||||
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"
|
||||
>
|
||||
<div className="pr-10">
|
||||
<div className="text-[10px] font-black tracking-[0.22em] text-[#ff4056]">
|
||||
LEDGER
|
||||
</div>
|
||||
<div className="mt-1 text-2xl font-black">泥点账单</div>
|
||||
<PlatformPillBadge
|
||||
tone="profile"
|
||||
icon={<Coins className="h-3.5 w-3.5 text-[#ff4056]" />}
|
||||
className="mt-3 bg-white/70"
|
||||
>
|
||||
{walletLedgerPresentation.balanceLabel}
|
||||
</PlatformPillBadge>
|
||||
</div>
|
||||
|
||||
{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>
|
||||
) : isLoading ? (
|
||||
<div className="mt-5 space-y-3">
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<div key={index} className="h-16 animate-pulse rounded-xl bg-zinc-100" />
|
||||
))}
|
||||
</div>
|
||||
) : entries.length === 0 ? (
|
||||
<PlatformEmptyState
|
||||
surface="subpanel"
|
||||
size="inline"
|
||||
className="mt-5 py-8"
|
||||
>
|
||||
暂无账单记录
|
||||
</PlatformEmptyState>
|
||||
) : (
|
||||
<div className="mt-5 space-y-2.5">
|
||||
{entries.map((entry) => {
|
||||
return (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
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">
|
||||
{formatPlatformWorldTime(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>
|
||||
</PlatformSubpanel>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</PlatformProfileSecondaryModalShell>
|
||||
);
|
||||
}
|
||||
|
||||
function ProfileTaskCenterModal({
|
||||
center,
|
||||
isLoading,
|
||||
error,
|
||||
success,
|
||||
claimingTaskId,
|
||||
fallbackBalance,
|
||||
onClose,
|
||||
onRetry,
|
||||
onClaim,
|
||||
}: {
|
||||
center: ProfileTaskCenterResponse | null;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
success: string | null;
|
||||
claimingTaskId: string | null;
|
||||
fallbackBalance: number;
|
||||
onClose: () => void;
|
||||
onRetry: () => void;
|
||||
onClaim: (taskId: string) => void;
|
||||
}) {
|
||||
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"
|
||||
>
|
||||
{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}
|
||||
{success ? (
|
||||
<PlatformStatusMessage
|
||||
tone="success"
|
||||
surface="profile"
|
||||
size="xs"
|
||||
className="rounded-2xl font-semibold"
|
||||
>
|
||||
{success}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
{isLoading ? (
|
||||
<div className="space-y-3">
|
||||
{Array.from({ length: 2 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="h-20 animate-pulse rounded-2xl bg-white/10"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : tasks.length === 0 ? (
|
||||
<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 (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
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>
|
||||
</PlatformSubpanel>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</PlatformProfileModalShell>
|
||||
);
|
||||
}
|
||||
|
||||
function RewardCodeRedeemModal({
|
||||
value,
|
||||
isSubmitting,
|
||||
error,
|
||||
success,
|
||||
onChange,
|
||||
onSubmit,
|
||||
onClose,
|
||||
}: {
|
||||
value: string;
|
||||
isSubmitting: boolean;
|
||||
error: string | null;
|
||||
success: string | null;
|
||||
onChange: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
return (
|
||||
<PlatformProfileModalShell
|
||||
title="兑换码"
|
||||
onClose={onClose}
|
||||
closeLabel="关闭兑换码"
|
||||
panelClassName="platform-recharge-modal !max-w-sm rounded-[1.4rem]"
|
||||
bodyClassName="space-y-3 px-5 py-5"
|
||||
>
|
||||
<PlatformTextField
|
||||
value={value}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
onSubmit();
|
||||
}
|
||||
}}
|
||||
size="sm"
|
||||
density="roomy"
|
||||
className="uppercase tracking-normal"
|
||||
placeholder="输入兑换码"
|
||||
aria-label="兑换码"
|
||||
autoFocus
|
||||
/>
|
||||
<PlatformActionButton
|
||||
surface="profile"
|
||||
fullWidth
|
||||
size="md"
|
||||
className="disabled:opacity-50"
|
||||
onClick={onSubmit}
|
||||
disabled={isSubmitting || !value.trim()}
|
||||
>
|
||||
{isSubmitting ? '兑换中' : '兑换'}
|
||||
</PlatformActionButton>
|
||||
{error ? (
|
||||
<PlatformStatusMessage
|
||||
tone="error"
|
||||
surface="profile"
|
||||
size="xs"
|
||||
className="rounded-2xl font-semibold"
|
||||
>
|
||||
{error}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
{success ? (
|
||||
<PlatformStatusMessage
|
||||
tone="success"
|
||||
surface="profile"
|
||||
size="xs"
|
||||
className="rounded-2xl font-semibold"
|
||||
>
|
||||
{success}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
</PlatformProfileModalShell>
|
||||
);
|
||||
}
|
||||
|
||||
function ProfileQrScannerModal({
|
||||
error,
|
||||
result,
|
||||
@@ -5653,7 +5090,7 @@ export function RpgEntryHomeView({
|
||||
</>
|
||||
);
|
||||
const rewardCodeModal: ReactNode = isRewardCodeOpen ? (
|
||||
<RewardCodeRedeemModal
|
||||
<PlatformProfileRewardCodeRedeemModal
|
||||
value={rewardCodeInput}
|
||||
isSubmitting={isSubmittingRewardCode}
|
||||
error={rewardCodeError}
|
||||
@@ -5664,7 +5101,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
) : null;
|
||||
const rechargeModal: ReactNode = isRechargeOpen ? (
|
||||
<ProfileRechargeModal
|
||||
<PlatformProfileRechargeModal
|
||||
center={rechargeCenter}
|
||||
isLoading={isLoadingRechargeCenter}
|
||||
error={rechargeError}
|
||||
@@ -5835,7 +5272,7 @@ export function RpgEntryHomeView({
|
||||
{qrScannerModal}
|
||||
{categoryFilterDialog}
|
||||
{isTaskCenterOpen ? (
|
||||
<ProfileTaskCenterModal
|
||||
<PlatformProfileTaskCenterModal
|
||||
center={taskCenter}
|
||||
isLoading={isLoadingTaskCenter}
|
||||
error={taskCenterError}
|
||||
@@ -5861,7 +5298,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
) : null}
|
||||
{isWalletLedgerOpen ? (
|
||||
<WalletLedgerModal
|
||||
<PlatformProfileWalletLedgerModal
|
||||
ledger={walletLedger}
|
||||
fallbackBalance={remainingNarrativeCoins}
|
||||
isLoading={isLoadingWalletLedger}
|
||||
@@ -5983,7 +5420,7 @@ export function RpgEntryHomeView({
|
||||
{rechargePaymentResultModal}
|
||||
{categoryFilterDialog}
|
||||
{isTaskCenterOpen ? (
|
||||
<ProfileTaskCenterModal
|
||||
<PlatformProfileTaskCenterModal
|
||||
center={taskCenter}
|
||||
isLoading={isLoadingTaskCenter}
|
||||
error={taskCenterError}
|
||||
@@ -6025,7 +5462,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
) : null}
|
||||
{isWalletLedgerOpen ? (
|
||||
<WalletLedgerModal
|
||||
<PlatformProfileWalletLedgerModal
|
||||
ledger={walletLedger}
|
||||
fallbackBalance={remainingNarrativeCoins}
|
||||
isLoading={isLoadingWalletLedger}
|
||||
|
||||
Reference in New Issue
Block a user