File size: 4,656 Bytes
4e7af9b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useState } from 'react'
import { useCliAuthStore } from '../../stores/cliAuthStore'

export function OpenCodeLoginPanel() {
  const { openCodeApiKey, saveOpenCodeApiKey, isLoading } = useCliAuthStore()
  const [mode, setMode] = useState<'menu' | 'api_key'>('menu')
  const [apiKey, setApiKey] = useState('')
  const [status, setStatus] = useState<string | null>(null)

  const handleFreeModels = async () => {
    setStatus(null)
    try {
      await saveOpenCodeApiKey('', '')
      setStatus('Free models configured!')
    } catch (err) {
      setStatus(err instanceof Error ? err.message : String(err))
    }
  }

  const handleSave = async () => {
    if (!apiKey.trim()) { setStatus('Please enter an API key'); return }
    setStatus(null)
    try {
      await saveOpenCodeApiKey(apiKey.trim(), '')
      setStatus('Saved!')
    } catch (err) {
      setStatus(err instanceof Error ? err.message : String(err))
    }
  }

  const handleClear = async () => {
    await useCliAuthStore.getState().clearAuth()
    setApiKey('')
    setStatus('Cleared')
  }

  if (mode === 'api_key') {
    return (
      <div className="flex flex-col gap-3 py-2">
        <div className="text-sm text-[var(--color-text-secondary)]">
          OpenCode Zen API keys use pay-as-you-go billing. Sign up at <a href="https://opencode.ai/zen" className="text-[var(--color-brand)]" target="_blank">opencode.ai/zen</a> to get your key.
        </div>
        <div className="flex items-center gap-2">
          <input
            type="password"
            value={apiKey}
            onChange={e => setApiKey(e.target.value)}
            placeholder={openCodeApiKey ? '••••••••' : 'oc-...'}
            className="flex-1 rounded-md border border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-2 text-sm text-[var(--color-text-primary)] placeholder-[var(--color-text-tertiary)] focus:border-[var(--color-brand)] focus:outline-none"
          />
          <button
            onClick={handleSave}
            disabled={isLoading}
            className="rounded-md bg-[var(--color-brand)] px-4 py-2 text-sm text-white hover:brightness-105 disabled:opacity-50"
          >
            {isLoading ? 'Saving...' : 'Save'}
          </button>
        </div>
        <button
          onClick={() => { setMode('menu'); setApiKey(''); setStatus(null) }}
          className="self-start text-xs text-[var(--color-text-tertiary)] hover:text-[var(--color-text-primary)]"
        >
          &larr; Back to options
        </button>
        {status && (
          <div className={`text-xs ${status === 'Saved!' ? 'text-[var(--color-success)]' : 'text-[var(--color-error)]'}`}>
            {status}
          </div>
        )}
      </div>
    )
  }

  return (
    <div className="flex flex-col gap-3 py-2">
      <div className="text-sm text-[var(--color-text-secondary)]">
        OpenCode Zen offers free models (no API key needed) or paid models via API key.
      </div>
      {status && (
        <div className={`text-xs ${status === 'Saved!' || status === 'Free models configured!' ? 'text-[var(--color-success)]' : 'text-[var(--color-error)]'}`}>
          {status}
        </div>
      )}
      <div className="flex flex-col gap-2">
        <button
          onClick={handleFreeModels}
          disabled={isLoading}
          className="flex items-center gap-3 rounded-lg border border-[var(--color-border)] px-4 py-3 text-left hover:border-[var(--color-border-focus)] hover:bg-[var(--color-surface-hover)] disabled:opacity-50"
        >
          <div>
            <div className="text-sm font-medium text-[var(--color-text-primary)]">Use free models</div>
            <div className="text-xs text-[var(--color-text-tertiary)]">No API key required</div>
          </div>
        </button>
        <button
          onClick={() => { setMode('api_key'); setApiKey('') }}
          className="flex items-center gap-3 rounded-lg border border-[var(--color-border)] px-4 py-3 text-left hover:border-[var(--color-border-focus)] hover:bg-[var(--color-surface-hover)]"
        >
          <div>
            <div className="text-sm font-medium text-[var(--color-text-primary)]">Paste OpenCode Zen API key</div>
            <div className="text-xs text-[var(--color-text-tertiary)]">Access paid models, pay-as-you-go</div>
          </div>
        </button>
        {openCodeApiKey && (
          <button
            onClick={handleClear}
            className="self-start text-xs text-[var(--color-text-tertiary)] hover:text-[var(--color-error)]"
          >
            Clear credentials
          </button>
        )}
      </div>
    </div>
  )
}