import { api } from './api'; export type ChallengeStatus = 'upcoming' | 'ongoing' | 'expired'; export enum ChallengeSource { SYSTEM = 'system', CUSTOM = 'custom', } export enum ChallengeState { DRAFT = 'draft', ACTIVE = 'active', ARCHIVED = 'archived', } export type ChallengeProgressDto = { completed: number; target: number; remaining: number checkedInToday: boolean; lastProgressAt?: string; last_progress_at?: string; }; export type RankingItemDto = { id: string; name: string; avatar: string | null; metric: string; badge?: string; todayReportedValue?: number; todayTargetValue?: number; }; export enum ChallengeType { WATER = 'water', EXERCISE = 'exercise', DIET = 'diet', MOOD = 'mood', SLEEP = 'sleep', WEIGHT = 'weight', } export type ChallengeListItemDto = { id: string; title: string; image: string; periodLabel?: string; durationLabel: string; requirementLabel: string; unit?: string; status?: ChallengeStatus; participantsCount: number; rankingDescription?: string; highlightTitle: string; highlightSubtitle: string; ctaLabel: string; progress?: ChallengeProgressDto; isJoined: boolean; startAt?: string; endAt?: string; minimumCheckInDays: number; // 最小打卡天数 type: ChallengeType; shareCode?: string | null; source?: ChallengeSource; creatorId?: string | null; isCreator?: boolean; isPublic?: boolean; maxParticipants?: number | null; challengeState?: ChallengeState; progressUnit?: string; targetValue?: number; summary?: string | null; }; export type ChallengeDetailDto = ChallengeListItemDto & { summary?: string | null; rankings?: RankingItemDto[]; userRank?: number; challengeState?: ChallengeState; }; export type ChallengeRankingsDto = { total: number; page: number; pageSize: number; items: RankingItemDto[]; }; export type ChallengeListResponse = { items: ChallengeListItemDto[]; total: number; page: number; pageSize: number; }; export type CreateCustomChallengePayload = { title: string; type: ChallengeType; image?: string | null; startAt: number; endAt: number; targetValue: number; minimumCheckInDays: number; durationLabel: string; requirementLabel: string; summary?: string | null; progressUnit?: string; periodLabel?: string | null; rankingDescription?: string | null; isPublic?: boolean; maxParticipants?: number | null; }; export async function listChallenges(): Promise { return api.get('/challenges'); } export async function getChallengeDetail(id: string): Promise { return api.get(`/challenges/${encodeURIComponent(id)}`); } export async function joinChallenge(id: string): Promise { return api.post(`/challenges/${encodeURIComponent(id)}/join`); } export async function leaveChallenge(id: string): Promise { return api.post(`/challenges/${encodeURIComponent(id)}/leave`); } export async function reportChallengeProgress(id: string, value?: number): Promise { const body = value != null ? { value } : undefined; return api.post(`/challenges/${encodeURIComponent(id)}/progress`, body); } export async function getChallengeRankings( id: string, params?: { page?: number; pageSize?: number } ): Promise { const searchParams = new URLSearchParams(); if (params?.page) { searchParams.append('page', String(params.page)); } if (params?.pageSize) { searchParams.append('pageSize', String(params.pageSize)); } const query = searchParams.toString(); const url = `/challenges/${encodeURIComponent(id)}/rankings${query ? `?${query}` : ''}`; return api.get(url); } export async function listMyCustomChallenges( params?: { page?: number; pageSize?: number; state?: ChallengeState } ): Promise { const searchParams = new URLSearchParams(); if (params?.page) { searchParams.append('page', String(params.page)); } if (params?.pageSize) { searchParams.append('pageSize', String(params.pageSize)); } if (params?.state) { searchParams.append('state', params.state); } const query = searchParams.toString(); const url = `/challenges/my/created${query ? `?${query}` : ''}`; return api.get(url); } export async function createCustomChallenge( payload: CreateCustomChallengePayload ): Promise { return api.post('/challenges/custom', payload); } export async function joinChallengeByCode(shareCode: string): Promise { return api.post('/challenges/join-by-code', { shareCode }); } export async function getChallengeByShareCode(shareCode: string): Promise { return api.get(`/challenges/share/${encodeURIComponent(shareCode)}`); } export async function regenerateChallengeShareCode( id: string ): Promise<{ shareCode: string }> { return api.post<{ shareCode: string }>( `/challenges/custom/${encodeURIComponent(id)}/regenerate-code` ); }