muitas melhorias pra descrever

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-11 12:54:25 -03:00
1 parent 89b08a19ef
commit c8fba4d240
21 files changed
+971 -17

No files matched your search

+71
View File
@@ -32,6 +32,39 @@ export interface QuizCard {
dueAt: string;
}
export interface PageVisit {
id: string;
path: string;
system: string | null;
ip: string;
port: number | null;
country: string | null;
city: string | null;
userAgent: string | null;
createdAt: string;
}
export interface FeedbackEntry {
id: string;
message: string;
email: string | null;
rating: number | null;
page: string | null;
ip: string | null;
createdAt: string;
}
export interface AdminStats {
onlineNow: number;
totalVisits: number;
visitsLast24h: number;
visitsLast7d: number;
visitsBySystem: { system: string | null; count: number }[];
visitsByCountry: { country: string; count: number }[];
recentVisits: PageVisit[];
feedback: FeedbackEntry[];
}
const BASE = "/api";
async function getJson<T>(url: string): Promise<T> {
@@ -40,6 +73,22 @@ async function getJson<T>(url: string): Promise<T> {
return res.json() as Promise<T>;
}
async function postJson<T>(url: string, body: unknown, token?: string): Promise<T> {
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify(body),
});
if (!res.ok) {
const data = await res.json().catch(() => null);
throw new Error(data?.error ?? `POST ${url} failed: ${res.status}`);
}
return res.json() as Promise<T>;
}
export const api = {
systems: () => getJson<AnatomicalSystem[]>(`${BASE}/systems`),
@@ -72,6 +121,28 @@ export const api = {
if (!res.ok) throw new Error(`quizReview failed: ${res.status}`);
return res.json();
},
onlineCount: () => getJson<{ count: number }>(`${BASE}/analytics/online-count`),
trackVisit: (path: string, system?: string) =>
postJson<{ ok: true }>(`${BASE}/analytics/visit`, { path, system }).catch(() => {}),
heartbeat: (sessionId: string) =>
postJson<{ ok: true }>(`${BASE}/analytics/heartbeat`, { sessionId }).catch(() => {}),
sendFeedback: (data: { message: string; email?: string; rating?: number; page?: string }) =>
postJson<{ ok: true }>(`${BASE}/feedback`, data),
adminLogin: (email: string, password: string) =>
postJson<{ token: string }>(`${BASE}/admin/login`, { email, password }),
adminStats: async (token: string): Promise<AdminStats> => {
const res = await fetch(`${BASE}/admin/stats`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error(`GET admin/stats failed: ${res.status}`);
return res.json();
},
};
export function modelUrl(modelFile: string): string {