File size: 4,442 Bytes
8c61b89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import { useState, useEffect } from "react";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { toast } from "sonner";

// API key configuration
interface ApiKeyConfig {
  name: string;
  key: string;
  storageKey: string;
  label: string;
  placeholder: string;
}

// Available API keys configuration
const API_KEYS_CONFIG: ApiKeyConfig[] = [
  {
    name: "OpenAI",
    key: "openai",
    storageKey: "OPENAI_API_KEY",
    label: "OpenAI API Key",
    placeholder: "sk-..."
  },
  {
    name: "Anthropic",
    key: "anthropic",
    storageKey: "ANTHROPIC_API_KEY",
    label: "Anthropic API Key",
    placeholder: "sk-ant-..."
  },
  {
    name: "Groq",
    key: "groq",
    storageKey: "GROQ_API_KEY",
    label: "Groq API Key",
    placeholder: "gsk_..."
  },
  {
    name: "XAI",
    key: "xai",
    storageKey: "XAI_API_KEY",
    label: "XAI API Key",
    placeholder: "xai-..."
  }
];

interface ApiKeyManagerProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

export function ApiKeyManager({ open, onOpenChange }: ApiKeyManagerProps) {
  // State to store API keys
  const [apiKeys, setApiKeys] = useState<Record<string, string>>({});

  // Load API keys from localStorage on initial mount
  useEffect(() => {
    const storedKeys: Record<string, string> = {};
    
    API_KEYS_CONFIG.forEach(config => {
      const value = localStorage.getItem(config.storageKey);
      if (value) {
        storedKeys[config.key] = value;
      }
    });
    
    setApiKeys(storedKeys);
  }, []);

  // Update API key in state
  const handleApiKeyChange = (key: string, value: string) => {
    setApiKeys(prev => ({
      ...prev,
      [key]: value
    }));
  };

  // Save API keys to localStorage
  const handleSaveApiKeys = () => {
    try {
      API_KEYS_CONFIG.forEach(config => {
        const value = apiKeys[config.key];
        
        if (value && value.trim()) {
          localStorage.setItem(config.storageKey, value.trim());
        } else {
          localStorage.removeItem(config.storageKey);
        }
      });
      
      toast.success("API keys saved successfully");
      onOpenChange(false);
    } catch (error) {
      console.error("Error saving API keys:", error);
      toast.error("Failed to save API keys");
    }
  };

  // Clear all API keys
  const handleClearApiKeys = () => {
    try {
      API_KEYS_CONFIG.forEach(config => {
        localStorage.removeItem(config.storageKey);
      });
      
      setApiKeys({});
      toast.success("All API keys cleared");
    } catch (error) {
      console.error("Error clearing API keys:", error);
      toast.error("Failed to clear API keys");
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-[500px]">
        <DialogHeader>
          <DialogTitle>API Key Settings</DialogTitle>
          <DialogDescription>
            Enter your own API keys for different AI providers. Keys are stored securely in your browser&apos;s local storage.
          </DialogDescription>
        </DialogHeader>
        
        <div className="grid gap-4 py-4">
          {API_KEYS_CONFIG.map(config => (
            <div key={config.key} className="grid gap-2">
              <Label htmlFor={config.key}>{config.label}</Label>
              <Input
                id={config.key}
                type="password"
                value={apiKeys[config.key] || ""}
                onChange={(e) => handleApiKeyChange(config.key, e.target.value)}
                placeholder={config.placeholder}
              />
            </div>
          ))}
        </div>
        
        <DialogFooter className="flex justify-between sm:justify-between">
          <Button
            variant="destructive"
            onClick={handleClearApiKeys}
          >
            Clear All Keys
          </Button>
          <div className="flex gap-2">
            <Button
              variant="outline"
              onClick={() => onOpenChange(false)}
            >
              Cancel
            </Button>
            <Button onClick={handleSaveApiKeys}>
              Save Keys
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}