+ АРМ курсанта — проверка звука
+
+
+ | Занятие | {sessionId} |
+ | Канал | {STATUS_LABEL[status]} |
+ | Микрофон | {micRate ? `включён, ${micRate} Гц → 16000 Гц` : "выключен"} |
+ | Кадров отправлено | {framesSent} ({(framesSent * 0.02).toFixed(1)} с звука) |
+
+
+
+
+
+ {error && Ошибка микрофона: {error}
}
+ События сервера
+
+
+ {events.map((event, index) => (
+ | {event.type} | {JSON.stringify(event).slice(0, 140)} |
+ ))}
+
+
+
+ );
+}
diff --git a/frontend/src/shared/api/http.ts b/frontend/src/shared/api/http.ts
new file mode 100644
index 0000000..dc43342
--- /dev/null
+++ b/frontend/src/shared/api/http.ts
@@ -0,0 +1,66 @@
+// HTTP-клиент и хуки. Типы ответов HTTP в generated.ts пока не попадают —
+// там только события WS; здесь описаны руками по docs/arch/CONTRACT.md#http-api.
+
+import { useMutation, useQuery } from "@tanstack/react-query";
+
+import type { Level, SessionMode } from "@/shared/types/generated";
+
+export class ApiError extends Error {
+ constructor(
+ readonly status: number,
+ readonly code: string,
+ ) {
+ super(`${status} ${code}`);
+ }
+}
+
+async function request