140 lines
3.0 KiB
TypeScript
140 lines
3.0 KiB
TypeScript
export type SubscriptionTier = 'free' | 'pro' | 'proplus';
|
|
export type SubscriptionStatus = 'none' | 'active' | 'expired' | 'cancelled';
|
|
export type NodeStatus = 'done' | 'current' | 'locked' | 'chest';
|
|
export type LeaderboardScope = 'region' | 'topic';
|
|
export type RewardSource = 'ad' | 'check_in' | 'subscription' | 'admin_grant' | 'debug';
|
|
export type SubscriptionPlatform = 'huawei' | 'apple' | 'google';
|
|
|
|
export interface UserBriefDto {
|
|
id: string;
|
|
nickname: string;
|
|
avatarUrl: string | null;
|
|
tier: SubscriptionTier;
|
|
level: number;
|
|
}
|
|
|
|
export interface SubscriptionDto {
|
|
status: SubscriptionStatus;
|
|
tier: SubscriptionTier;
|
|
expiresAt: string | null;
|
|
autoRenew?: boolean;
|
|
}
|
|
|
|
export interface ProgressSummaryDto {
|
|
hearts: number;
|
|
maxHearts: number;
|
|
nextHeartRestoreAt: string | null;
|
|
dailyAttemptsLeft: number;
|
|
dailyAttemptsMax: number;
|
|
nextAttemptResetAt: string | null;
|
|
highRewardSessionsLeft: number;
|
|
highRewardSessionsMax: number;
|
|
xp: number;
|
|
level: number;
|
|
xpToNextLevel: number;
|
|
streakDays: number;
|
|
checkInDays: number;
|
|
streakProtectedUntil: string | null;
|
|
activeTrackId: string | null;
|
|
isSubscribed: boolean;
|
|
}
|
|
|
|
export interface ThemeNodeDto {
|
|
id: string;
|
|
title: string;
|
|
status: NodeStatus;
|
|
reward: string;
|
|
questionCount: number;
|
|
}
|
|
|
|
export interface ThemeTrackDto {
|
|
id: string;
|
|
name: string;
|
|
icon: string;
|
|
progress: number;
|
|
nodes: ThemeNodeDto[];
|
|
}
|
|
|
|
export interface ShopBenefitDto {
|
|
id: string;
|
|
type: 'hearts' | 'attempts' | 'streak' | 'subscription';
|
|
title: string;
|
|
description: string;
|
|
enabled: boolean;
|
|
requiresAd: boolean;
|
|
}
|
|
|
|
export interface BootstrapDto {
|
|
user: UserBriefDto;
|
|
progress: ProgressSummaryDto;
|
|
tracks: ThemeTrackDto[];
|
|
shopBenefits: readonly ShopBenefitDto[];
|
|
subscription: SubscriptionDto;
|
|
}
|
|
|
|
export interface ChallengeQuestionDto {
|
|
challengeId: string;
|
|
trackId: string;
|
|
nodeId: string;
|
|
question: {
|
|
id: string;
|
|
prompt: string;
|
|
options: ReadonlyArray<{ id: string; text: string }>;
|
|
};
|
|
}
|
|
|
|
export interface ChallengeSessionDto {
|
|
challengeId: string;
|
|
trackId: string;
|
|
nodeId: string;
|
|
totalQuestions: number;
|
|
highRewardEligible: boolean;
|
|
questions: readonly ChallengeQuestionDto[];
|
|
}
|
|
|
|
export interface AnswerRequestDto {
|
|
challengeId: string;
|
|
questionId: string;
|
|
selectedOptionId: string;
|
|
timeMs: number;
|
|
submitRequestId?: string;
|
|
}
|
|
|
|
export interface AnswerResultDto {
|
|
answerState: 'correct' | 'wrong';
|
|
correctOptionId: string;
|
|
xpDelta: number;
|
|
progress: {
|
|
hearts: number;
|
|
dailyAttemptsLeft: number;
|
|
highRewardSessionsLeft: number;
|
|
highRewardSessionsMax: number;
|
|
xp: number;
|
|
streakDays: number;
|
|
};
|
|
knowledgeCard: {
|
|
id: string;
|
|
title: string;
|
|
summary: string;
|
|
fact: string;
|
|
};
|
|
rewards: ReadonlyArray<{
|
|
type: string;
|
|
source?: string;
|
|
amount?: number;
|
|
itemId?: string;
|
|
quantity?: number;
|
|
title?: string;
|
|
}>;
|
|
}
|
|
|
|
export interface LeaderboardEntryDto {
|
|
rank: number;
|
|
userId: string;
|
|
displayName: string;
|
|
avatarUrl: string | null;
|
|
xp: number;
|
|
badge: string;
|
|
isMe: boolean;
|
|
}
|