Implement registration invite code flow and admin invite codes
This commit is contained in:
@@ -47,7 +47,6 @@ import type {
|
||||
ProfileReferralInviteCenterResponse,
|
||||
ProfileSaveArchiveSummary,
|
||||
ProfileWalletLedgerResponse,
|
||||
RedeemProfileReferralInviteCodeResponse,
|
||||
RedeemProfileRewardCodeResponse,
|
||||
} from '../../../packages/shared/src/contracts/runtime';
|
||||
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
|
||||
@@ -57,7 +56,6 @@ import { copyTextToClipboard } from '../../services/clipboard';
|
||||
import {
|
||||
getRpgProfileReferralInviteCenter,
|
||||
getRpgProfileWalletLedger,
|
||||
redeemRpgProfileReferralInviteCode,
|
||||
redeemRpgProfileRewardCode,
|
||||
} from '../../services/rpg-entry/rpgProfileClient';
|
||||
import type { CustomWorldProfile } from '../../types';
|
||||
@@ -144,7 +142,7 @@ const PLATFORM_HOME_TABS: PlatformHomeTab[] = [
|
||||
const AVATAR_MAX_FILE_SIZE = 5 * 1024 * 1024;
|
||||
const AVATAR_OUTPUT_SIZE = 256;
|
||||
const AVATAR_ALLOWED_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp']);
|
||||
type ProfilePopupPanel = 'invite' | 'redeem' | 'community';
|
||||
type ProfilePopupPanel = 'invite' | 'community';
|
||||
type MobileHomeChannel = 'recommend' | 'today' | 'category';
|
||||
type PlatformRankingTab = 'hot' | 'remix' | 'new' | 'like';
|
||||
|
||||
@@ -1841,34 +1839,21 @@ function RewardCodeRedeemModal({
|
||||
function ProfileReferralModal({
|
||||
panel,
|
||||
center,
|
||||
inviteCodeInput,
|
||||
isLoading,
|
||||
isSubmitting,
|
||||
error,
|
||||
success,
|
||||
onClose,
|
||||
onInputChange,
|
||||
onCopyInvite,
|
||||
onSubmitRedeem,
|
||||
}: {
|
||||
panel: ProfilePopupPanel;
|
||||
center: ProfileReferralInviteCenterResponse | null;
|
||||
inviteCodeInput: string;
|
||||
isLoading: boolean;
|
||||
isSubmitting: boolean;
|
||||
error: string | null;
|
||||
success: string | null;
|
||||
onClose: () => void;
|
||||
onInputChange: (value: string) => void;
|
||||
onCopyInvite: () => void;
|
||||
onSubmitRedeem: () => void;
|
||||
}) {
|
||||
const title =
|
||||
panel === 'invite'
|
||||
? '邀请好友'
|
||||
: panel === 'redeem'
|
||||
? '填邀请码'
|
||||
: '玩家社区';
|
||||
const title = panel === 'invite' ? '邀请好友' : '玩家社区';
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/42 px-3 py-5">
|
||||
@@ -1911,7 +1896,7 @@ function ProfileReferralModal({
|
||||
<div className="h-20 animate-pulse rounded-xl bg-zinc-100" />
|
||||
<div className="h-10 animate-pulse rounded-xl bg-zinc-100" />
|
||||
</div>
|
||||
) : panel === 'invite' ? (
|
||||
) : (
|
||||
<div className="mt-5 space-y-3">
|
||||
<div className="rounded-xl bg-zinc-50 px-4 py-4 text-center">
|
||||
<div className="text-[11px] font-bold text-zinc-500">
|
||||
@@ -1951,31 +1936,6 @@ function ProfileReferralModal({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-5 space-y-3">
|
||||
{center?.hasRedeemedCode ? (
|
||||
<div className="rounded-xl bg-emerald-50 px-4 py-4 text-center text-sm font-bold text-emerald-700">
|
||||
已填写邀请码
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<input
|
||||
value={inviteCodeInput}
|
||||
onChange={(event) => onInputChange(event.target.value)}
|
||||
placeholder="输入邀请码"
|
||||
className="w-full rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 text-center text-base font-black tracking-[0.14em] outline-none focus:border-[#ff4056]"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onSubmitRedeem}
|
||||
disabled={isSubmitting || !inviteCodeInput.trim()}
|
||||
className="w-full rounded-xl bg-[#ff4056] px-4 py-3 text-sm font-black text-white disabled:opacity-60"
|
||||
>
|
||||
{isSubmitting ? '提交中' : '确认填写'}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error ? (
|
||||
@@ -2153,10 +2113,8 @@ export function RpgEntryHomeView({
|
||||
const [referralCenter, setReferralCenter] =
|
||||
useState<ProfileReferralInviteCenterResponse | null>(null);
|
||||
const [isLoadingReferral, setIsLoadingReferral] = useState(false);
|
||||
const [isSubmittingReferral, setIsSubmittingReferral] = useState(false);
|
||||
const [referralError, setReferralError] = useState<string | null>(null);
|
||||
const [referralSuccess, setReferralSuccess] = useState<string | null>(null);
|
||||
const [inviteCodeInput, setInviteCodeInput] = useState('');
|
||||
const [selectedCategoryTag, setSelectedCategoryTag] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
@@ -2519,30 +2477,6 @@ export function RpgEntryHomeView({
|
||||
},
|
||||
);
|
||||
};
|
||||
const submitReferralInviteCode = () => {
|
||||
if (isSubmittingReferral || !inviteCodeInput.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmittingReferral(true);
|
||||
setReferralError(null);
|
||||
setReferralSuccess(null);
|
||||
void redeemRpgProfileReferralInviteCode(inviteCodeInput)
|
||||
.then((response: RedeemProfileReferralInviteCodeResponse) => {
|
||||
setReferralCenter(response.center);
|
||||
setInviteCodeInput('');
|
||||
setReferralSuccess(
|
||||
response.inviteeRewardGranted ? '已获得30陶泥币' : '填写成功',
|
||||
);
|
||||
void onRechargeSuccess?.();
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
setReferralError(
|
||||
error instanceof Error ? error.message : '填写邀请码失败',
|
||||
);
|
||||
})
|
||||
.finally(() => setIsSubmittingReferral(false));
|
||||
};
|
||||
const openRewardCodeModal = () => {
|
||||
setIsRewardCodeOpen(true);
|
||||
setRewardCodeError(null);
|
||||
@@ -3061,17 +2995,12 @@ export function RpgEntryHomeView({
|
||||
|
||||
<section className={`${PANEL_SURFACE_CLASS} px-4 py-3.5`}>
|
||||
<SectionHeader title="常用功能" detail="快捷入口" />
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<ProfileShortcutButton
|
||||
label="邀请好友"
|
||||
icon={UserPlus}
|
||||
onClick={() => openProfilePopupPanel('invite')}
|
||||
/>
|
||||
<ProfileShortcutButton
|
||||
label="填邀请码"
|
||||
icon={Ticket}
|
||||
onClick={() => openProfilePopupPanel('redeem')}
|
||||
/>
|
||||
<ProfileShortcutButton
|
||||
label="玩家社区"
|
||||
icon={MessageCircle}
|
||||
@@ -3506,15 +3435,11 @@ export function RpgEntryHomeView({
|
||||
<ProfileReferralModal
|
||||
panel={profilePopupPanel}
|
||||
center={referralCenter}
|
||||
inviteCodeInput={inviteCodeInput}
|
||||
isLoading={isLoadingReferral}
|
||||
isSubmitting={isSubmittingReferral}
|
||||
error={referralError}
|
||||
success={referralSuccess}
|
||||
onClose={() => setProfilePopupPanel(null)}
|
||||
onInputChange={setInviteCodeInput}
|
||||
onCopyInvite={copyInviteInfo}
|
||||
onSubmitRedeem={submitReferralInviteCode}
|
||||
/>
|
||||
) : null}
|
||||
{rewardCodeModal}
|
||||
@@ -3628,15 +3553,11 @@ export function RpgEntryHomeView({
|
||||
<ProfileReferralModal
|
||||
panel={profilePopupPanel}
|
||||
center={referralCenter}
|
||||
inviteCodeInput={inviteCodeInput}
|
||||
isLoading={isLoadingReferral}
|
||||
isSubmitting={isSubmittingReferral}
|
||||
error={referralError}
|
||||
success={referralSuccess}
|
||||
onClose={() => setProfilePopupPanel(null)}
|
||||
onInputChange={setInviteCodeInput}
|
||||
onCopyInvite={copyInviteInfo}
|
||||
onSubmitRedeem={submitReferralInviteCode}
|
||||
/>
|
||||
) : null}
|
||||
{isProfilePlayStatsOpen ? (
|
||||
|
||||
Reference in New Issue
Block a user