2026-07-26 16:55:20 +07:00
|
|
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
2026-07-27 21:54:31 +07:00
|
|
|
import { useCallback, useState } from "react";
|
2026-07-26 16:14:32 +07:00
|
|
|
|
|
|
|
|
import { voiceApi } from "@/lib/api";
|
2026-07-27 21:54:31 +07:00
|
|
|
import type { ActiveSpeaker, Channel, VoiceStatus } from "@/lib/types";
|
|
|
|
|
import type { WsHook } from "@/lib/ws-hook";
|
2026-07-26 16:14:32 +07:00
|
|
|
|
2026-07-26 16:55:20 +07:00
|
|
|
export function useVoiceStatus() {
|
|
|
|
|
return useQuery<VoiceStatus>({
|
|
|
|
|
queryKey: ["voice-status"],
|
|
|
|
|
queryFn: () => voiceApi.getStatus(),
|
|
|
|
|
retry: false,
|
|
|
|
|
});
|
2026-07-26 16:14:32 +07:00
|
|
|
}
|
|
|
|
|
|
2026-07-27 21:54:31 +07:00
|
|
|
export function useVoiceChannels(guildId: string) {
|
|
|
|
|
return useQuery<Channel[]>({
|
|
|
|
|
queryKey: ["voice-channels", guildId],
|
|
|
|
|
queryFn: () => voiceApi.getVoiceChannels(guildId),
|
|
|
|
|
enabled: !!guildId,
|
|
|
|
|
});
|
2026-07-26 16:14:32 +07:00
|
|
|
}
|
|
|
|
|
|
2026-07-26 16:55:20 +07:00
|
|
|
export function useSpeakers() {
|
2026-07-26 16:14:32 +07:00
|
|
|
const [speakers, setSpeakers] = useState<ActiveSpeaker[]>([]);
|
|
|
|
|
|
|
|
|
|
const subscribe = useCallback((ws: WsHook) => {
|
|
|
|
|
const unsub = ws.on("voice_active_user", (data) => {
|
|
|
|
|
const speaker = data as ActiveSpeaker;
|
|
|
|
|
setSpeakers((prev) => {
|
|
|
|
|
const idx = prev.findIndex((s) => s.userId === speaker.userId);
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
const next = [...prev];
|
|
|
|
|
next[idx] = speaker;
|
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
return [...prev, speaker];
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return () => {
|
|
|
|
|
unsub();
|
|
|
|
|
setSpeakers([]);
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return { speakers, subscribe };
|
|
|
|
|
}
|
2026-07-26 16:55:20 +07:00
|
|
|
|
|
|
|
|
export function useVoiceConnect() {
|
|
|
|
|
const qc = useQueryClient();
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: ({
|
|
|
|
|
guildId,
|
|
|
|
|
channelId,
|
|
|
|
|
}: {
|
|
|
|
|
guildId: string;
|
|
|
|
|
channelId: string;
|
|
|
|
|
}) => voiceApi.connect(guildId, channelId),
|
|
|
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: ["voice-status"] }),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useVoiceDisconnect() {
|
|
|
|
|
const qc = useQueryClient();
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: () => voiceApi.disconnect(),
|
|
|
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: ["voice-status"] }),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useMicTransmit() {
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: (active: boolean) =>
|
|
|
|
|
voiceApi.sendCommand(
|
|
|
|
|
active ? "voice:transmit:start" : "voice:transmit:stop",
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
}
|