"use client";
import { useState } from "react";
import {
Key,
Copy,
Eye,
EyeOff,
RefreshCw,
Shield,
Check,
AlertTriangle,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
const scopes = [
{ id: "read", label: "Read", description: "Access to read resources" },
{ id: "write", label: "Write", description: "Create and update resources" },
{ id: "delete", label: "Delete", description: "Remove resources permanently" },
{ id: "admin", label: "Admin", description: "Full administrative access" },
];
export const title = "React Dialog Block API Key Management";
export default function DialogApiKey() {
const [open, setOpen] = useState(false);
const [keyName, setKeyName] = useState("");
const [expiration, setExpiration] = useState("90");
const [selectedScopes, setSelectedScopes] = useState<string[]>(["read"]);
const [generatedKey, setGeneratedKey] = useState("");
const [showKey, setShowKey] = useState(false);
const [copied, setCopied] = useState(false);
const generateKey = () => {
const key = `sk_live_${Array.from({ length: 32 }, () =>
Math.random().toString(36).charAt(2)
).join("")}`;
setGeneratedKey(key);
setShowKey(true);
};
const handleCopy = () => {
navigator.clipboard.writeText(generatedKey);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const toggleScope = (scopeId: string) => {
setSelectedScopes((prev) =>
prev.includes(scopeId)
? prev.filter((s) => s !== scopeId)
: [...prev, scopeId]
);
};
const handleClose = () => {
setOpen(false);
setTimeout(() => {
setKeyName("");
setExpiration("90");
setSelectedScopes(["read"]);
setGeneratedKey("");
setShowKey(false);
}, 200);
};
const maskedKey = generatedKey
? `sk_live_${"•".repeat(28)}${generatedKey.slice(-4)}`
: "";
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Key className="mr-2 h-4 w-4" />
Generate API Key
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Shield className="h-5 w-5" />
{generatedKey ? "API Key Generated" : "Create API Key"}
</DialogTitle>
<DialogDescription>
{generatedKey
? "Your new API key has been created. Copy it now—you won't see it again."
: "Generate a new API key with specific permissions and expiration."}
</DialogDescription>
</DialogHeader>
{generatedKey ? (
<div className="py-4 space-y-4">
<div className="rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-900 dark:bg-amber-950">
<div className="flex items-start gap-2">
<AlertTriangle className="h-4 w-4 text-amber-600 mt-0.5" />
<p className="text-sm text-amber-800 dark:text-amber-200">
Make sure to copy your API key now. You won't be able to
see it again!
</p>
</div>
</div>
<div className="space-y-2">
<Label>Your API Key</Label>
<div className="flex gap-2">
<div className="relative flex-1">
<Input
readOnly
value={showKey ? generatedKey : maskedKey}
className="pr-10 font-mono text-sm"
/>
<Button
type="button"
variant="ghost"
size="icon"
className="absolute right-0 top-0 h-full px-3"
onClick={() => setShowKey(!showKey)}
>
{showKey ? (
<EyeOff className="h-4 w-4" />
) : (
<Eye className="h-4 w-4" />
)}
</Button>
</div>
<Button variant="outline" onClick={handleCopy}>
{copied ? (
<Check className="h-4 w-4" />
) : (
<Copy className="h-4 w-4" />
)}
</Button>
</div>
</div>
<div className="flex flex-wrap gap-2">
<Badge variant="secondary">{keyName || "Unnamed key"}</Badge>
<Badge variant="outline">Expires in {expiration} days</Badge>
{selectedScopes.map((scope) => (
<Badge key={scope} variant="outline" className="capitalize">
{scope}
</Badge>
))}
</div>
</div>
) : (
<div className="py-4 space-y-4">
<div className="space-y-2">
<Label htmlFor="key-name">Key Name</Label>
<Input
id="key-name"
placeholder="e.g., Production Backend"
value={keyName}
onChange={(e) => setKeyName(e.target.value)}
/>
<p className="text-xs text-muted-foreground">
A descriptive name to identify this key
</p>
</div>
<div className="space-y-2">
<Label htmlFor="expiration">Expiration</Label>
<Select value={expiration} onValueChange={setExpiration}>
<SelectTrigger id="expiration">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="30">30 days</SelectItem>
<SelectItem value="90">90 days</SelectItem>
<SelectItem value="365">1 year</SelectItem>
<SelectItem value="never">Never expires</SelectItem>
</SelectContent>
</Select>
</div>
<Separator />
<div className="space-y-3">
<Label>Permissions</Label>
<div className="grid grid-cols-2 gap-2">
{scopes.map((scope) => {
const isSelected = selectedScopes.includes(scope.id);
return (
<label
key={scope.id}
htmlFor={scope.id}
className={`flex items-center gap-3 rounded-lg border p-3 cursor-pointer transition-colors ${
isSelected ? "border-primary bg-primary/5" : "hover:bg-muted"
}`}
>
<Checkbox
id={scope.id}
checked={isSelected}
onCheckedChange={() => toggleScope(scope.id)}
/>
<div>
<p className="text-sm font-medium">{scope.label}</p>
<p className="text-xs text-muted-foreground">
{scope.description}
</p>
</div>
</label>
);
})}
</div>
</div>
</div>
)}
<DialogFooter>
{generatedKey ? (
<Button onClick={handleClose} className="w-full">
Done
</Button>
) : (
<>
<Button variant="outline" onClick={handleClose}>
Cancel
</Button>
<Button
onClick={generateKey}
disabled={selectedScopes.length === 0}
>
<RefreshCw className="mr-2 h-4 w-4" />
Generate Key
</Button>
</>
)}
</DialogFooter>
</DialogContent>
</Dialog>
);
}