Files
edbridge-scholars/src/utils/api.ts
shafin-r 121cc2bf71 feat(quests): improve 3d island styling
fix(test): fix context image not appearing on test screen
2026-03-12 01:09:07 +06:00

285 lines
7.1 KiB
TypeScript

import type { Leaderboard, PredictedScore } from "../types/leaderboard";
import type { Lesson, LessonsResponse } from "../types/lesson";
import type {
ClaimedRewardResponse,
QuestArc,
UserInventory,
UserTitle,
} from "../types/quest";
import type {
SessionAnswerResponse,
SessionQuestionsResponse,
SessionRequest,
SessionResponse,
SubmitAnswer,
} from "../types/session";
import type { PracticeSheet } from "../types/sheet";
import type { Topic } from "../types/topic";
const API_URL = "https://ed-dev-api.omukk.dev";
export interface LoginRequest {
email: string;
password: string;
}
export interface RegistrationRequest {
email: string;
name: string;
avatar_url: string;
password: string;
}
export interface User {
email: string;
name: string;
role: "STUDENT" | "TEACHER" | "ADMIN";
avatar_url: string;
id: string;
status: "ACTIVE" | "INACTIVE";
joined_at: string;
last_active: string;
total_xp: number;
current_level: number;
next_level_threshold: number;
current_level_start: number;
}
export interface LoginResponse {
token: string;
token_type: string;
user: User;
}
export interface ApiError {
detail?: string;
message?: string;
}
class ApiClient {
private baseURL: string;
constructor(baseURL: string) {
this.baseURL = baseURL;
}
private async request<T>(
endpoint: string,
options: RequestInit = {},
): Promise<T> {
const url = `${this.baseURL}${endpoint}`;
const config: RequestInit = {
...options,
headers: {
"Content-Type": "application/json",
...options.headers,
},
};
try {
const response = await fetch(url, config);
if (!response.ok) {
const error: ApiError = await response.json().catch(() => ({
message: "An error occurred",
}));
throw new Error(error.detail || error.message || "Request failed");
}
return await response.json();
} catch (error) {
if (error instanceof Error) {
throw error;
}
throw new Error("Network error occurred");
}
}
// Auth endpoints
async login(credentials: LoginRequest): Promise<LoginResponse> {
return this.request<LoginResponse>("/auth/login/", {
method: "POST",
body: JSON.stringify(credentials),
});
}
async register(
credentials: RegistrationRequest,
): Promise<{ message: string }> {
return this.request<{ message: string }>("/auth/register/", {
method: "POST",
body: JSON.stringify(credentials),
});
}
// Authenticated request helper
async authenticatedRequest<T>(
endpoint: string,
token: string,
options: RequestInit = {},
): Promise<T> {
return this.request<T>(endpoint, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`,
},
});
}
// Example: Get user profile (authenticated endpoint)
async getUserProfile(token: string): Promise<User> {
return this.authenticatedRequest<User>("/auth/me/", token);
}
async getPracticeSheets(
token: string,
page: number,
limit: number,
): Promise<any> {
const queryParams = new URLSearchParams({
page: page.toString(),
limit: limit.toString(),
}).toString();
return this.authenticatedRequest<any>(
`/practice-sheets/?${queryParams}`,
token,
);
}
async getPracticeSheetById(
token: string,
sheetId: string,
): Promise<PracticeSheet> {
return this.authenticatedRequest<PracticeSheet>(
`/practice-sheets/${sheetId}`,
token,
);
}
async startSession(
token: string,
sessionData: SessionRequest,
): Promise<SessionResponse> {
return this.authenticatedRequest<SessionResponse>(`/sessions/`, token, {
method: "POST",
body: JSON.stringify(sessionData),
});
}
async fetchSessionQuestions(
token: string,
sessionId: string,
): Promise<SessionQuestionsResponse> {
return this.authenticatedRequest<SessionQuestionsResponse>(
`/sessions/${sessionId}/questions/`,
token,
);
}
async submitAnswer(
token: string,
sessionId: string,
answerSubmissionData: SubmitAnswer,
): Promise<SessionAnswerResponse> {
return this.authenticatedRequest<SessionAnswerResponse>(
`/sessions/${sessionId}/answer/`,
token,
{
method: "POST",
body: JSON.stringify(answerSubmissionData),
},
);
}
async fetchNextModule(token: string, sessionId: string): Promise<any> {
return this.authenticatedRequest<any>(
`/sessions/${sessionId}/next-module/`,
token,
{
method: "POST",
},
);
}
async fetchSessionStateById(
token: string,
sessionId: string,
): Promise<SessionResponse> {
return this.authenticatedRequest<SessionResponse>(
`/sessions/${sessionId}`,
token,
);
}
async fetchLessonVideos(token: string): Promise<LessonsResponse> {
return this.authenticatedRequest<LessonsResponse>(`/lessons/`, token);
}
async fetchLessonById(token: string, lessonId: string): Promise<Lesson> {
return this.authenticatedRequest<Lesson>(`/lessons/${lessonId}`, token);
}
async fetchAllTopics(token: string): Promise<Topic[]> {
return this.authenticatedRequest<Topic[]>(`/topics/`, token);
}
async fetchTopicById(token: string, topicId: string): Promise<Topic> {
return this.authenticatedRequest<Topic>(`/topics/${topicId}`, token);
}
async fetchLeaderboard(
token: string,
metric: string,
timeframe: string,
): Promise<Leaderboard> {
return this.authenticatedRequest<Leaderboard>(
`/leaderboard/?metric=${metric}&timeframe=${timeframe}`,
token,
);
}
async fetchPredictedScore(token: string): Promise<PredictedScore> {
return this.authenticatedRequest<PredictedScore>(`/prediction/`, token);
}
/*------------QUEST JOURNEY-------------- */
async fetchUserJourney(token: string): Promise<QuestArc[]> {
return this.authenticatedRequest<QuestArc[]>(`/journey/`, token);
}
async claimReward(
token: string,
node_id: string,
): Promise<ClaimedRewardResponse> {
return this.authenticatedRequest<ClaimedRewardResponse>(
`/journey/claim/${node_id}`,
token,
{
method: "POST",
},
);
}
/*------------INVENTORY-------------- */
async fetchUserInventory(token: string): Promise<UserInventory> {
return this.authenticatedRequest<UserInventory>(`/inventory/`, token);
}
async activateItem(token: string, itemId: string): Promise<UserInventory> {
return this.authenticatedRequest<UserInventory>(
`/inventory/use/${itemId}`,
token,
);
}
/*------------TITLES-------------- */
async fetchUserTitles(token: string): Promise<UserTitle[]> {
return this.authenticatedRequest<UserTitle[]>(`/inventory/titles/`, token);
}
async equipTitle(
token: string,
titleData: { title_id: string },
): Promise<string> {
return this.authenticatedRequest<string>(`/inventory/titles/equip`, token, {
method: "POST",
body: JSON.stringify(titleData),
});
}
}
export const api = new ApiClient(API_URL);