/** * Component: User Permissions Modal * Documentation: documentation/admin-dashboard.md */ 'use client'; import { Modal } from '@/components/ui/Modal'; interface UserPermissionsUser { id: string; plexUsername: string; plexEmail: string; avatarUrl: string | null; role: 'user' | 'admin'; autoApproveRequests: boolean | null; interactiveSearchAccess: boolean | null; downloadAccess: boolean | null; hasLoginToken: boolean; } interface UserPermissionsModalProps { isOpen: boolean; onClose: () => void; user: UserPermissionsUser | null; globalAutoApprove: boolean; globalInteractiveSearch: boolean; globalDownloadAccess: boolean; generatedToken: string | null; onToggleAutoApprove: (user: UserPermissionsUser, newValue: boolean) => void; onToggleInteractiveSearch: (user: UserPermissionsUser, newValue: boolean) => void; onToggleDownloadAccess: (user: UserPermissionsUser, newValue: boolean) => void; onToggleToken: (user: UserPermissionsUser, newValue: boolean) => void; } interface PermissionToggleProps { label: string; ariaLabel: string; value: boolean; disabled: boolean; disabledMessage?: string; description: string; onToggle: () => void; } function PermissionToggle({ label, ariaLabel, value, disabled, disabledMessage, description, onToggle }: PermissionToggleProps) { return (
{label}
{disabledMessage ? (

{disabledMessage}

) : (

{description}

)}
); } interface LoginTokenRowProps { value: boolean; generatedToken: string | null; onToggle: () => void; } function LoginTokenRow({ value, generatedToken, onToggle }: LoginTokenRowProps) { const loginUrl = generatedToken ? `${typeof window !== 'undefined' ? window.location.origin : ''}/auth/token/login?token=${generatedToken}` : null; const copyUrl = async () => { if (!loginUrl) return; try { await navigator.clipboard.writeText(loginUrl); } catch { // ignore } }; return (
Login Token

When enabled, this user can log in via a direct URL without credentials

{loginUrl && (

Copy the login URL - it won't be shown again

{loginUrl}
)}
); } export function UserPermissionsModal({ isOpen, onClose, user, globalAutoApprove, globalInteractiveSearch, globalDownloadAccess, generatedToken, onToggleAutoApprove, onToggleInteractiveSearch, onToggleDownloadAccess, onToggleToken, }: UserPermissionsModalProps) { if (!user) return null; const isAdmin = user.role === 'admin'; // Auto-Approve resolution const isAutoApproveGlobalOverride = !isAdmin && globalAutoApprove; const isAutoApproveDisabled = isAdmin || isAutoApproveGlobalOverride; const autoApproveValue = isAdmin ? true : isAutoApproveGlobalOverride ? true : (user.autoApproveRequests ?? false); // Interactive Search resolution const isSearchGlobalOverride = !isAdmin && globalInteractiveSearch; const isSearchDisabled = isAdmin || isSearchGlobalOverride; const searchValue = isAdmin ? true : isSearchGlobalOverride ? true : (user.interactiveSearchAccess ?? false); // Download Access resolution const isDownloadGlobalOverride = !isAdmin && globalDownloadAccess; const isDownloadDisabled = isAdmin || isDownloadGlobalOverride; const downloadValue = isAdmin ? true : isDownloadGlobalOverride ? true : (user.downloadAccess ?? false); const getDisabledMessage = (isAdminUser: boolean, isGlobalOverride: boolean, adminMessage: string, globalMessage: string): string | undefined => { if (isAdminUser) return adminMessage; if (isGlobalOverride) return globalMessage; return undefined; }; return (
{/* User Info */}
{user.avatarUrl && ( {user.plexUsername} )}
{user.plexUsername}
{user.plexEmail || 'No email'}
{user.role.toUpperCase()}
{/* Permissions Section */}

Permissions

{/* Auto-Approve Permission */} onToggleAutoApprove(user, !autoApproveValue)} /> {/* Interactive Search Access Permission */} onToggleInteractiveSearch(user, !searchValue)} /> {/* Download Access Permission */} onToggleDownloadAccess(user, !downloadValue)} /> {/* Login Token */} onToggleToken(user, !(user.hasLoginToken || generatedToken !== null))} />
); }