diff --git a/services/frontend/src/app/(dashboard)/media/view.tsx b/services/frontend/src/app/(dashboard)/media/view.tsx
index e1fc536..c95f090 100644
--- a/services/frontend/src/app/(dashboard)/media/view.tsx
+++ b/services/frontend/src/app/(dashboard)/media/view.tsx
@@ -1,30 +1,23 @@
"use client";
-import {
- Pause,
- Play,
- Repeat2,
- SkipForward,
- Square,
- Volume2,
-} from "lucide-react";
+import { Pause, Play, Repeat2, SkipForward, Square, Volume2 } from "lucide-react";
import { motion } from "motion/react";
-import { useEffect } from "react";
+import { useState } from "react";
import { Waveform } from "@/components/charts/waveform";
import { StaggerGroup, StaggerItem } from "@/components/motion/stagger";
-import { Avatar } from "@/components/primitives/avatar";
import { Badge } from "@/components/primitives/badge";
import { Button } from "@/components/primitives/button";
+import { Input } from "@/components/primitives/input";
import { Progress } from "@/components/primitives/progress";
import {
useMediaLoop,
+ useMediaQueue,
useMediaSkip,
useMediaState,
useMediaStop,
useMediaWsSync,
} from "@/hooks";
import type { MediaState } from "@/lib/types";
-import { cn } from "@/lib/utils";
import { useWebSocket } from "@/lib/ws/context";
export default function MediaView({
@@ -33,7 +26,8 @@ export default function MediaView({
initialStatus?: MediaState;
}) {
const ws = useWebSocket();
- const { data: state, mutate } = useMediaState(initialStatus);
+ const { data: state } = useMediaState(initialStatus);
+ const queueMut = useMediaQueue();
const skip = useMediaSkip();
const stop = useMediaStop();
const loopMut = useMediaLoop();
@@ -45,23 +39,55 @@ export default function MediaView({
const loop = state?.loop ?? false;
const duration = current?.durationMs ?? 0;
- const [seed] = useWaveformSeed();
+ const [queueUrl, setQueueUrl] = useState("");
+ const [screenMode, setScreenMode] = useState(false);
+
+ const handleQueue = () => {
+ if (!queueUrl.trim()) return;
+ queueMut.mutate({ url: queueUrl.trim(), mode: screenMode ? "screen" : "music" });
+ setQueueUrl("");
+ };
return (
+ {/* URL queue input */}
+
+
setQueueUrl(e.target.value)}
+ onKeyDown={(e) => e.key === "Enter" && handleQueue()}
+ className="flex-1 h-9"
+ />
+
+
+
+
{/* Turntable hero */}
{current && (
@@ -97,11 +123,7 @@ export default function MediaView({
variant="primary"
onClick={() => loopMut.mutate(!loop)}
>
- {playing ? (
-
- ) : (
-
- )}
+ {playing ? : }
@@ -131,9 +153,9 @@ export default function MediaView({
{loop ? "loop" : "queue"}
- {queue.map((item, i) => (
+ {queue.map((item) => (
("stage");
+ const [selectedGuild, setSelectedGuild] = useState("");
+ const [selectedChannel, setSelectedChannel] = useState("");
const initialSpeakers = useMemo(
() => initialStatus?.activeSpeakers ?? [],
[initialStatus],
);
const { speakers, subscribe } = useSpeakers(initialSpeakers);
+ const { data: guilds = [] } = useGuilds();
+ const { data: voiceChannels = [] } = useVoiceChannels(selectedGuild);
const connect = useVoiceConnect();
const disconnect = useVoiceDisconnect();
const listen = useVoiceListen(ws);
@@ -57,45 +47,101 @@ export default function VoiceView({
}, [subscribe, ws]);
const active = speakers.filter((s) => s.speaking);
+ const connected = initialStatus?.connected ?? false;
+
+ const handleGuildChange = (e: React.ChangeEvent) => {
+ const g = e.target.value;
+ setSelectedGuild(g);
+ setSelectedChannel("");
+ };
return (
- {/* Connection bar */}
-
-
- {initialStatus?.connected ? "Connected" : "Disconnected"}
-
- {initialStatus?.activeChannelName && (
-
- #{initialStatus.activeChannelName}
-
- )}
- {initialStatus?.connected ? (
-
+ {/* Connection bar with guild + voice channel pickers */}
+
+
+
+ {connected ? "Connected" : "Disconnected"}
+
+ {connected && initialStatus?.activeChannelName && (
+
+
+ {initialStatus.activeChannelName}
+
+ )}
+
+
+ {!connected ? (
+
+
+
+
+
+
+
) : (
)}
{/* Stage hero */}
-
+
- {/* Tabs */}
-
- {(["stage", "activity"] as const).map((t) => (
-
- ))}
+ {/* Activity timeline */}
+
+
+ Live session timeline
+
+ ({
+ id: s.userId,
+ label: s.username,
+ value: s.speaking ? 3 : 1,
+ tone: s.speaking ? "signal" : "neutral",
+ }))}
+ />
- {tab === "stage" &&
}
- {tab === "activity" && (
-
-
Live session timeline
- ({
- id: s.userId,
- label: s.username,
- value: s.speaking ? 3 : 1,
- tone: s.speaking ? "signal" : "neutral",
- }))}
- />
-
- )}
+
);
}