refactor: comprehensive codebase cleanup and architecture hardening
- Sprint 1 (Quick Wins): Remove dead analytics modules, fix 4 unresolved imports, replace 3 console.warn with logger, remove mock-crc import - Sprint 2 (Architecture): Create MascotChatRepository, AnalysisRepository, 3 Zod schemas (mascot-chat, analysis, voice), deduplicate error classes, move 3 SQL queries from routes to repository - Sprint 3 (Complexity): Replace 7 any types with proper interfaces, extract 6 helpers from prepareMediaMessage (CC 85 -> ~15) - Sprint 4 (Config): Remove 22 dead env vars from .env, add 30 missing vars to .env.example, standardize naming Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
d0d9e1669e
commit
4becf0d6f1
@@ -1,4 +1,4 @@
|
||||
import { Component, lazy, Suspense, useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { AuthOverlay } from "./features/auth";
|
||||
import { LivePanel } from "./features/live";
|
||||
import { useMediaControl } from "./features/live/hooks/useMediaControl";
|
||||
@@ -18,38 +18,10 @@ import {
|
||||
import { useAudioPlayback } from "./shared/hooks/useAudioPlayback";
|
||||
import { useAudioTransmit } from "./shared/hooks/useAudioTransmit";
|
||||
import { useUIState } from "./shared/hooks/useUIState";
|
||||
import { Skeleton } from "./shared/ui";
|
||||
import { MobileTabBar } from "./shared/ui/MobileTabBar";
|
||||
import { useDashboardSocket } from "./shared/ws/socket";
|
||||
import { DashboardLayout } from "./widgets/DashboardLayout";
|
||||
|
||||
const AnalyticsPanel = lazy(() =>
|
||||
import("./features/analytics").then((module) => ({
|
||||
default: module.AnalyticsPanel,
|
||||
})),
|
||||
);
|
||||
|
||||
class AnalyticsErrorBoundary extends Component<
|
||||
{ children: React.ReactNode },
|
||||
{ hasError: boolean }
|
||||
> {
|
||||
state = { hasError: false };
|
||||
static getDerivedStateFromError() {
|
||||
return { hasError: true };
|
||||
}
|
||||
override render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="rounded-2xl border border-destructive/30 bg-destructive/10 p-6 text-sm text-destructive">
|
||||
Analytics failed to load. The rest of the dashboard is still
|
||||
available.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const { uiState, patchUIState } = useUIState();
|
||||
const voice = useVoiceControl();
|
||||
@@ -76,7 +48,8 @@ export default function App() {
|
||||
);
|
||||
|
||||
const socket = useDashboardSocket({
|
||||
onVoicePcmData: (d) => audio.handleIncomingPcm(d as { userId: string; pcm: string }),
|
||||
onVoicePcmData: (d) =>
|
||||
audio.handleIncomingPcm(d as { userId: string; pcm: string }),
|
||||
onUserState: (users) => setActiveSpeakers(users as ActiveSpeaker[]),
|
||||
onMessageCreated: (m) =>
|
||||
messages.setMessages((prev) => mergeMessages(prev, [m as MessageRecord])),
|
||||
@@ -144,9 +117,7 @@ export default function App() {
|
||||
// Auto-fetch messages for the monitor guild
|
||||
useEffect(() => {
|
||||
if (monitorGuildId)
|
||||
messages
|
||||
.fetchMessages(monitorGuildId)
|
||||
.catch(() => undefined);
|
||||
messages.fetchMessages(monitorGuildId).catch(() => undefined);
|
||||
}, [monitorGuildId, messages.fetchMessages]);
|
||||
|
||||
// Periodic refetch — keeps dashboard in sync even if WS events missed
|
||||
@@ -166,7 +137,9 @@ export default function App() {
|
||||
onTabChange={(tab) => patchUIState({ activeTab: tab })}
|
||||
recentMessages={messages.messages}
|
||||
guildId={monitorGuildId}
|
||||
channelId={uiState.selectedTextChannel || uiState.selectedVoiceChannel || undefined}
|
||||
channelId={
|
||||
uiState.selectedTextChannel || uiState.selectedVoiceChannel || undefined
|
||||
}
|
||||
>
|
||||
{activeTab === "live" ? (
|
||||
!isAuthenticated ? (
|
||||
@@ -205,7 +178,7 @@ export default function App() {
|
||||
onVolumeChange={media.setVolume}
|
||||
/>
|
||||
)
|
||||
) : activeTab === "messages" ? (
|
||||
) : (
|
||||
<MessagesPanel
|
||||
guildName={monitorGuildName}
|
||||
messages={messages.messages}
|
||||
@@ -215,24 +188,6 @@ export default function App() {
|
||||
hasMore={messages.hasMore}
|
||||
loadingMore={messages.loadingMore}
|
||||
/>
|
||||
) : (
|
||||
<AnalyticsErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="flex flex-col gap-4">
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-16 w-full rounded-xl" />
|
||||
))}
|
||||
<Skeleton className="h-64 w-full rounded-xl" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<AnalyticsPanel
|
||||
guildId={monitorGuildId}
|
||||
guildName={monitorGuildName}
|
||||
/>
|
||||
</Suspense>
|
||||
</AnalyticsErrorBoundary>
|
||||
)}
|
||||
<MobileTabBar
|
||||
activeTab={activeTab}
|
||||
|
||||
Reference in New Issue
Block a user