收口个人中心邀请弹层壳层
RpgEntryHomeView 的 ProfileReferralModal 改用 UnifiedModal 并保留社区与邀请码表单语义 更新玩家社区与邀请码弹层测试的具名 dialog 与关闭路径断言 同步 PlatformUiKit 收口计划与 .hermes 决策记录
This commit is contained in:
@@ -2815,6 +2815,8 @@ const PROFILE_MODAL_OVERLAY_CLASS =
|
||||
'platform-modal-backdrop !items-center !justify-center !px-4 !py-6';
|
||||
const PROFILE_SECONDARY_MODAL_OVERLAY_CLASS =
|
||||
'!items-center !bg-black/48 !px-3 !py-5 !backdrop-blur-none';
|
||||
const PROFILE_SECONDARY_MODAL_SOFT_OVERLAY_CLASS =
|
||||
'!items-center !bg-black/42 !px-3 !py-5 !backdrop-blur-none';
|
||||
const PROFILE_MODAL_HEADER_CLASS = 'border-white/10 px-5 py-4';
|
||||
const PROFILE_MODAL_TITLE_CLASS = 'text-base font-black';
|
||||
const PROFILE_MODAL_DESCRIPTION_CLASS =
|
||||
@@ -3957,201 +3959,216 @@ function ProfileReferralModal({
|
||||
.trim()
|
||||
.replace(/[^0-9a-z]/gi, '')
|
||||
.toUpperCase();
|
||||
let content: ReactNode;
|
||||
|
||||
if (panel === 'community') {
|
||||
content = (
|
||||
<div className="mt-5 grid grid-cols-2 gap-3">
|
||||
{COMMUNITY_QR_CODES.map((qrCode) => (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
key={qrCode.label}
|
||||
surface="flat"
|
||||
radius="xs"
|
||||
padding="xs"
|
||||
className="text-center"
|
||||
>
|
||||
<div className="aspect-square overflow-hidden rounded-lg border border-zinc-200 bg-white p-1.5">
|
||||
<img
|
||||
src={qrCode.src}
|
||||
alt={qrCode.alt}
|
||||
className="h-full w-full object-contain"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 text-sm font-bold text-zinc-700">
|
||||
{qrCode.label}
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
} else if (panel === 'redeem') {
|
||||
content = isLoading ? (
|
||||
<div className="mt-5 space-y-3">
|
||||
<div className="h-12 animate-pulse rounded-xl bg-zinc-100" />
|
||||
<div className="h-11 animate-pulse rounded-xl bg-zinc-100" />
|
||||
</div>
|
||||
) : center?.hasRedeemedCode ? (
|
||||
<PlatformEmptyState
|
||||
surface="subpanel"
|
||||
size="inline"
|
||||
tone="base"
|
||||
className="mt-5"
|
||||
>
|
||||
已填写邀请码
|
||||
</PlatformEmptyState>
|
||||
) : (
|
||||
<form
|
||||
className="mt-5 space-y-3"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
onSubmitRedeemCode();
|
||||
}}
|
||||
>
|
||||
<PlatformTextField
|
||||
value={redeemCode}
|
||||
onChange={(event) => onRedeemCodeChange(event.target.value)}
|
||||
size="lg"
|
||||
density="roomy"
|
||||
tone="rose"
|
||||
className="rounded-xl text-center font-black uppercase tracking-[0.16em]"
|
||||
placeholder="邀请码"
|
||||
aria-label="邀请码"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<PlatformActionButton
|
||||
type="submit"
|
||||
surface="profile"
|
||||
fullWidth
|
||||
size="md"
|
||||
className="rounded-xl"
|
||||
disabled={isSubmittingRedeem || !normalizedRedeemCode}
|
||||
>
|
||||
{isSubmittingRedeem ? '提交中' : '提交'}
|
||||
</PlatformActionButton>
|
||||
</form>
|
||||
);
|
||||
} else if (isLoading) {
|
||||
content = (
|
||||
<div className="mt-5 space-y-3">
|
||||
<div className="h-20 animate-pulse rounded-xl bg-zinc-100" />
|
||||
<div className="h-10 animate-pulse rounded-xl bg-zinc-100" />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<div className="mt-5 space-y-3">
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
surface="flat"
|
||||
radius="xs"
|
||||
padding="md"
|
||||
className="text-center"
|
||||
>
|
||||
<PlatformFieldLabel
|
||||
variant="section"
|
||||
className="block text-[11px] text-zinc-500"
|
||||
>
|
||||
邀请码
|
||||
</PlatformFieldLabel>
|
||||
<div className="mt-1 text-3xl font-black tracking-[0.16em] text-[#ff4056]">
|
||||
{center?.inviteCode ?? '--------'}
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
<PlatformStatusMessage
|
||||
tone="warning"
|
||||
surface="profile"
|
||||
size="md"
|
||||
className="space-y-0.5 px-3.5 font-semibold"
|
||||
>
|
||||
<div>
|
||||
{`邀请一个用户注册,双方都可以获得${center?.rewardPoints ?? 30}泥点。`}
|
||||
</div>
|
||||
<div>每日最多获得十次邀请奖励。</div>
|
||||
</PlatformStatusMessage>
|
||||
<CopyFeedbackButton
|
||||
state={copyInviteState}
|
||||
onClick={onCopyInvite}
|
||||
disabled={!center?.inviteCode}
|
||||
idleLabel="复制邀请"
|
||||
copiedLabel="已复制"
|
||||
failedLabel="复制失败"
|
||||
idleIcon={<Copy className="h-4 w-4" />}
|
||||
actionSurface="profile"
|
||||
actionSize="md"
|
||||
actionFullWidth
|
||||
className="gap-2 rounded-xl"
|
||||
/>
|
||||
<PlatformSubpanel as="div" surface="flat" radius="xs" padding="sm">
|
||||
<PlatformFieldLabel
|
||||
variant="section"
|
||||
className="block text-zinc-900"
|
||||
>
|
||||
成功邀请
|
||||
</PlatformFieldLabel>
|
||||
{center?.invitedUsers?.length ? (
|
||||
<div className="mt-3 max-h-44 space-y-2 overflow-y-auto pr-1">
|
||||
{center.invitedUsers.map((user) => (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
key={`${user.userId}-${user.boundAt}`}
|
||||
surface="soft"
|
||||
radius="xs"
|
||||
padding="row"
|
||||
className="flex items-center gap-3"
|
||||
>
|
||||
<ProfileReferralUserAvatar
|
||||
name={user.displayName}
|
||||
avatarUrl={user.avatarUrl}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-sm font-bold text-zinc-900">
|
||||
{user.displayName || '玩家'}
|
||||
</div>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState
|
||||
surface="subpanel"
|
||||
size="compact"
|
||||
className="mt-3 text-center text-xs font-semibold leading-normal"
|
||||
>
|
||||
暂无成功邀请
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformSubpanel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/42 px-3 py-5">
|
||||
<div className="relative w-full max-w-[24rem] overflow-hidden rounded-[1.35rem] bg-white text-zinc-950 shadow-2xl">
|
||||
<UnifiedModal
|
||||
open
|
||||
title={title}
|
||||
onClose={onClose}
|
||||
showHeader={false}
|
||||
showCloseButton={false}
|
||||
closeOnBackdrop={false}
|
||||
closeOnEscape={false}
|
||||
portal={false}
|
||||
size="sm"
|
||||
zIndexClassName="z-[80]"
|
||||
overlayClassName={PROFILE_SECONDARY_MODAL_SOFT_OVERLAY_CLASS}
|
||||
panelClassName="relative !max-w-[24rem] bg-white text-zinc-950 shadow-2xl !rounded-[1.35rem] sm:!rounded-[1.35rem]"
|
||||
bodyClassName="!p-0"
|
||||
>
|
||||
<div className="relative px-5 pb-5 pt-4">
|
||||
<PlatformModalCloseButton
|
||||
label={`关闭${title}`}
|
||||
variant="floatingPlain"
|
||||
onClick={onClose}
|
||||
icon="×"
|
||||
/>
|
||||
<div className="px-5 pb-5 pt-4">
|
||||
<div className="text-center text-xl font-black">{title}</div>
|
||||
<div className="text-center text-xl font-black">{title}</div>
|
||||
{content}
|
||||
|
||||
{panel === 'community' ? (
|
||||
<div className="mt-5 grid grid-cols-2 gap-3">
|
||||
{COMMUNITY_QR_CODES.map((qrCode) => (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
key={qrCode.label}
|
||||
surface="flat"
|
||||
radius="xs"
|
||||
padding="xs"
|
||||
className="text-center"
|
||||
>
|
||||
<div className="aspect-square overflow-hidden rounded-lg border border-zinc-200 bg-white p-1.5">
|
||||
<img
|
||||
src={qrCode.src}
|
||||
alt={qrCode.alt}
|
||||
className="h-full w-full object-contain"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 text-sm font-bold text-zinc-700">
|
||||
{qrCode.label}
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
) : panel === 'redeem' ? (
|
||||
isLoading ? (
|
||||
<div className="mt-5 space-y-3">
|
||||
<div className="h-12 animate-pulse rounded-xl bg-zinc-100" />
|
||||
<div className="h-11 animate-pulse rounded-xl bg-zinc-100" />
|
||||
</div>
|
||||
) : center?.hasRedeemedCode ? (
|
||||
<PlatformEmptyState
|
||||
surface="subpanel"
|
||||
size="inline"
|
||||
tone="base"
|
||||
className="mt-5"
|
||||
>
|
||||
已填写邀请码
|
||||
</PlatformEmptyState>
|
||||
) : (
|
||||
<form
|
||||
className="mt-5 space-y-3"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
onSubmitRedeemCode();
|
||||
}}
|
||||
>
|
||||
<PlatformTextField
|
||||
value={redeemCode}
|
||||
onChange={(event) => onRedeemCodeChange(event.target.value)}
|
||||
size="lg"
|
||||
density="roomy"
|
||||
tone="rose"
|
||||
className="rounded-xl text-center font-black uppercase tracking-[0.16em]"
|
||||
placeholder="邀请码"
|
||||
aria-label="邀请码"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<PlatformActionButton
|
||||
type="submit"
|
||||
surface="profile"
|
||||
fullWidth
|
||||
size="md"
|
||||
className="rounded-xl"
|
||||
disabled={isSubmittingRedeem || !normalizedRedeemCode}
|
||||
>
|
||||
{isSubmittingRedeem ? '提交中' : '提交'}
|
||||
</PlatformActionButton>
|
||||
</form>
|
||||
)
|
||||
) : isLoading ? (
|
||||
<div className="mt-5 space-y-3">
|
||||
<div className="h-20 animate-pulse rounded-xl bg-zinc-100" />
|
||||
<div className="h-10 animate-pulse rounded-xl bg-zinc-100" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-5 space-y-3">
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
surface="flat"
|
||||
radius="xs"
|
||||
padding="md"
|
||||
className="text-center"
|
||||
>
|
||||
<PlatformFieldLabel
|
||||
variant="section"
|
||||
className="block text-[11px] text-zinc-500"
|
||||
>
|
||||
邀请码
|
||||
</PlatformFieldLabel>
|
||||
<div className="mt-1 text-3xl font-black tracking-[0.16em] text-[#ff4056]">
|
||||
{center?.inviteCode ?? '--------'}
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
<PlatformStatusMessage
|
||||
tone="warning"
|
||||
surface="profile"
|
||||
size="md"
|
||||
className="space-y-0.5 px-3.5 font-semibold"
|
||||
>
|
||||
<div>
|
||||
{`邀请一个用户注册,双方都可以获得${center?.rewardPoints ?? 30}泥点。`}
|
||||
</div>
|
||||
<div>每日最多获得十次邀请奖励。</div>
|
||||
</PlatformStatusMessage>
|
||||
<CopyFeedbackButton
|
||||
state={copyInviteState}
|
||||
onClick={onCopyInvite}
|
||||
disabled={!center?.inviteCode}
|
||||
idleLabel="复制邀请"
|
||||
copiedLabel="已复制"
|
||||
failedLabel="复制失败"
|
||||
idleIcon={<Copy className="h-4 w-4" />}
|
||||
actionSurface="profile"
|
||||
actionSize="md"
|
||||
actionFullWidth
|
||||
className="gap-2 rounded-xl"
|
||||
/>
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
surface="flat"
|
||||
radius="xs"
|
||||
padding="sm"
|
||||
>
|
||||
<PlatformFieldLabel
|
||||
variant="section"
|
||||
className="block text-zinc-900"
|
||||
>
|
||||
成功邀请
|
||||
</PlatformFieldLabel>
|
||||
{center?.invitedUsers?.length ? (
|
||||
<div className="mt-3 max-h-44 space-y-2 overflow-y-auto pr-1">
|
||||
{center.invitedUsers.map((user) => (
|
||||
<PlatformSubpanel
|
||||
as="div"
|
||||
key={`${user.userId}-${user.boundAt}`}
|
||||
surface="soft"
|
||||
radius="xs"
|
||||
padding="row"
|
||||
className="flex items-center gap-3"
|
||||
>
|
||||
<ProfileReferralUserAvatar
|
||||
name={user.displayName}
|
||||
avatarUrl={user.avatarUrl}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-sm font-bold text-zinc-900">
|
||||
{user.displayName || '玩家'}
|
||||
</div>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState
|
||||
surface="subpanel"
|
||||
size="compact"
|
||||
className="mt-3 text-center text-xs font-semibold leading-normal"
|
||||
>
|
||||
暂无成功邀请
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformSubpanel>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error ? (
|
||||
<PlatformStatusMessage tone="error" className="mt-4">
|
||||
{error}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
{success ? (
|
||||
<PlatformStatusMessage tone="success" className="mt-4">
|
||||
{success}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
</div>
|
||||
{error ? (
|
||||
<PlatformStatusMessage tone="error" className="mt-4">
|
||||
{error}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
{success ? (
|
||||
<PlatformStatusMessage tone="success" className="mt-4">
|
||||
{success}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</UnifiedModal>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user