import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; import { AlertTriangle, Loader2, Pencil, Plus, Send, Trash2, } from "lucide-react"; import { useTranslation } from "@termix/plugin-sdk/frontend"; import { Badge, Button, Switch, useConfirmation } from "@termix/plugin-sdk/ui"; import type { ChannelSummary } from "../types"; import type { AlertsApi } from "./api"; import { ChannelDialog } from "./ChannelDialog"; export function ChannelsView({ api, onChanged, }: { api: AlertsApi; onChanged?: () => void; }) { const { t } = useTranslation(); const { confirmWithToast } = useConfirmation(); const [channels, setChannels] = useState([]); const [loading, setLoading] = useState(true); const [emailAvailable, setEmailAvailable] = useState(false); const [dialogOpen, setDialogOpen] = useState(false); const [editingId, setEditingId] = useState(null); const [testing, setTesting] = useState(null); const load = useCallback(async () => { try { const [list, meta] = await Promise.all([api.channels(), api.meta()]); setChannels(list); setEmailAvailable(meta.emailAvailable); } catch (error) { toast.error(error instanceof Error ? error.message : String(error)); } finally { setLoading(false); } }, [api]); useEffect(() => { void load(); }, [load]); const test = async (channel: ChannelSummary) => { setTesting(channel.id); try { await api.testChannel(channel.id); toast.success(t("channels.testSent")); } catch (error) { toast.error( t("channels.testFailed", { error: error instanceof Error ? error.message : String(error), }), ); } finally { setTesting(null); } }; const toggle = async (channel: ChannelSummary, enabled: boolean) => { try { await api.updateChannel(channel.id, { enabled }); setChannels((current) => current.map((entry) => entry.id === channel.id ? { ...entry, enabled } : entry, ), ); } catch (error) { toast.error(error instanceof Error ? error.message : String(error)); } }; const remove = (channel: ChannelSummary) => { void confirmWithToast( t("channels.deleteConfirm", { name: channel.name }), async () => { try { await api.deleteChannel(channel.id); toast.success(t("channels.deleted")); await load(); onChanged?.(); } catch (error) { toast.error(error instanceof Error ? error.message : String(error)); } }, t("actions.delete"), t("actions.cancel"), ); }; return (

{t("channels.intro")}

{loading ? ( ) : channels.length === 0 ? (

{t("channels.empty")}

) : (
{channels.map((channel) => (
void toggle(channel, checked)} aria-label={t("channels.enabled")} /> {channel.name} {!channel.usable && ( )} {t(`channels.types.${channel.type}`)}
))}
)} { setDialogOpen(false); void load(); onChanged?.(); }} />
); }