import { ChangelogSettingsCard } from "@agent-native/core/client/changelog"; import { callAction } from "@agent-native/core/client/hooks"; import { LanguagePicker, useT } from "@agent-native/core/client/i18n"; import { TeamPage } from "@agent-native/core/client/org"; import { AccountSettingsCard, SettingsTabsPage, useAgentSettingsTabs, type SettingsSearchEntry, } from "@agent-native/core/client/settings"; import { AppearancePicker, type AppearancePresetId, } from "@agent-native/core/client/ui"; import { IconBrandZoom, IconExternalLink, IconLink, IconUnlink, IconCircleCheck, IconCircleX, } from "@tabler/icons-react"; import { useState, useEffect, useMemo } from "react"; import { Link } from "react-router"; import { toast } from "sonner"; import { GoogleSetupWizard } from "@/components/calendar/GoogleSetupWizard"; import { TimezoneCombobox } from "@/components/TimezoneCombobox"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Separator } from "@/components/ui/separator"; import { Textarea } from "@/components/ui/textarea"; import { useGoogleAuthStatus, useGoogleAuthUrl, useGoogleDesktopAuth, useDisconnectGoogle, } from "@/hooks/use-google-auth"; import { useSettings, useUpdateSettings } from "@/hooks/use-settings"; import { useConnectZoom, useDisconnectZoom, useZoomStatus, } from "@/hooks/use-zoom-auth"; import { shouldOfferGoogleOAuthSetup } from "@/lib/google-oauth-setup"; import changelog from "../../CHANGELOG.md?raw"; export default function Settings() { const t = useT(); const agentSettingsTabs = useAgentSettingsTabs(); const { data: settings } = useSettings(); const updateSettings = useUpdateSettings(); const googleStatus = useGoogleAuthStatus(); const disconnectGoogle = useDisconnectGoogle(); const { isDesktopGoogleAuth, isGoogleDesktopAuthPending, startDesktopGoogleAuth, } = useGoogleDesktopAuth({ onError: (issue) => toast.error(issue.message || issue.error || t("settings.googleFailed")), onSuccess: () => window.location.reload(), }); const zoomStatus = useZoomStatus(); const connectZoom = useConnectZoom(); const disconnectZoom = useDisconnectZoom(); const [wantAuthUrl, setWantAuthUrl] = useState(false); const authUrl = useGoogleAuthUrl(wantAuthUrl); const canOfferGoogleOAuthSetup = shouldOfferGoogleOAuthSetup(); const [timezone, setTimezone] = useState(""); const [bookingTitle, setBookingTitle] = useState(""); const [bookingDescription, setBookingDescription] = useState(""); const [defaultDuration, setDefaultDuration] = useState(30); useEffect(() => { if (settings) { setTimezone(settings.timezone); setBookingTitle(settings.bookingPageTitle); setBookingDescription(settings.bookingPageDescription); setDefaultDuration(settings.defaultEventDuration); } }, [settings]); function handleSave() { updateSettings.mutate( { timezone, bookingPageTitle: bookingTitle, bookingPageDescription: bookingDescription, defaultEventDuration: defaultDuration, }, { onSuccess: () => toast.success(t("settings.saved")), onError: () => toast.error(t("settings.saveFailed")), }, ); } function handleConnect() { if (isDesktopGoogleAuth) { startDesktopGoogleAuth({ previousAccountCount: googleStatus.data?.accounts?.length ?? 0, }); return; } setWantAuthUrl(true); } useEffect(() => { if (!wantAuthUrl || !authUrl.data?.url) return; setWantAuthUrl(false); window.open(authUrl.data.url, "_blank"); }, [wantAuthUrl, authUrl.data]); useEffect(() => { if (authUrl.error) { toast.error(authUrl.error.message); setWantAuthUrl(false); } }, [authUrl.error]); async function handleDisconnect() { const accounts = googleStatus.data?.accounts ?? []; try { for (const account of accounts) { await disconnectGoogle.mutateAsync(account.email); } toast.success(t("settings.googleDisconnected")); } catch { toast.error(t("settings.disconnectFailed")); } } function handleConnectZoom() { connectZoom.mutate(undefined, { onSuccess: () => toast(t("settings.zoomOpened")), onError: (error) => toast.error( error instanceof Error ? error.message : t("settings.zoomConnectFailed"), ), }); } function handleDisconnectZoom() { disconnectZoom.mutate(undefined, { onSuccess: () => toast.success(t("settings.zoomDisconnected")), onError: () => toast.error(t("settings.zoomDisconnectFailed")), }); } const generalSearchEntries = useMemo( () => [ { id: "calendar-language", label: t("settings.languageTitle"), keywords: "language locale translation i18n", hash: "language", }, { id: "calendar-google", label: t("settings.googleCalendar"), keywords: "google calendar connect oauth sync account", hash: "google-calendar", }, { id: "calendar-zoom", label: "Zoom", keywords: "zoom meeting video conferencing connect", hash: "zoom", }, { id: "calendar-general", label: t("settings.general"), keywords: "timezone booking duration defaults general", hash: "general-settings", }, { id: "calendar-appearance", label: t("settings.appearance"), keywords: "appearance theme color mode dark light", hash: "appearance", }, ], [t], ); return ( } generalLabel={t("settings.general")} teamLabel={t("navigation.team")} extraTabs={agentSettingsTabs} generalSearchEntries={generalSearchEntries} general={

{t("settings.description")}

{t("settings.languageTitle")} {t("settings.languageDescription")} {/* Google Calendar Connection */} {t("settings.googleCalendar")} {t("settings.googleDescription")}
{googleStatus.data?.connected ? ( <>

{t("common.connected")}

{googleStatus.data.accounts?.length > 0 && (

{googleStatus.data.accounts .map((a) => a.email) .join(", ")}

)}
) : ( <>

{t("common.notConnected")}

)}
{googleStatus.data?.connected ? ( ) : ( )}
Zoom {t("settings.zoomDescription")}
{zoomStatus.data?.connected ? ( <>

{t("common.connected")}

{zoomStatus.data.accounts?.length > 0 && (

{zoomStatus.data.accounts .map((a) => a.email || a.displayName || a.id) .join(", ")}

)}
) : ( <>

{zoomStatus.data?.configured === false ? t("settings.zoomNotConfigured") : t("common.notConnected")}

{zoomStatus.data?.configured === false && (

{t("settings.zoomCredentialsPrompt")}

)}
)}
{zoomStatus.data?.connected ? ( ) : ( )}
{/* Google Setup Wizard */} {!googleStatus.data?.connected && canOfferGoogleOAuthSetup && ( {t("settings.connectGoogleCalendar")} {t("settings.connectGoogleDescription")} )} {/* General Settings */} {t("settings.general")} {t("settings.generalDescription")}
setBookingTitle(e.target.value)} placeholder={t("settings.bookingTitlePlaceholder")} />

{t("settings.bookingTitleHelp")}