// Points API Client const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080/api'; // ===================== // Type Definitions // ===================== export interface WalletRegisterData { walletAddress: string; inviteCode: string; usedCount: number; memberTier: string; vipLevel: number; totalPoints: number; globalRank: number; } export interface DashboardData { totalPoints: number; globalRank: number; topPercentage: string; memberTier: string; vipLevel: number; pointsToNextTier: number; nextTier: string; season: { seasonNumber: number; seasonName: string; isLive: boolean; endTime: string; daysRemaining: number; hoursRemaining: number; }; } export interface LeaderboardUser { rank: number; address: string; points: number; } export interface LeaderboardData { topUsers: LeaderboardUser[]; myRank: number; myPoints: number; } export interface InviteCodeData { code: string; usedCount: number; maxUses: number; } export interface RoleCount { icon: string; label: string; current: number; target: number; } export interface TeamTVLData { currentTVL: string; targetTVL: string; progressPercent: number; totalMembers: number; roles: RoleCount[]; } export interface ActivityRecord { type: string; userAddress: string; friendAddress?: string; inviteCode?: string; points: number; createdAt: string; } export interface ActivitiesData { activities: ActivityRecord[]; pagination: { page: number; pageSize: number; total: number; totalPage: number; }; } // ===================== // API Functions // ===================== /** * Register or retrieve a user by wallet address * @param walletAddress - The connected wallet address */ export async function registerWallet(walletAddress: string): Promise { try { const response = await fetch(`${API_BASE_URL}/points/wallet-register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ wallet_address: walletAddress }), cache: 'no-store', }); if (!response.ok) { console.error('Wallet register API error:', response.status); return null; } const data = await response.json(); if (!data.success) { console.error('Wallet register error:', data.error); return null; } return data.data; } catch (error: unknown) { console.error('Error registering wallet:', error); return null; } } /** * Fetch user points dashboard */ export async function fetchDashboard(walletAddress?: string): Promise { try { const params = walletAddress ? `?wallet_address=${encodeURIComponent(walletAddress)}` : ''; const response = await fetch(`${API_BASE_URL}/points/dashboard${params}`, { cache: 'no-store', }); if (!response.ok) { console.error('Dashboard API error:', response.status); return null; } const data = await response.json(); if (!data.success) { console.error('Dashboard API error:', data.error); return null; } return data.data; } catch (error: unknown) { console.error('Error fetching dashboard:', error); return null; } } /** * Fetch leaderboard * @param limit - Number of top users to fetch (default: 5) * @param walletAddress - Optional wallet address to identify current user's rank */ export async function fetchLeaderboard(limit: number = 5, walletAddress?: string): Promise { try { const params = new URLSearchParams({ limit: limit.toString() }); if (walletAddress) params.set('wallet_address', walletAddress); const response = await fetch(`${API_BASE_URL}/points/leaderboard?${params}`, { cache: 'no-store', }); if (!response.ok) { console.error('Leaderboard API error:', response.status); return null; } const data = await response.json(); if (!data.success) { console.error('Leaderboard API error:', data.error); return null; } return data.data; } catch (error: unknown) { console.error('Error fetching leaderboard:', error); return null; } } /** * Fetch user's invite code information */ export async function fetchInviteCode(): Promise { try { const response = await fetch(`${API_BASE_URL}/points/invite-code`, { cache: 'no-store', }); if (!response.ok) { throw new Error('Failed to fetch invite code'); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to fetch invite code'); } return data.data; } catch (error: unknown) { console.error('Error fetching invite code:', error); return null; } } /** * Bind an invite code * @param code - Invite code to bind * @param signature - User signature for verification * @param walletAddress - Optional wallet address of the current user */ export async function bindInviteCode(code: string, signature: string, walletAddress?: string): Promise<{ success: boolean; message?: string; error?: string }> { try { const response = await fetch(`${API_BASE_URL}/points/bind-invite`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ code, signature, wallet_address: walletAddress }), }); const data = await response.json(); if (!response.ok || !data.success) { return { success: false, error: data.error || 'Failed to bind invite code', }; } return { success: true, message: data.message, }; } catch (error: unknown) { console.error('Error binding invite code:', error); return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * Fetch team TVL statistics * @param walletAddress - Optional wallet address to identify current user's team */ export async function fetchTeamTVL(walletAddress?: string): Promise { try { const params = walletAddress ? `?wallet_address=${encodeURIComponent(walletAddress)}` : ''; const response = await fetch(`${API_BASE_URL}/points/team${params}`, { cache: 'no-store', }); if (!response.ok) { console.error('Team TVL API error:', response.status, response.statusText); // 返回默认值而不是 null return { currentTVL: "$0", targetTVL: "$10M", progressPercent: 0, totalMembers: 0, roles: [] }; } const data = await response.json(); if (!data.success) { console.error('Team TVL API error:', data.error); // 返回默认值 return { currentTVL: "$0", targetTVL: "$10M", progressPercent: 0, totalMembers: 0, roles: [] }; } return data.data; } catch (error: unknown) { console.error('Error fetching team TVL:', error); // 返回默认值而不是 null return { currentTVL: "$0", targetTVL: "$10M", progressPercent: 0, totalMembers: 0, roles: [] }; } } /** * Fetch user activities * @param type - Activity type: 'all', 'referrals', 'deposits' * @param page - Page number (default: 1) * @param pageSize - Items per page (default: 10) * @param walletAddress - Optional wallet address */ export async function fetchActivities( type: 'all' | 'referrals' | 'deposits' = 'all', page: number = 1, pageSize: number = 10, walletAddress?: string ): Promise { try { const params = new URLSearchParams({ type, page: page.toString(), pageSize: pageSize.toString(), }); if (walletAddress) params.set('wallet_address', walletAddress); const response = await fetch(`${API_BASE_URL}/points/activities?${params}`, { cache: 'no-store', }); if (!response.ok) { throw new Error('Failed to fetch activities'); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to fetch activities'); } return data.data; } catch (error: unknown) { console.error('Error fetching activities:', error); return null; } } /** * Format points to display format (e.g., 52000 -> "52k") */ export function formatPoints(points: number): string { if (points >= 1000000) { return `${(points / 1000000).toFixed(1)}M`; } else if (points >= 1000) { return `${(points / 1000).toFixed(0)}k`; } return points.toString(); } /** * Calculate progress percentage */ export function calculateProgress(current: number, target: number): number { if (target === 0) return 0; return Math.round((current / target) * 100 * 100) / 100; }