import { useState, useEffect } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { Card, CardContent } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch"; import { Eye, EyeOff, CheckCircle } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; type AiSettings = { id?: number; apiKey: string; aiEnabled: boolean; openAiKey: string; openAiEnabled: boolean; claudeAiKey: string; claudeAiEnabled: boolean; dentalMgmtKey: string; dentalMgmtEnabled: boolean; }; type Provider = "openAi" | "claudeAi" | "dentalMgmt"; function ApiKeySection({ title, description, apiKey, enabled, isConfigured, onSave, onToggle, isSaving, isToggling, }: { title: string; description: string; apiKey: string; enabled: boolean; isConfigured: boolean; onSave: (key: string) => void; onToggle: (enabled: boolean) => void; isSaving: boolean; isToggling: boolean; }) { const [localKey, setLocalKey] = useState(apiKey); const [showKey, setShowKey] = useState(false); useEffect(() => { setLocalKey(apiKey); }, [apiKey]); return (

{title}

{isConfigured && ( Configured )}
{enabled ? "On" : "Off"}

{description}

setLocalKey(e.target.value)} className="p-2 border rounded w-full pr-10 font-mono text-sm" placeholder="••••••••••••••••••••••••••••••••••••••" />
); } export function AiSettingsCard() { const { toast } = useToast(); const [apiKey, setApiKey] = useState(""); const [showGoogleKey, setShowGoogleKey] = useState(false); const [aiEnabled, setAiEnabled] = useState(true); const { data: settings, isLoading } = useQuery({ queryKey: ["/api/ai/settings"], queryFn: async () => { const res = await apiRequest("GET", "/api/ai/settings"); if (!res.ok) return null; return res.json(); }, }); useEffect(() => { if (settings) { setApiKey(settings.apiKey ?? ""); setAiEnabled(settings.aiEnabled ?? true); } }, [settings]); // Google AI save const googleSaveMutation = useMutation({ mutationFn: async (key: string) => { const res = await apiRequest("PUT", "/api/ai/settings", { apiKey: key }); if (!res.ok) throw new Error((await res.json().catch(() => null))?.message || "Failed to save"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/ai/settings"] }); toast({ title: "Saved", description: "Google AI API key saved." }); }, onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }), }); // Google AI toggle const googleToggleMutation = useMutation({ mutationFn: async (enabled: boolean) => { const res = await apiRequest("PUT", "/api/ai/enabled", { aiEnabled: enabled }); if (!res.ok) throw new Error((await res.json().catch(() => null))?.message || "Failed"); return res.json(); }, onSuccess: (_d, enabled) => { queryClient.invalidateQueries({ queryKey: ["/api/ai/settings"] }); toast({ title: enabled ? "Google AI Enabled" : "Google AI Disabled" }); }, onError: (err: any) => { setAiEnabled((v) => !v); toast({ title: "Error", description: err?.message, variant: "destructive" }); }, }); // Provider key save const providerKeyMutation = useMutation({ mutationFn: async ({ provider, apiKey }: { provider: Provider; apiKey: string }) => { const res = await apiRequest("PUT", "/api/ai/provider-key", { provider, apiKey }); if (!res.ok) throw new Error((await res.json().catch(() => null))?.message || "Failed"); return { provider }; }, onSuccess: ({ provider }) => { queryClient.invalidateQueries({ queryKey: ["/api/ai/settings"] }); const names: Record = { openAi: "OpenAI", claudeAi: "Claude AI", dentalMgmt: "DentalManagement AI" }; toast({ title: "Saved", description: `${names[provider]} API key saved.` }); }, onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }), }); // Provider toggle const providerToggleMutation = useMutation({ mutationFn: async ({ provider, enabled }: { provider: Provider; enabled: boolean }) => { const res = await apiRequest("PUT", "/api/ai/provider-enabled", { provider, enabled }); if (!res.ok) throw new Error((await res.json().catch(() => null))?.message || "Failed"); return { provider, enabled }; }, onSuccess: ({ provider, enabled }) => { queryClient.invalidateQueries({ queryKey: ["/api/ai/settings"] }); const names: Record = { openAi: "OpenAI", claudeAi: "Claude AI", dentalMgmt: "DentalManagement AI" }; toast({ title: `${names[provider]} ${enabled ? "Enabled" : "Disabled"}` }); }, onError: (err: any) => toast({ title: "Error", description: err?.message, variant: "destructive" }), }); if (isLoading) { return

Loading...

; } return ( {/* Google AI */}

Google AI Settings

{!!settings?.apiKey && ( Configured )}
{aiEnabled ? "On" : "Off"} { setAiEnabled(v); googleToggleMutation.mutate(v); }} disabled={googleToggleMutation.isPending} />

Enter your Google AI Studio API key to enable AI-powered SMS replies.

setApiKey(e.target.value)} className="p-2 border rounded w-full pr-10 font-mono text-sm" placeholder="AIza••••••••••••••••••••••••••••••••••••••" />
{!!settings?.apiKey && (

AI Auto-Reply Rules

Patient replies "Yes" → AI sends a thank-you confirmation

Patient replies "No" / "Not available" → AI notifies them an assistant will follow up

)}
{/* OpenAI */} providerKeyMutation.mutate({ provider: "openAi", apiKey: key })} onToggle={(v) => providerToggleMutation.mutate({ provider: "openAi", enabled: v })} isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "openAi"} isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "openAi"} /> {/* Claude AI */} providerKeyMutation.mutate({ provider: "claudeAi", apiKey: key })} onToggle={(v) => providerToggleMutation.mutate({ provider: "claudeAi", enabled: v })} isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "claudeAi"} isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "claudeAi"} /> {/* DentalManagement AI */} providerKeyMutation.mutate({ provider: "dentalMgmt", apiKey: key })} onToggle={(v) => providerToggleMutation.mutate({ provider: "dentalMgmt", enabled: v })} isSaving={providerKeyMutation.isPending && (providerKeyMutation.variables as any)?.provider === "dentalMgmt"} isToggling={providerToggleMutation.isPending && (providerToggleMutation.variables as any)?.provider === "dentalMgmt"} />
); }