97 lines
2.5 KiB
TypeScript
97 lines
2.5 KiB
TypeScript
|
|
/**
|
|||
|
|
* Streak Service - API calls for user streak management
|
|||
|
|
* 连续记账功能服务
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import api from './api';
|
|||
|
|
import type { ApiResponse } from '../types';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Streak info returned from backend
|
|||
|
|
*/
|
|||
|
|
export interface StreakInfo {
|
|||
|
|
current_streak: number; // 当前连续天数
|
|||
|
|
longest_streak: number; // 最长连续记录
|
|||
|
|
total_record_days: number; // 累计记账天数
|
|||
|
|
has_record_today: boolean; // 今天是否已记账
|
|||
|
|
message: string; // 提示信息
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Daily contribution data
|
|||
|
|
*/
|
|||
|
|
export interface DailyContribution {
|
|||
|
|
date: string;
|
|||
|
|
count: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Streak info in camelCase for frontend
|
|||
|
|
*/
|
|||
|
|
export interface StreakInfoFormatted {
|
|||
|
|
currentStreak: number;
|
|||
|
|
longestStreak: number;
|
|||
|
|
totalRecordDays: number;
|
|||
|
|
hasRecordToday: boolean;
|
|||
|
|
message: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Map streak data from API (snake_case) to frontend (camelCase)
|
|||
|
|
*/
|
|||
|
|
function mapStreakFromApi(data: StreakInfo): StreakInfoFormatted {
|
|||
|
|
return {
|
|||
|
|
currentStreak: data.current_streak,
|
|||
|
|
longestStreak: data.longest_streak,
|
|||
|
|
totalRecordDays: data.total_record_days,
|
|||
|
|
hasRecordToday: data.has_record_today,
|
|||
|
|
message: data.message,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Get current user's streak info
|
|||
|
|
* 获取当前用户的连续记账信息
|
|||
|
|
*/
|
|||
|
|
export async function getStreakInfo(): Promise<StreakInfoFormatted> {
|
|||
|
|
const response = await api.get<ApiResponse<StreakInfo>>('/user/streak');
|
|||
|
|
if (!response.data) {
|
|||
|
|
// Return default values if no streak data
|
|||
|
|
return {
|
|||
|
|
currentStreak: 0,
|
|||
|
|
longestStreak: 0,
|
|||
|
|
totalRecordDays: 0,
|
|||
|
|
hasRecordToday: false,
|
|||
|
|
message: '开始记录你的第一笔账吧!',
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return mapStreakFromApi(response.data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Recalculate streak from transaction history
|
|||
|
|
* 重新计算连续记账天数(基于交易历史)
|
|||
|
|
*/
|
|||
|
|
export async function recalculateStreak(): Promise<StreakInfoFormatted> {
|
|||
|
|
const response = await api.post<ApiResponse<StreakInfo>>('/user/streak/recalculate');
|
|||
|
|
if (!response.data) {
|
|||
|
|
throw new Error(response.error || 'Failed to recalculate streak');
|
|||
|
|
}
|
|||
|
|
return mapStreakFromApi(response.data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Get daily contribution data for heatmap
|
|||
|
|
* 获取热力图数据
|
|||
|
|
*/
|
|||
|
|
export async function getContributionData(): Promise<DailyContribution[]> {
|
|||
|
|
const response = await api.get<ApiResponse<DailyContribution[]>>('/user/streak/contribution');
|
|||
|
|
return response.data || [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
getStreakInfo,
|
|||
|
|
recalculateStreak,
|
|||
|
|
getContributionData,
|
|||
|
|
};
|