import React, { useEffect, useState } from "react"; import { http, BACKEND_URL } from "../lib/api"; import { KeyRound, RefreshCw, Save, Sparkles, Brain, Bug, Package, Download, ShieldCheck, CreditCard, MessageSquare, Link2 } from "lucide-react"; import { toast } from "sonner"; import EmoIdentityPanel from "./EmoIdentityPanel"; import MemoryPanel from "./MemoryPanel"; import DebugWindow from "./DebugWindow"; import FeedbackSessionsPanel from "./FeedbackSessionsPanel"; import ConnectedAccountsPanel from "./ConnectedAccountsPanel"; const KEY_META = [ { id: "groq", label: "Groq", hint: "Llama / Gemma gratuit" }, { id: "openrouter", label: "OpenRouter", hint: "Modèles :free" }, { id: "huggingface", label: "Hugging Face", hint: "HF_TOKEN" }, { id: "gemini", label: "Gemini", hint: "Google AI Studio" }, { id: "openai", label: "OpenAI", hint: "ChatGPT" }, { id: "anthropic", label: "Anthropic", hint: "Claude" }, { id: "deepseek", label: "DeepSeek", hint: "Chat / R1" }, ]; export default function AdminPanel({ debugEvents, onClearDebugEvents }) { const [tab, setTab] = useState("keys"); const [keys, setKeys] = useState({}); const [draft, setDraft] = useState({}); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [debugOpen, setDebugOpen] = useState(false); const [stripe, setStripe] = useState({}); const [stripeDraft, setStripeDraft] = useState({}); const [stripeLoading, setStripeLoading] = useState(false); const [stripeSaving, setStripeSaving] = useState(false); const loadKeys = async () => { setLoading(true); try { const r = await http.get("/admin/llm-keys"); setKeys(r.data?.keys || {}); setDraft({}); } catch (e) { toast.error(e?.response?.data?.detail || "Accès admin requis"); } finally { setLoading(false); } }; useEffect(() => { loadKeys(); }, []); const loadStripe = async () => { setStripeLoading(true); try { const r = await http.get("/admin/settings"); setStripe(r.data || {}); setStripeDraft({}); } catch (e) { toast.error(e?.response?.data?.detail || "Chargement Stripe impossible"); } finally { setStripeLoading(false); } }; useEffect(() => { if (tab === "stripe") loadStripe(); }, [tab]); const saveStripe = async () => { if (!Object.keys(stripeDraft).length) return; setStripeSaving(true); try { await http.patch("/admin/settings", stripeDraft); toast.success("Liens Stripe enregistrés"); setStripeDraft({}); await loadStripe(); } catch (e) { toast.error(e?.response?.data?.detail || "Erreur"); } finally { setStripeSaving(false); } }; const saveKeys = async () => { if (!Object.keys(draft).length) return; setSaving(true); try { await http.patch("/admin/llm-keys", { keys: draft }); toast.success("Clés enregistrées"); setDraft({}); await loadKeys(); } catch (e) { toast.error(e?.response?.data?.detail || "Erreur"); } finally { setSaving(false); } }; const tabs = [ { id: "keys", label: "Clés IA", icon: KeyRound }, { id: "stripe", label: "Stripe", icon: CreditCard }, { id: "feedback", label: "Retours utilisateurs", icon: MessageSquare }, { id: "emo", label: "Émo", icon: Sparkles }, { id: "memory", label: "Mémoire", icon: Brain }, { id: "system", label: "Système", icon: ShieldCheck }, { id: "connections", label: "Comptes OAuth", icon: Link2 }, ]; return (
{tabs.map((t) => { const Icon = t.icon; const active = tab === t.id; return ( ); })}
{tab === "keys" && (

Modifiables depuis le site — stockées chiffrées côté serveur.

{KEY_META.map((k) => { const row = keys[k.id] || {}; const value = draft[k.id] ?? ""; return (
setDraft((d) => ({ ...d, [k.id]: e.target.value }))} className="w-full px-3 py-2 rounded-lg text-xs font-code em-input focus:border-amber-500/40" />
); })}
)} {tab === "stripe" && (

Liens Payment Links Stripe par offre (Basic / Premium / Ultra).

{[ { id: "stripe_basic_link", label: "Basic", hint: "https://buy.stripe.com/..." }, { id: "stripe_premium_link", label: "Premium", hint: "https://buy.stripe.com/..." }, { id: "stripe_ultra_link", label: "Ultra", hint: "https://buy.stripe.com/..." }, { id: "stripe_payment_link", label: "Paiement unique (legacy)", hint: "Optionnel" }, { id: "stripe_subscription_link", label: "Abonnement (legacy)", hint: "Optionnel" }, ].map((row) => (
setStripeDraft((d) => ({ ...d, [row.id]: e.target.value }))} className="w-full px-3 py-2 rounded-lg text-xs font-code em-input focus:border-amber-500/40" /> {stripe[row.id] && !stripeDraft[row.id] && (

Actuel : {stripe[row.id]}

)}
))}
)} {tab === "feedback" && } {tab === "emo" && } {tab === "memory" && } {tab === "system" && (
)} {tab === "connections" && (

Comptes liés pour l'admin (GitHub API + token Google stocké pour Gmail/Drive à venir).

)} {debugOpen && ( setDebugOpen(false)} onClearEvents={onClearDebugEvents} /> )}
); }