feat: update dependencies and improve dashboard functionality
Deploy to VPS / deploy (push) Failing after 1m43s

- Added new dependencies for Next.js and lucide-react in pnpm-workspace.yaml.
- Refactored DashboardPage component to improve readability and error handling.
- Enhanced Header component to display error status with an alert icon.
- Updated MobileTabBar and Sidebar components to use a centralized tabs definition.
- Improved ChannelsView in dashboard-panel to handle channel fetching more cleanly.
- Fixed ActiveSpeaker type to use camelCase for userId.
- Updated MessagesPanel to handle guildId checks more gracefully.
- Adjusted API calls in dashboard and messages to align with backend expectations.
- Refined type definitions across various interfaces for consistency and clarity.
This commit is contained in:
asepharyana
2026-07-26 14:27:36 +07:00
parent 9ecc4a6caa
commit 0a6a9fd982
62 changed files with 2764 additions and 305 deletions
@@ -26,6 +26,7 @@ export const dashboardApi = {
const params = new URLSearchParams();
if (limit) params.set("limit", String(limit));
if (search) params.set("search", search);
// Backend reads req.query.guild_id (snake_case) — see createDashboardRouter in dashboard.routes.ts
if (guildId) params.set("guild_id", guildId);
const qs = params.toString();
return api.get<PaginatedChannels>(
@@ -8,6 +8,7 @@ export const messagesApi = {
channelId?: string,
cursor?: string,
) => {
// Backend messageQuerySchema expects camelCase guildId (see messages.schema.ts)
const params = new URLSearchParams({ guildId });
if (limit) params.set("limit", String(limit));
if (channelId) params.set("channelId", channelId);
@@ -31,6 +32,7 @@ export const messagesApi = {
api.get<MessageRecord>(`/api/messages/detail/${id}`),
getImages: (guildId: string, limit?: number) => {
// Backend reads req.query.guildId (camelCase) — see handleGetImageMessages in messages.controller.ts
const params = new URLSearchParams({ guildId });
if (limit) params.set("limit", String(limit));
return api.get<{ data: MessageRecord[]; nextCursor: string | null }>(
+9
View File
@@ -0,0 +1,9 @@
import { LayoutDashboard, MessageSquare, Radio } from "lucide-react";
export const tabs = [
{ id: "messages", label: "Messages", icon: MessageSquare },
{ id: "live", label: "Live", icon: Radio },
{ id: "dashboard", label: "Dashboard", icon: LayoutDashboard },
] as const;
export type TabId = (typeof tabs)[number]["id"];
+3 -3
View File
@@ -37,13 +37,13 @@ export interface DashboardUser {
flagged_count: number;
last_message_at?: number | null;
trust_score?: number | null;
clean_message_streak?: number;
clean_message_streak?: number | null;
}
export interface DashboardUserDetail extends DashboardUser {
last_analyzed_at?: number | null;
clean_message_streak: number;
total_infractions: number;
clean_message_streak: number | null;
total_infractions: number | null;
clean_count: number;
recent_messages: MessageRecord[];
}
+2 -3
View File
@@ -1,14 +1,13 @@
export interface Guild {
id: string;
name: string;
icon?: string | null;
icon: string | null;
}
export interface Channel {
id: string;
name: string;
type?: string | null; // "voice" | "text"
parent_id?: string | null;
type: "voice" | "text";
}
/** Shape of the /api/config response (camelCase keys from backend). */
+2 -2
View File
@@ -3,7 +3,7 @@ export type MediaMode = "music" | "screen";
export interface MediaItem {
id?: string | null;
source: string;
title?: string | null;
title: string;
mode?: MediaMode | null;
durationMs?: number | null;
thumbnailUrl?: string | null;
@@ -12,6 +12,6 @@ export interface MediaItem {
export interface MediaState {
playing: boolean;
musicVolume: number;
current?: MediaItem | null;
current: MediaItem | null;
queue: MediaItem[];
}
+3 -1
View File
@@ -82,12 +82,14 @@ export interface MessageRecord {
channel_id: string;
thread_id?: string | null;
reference_message_id?: string | null;
reference_channel_id?: string | null;
reference_guild_id?: string | null;
user_id: string;
username: string;
avatar_url?: string | null;
content: string;
edited_content?: string | null;
type: string; // "text" | "edited" | "deleted"
type: "text" | "edited" | "deleted";
is_reply?: boolean | null;
is_forward?: boolean | null;
is_crosspost?: boolean | null;
+1 -1
View File
@@ -8,10 +8,10 @@ export interface VoiceRecording {
channel_name?: string | null;
filename: string;
size_bytes: number;
duration_bytes: number;
download_url?: string | null;
upload_status: string;
upload_error?: string | null;
transcription?: string | null;
created_at: number;
uploaded_at?: number | null;
}
+1 -2
View File
@@ -14,8 +14,7 @@ export interface VoiceStatus {
}
export interface ActiveSpeaker {
id?: string | null;
user_id: string;
userId: string;
username: string;
avatar?: string | null;
speaking: boolean;
+2 -1
View File
@@ -36,7 +36,8 @@ export interface WsEventMap {
voice_recording_stopped: unknown;
voice_recording_uploaded: VoiceRecording;
voice_active_user: ActiveSpeaker;
voice_pcm_data: { userId: string; pcm: string };
/** NOT delivered as JSON — arrives only via onPcm() binary handler as PcmChunk */
voice_pcm_data: never;
voice_analyzed: unknown;
analysis_queue_status: unknown;
reaction_added: unknown;