337 lines
7.6 KiB
TypeScript
337 lines
7.6 KiB
TypeScript
// API сервис для работы с бэкендом
|
|
|
|
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3001";
|
|
|
|
// ============ AUTH ============
|
|
|
|
export interface User {
|
|
id: string;
|
|
discordId: string;
|
|
username: string;
|
|
email: string;
|
|
avatar: string | null;
|
|
}
|
|
|
|
export function getDiscordLoginUrl(): string {
|
|
return `${API_URL}/auth/discord`;
|
|
}
|
|
|
|
export async function getCurrentUser(): Promise<User | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/auth/me`, {
|
|
credentials: "include",
|
|
});
|
|
const data = await response.json();
|
|
return data.user;
|
|
} catch (error) {
|
|
console.error("Failed to get current user:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function logout(): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/auth/logout`, {
|
|
method: "POST",
|
|
credentials: "include",
|
|
});
|
|
return response.ok;
|
|
} catch (error) {
|
|
console.error("Failed to logout:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function getDiscordAvatarUrl(user: User): string {
|
|
if (user.avatar) {
|
|
return `https://cdn.discordapp.com/avatars/${user.discordId}/${user.avatar}.png`;
|
|
}
|
|
// Default Discord avatar
|
|
const defaultAvatarIndex = parseInt(user.discordId) % 5;
|
|
return `https://cdn.discordapp.com/embed/avatars/${defaultAvatarIndex}.png`;
|
|
}
|
|
|
|
// ============ STORIES ============
|
|
|
|
import type { Story } from "../types";
|
|
|
|
export async function getStories(): Promise<Story[]> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/stories`, {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (response.status === 401) {
|
|
return [];
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Failed to fetch stories");
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error("Failed to get stories:", error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function getStory(id: string): Promise<Story | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/stories/${id}`, {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return null;
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error("Failed to get story:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function createStory(
|
|
story: Omit<Story, "id" | "createdAt" | "updatedAt">,
|
|
): Promise<Story | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/stories`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
credentials: "include",
|
|
body: JSON.stringify(story),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Failed to create story");
|
|
}
|
|
|
|
const data = await response.json();
|
|
return { ...data, id: data._id };
|
|
} catch (error) {
|
|
console.error("Failed to create story:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function updateStory(
|
|
id: string,
|
|
story: Partial<Story>,
|
|
): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/stories/${id}`, {
|
|
method: "PUT",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
credentials: "include",
|
|
body: JSON.stringify(story),
|
|
});
|
|
|
|
return response.ok;
|
|
} catch (error) {
|
|
console.error("Failed to update story:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function deleteStory(id: string): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/stories/${id}`, {
|
|
method: "DELETE",
|
|
credentials: "include",
|
|
});
|
|
|
|
return response.ok;
|
|
} catch (error) {
|
|
console.error("Failed to delete story:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ============ GAME SESSIONS ============
|
|
|
|
import type { GameSession } from "../types";
|
|
|
|
export async function getSession(storyId: string): Promise<GameSession | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/sessions/${storyId}`, {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return null;
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error("Failed to get session:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function saveSession(
|
|
storyId: string,
|
|
session: Omit<GameSession, "storyId">,
|
|
): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/sessions/${storyId}`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
credentials: "include",
|
|
body: JSON.stringify(session),
|
|
});
|
|
|
|
return response.ok;
|
|
} catch (error) {
|
|
console.error("Failed to save session:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ============ PLAYER CHARACTERS ============
|
|
|
|
import type { PlayerCharacter } from "../types";
|
|
|
|
export async function getPlayerCharacters(): Promise<PlayerCharacter[]> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/characters`, {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (response.status === 401) {
|
|
return [];
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Failed to fetch characters");
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data.map((c: any) => ({ ...c, id: c._id || c.id }));
|
|
} catch (error) {
|
|
console.error("Failed to get characters:", error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function getPlayerCharacter(
|
|
id: string,
|
|
): Promise<PlayerCharacter | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/characters/${id}`, {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return null;
|
|
}
|
|
|
|
const data = await response.json();
|
|
return { ...data, id: data._id || data.id };
|
|
} catch (error) {
|
|
console.error("Failed to get character:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function createPlayerCharacter(
|
|
character: Omit<PlayerCharacter, "id" | "userId" | "createdAt" | "updatedAt">,
|
|
): Promise<PlayerCharacter | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/characters`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
credentials: "include",
|
|
body: JSON.stringify(character),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Failed to create character");
|
|
}
|
|
|
|
const data = await response.json();
|
|
return { ...data, id: data._id };
|
|
} catch (error) {
|
|
console.error("Failed to create character:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function updatePlayerCharacter(
|
|
id: string,
|
|
character: Partial<PlayerCharacter>,
|
|
): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/characters/${id}`, {
|
|
method: "PUT",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
credentials: "include",
|
|
body: JSON.stringify(character),
|
|
});
|
|
|
|
return response.ok;
|
|
} catch (error) {
|
|
console.error("Failed to update character:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function deletePlayerCharacter(id: string): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/characters/${id}`, {
|
|
method: "DELETE",
|
|
credentials: "include",
|
|
});
|
|
|
|
return response.ok;
|
|
} catch (error) {
|
|
console.error("Failed to delete character:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ============ ADMIN STATS ============
|
|
|
|
interface StoryStats {
|
|
id: string;
|
|
title: string;
|
|
messageCount: number;
|
|
tokens: number;
|
|
lastPlayed: string | null;
|
|
}
|
|
|
|
interface AdminStats {
|
|
totalStories: number;
|
|
totalSessions: number;
|
|
totalTokens: number;
|
|
stories: StoryStats[];
|
|
}
|
|
|
|
export async function getAdminStats(): Promise<AdminStats | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/admin/stats`, {
|
|
credentials: "include",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return null;
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error("Failed to get admin stats:", error);
|
|
return null;
|
|
}
|
|
}
|