Files
GMW/services/frontend/src/shared/ws/events.ts
T
MythEclipse 41e67423b8 chore(services): update components based on recent changes
Changes:
 services/frontend/src/features/dashboard/components/ChannelProfileDetail.tsx | 258 +++++++++++-----------------------------------------------------------------
 services/frontend/src/features/dashboard/components/ChannelSummaryList.tsx   | 171 ++++++++-------------------------------------------
 services/frontend/src/features/dashboard/components/DashboardStats.tsx       |   8 ++-
 services/frontend/src/features/dashboard/components/UserProfileDetail.tsx    | 297 +++++++++++++---------------------------------------------------------------------------
 services/frontend/src/features/dashboard/components/UserSummaryList.tsx      | 204 +++++++++++-------------------------------------------------
 services/frontend/src/features/dashboard/hooks/useDashboard.ts               | 203 +++++++++++++++---------------------------------------------
 services/frontend/src/features/messages/components/MessageCard.tsx           |  10 +--
 services/frontend/src/shared/api/client.ts                                   |  87 +++++++++++++++++++-------
 services/frontend/src/shared/hooks/useItemDetail.ts                          |  58 +++++++++++++++++
 services/frontend/src/shared/hooks/usePaginatedList.ts                       | 105 +++++++++++++++++++++++++++++++
2026-06-14 15:16:18 +07:00

78 lines
2.7 KiB
TypeScript

// ─── Typed event map for WebSocket events ────────────────────────────────────
//
// Types correspond to the data field sent by the backend's broadcastEvent().
// The backend unwraps the DiscordGatewayEvent envelope and forwards only
// the inner `data` field to frontend WebSocket clients.
import type {
AnalysisQueueStatus,
AttachmentRecord,
MessageRecord,
VoiceRecordingUploadData,
} from "@bete/shared";
export interface ActiveSpeakerData {
userId: string;
username: string;
avatar: string;
speaking: boolean;
}
export interface WsEventMap {
message_created: { data: MessageRecord };
message_updated: { data: MessageRecord & { edited_content?: string | null } };
message_deleted: {
data: { id: string; channel_id?: string; deleted_at: number };
};
message_analyzed: { data: MessageRecord };
attachment_created: { data: AttachmentRecord };
attachment_uploaded: { data: AttachmentRecord };
voice_recording_started: { data: Record<string, unknown> };
voice_recording_stopped: {
data: {
guild_id: string;
session_id: string;
duration_ms: number;
participants: number;
segment_count: number;
status: string;
stopped_at: number;
};
};
voice_recording_uploaded: { data: VoiceRecordingUploadData };
voice_pcm_data: {
data: { userId: string; pcm: string; metadata?: Record<string, unknown> };
};
voice_analyzed: { data: Record<string, unknown> };
voice_active_user: { data: ActiveSpeakerData };
user_state: { users: unknown[] };
ui_state: { state: Record<string, unknown> };
media_state: { state: Record<string, unknown> };
analysis_queue_status: { data: AnalysisQueueStatus };
reaction_added: { data: Record<string, unknown> };
reaction_removed: { data: Record<string, unknown> };
thread_created: { data: Record<string, unknown> };
thread_deleted: { data: Record<string, unknown> };
thread_updated: { data: Record<string, unknown> };
channel_topic_updated: { data: Record<string, unknown> };
presence_updated: { data: Record<string, unknown> };
guild_member_added: { data: Record<string, unknown> };
guild_member_removed: { data: Record<string, unknown> };
heartbeat: { data?: { timestamp: number } };
}
export type WsEventType = keyof WsEventMap;
export function parseWsMessage(
raw: string,
): { type: WsEventType; payload: Record<string, unknown> } | null {
try {
const parsed = JSON.parse(raw);
if (!parsed.type || typeof parsed.type !== "string") return null;
const { type, ...rest } = parsed;
return { type: type as WsEventType, payload: rest };
} catch {
return null;
}
}