veza/apps/web/src/components/developer/modals/CreateAPIKeyModal.tsx

125 lines
5.6 KiB
TypeScript
Raw Normal View History

import React, { useState } from 'react';
import { Button } from '../../ui/button';
import { Input } from '../../ui/input';
import { X, Key, Copy, Check } from 'lucide-react';
import { useToast } from '../../../context/ToastContext';
interface CreateAPIKeyModalProps {
onClose: () => void;
onCreate: (keyData: { name: string, scopes: string[] }) => void;
}
const SCOPES = [
{ id: 'user.read', label: 'Read User Data' },
{ id: 'user.write', label: 'Update User Profile' },
{ id: 'tracks.read', label: 'Read Tracks' },
{ id: 'tracks.upload', label: 'Upload Tracks' },
{ id: 'sales.read', label: 'Read Sales Data' },
];
export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({ onClose, onCreate }) => {
const { addToast } = useToast();
const [step, setStep] = useState(1);
const [name, setName] = useState('');
const [selectedScopes, setSelectedScopes] = useState<string[]>(['user.read']);
const [generatedKey, setGeneratedKey] = useState('');
const toggleScope = (id: string) => {
setSelectedScopes(prev => prev.includes(id) ? prev.filter(s => s !== id) : [...prev, id]);
};
const handleGenerate = () => {
if (!name) {
addToast("Please name your key", "error");
return;
}
// Mock Key Generation
const mockKey = `vz_${Math.random().toString(36).substr(2, 8)}_${Math.random().toString(36).substr(2, 16)}`;
setGeneratedKey(mockKey);
onCreate({ name, scopes: selectedScopes }); // Notify parent
setStep(2);
};
const copyKey = () => {
navigator.clipboard.writeText(generatedKey);
addToast("API Key copied to clipboard", "success");
};
return (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
<div className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm" onClick={onClose}></div>
<div className="relative w-full max-w-lg bg-kodo-graphite border border-kodo-steel rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
<div className="p-4 border-b border-kodo-steel bg-kodo-ink flex justify-between items-center">
<h3 className="font-bold text-white flex items-center gap-2">
<Key className="w-4 h-4 text-kodo-gold" /> {step === 1 ? 'Create API Key' : 'API Key Generated'}
</h3>
<button onClick={onClose}><X className="w-5 h-5 text-gray-400 hover:text-white" /></button>
</div>
<div className="p-6">
{step === 1 ? (
<div className="space-y-6">
<Input
label="Key Name"
placeholder="e.g. Production Server, Mobile App"
value={name}
onChange={(e) => setName(e.target.value)}
autoFocus
/>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase mb-3">Permissions (Scopes)</label>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{SCOPES.map(scope => (
<label key={scope.id} className="flex items-center gap-3 p-3 bg-kodo-ink rounded border border-kodo-steel cursor-pointer hover:border-gray-500 transition-colors">
<input
type="checkbox"
className="rounded border-gray-600 bg-transparent text-kodo-gold focus:ring-0"
checked={selectedScopes.includes(scope.id)}
onChange={() => toggleScope(scope.id)}
/>
<span className="text-sm text-gray-300">{scope.label}</span>
</label>
))}
</div>
</div>
</div>
) : (
<div className="text-center space-y-6">
<div className="w-16 h-16 bg-kodo-lime/20 rounded-full flex items-center justify-center mx-auto text-kodo-lime">
<Check className="w-8 h-8" />
</div>
<div>
<h4 className="text-xl font-bold text-white mb-2">Key Created Successfully</h4>
<p className="text-sm text-gray-400 max-w-xs mx-auto">
Please copy your API key now. For security reasons, you won't be able to see it again.
</p>
</div>
<div className="bg-black border border-kodo-steel rounded-lg p-4 flex items-center gap-2 relative group">
<code className="text-kodo-gold font-mono text-sm flex-1 break-all">{generatedKey}</code>
<Button variant="ghost" size="icon" onClick={copyKey} className="hover:text-white">
<Copy className="w-4 h-4" />
</Button>
</div>
</div>
)}
</div>
<div className="p-4 border-t border-kodo-steel bg-kodo-ink flex justify-end gap-3">
{step === 1 ? (
<>
<Button variant="ghost" onClick={onClose}>Cancel</Button>
<Button variant="primary" onClick={handleGenerate}>Generate Key</Button>
</>
) : (
<Button variant="primary" onClick={onClose}>Done</Button>
)}
</div>
</div>
</div>
);
};