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}
);
}
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.
{!!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"}
/>
);
}