"use client"; import React from 'react'; import { get } from '@/api/request'; import { DashboardLayout } from "@/components/layout/dashboard-layout"; /** * Share (Invite) Page - Static UI with mocked data. * Sections: Invite Flow, My Invitation Code, Invite Records (with pagination) */ /** * 邀请记录项 */ type InviteRecord = { user_email: string; user_id: string; user_name: string; created_at: number; reward_status: number; activation_credits: number; first_payment_credits: number; }; /** * 分页信息 */ type PaginationInfo = { page: number; page_size: number; total: number; total_pages: number; has_next: boolean; has_prev: boolean; }; /** * 邀请记录API响应 */ type InviteRecordsResponse = { successful: boolean; code: number; message: string; data: { record_list: InviteRecord[]; pagination: PaginationInfo; }; }; const PAGE_SIZE = 10; /** * Format epoch ms using browser preferred language. * @param {number} epochMs - timestamp in milliseconds * @returns {string} - localized date time string */ function formatLocalTime(epochMs: number): string { try { const locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US'; const dtf = new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'medium', }); return dtf.format(new Date(epochMs)); } catch { return new Date(epochMs).toLocaleString(); } } /** * 从后端获取邀请记录 * @returns {Promise} */ async function fetchInviteRecords(): Promise { const res = await get('/api/user_fission/query_invite_record'); return res; } export default function SharePage(): JSX.Element { // Mocked data (to be replaced by real API integration later) const [inviteCode, setInviteCode] = React.useState(''); const [invitedCount, setInvitedCount] = React.useState(0); const [totalInviteCredits, setTotalInviteCredits] = React.useState(0); const [copyState, setCopyState] = React.useState<'idle' | 'copied' | 'error'>('idle'); const [records, setRecords] = React.useState([]); const [pagination, setPagination] = React.useState({ page: 1, page_size: 20, total: 0, total_pages: 1, has_next: false, has_prev: false }); const [pageIndex, setPageIndex] = React.useState(0); const [expandedRowIds, setExpandedRowIds] = React.useState>(() => new Set()); React.useEffect(() => { let mounted = true; // 并行发起所有请求,每个请求完成后立即处理 const fetchRecords = async () => { try { const response = await fetchInviteRecords(); if (!mounted) return; // 早期返回检查 if (response.successful) { setRecords(response.data.record_list); setPagination(response.data.pagination); } } catch (error) { if (mounted) { console.warn('Failed to fetch invite records:', error); } } }; const fetchStats = async () => { try { const res = await get('/api/user_fission/my_invite_stats'); if (!mounted) return; // 早期返回检查 const stats = res?.data ?? {}; if (typeof stats.total_invited === 'number') { setInvitedCount(stats.total_invited); } if (typeof stats.total_invite_credits === 'number') { setTotalInviteCredits(stats.total_invite_credits); } } catch (error) { if (mounted) { console.warn('Failed to fetch invite stats:', error); } } }; const fetchInviteCode = async () => { try { const res = await get('/api/user_fission/my_invite_code'); if (!mounted) return; // 早期返回检查 const code = res?.data?.invite_code ?? res?.data?.inviteCode ?? ''; if (typeof code === 'string') { setInviteCode(code); } } catch (error) { if (mounted) { console.warn('Failed to fetch invite code:', error); } } }; // 并行发起所有请求,每个请求完成后立即处理响应 fetchRecords(); fetchStats(); fetchInviteCode(); return () => { mounted = false; }; }, []); const totalPages = pagination.total_pages; const pagedRecords = records; // 后端已经分页,直接使用records const handleCopy = React.useCallback(async () => { try { await navigator.clipboard.writeText(location.origin + '/signup?inviteCode=' + inviteCode); setCopyState('copied'); window.setTimeout(() => setCopyState('idle'), 1600); } catch { setCopyState('error'); window.setTimeout(() => setCopyState('idle'), 1600); } }, [inviteCode]); const toggleRow = React.useCallback((id: string) => { setExpandedRowIds((prev: Set) => { const next = new Set(prev); if (next.has(id)) { next.delete(id); } else { next.add(id); } return next; }); }, []); return (

Invite Friends

Invite friends to join and earn rewards.

{/* Section 1: My Invitation Link */}

My Invitation Link

{inviteCode ? `${'https://www.movieflow.ai'}/signup?inviteCode=${inviteCode}` : '-'}
{/* 右侧渐变遮挡 */}

Share this link. Your friends can register directly through it.

Total Credits {totalInviteCredits} All credits earned from invitations.
Invited Friends {invitedCount} Point details will be available soon.
{/* Section 2: Invite Flow - Two Columns (Left: Steps, Right: Rules) */}
{/* Left: Steps */}

Invitation Flow

  1. Step 1 Share

    Copy your invitation link and share it with friends.

  2. Step 2 Register

    Friends click the link and register directly.

  3. Step 3 Reward

    You will receive 500 credits after your friends successfully sign in.

{/* Right: Rules */}

MovieFlow Credits Rewards Program

Welcome to MovieFlow! Our Credits Program is designed to reward your growth and contributions.
Credits can be redeemed for watermark removal.
In the future, credits may be used to redeem advanced template features.

How to Earn Credits?

Invite & Earn

Invite friends to join using your unique referral link.

You will get 500 credits once they successfully sign in.


When your invited friends complete their first purchase, you will receive a 20% share of the credits they earn from that purchase.

{/* Section 3: Invite Records */}

Invite Records

{pagination.page} / {pagination.total_pages}
{pagedRecords.map((r: any) => { const inviteRewardDisplay = r.reward_status === 1 ? r.activation_credits : 0; const payRewardDisplay = r.first_payment_credits; const totalReward = inviteRewardDisplay + payRewardDisplay; const isExpanded = expandedRowIds.has(r.user_id); return ( {isExpanded && ( )} ); })}
Invited Username Registered At Reward
{r.user_name} {formatLocalTime(r.created_at * 1000)}
{totalReward}
{inviteRewardDisplay ? inviteRewardDisplay : 'Unverified'} Register Reward
{payRewardDisplay ? payRewardDisplay : 'Unpaid'} First Payment Reward
); }