"use client" import { useCallback, useEffect, useState } from "react" import { Loader2, MessageCircle, Pencil, Plus, Power, PowerOff, Trash2, Zap, } from "lucide-react" import { useTranslations } from "next-intl" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { Switch } from "@/components/ui/switch" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog" import { listChatChannels, deleteChatChannel, connectChatChannel, disconnectChatChannel, testChatChannel, updateChatChannel, getChatChannelStatus, } from "@/lib/api" import { subscribe } from "@/lib/platform" import type { ChatChannelInfo, ChannelStatusInfo } from "@/lib/types" import { AddChatChannelDialog } from "./add-chat-channel-dialog" import { EditChatChannelDialog } from "./edit-chat-channel-dialog" export function ChannelListTab() { const t = useTranslations("ChatChannelSettings") const [channels, setChannels] = useState([]) const [statuses, setStatuses] = useState([]) const [loading, setLoading] = useState(true) const [addDialogOpen, setAddDialogOpen] = useState(false) const [editTarget, setEditTarget] = useState(null) const [deleteTarget, setDeleteTarget] = useState(null) const [actionLoading, setActionLoading] = useState(null) const loadChannels = useCallback(async () => { try { const [chs, sts] = await Promise.all([ listChatChannels(), getChatChannelStatus().catch(() => []), ]) setChannels(chs) setStatuses(sts) } catch { toast.error(t("loadFailed")) } finally { setLoading(false) } }, [t]) useEffect(() => { loadChannels().catch(console.error) }, [loadChannels]) // Subscribe to real-time status change events from backend useEffect(() => { let cancelled = false let unsub: (() => void) | undefined subscribe<{ channel_id: number status: ChannelStatusInfo["status"] }>("chat-channel://status", (payload) => { setStatuses((prev) => { const idx = prev.findIndex((s) => s.channel_id === payload.channel_id) if (idx >= 0) { const updated = [...prev] updated[idx] = { ...updated[idx], status: payload.status } return updated } return prev }) }).then((fn) => { if (cancelled) fn() else unsub = fn }) return () => { cancelled = true unsub?.() } }, []) const handleToggleEnabled = useCallback( async (ch: ChatChannelInfo, connected: boolean) => { try { const disabling = ch.enabled if (disabling && connected) { await disconnectChatChannel(ch.id) } await updateChatChannel({ id: ch.id, enabled: !ch.enabled }) await loadChannels() } catch { toast.error(t("saveFailed")) } }, [loadChannels, t] ) const handleConnect = useCallback( async (id: number) => { setActionLoading(id) try { await connectChatChannel(id) toast.success(t("connectSuccess")) await loadChannels() } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err) toast.error(t("connectFailed") + ": " + msg) } finally { setActionLoading(null) } }, [loadChannels, t] ) const handleDisconnect = useCallback( async (id: number) => { setActionLoading(id) try { await disconnectChatChannel(id) toast.success(t("disconnectSuccess")) await loadChannels() } catch { toast.error(t("disconnectFailed")) } finally { setActionLoading(null) } }, [loadChannels, t] ) const handleTest = useCallback( async (id: number) => { setActionLoading(id) try { await testChatChannel(id) toast.success(t("testSuccess")) } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err) toast.error(t("testFailed") + ": " + msg) } finally { setActionLoading(null) } }, [t] ) const handleDelete = useCallback(async () => { if (!deleteTarget) return try { await deleteChatChannel(deleteTarget.id) toast.success(t("deleteSuccess")) setDeleteTarget(null) await loadChannels() } catch { toast.error(t("deleteFailed")) } }, [deleteTarget, loadChannels, t]) const getChannelStatus = (id: number) => statuses.find((s) => s.channel_id === id)?.status ?? "disconnected" if (loading) { return (
{t("loading")}
) } return (

{t("channelListTitle")}

{t("channelListDescription")}

{channels.length === 0 ? (

{t("noChannels")}

) : (
{channels.map((ch) => { const status = getChannelStatus(ch.id) const isConnected = status === "connected" const isLoading = actionLoading === ch.id return (
{ch.name} {ch.channel_type}
{ch.daily_report_enabled && ( {t("dailyReport")}: {ch.daily_report_time || "18:00"} )}
handleToggleEnabled(ch, isConnected)} /> {isConnected ? ( ) : ( )}
) })}
)} {editTarget && ( !open && setEditTarget(null)} onChannelUpdated={loadChannels} /> )} !open && setDeleteTarget(null)} > {t("deleteConfirmTitle")} {t("deleteConfirmMessage")} {t("cancel")} {t("delete")}
) }