Files
movieloop-frontend/src/api/versus.ts
T
2026-03-09 15:03:08 -07:00

154 lines
3.8 KiB
TypeScript

import apiClient from './client';
export interface VersusMatch {
id: string;
movieAId: number;
movieATitle?: string;
movieBId: number;
movieBTitle?: string;
difficulty: string;
status: string;
lobbyName: string | null;
hasPassword?: boolean;
winnerId: string | null;
player1: { id: string; username: string };
player2: { id: string; username: string } | null;
player1Score: object | null;
player2Score: object | null;
createdAt: string;
startedAt: string | null;
finishedAt: string | null;
isAsync?: boolean;
chainLength?: number | null;
expiresAt?: string | null;
attemptCount?: number;
}
export async function createMatch(
difficulty = 'medium',
lobbyName?: string,
password?: string,
isAsync?: boolean,
): Promise<VersusMatch> {
const { data } = await apiClient.post<VersusMatch>('/versus', {
difficulty,
lobbyName,
password,
isAsync,
});
return data;
}
export async function getWaitingMatches(
excludeUser?: string,
mode?: string,
): Promise<VersusMatch[]> {
const params: Record<string, string> = {};
if (excludeUser) params.excludeUser = excludeUser;
if (mode) params.mode = mode;
const { data } = await apiClient.get<VersusMatch[]>('/versus/waiting', { params });
return data;
}
export async function joinMatch(matchId: string, password?: string): Promise<VersusMatch> {
const { data } = await apiClient.post<VersusMatch>(`/versus/${matchId}/join`, {
password,
});
return data;
}
export async function cancelMatch(matchId: string): Promise<void> {
await apiClient.post(`/versus/${matchId}/cancel`);
}
export async function getMyWaitingMatches(): Promise<VersusMatch[]> {
const { data } = await apiClient.get<VersusMatch[]>('/versus/me/waiting');
return data;
}
export async function getMatch(matchId: string): Promise<VersusMatch> {
const { data } = await apiClient.get<VersusMatch>(`/versus/${matchId}`);
return data;
}
export async function getUserMatchHistory(page = 1, limit = 20) {
const { data } = await apiClient.get('/versus/me/history', {
params: { page, limit },
});
return data;
}
export async function submitCreatorScore(
matchId: string,
score: object,
chainLength: number,
): Promise<VersusMatch> {
const { data } = await apiClient.post<VersusMatch>(`/versus/${matchId}/creator-score`, {
score,
chainLength,
});
return data;
}
export interface AsyncAttemptResponse {
attempt: { id: string; matchId: string; playerId: string };
movieAId: number;
movieATitle: string;
movieBId: number;
movieBTitle: string;
chainLength: number | null;
}
export async function startAsyncAttempt(
matchId: string,
password?: string,
): Promise<AsyncAttemptResponse> {
const { data } = await apiClient.post<AsyncAttemptResponse>(
`/versus/${matchId}/async-attempt`,
{ password },
);
return data;
}
export async function submitAsyncAttempt(
matchId: string,
score: object,
chainLength: number,
) {
const { data } = await apiClient.post(`/versus/${matchId}/async-attempt/submit`, {
score,
chainLength,
});
return data;
}
export interface LeaderboardEntry {
playerId: string;
username: string;
score: { totalScore: number; [key: string]: unknown } | null;
chainLength: number | null;
isCreator: boolean;
rank: number;
}
export interface AsyncLeaderboardResponse {
match: {
id: string;
difficulty: string;
lobbyName: string | null;
expiresAt: string | null;
status: string;
movieATitle: string;
movieBTitle: string;
};
creator: { id: string; username: string };
leaderboard: LeaderboardEntry[];
}
export async function getAsyncLeaderboard(matchId: string): Promise<AsyncLeaderboardResponse> {
const { data } = await apiClient.get<AsyncLeaderboardResponse>(
`/versus/${matchId}/leaderboard`,
);
return data;
}