Comprehensive admin + user dashboards (production-ready)
This commit is contained in:
@@ -2,11 +2,13 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Loader2, Copy, KeyRound, Trash2, Check } from "lucide-react";
|
||||
import { Loader2, Copy, KeyRound, Trash2 } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { ConfirmDialog } from "@/components/admin/ui/confirm-dialog";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
import { createApiKeyAction, revokeApiKeyAction } from "@/app/(app)/api-keys/actions";
|
||||
|
||||
interface KeyRow {
|
||||
@@ -37,17 +39,6 @@ export function ApiKeysClient({ keys }: { keys: KeyRow[] }) {
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
async function revoke(id: string) {
|
||||
if (!confirm("Revoke this key? Apps using it will stop working.")) return;
|
||||
const res = await revokeApiKeyAction(id);
|
||||
if (res.ok) {
|
||||
toast.success("Key revoked");
|
||||
router.refresh();
|
||||
} else {
|
||||
toast.error(res.error ?? "Could not revoke");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl space-y-6">
|
||||
{newKey && (
|
||||
@@ -88,9 +79,13 @@ export function ApiKeysClient({ keys }: { keys: KeyRow[] }) {
|
||||
</Card>
|
||||
|
||||
{keys.length === 0 ? (
|
||||
<p className="text-center text-sm text-muted-foreground">No API keys yet.</p>
|
||||
<EmptyState
|
||||
icon={KeyRound}
|
||||
title="No API keys yet"
|
||||
description="Create a key above to start generating episodes programmatically."
|
||||
/>
|
||||
) : (
|
||||
<div className="divide-y rounded-lg border">
|
||||
<div className="divide-y rounded-2xl border">
|
||||
{keys.map((k) => (
|
||||
<div key={k.id} className="flex items-center justify-between gap-3 p-4">
|
||||
<div className="min-w-0">
|
||||
@@ -100,9 +95,21 @@ export function ApiKeysClient({ keys }: { keys: KeyRow[] }) {
|
||||
{k.lastUsedAt ? ` · last used ${new Date(k.lastUsedAt).toLocaleDateString()}` : " · never used"}
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" className="text-destructive" onClick={() => revoke(k.id)}>
|
||||
<Trash2 className="h-4 w-4" /> Revoke
|
||||
</Button>
|
||||
<ConfirmDialog
|
||||
trigger={
|
||||
<Button variant="ghost" size="sm" className="text-destructive">
|
||||
<Trash2 className="h-4 w-4" /> Revoke
|
||||
</Button>
|
||||
}
|
||||
title="Revoke this key?"
|
||||
description={`Apps using "${k.name}" will immediately stop working. This cannot be undone.`}
|
||||
confirmLabel="Revoke key"
|
||||
successMessage="Key revoked"
|
||||
onConfirm={async () => {
|
||||
const res = await revokeApiKeyAction(k.id);
|
||||
return { ok: res.ok, error: res.error };
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user