"use client"; import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Info, Loader2, MessageCircle, Save } from "lucide-react"; import { Button } from "@/components/ui/button"; import { SettingsInfoTile } from "@/components/settings/_info-tile"; import { SettingsCardActions } from "@/components/settings/_card-actions"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { PasswordInput } from "@/components/ui/password-input"; import { SettingsCard } from "@/components/settings/settings-card"; import { SettingsCardHeader } from "@/components/settings/_card-header"; import { TestConnectionButton } from "@/components/settings/test-connection-button"; import { isTelegramFormDirty } from "@/components/settings/channel-form-dirty"; import { optimisticallySetChannelEnabled, persistChannelEnabled, rollbackChannelEnabled, } from "@/components/settings/notification-channel-toggle"; import { useTranslations } from "@/lib/i18n/context"; import { queryKeys } from "@/lib/query-keys"; import { apiFetchRaw, apiGet } from "@/lib/api/api-fetch"; interface TelegramSettings { enabled: boolean; hasBotToken: boolean; chatId: string | null; } export function TelegramCard({ isAuthenticated, }: { isAuthenticated: boolean; }) { const { t } = useTranslations(); const queryClient = useQueryClient(); const [botToken, setBotToken] = useState(""); const [chatId, setChatId] = useState(""); const [saving, setSaving] = useState(false); const [msg, setMsg] = useState(null); const [msgType, setMsgType] = useState<"success" | "error" | null>(null); const { data: settings } = useQuery({ queryKey: queryKeys.telegramSettings(), queryFn: async () => { return apiGet("/api/settings/telegram"); }, enabled: isAuthenticated, }); // Sync from server using the React-recommended "previous-payload-id" // pattern instead of setState-in-effect. This avoids the strict // `react-hooks/set-state-in-effect` lint failure that the legacy file // disabled at module scope. const settingsKey = settings ? (settings.chatId ?? "") : null; const [seededKey, setSeededKey] = useState(null); if (settingsKey && settingsKey !== seededKey) { setSeededKey(settingsKey); if (settings!.chatId) setChatId(settings!.chatId); } const dirty = isTelegramFormDirty({ botToken, chatId }, settings); const toggleEnabled = useMutation< void, Error, boolean, TelegramSettings | undefined >({ mutationFn: (enabled) => persistChannelEnabled( "/api/settings/telegram", enabled, t("settings.savingError"), ), onMutate: async (enabled) => { const queryKey = queryKeys.telegramSettings(); await queryClient.cancelQueries({ queryKey }); setMsg(null); setMsgType(null); return optimisticallySetChannelEnabled( queryClient, queryKey, enabled, ); }, onSuccess: () => { setMsg(t("settings.saved")); setMsgType("success"); }, onError: (err, _enabled, previous) => { rollbackChannelEnabled( queryClient, queryKeys.telegramSettings(), previous, ); setMsg(err.message); setMsgType("error"); }, onSettled: () => { queryClient.invalidateQueries({ queryKey: queryKeys.telegramSettings() }); }, }); async function handleSave(e: React.FormEvent) { e.preventDefault(); setSaving(true); setMsg(null); setMsgType(null); const body: Record = { enabled: settings?.enabled ?? false, }; if (botToken.trim()) body.botToken = botToken.trim(); if (chatId !== (settings?.chatId ?? "")) body.chatId = chatId; const res = await apiFetchRaw("/api/settings/telegram", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (res.ok) { setMsg(t("settings.saved")); setMsgType("success"); setBotToken(""); queryClient.invalidateQueries({ queryKey: queryKeys.telegram() }); } else { const json = await res.json(); setMsg(json.error || t("settings.savingError")); setMsgType("error"); } setSaving(false); } return (
setBotToken(e.target.value)} placeholder={ settings?.hasBotToken ? t("settings.withingsCredentialsSavedPlaceholder") : "123456:ABC-DEF..." } maxLength={100} autoComplete="off" inputMode="text" spellCheck={false} autoCapitalize="none" enterKeyHint="next" />
setChatId(e.target.value)} placeholder="123456789" maxLength={50} autoComplete="off" inputMode="text" spellCheck={false} autoCapitalize="none" enterKeyHint="done" />
toggleEnabled.mutate(checked)} disabled={saving || toggleEnabled.isPending} />
  1. {t("settings.telegramStep1")}
  2. {t("settings.telegramStep2")}
  3. {t("settings.telegramStep3")}
{msg && (msgType === "error" || !dirty) && (

{msg}

)}
); }