Yaltopia-Ticket-Admin/src/pages/admin/security/api-keys.tsx
debudebuye 9c7e33499a
Some checks are pending
CI / Test & Build (18.x) (push) Waiting to run
CI / Test & Build (20.x) (push) Waiting to run
CI / Security Audit (push) Waiting to run
Deploy to Production / Deploy to Netlify/Vercel (push) Waiting to run
chore: Update dependencies, refactor ESLint config, and enhance test infrastructure
2026-02-26 11:18:40 +03:00

103 lines
3.4 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Ban } from "lucide-react"
import { securityService, type ApiKey } from "@/services"
import { toast } from "sonner"
import { format } from "date-fns"
import type { ApiError } from "@/types/error.types"
export default function ApiKeysPage() {
const queryClient = useQueryClient()
const { data: apiKeys, isLoading } = useQuery({
queryKey: ['admin', 'security', 'api-keys'],
queryFn: () => securityService.getAllApiKeys(),
})
const revokeMutation = useMutation({
mutationFn: (id: string) => securityService.revokeApiKey(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin', 'security', 'api-keys'] })
toast.success("API key revoked successfully")
},
onError: (error) => {
const apiError = error as ApiError
toast.error(apiError.response?.data?.message || "Failed to revoke API key")
},
})
return (
<div className="space-y-6">
<h2 className="text-3xl font-bold">API Keys</h2>
<Card>
<CardHeader>
<CardTitle>All API Keys</CardTitle>
</CardHeader>
<CardContent>
{isLoading ? (
<div className="text-center py-8">Loading API keys...</div>
) : (
<>
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>User</TableHead>
<TableHead>Last Used</TableHead>
<TableHead>Status</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{apiKeys?.map((key: ApiKey) => (
<TableRow key={key.id}>
<TableCell className="font-medium">{key.name}</TableCell>
<TableCell>{key.userId || 'N/A'}</TableCell>
<TableCell>
{key.lastUsed ? format(new Date(key.lastUsed), 'MMM dd, yyyy') : 'Never'}
</TableCell>
<TableCell>
<Badge variant={key.isActive ? 'default' : 'destructive'}>
{key.isActive ? 'Active' : 'Revoked'}
</Badge>
</TableCell>
<TableCell>
{key.isActive && (
<Button
variant="ghost"
size="icon"
onClick={() => revokeMutation.mutate(key.id)}
>
<Ban className="w-4 h-4" />
</Button>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{apiKeys?.length === 0 && (
<div className="text-center py-8 text-muted-foreground">
No API keys found
</div>
)}
</>
)}
</CardContent>
</Card>
</div>
)
}