"use client"; import { useState, useCallback } from "react"; import { format } from "date-fns"; import { Copy, Check, RefreshCw, Pencil, Trash2, ExternalLink } from "lucide-react"; import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Label, Separator, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "../../../shadcnui"; import { OAuthClientInterface, OAUTH_SCOPE_DISPLAY } from "../interfaces/oauth.interface"; export interface OAuthClientDetailProps { /** The OAuth client to display */ client: OAuthClientInterface; /** Whether data is loading */ isLoading?: boolean; /** Called when edit is clicked */ onEdit?: () => void; /** Called when delete is clicked */ onDelete?: () => Promise; /** Called when regenerate secret is clicked */ onRegenerateSecret?: () => Promise; } /** * Detailed view of an OAuth client */ export function OAuthClientDetail({ client, isLoading = false, onEdit, onDelete, onRegenerateSecret, }: OAuthClientDetailProps) { const [copiedField, setCopiedField] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [showRegenerateConfirm, setShowRegenerateConfirm] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [isRegenerating, setIsRegenerating] = useState(false); const copyToClipboard = useCallback(async (text: string, field: string) => { try { await navigator.clipboard.writeText(text); setCopiedField(field); setTimeout(() => setCopiedField(null), 2000); } catch (err) { console.error("Failed to copy:", err); } }, []); const handleDelete = useCallback(async () => { if (!onDelete) return; setIsDeleting(true); try { await onDelete(); } finally { setIsDeleting(false); setShowDeleteConfirm(false); } }, [onDelete]); const handleRegenerateSecret = useCallback(async () => { if (!onRegenerateSecret) return; setIsRegenerating(true); try { await onRegenerateSecret(); } finally { setIsRegenerating(false); setShowRegenerateConfirm(false); } }, [onRegenerateSecret]); const createdDate = client.createdAt ? format(new Date(client.createdAt), "MMMM d, yyyy") : "Unknown"; return ( <>
{client.name} {client.description && {client.description}}
{client.isActive ? "Active" : "Inactive"} {client.isConfidential ? "Confidential" : "Public"}
{/* Client ID */}
{/* Client Secret */}
{onRegenerateSecret && ( )}

Regenerating will invalidate the current secret and all existing tokens.

{/* Redirect URIs */}
    {client.redirectUris.map((uri, index) => (
  • {uri}
  • ))}
{/* Scopes */}
{client.allowedScopes.map((scope) => ( {OAUTH_SCOPE_DISPLAY[scope]?.name || scope} ))}
{/* Grant Types */}
{client.allowedGrantTypes.map((grant) => ( {grant.replace(/_/g, " ")} ))}
{/* Metadata */}
Created: {createdDate}
{/* Actions */}
{onEdit && ( )} {onDelete && ( )}
{/* Delete Confirmation */} Delete OAuth Application? This will permanently delete "{client.name}" and revoke all access tokens. This action cannot be undone. Cancel {isDeleting ? "Deleting..." : "Delete"} {/* Regenerate Confirmation */} Regenerate Client Secret? This will generate a new client secret and invalidate the old one. All existing tokens will be revoked. You will need to update your application with the new secret. Cancel {isRegenerating ? "Regenerating..." : "Regenerate"} ); }