File size: 3,487 Bytes
e310cf5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | import { ApiError } from "@/types";
import type {
ConflictResponse,
Room,
Instructor,
Student,
Class,
ClassFormData,
} from "@/types";
const API_BASE_URL = "/api";
async function fetchJson<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${API_BASE_URL}${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
"Content-Type": "application/json",
...options.headers,
},
});
if (response.status === 204) {
return undefined as T;
}
const contentType = response.headers.get("content-type") || "";
const rawText = await response.text();
const trimmed = rawText.trim();
let data: unknown = undefined;
if (trimmed.length > 0) {
const looksJson =
contentType.includes("application/json") ||
trimmed.startsWith("{") ||
trimmed.startsWith("[");
if (looksJson) {
try {
data = JSON.parse(rawText);
} catch {
data = rawText;
}
} else {
data = rawText;
}
}
if (!response.ok) {
const asObj =
data && typeof data === "object"
? (data as Record<string, unknown>)
: null;
const detail = asObj?.detail;
if (response.status === 409 && detail && typeof detail === "object") {
const conflictData = detail as Record<string, unknown>;
const conflicts = conflictData.conflicts;
if (Array.isArray(conflicts)) {
throw new ApiError(
typeof conflictData.message === "string"
? conflictData.message
: "Scheduling conflict detected",
response.status,
conflicts as ConflictResponse["conflicts"]
);
}
}
let message = "An error occurred";
if (typeof data === "string" && data.trim().length > 0) {
message = data;
} else if (asObj) {
if (typeof detail === "string" && detail.trim().length > 0) {
message = detail;
} else if (
detail &&
typeof detail === "object" &&
typeof (detail as any).message === "string"
) {
message = (detail as any).message;
} else if (typeof asObj.message === "string") {
message = asObj.message;
} else if (detail != null) {
message = JSON.stringify(detail);
} else {
message = JSON.stringify(asObj);
}
}
throw new ApiError(message, response.status);
}
return data as T;
}
export async function getRooms(): Promise<Room[]> {
return fetchJson<Room[]>("/rooms");
}
export async function getInstructors(): Promise<Instructor[]> {
return fetchJson<Instructor[]>("/instructors");
}
export async function getStudents(): Promise<Student[]> {
return fetchJson<Student[]>("/students");
}
export async function getClasses(date: string): Promise<Class[]> {
return fetchJson<Class[]>(`/classes?date=${date}`);
}
export async function getClass(id: number): Promise<Class> {
return fetchJson<Class>(`/classes/${id}`);
}
export async function createClass(data: ClassFormData): Promise<Class> {
return fetchJson<Class>("/classes", {
method: "POST",
body: JSON.stringify(data),
});
}
export async function updateClass(
id: number,
data: ClassFormData
): Promise<Class> {
return fetchJson<Class>(`/classes/${id}`, {
method: "PUT",
body: JSON.stringify(data),
});
}
export async function deleteClass(id: number): Promise<void> {
return fetchJson<void>(`/classes/${id}`, {
method: "DELETE",
});
}
|