# All files / src/components/settings OpenAISettingsCard.tsx

0% Statements 0/112
0% Branches 0/1
0% Functions 0/1
0% Lines 0/112

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    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

     'use client';

    import { useState } from 'react';
    import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
    import { Input } from '@/components/ui/input';
    import { Button } from '@/components/ui/button';
    import { Label } from '@/components/ui/label';
    import { Eye, EyeClosed, Key } from '@phosphor-icons/react';

    export function OpenAISettingsCard() {
      const [apiKey, setApiKey] = useState(() => (typeof window !== 'undefined' ? localStorage.getItem('openai_api_key') || '' : ''));
      const [showKey, setShowKey] = useState(false);
      const [saved, setSaved] = useState(false);

      const handleSave = () => {
        if (apiKey.trim()) {
          localStorage.setItem('openai_api_key', apiKey.trim());
          setSaved(true);
          setTimeout(() => setSaved(false), 2000);
        } else {
          localStorage.removeItem('openai_api_key');
          setSaved(true);
          setTimeout(() => setSaved(false), 2000);
        }
      };

      const handleClear = () => {
        setApiKey('');
        localStorage.removeItem('openai_api_key');
        setSaved(true);
        setTimeout(() => setSaved(false), 2000);
      };

      return (
        <Card data-testid="openai-settings-card">
          <CardHeader>
            <div className="flex items-center gap-2">
              <Key className="h-5 w-5 text-primary" weight="duotone" aria-hidden="true" />
              <CardTitle>OpenAI API Settings</CardTitle>
            </div>
            <CardDescription>
              Configure your OpenAI API key for AI-powered error analysis. Your key is stored locally in your browser.
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            <div className="space-y-2">
              <Label htmlFor="openai-key">OpenAI API Key</Label>
              <div className="flex gap-2">
                <div className="relative flex-1">
                  <Input
                    id="openai-key"
                    type={showKey ? 'text' : 'password'}
                    value={apiKey}
                    onChange={(e) => setApiKey(e.target.value)}
                    placeholder="sk-..."
                    className="pr-10"
                    data-testid="openai-api-key-input"
                    aria-label="OpenAI API key"
                  />
                  <button
                    type="button"
                    onClick={() => setShowKey(!showKey)}
                    className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                    data-testid="toggle-api-key-visibility"
                    aria-label={showKey ? 'Hide API key' : 'Show API key'}
                    aria-pressed={showKey}
                  >
                    {showKey ? <EyeClosed size={18} aria-hidden="true" /> : <Eye size={18} aria-hidden="true" />}
                  </button>
                </div>
              </div>
              <p className="text-xs text-muted-foreground">
                Get your API key from{' '}
                <a
                  href="https://platform.openai.com/api-keys"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-primary hover:underline"
                >
                  OpenAI Platform
                </a>
              </p>
            </div>

            <div className="flex gap-2">
              <Button
                onClick={handleSave}
                disabled={!apiKey.trim()}
                data-testid="save-api-key-btn"
              >
                {saved ? 'Saved!' : 'Save API Key'}
              </Button>
              {apiKey && (
                <Button
                  onClick={handleClear}
                  variant="outline"
                  data-testid="clear-api-key-btn"
                >
                  Clear
                </Button>
              )}
            </div>

            {apiKey && (
              <div className="text-sm text-muted-foreground bg-muted/50 p-3 rounded-md">
                ✓ API key is configured. Error analysis will use OpenAI GPT-4o-mini.
              </div>
            )}
          </CardContent>
        </Card>
      );
    }