Spaces:
Sleeping
Sleeping
| import { Copy, KeyRound } from 'lucide-react'; | |
| import { useState } from 'react'; | |
| import { toast } from 'sonner'; | |
| import { ConfigError } from '@/components/admin/admin-form-parts'; | |
| import { Button } from '@/components/ui/button'; | |
| import { | |
| Card, | |
| CardContent, | |
| CardDescription, | |
| CardHeader, | |
| CardTitle, | |
| } from '@/components/ui/card'; | |
| import { Input } from '@/components/ui/input'; | |
| import { Label } from '@/components/ui/label'; | |
| import { Spinner } from '@/components/ui/spinner'; | |
| import { generateApiKey } from '@/lib/rag-client'; | |
| import type { GeneratedApiKey } from '@/types/admin'; | |
| export function AdminApiKeyCard() { | |
| const [generatedApiKey, setGeneratedApiKey] = | |
| useState<GeneratedApiKey | null>(null); | |
| const [isLoading, setIsLoading] = useState(false); | |
| const [error, setError] = useState<string | undefined>(); | |
| async function handleGenerateApiKey(): Promise<void> { | |
| setIsLoading(true); | |
| setError(undefined); | |
| try { | |
| const result = await generateApiKey(); | |
| setGeneratedApiKey(result); | |
| } catch (e) { | |
| setError( | |
| e instanceof Error ? e.message : 'Gagal membuat API key.', | |
| ); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| } | |
| function handleCopyApiKey(): void { | |
| if (!generatedApiKey?.api_key) { | |
| return; | |
| } | |
| void navigator.clipboard.writeText(generatedApiKey.api_key); | |
| toast.success('API key disalin.'); | |
| } | |
| return ( | |
| <Card className="border-(--lecturer-border) bg-(--lecturer-surface)"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <KeyRound className="size-5 text-(--lecturer-primary)" /> | |
| API Key Iframe | |
| </CardTitle> | |
| <CardDescription> | |
| API key hanya ditampilkan sekali setelah dibuat. | |
| </CardDescription> | |
| </CardHeader> | |
| <CardContent className="grid gap-4"> | |
| <Button | |
| disabled={isLoading} | |
| onClick={() => { | |
| void handleGenerateApiKey(); | |
| }} | |
| type="button" | |
| > | |
| {isLoading ? ( | |
| <Spinner className="size-4" /> | |
| ) : ( | |
| <KeyRound className="size-4" /> | |
| )} | |
| Generate API Key | |
| </Button> | |
| <ConfigError message={error} /> | |
| {generatedApiKey ? ( | |
| <div className="grid gap-3 rounded-xl border border-(--lecturer-border) bg-(--lecturer-surface) p-4"> | |
| <Label>API Key Baru</Label> | |
| <div className="flex gap-2"> | |
| <Input readOnly value={generatedApiKey.api_key} /> | |
| <Button | |
| onClick={handleCopyApiKey} | |
| type="button" | |
| variant="outline" | |
| > | |
| <Copy className="size-4" /> | |
| </Button> | |
| </div> | |
| <p className="text-sm text-muted-foreground"> | |
| Expired: {generatedApiKey.expires_at ?? '-'} | |
| </p> | |
| </div> | |
| ) : null} | |
| </CardContent> | |
| </Card> | |
| ); | |
| } | |