| import React, { useState, useEffect } from 'react'; | |
| const STORAGE_KEY = 'gemini_api_key'; | |
| interface ApiKeySettingsProps { | |
| onKeyConfigured: (hasKey: boolean) => void; | |
| } | |
| export const ApiKeySettings: React.FC<ApiKeySettingsProps> = ({ onKeyConfigured }) => { | |
| const [apiKey, setApiKey] = useState(''); | |
| const [showKey, setShowKey] = useState(false); | |
| const [hasStoredKey, setHasStoredKey] = useState(false); | |
| useEffect(() => { | |
| const storedKey = localStorage.getItem(STORAGE_KEY); | |
| if (storedKey) { | |
| setHasStoredKey(true); | |
| onKeyConfigured(true); | |
| } else { | |
| onKeyConfigured(false); | |
| } | |
| }, [onKeyConfigured]); | |
| const handleSaveKey = () => { | |
| if (apiKey.trim()) { | |
| localStorage.setItem(STORAGE_KEY, apiKey.trim()); | |
| setHasStoredKey(true); | |
| setApiKey(''); | |
| onKeyConfigured(true); | |
| } | |
| }; | |
| const handleClearKey = () => { | |
| localStorage.removeItem(STORAGE_KEY); | |
| setHasStoredKey(false); | |
| setApiKey(''); | |
| onKeyConfigured(false); | |
| }; | |
| const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { | |
| if (e.key === 'Enter') { | |
| handleSaveKey(); | |
| } | |
| }; | |
| if (hasStoredKey) { | |
| return ( | |
| <div className="p-6 bg-green-900/20 rounded-lg border border-green-500/50"> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center space-x-2"> | |
| <svg className="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /> | |
| </svg> | |
| <span className="text-green-400 font-semibold">API Key Configured</span> | |
| </div> | |
| <button | |
| onClick={handleClearKey} | |
| className="px-4 py-2 bg-red-600 text-white text-sm font-semibold rounded-lg hover:bg-red-700 transition-all" | |
| > | |
| Clear Key | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="p-6 bg-blue-900/20 rounded-lg border border-blue-500/50"> | |
| <h3 className="text-xl font-bold text-blue-300 mb-2">Configure Gemini API Key</h3> | |
| <p className="text-gray-400 text-sm mb-4"> | |
| Enter your Gemini API key to use this app. Your key will be stored locally in your browser. | |
| Get your API key from{' '} | |
| <a | |
| href="https://aistudio.google.com/apikey" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-blue-400 hover:text-blue-300 underline" | |
| > | |
| Google AI Studio | |
| </a> | |
| </p> | |
| <div className="flex flex-col sm:flex-row gap-3"> | |
| <div className="flex-1 relative"> | |
| <input | |
| type={showKey ? 'text' : 'password'} | |
| value={apiKey} | |
| onChange={(e) => setApiKey(e.target.value)} | |
| onKeyPress={handleKeyPress} | |
| placeholder="Enter your Gemini API key..." | |
| className="w-full px-4 py-2 bg-gray-800 border border-gray-600 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:border-blue-500 pr-10" | |
| /> | |
| <button | |
| type="button" | |
| onClick={() => setShowKey(!showKey)} | |
| className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-300" | |
| > | |
| {showKey ? ( | |
| <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" /> | |
| </svg> | |
| ) : ( | |
| <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /> | |
| </svg> | |
| )} | |
| </button> | |
| </div> | |
| <button | |
| onClick={handleSaveKey} | |
| disabled={!apiKey.trim()} | |
| className="px-6 py-2 bg-brand-blue text-white font-semibold rounded-lg hover:bg-opacity-80 transition-all disabled:opacity-50 disabled:cursor-not-allowed" | |
| > | |
| Save Key | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export const getApiKey = (): string | null => { | |
| return localStorage.getItem(STORAGE_KEY); | |
| }; | |