import { useState, useEffect, useCallback } from 'react' import { useParams, useNavigate } from 'react-router-dom' import { ArrowLeft, Shield, Crown, UserCheck, UserX, Clock, Ticket, KeyRound, Copy, Check, Archive, ArchiveRestore, Trash2 } from 'lucide-react' import { Button } from '@/components/ui/Button' import { Input } from '@/components/ui/Input' import { StatusBadge } from '@/components/admin' import { Modal } from '@/components/common/Modal' import { Spinner } from '@/components/common/Spinner' import { EmptyState } from '@/components/common/EmptyState' import { adminApi } from '@/api/admin' import { toast } from '@/lib/toast' import { cn } from '@/lib/utils' import type { UserDetailResponse } from '@/types/admin' const PLAN_OPTIONS = ['free', 'pro', 'team'] as const export function UserDetailPage() { const { userId } = useParams<{ userId: string }>() const navigate = useNavigate() const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) // Modal state const [planModalOpen, setPlanModalOpen] = useState(false) const [selectedPlan, setSelectedPlan] = useState('') const [trialModalOpen, setTrialModalOpen] = useState(false) const [trialDays, setTrialDays] = useState('14') const [activeTab, setActiveTab] = useState<'sessions' | 'audit'>('sessions') // Password reset modal const [resetModalOpen, setResetModalOpen] = useState(false) const [resetMode, setResetMode] = useState<'email_link' | 'temp_password'>('email_link') const [resetLoading, setResetLoading] = useState(false) const [resetTempPassword, setResetTempPassword] = useState(null) const [resetCopied, setResetCopied] = useState(false) // Super admin const [superAdminModalOpen, setSuperAdminModalOpen] = useState(false) // Hard delete const [hardDeleteModalOpen, setHardDeleteModalOpen] = useState(false) const [hardDeleteChecking, setHardDeleteChecking] = useState(false) const [hardDeleteBlockers, setHardDeleteBlockers] = useState | null>(null) const fetchUser = useCallback(async () => { if (!userId) return setLoading(true) try { const data = await adminApi.getUserDetail(userId) setUser(data) } catch { toast.error('Failed to load user details') } finally { setLoading(false) } }, [userId]) useEffect(() => { fetchUser() }, [fetchUser]) const handleChangePlan = async () => { if (!userId || !selectedPlan) return try { await adminApi.updateUserSubscriptionPlan(userId, selectedPlan) toast.success(`Plan changed to ${selectedPlan}`) setPlanModalOpen(false) fetchUser() } catch { toast.error('Failed to change plan') } } const handleExtendTrial = async () => { if (!userId || !trialDays) return try { await adminApi.extendUserTrial(userId, parseInt(trialDays)) toast.success(`Trial extended by ${trialDays} days`) setTrialModalOpen(false) fetchUser() } catch { toast.error('Failed to extend trial') } } const handleToggleActive = async () => { if (!userId || !user) return try { if (user.is_active) { await adminApi.deactivateUser(userId) toast.success('User deactivated') } else { await adminApi.activateUser(userId) toast.success('User activated') } fetchUser() } catch { toast.error('Failed to update user status') } } const handleResetPassword = async () => { if (!userId) return setResetLoading(true) try { const result = await adminApi.adminResetPassword(userId, resetMode) if (resetMode === 'temp_password' && result.temporary_password) { setResetTempPassword(result.temporary_password) setResetCopied(false) } else { toast.success(result.email_sent ? 'Password reset email sent' : result.message) setResetModalOpen(false) } fetchUser() } catch { toast.error('Failed to reset password') } finally { setResetLoading(false) } } const handleCopyResetPassword = async () => { if (!resetTempPassword) return await navigator.clipboard.writeText(resetTempPassword) setResetCopied(true) setTimeout(() => setResetCopied(false), 2000) } const handleToggleSuperAdmin = async () => { if (!userId || !user) return try { await adminApi.updateSuperAdminStatus(userId, !user.is_super_admin) toast.success(user.is_super_admin ? 'Super admin access removed' : 'Promoted to super admin') setSuperAdminModalOpen(false) fetchUser() } catch { toast.error('Failed to update super admin status') } } const handleArchive = async () => { if (!userId) return try { await adminApi.archiveUser(userId) toast.success('User archived') fetchUser() } catch { toast.error('Failed to archive user') } } const handleRestore = async () => { if (!userId) return try { await adminApi.restoreUser(userId) toast.success('User restored') fetchUser() } catch { toast.error('Failed to restore user') } } const handleHardDeleteCheck = async () => { if (!userId) return setHardDeleteChecking(true) try { const result = await adminApi.hardDeleteCheck(userId) setHardDeleteBlockers(result.blockers) setHardDeleteModalOpen(true) } catch { toast.error('Failed to check delete eligibility') } finally { setHardDeleteChecking(false) } } const handleHardDelete = async () => { if (!userId) return try { await adminApi.hardDeleteUser(userId) toast.success('User permanently deleted') navigate('/admin/accounts') } catch (err: unknown) { if (err && typeof err === 'object' && 'response' in err) { const axiosErr = err as { response?: { data?: { detail?: string } } } toast.error(axiosErr.response?.data?.detail || 'Failed to delete user') } else { toast.error('Failed to delete user') } } } const selectClass = cn( 'w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground', 'placeholder:text-muted-foreground focus:outline-hidden focus:border-primary focus:ring-2 focus:ring-primary/20' ) if (loading) { return (
) } if (!user) { return ( navigate('/admin/accounts')}> Back to Accounts )} /> ) } const fmt = (d: string | null) => d ? new Date(d).toLocaleDateString() : '—' const fmtFull = (d: string | null) => d ? new Date(d).toLocaleString() : '—' return (
{/* Header */}

{user.full_name || user.email}

{user.email}

{user.is_super_admin && ( Super Admin )} {user.is_active ? 'Active' : 'Inactive'} {user.role} {user.deleted_at && ( Archived )}
{/* Account & Subscription */}

Account & Subscription

{user.account && ( <>
Account
{user.account.name}
{user.account.display_code && (
Display Code
{user.account.display_code}
)} )} {user.subscription ? ( <>
Plan
{user.subscription.plan.charAt(0).toUpperCase() + user.subscription.plan.slice(1)}
Status
{user.subscription.status}
{user.subscription.current_period_end && (
Period End
{fmt(user.subscription.current_period_end)}
)} ) : (
No subscription
)}
Joined
{fmt(user.created_at)}
{/* Admin Actions */}

Admin Actions

{user.account && ( <> )} {/* Archive / Restore */} {user.deleted_at ? ( ) : ( )} {/* Hard Delete (only if archived) */} {user.deleted_at && ( )}
{/* Invite Code Used */} {user.invite_code_used && (

Invite Code Used

Code
{user.invite_code_used.code}
Plan Assigned
{user.invite_code_used.assigned_plan.charAt(0).toUpperCase() + user.invite_code_used.assigned_plan.slice(1)}
Trial Days
{user.invite_code_used.trial_duration_days ?? '—'}
Created By
{user.invite_code_used.created_by_email ?? '—'}
)} {/* Tabs: Sessions / Audit Logs */}
{activeTab === 'sessions' && ( user.recent_sessions.length > 0 ? ( {user.recent_sessions.map(s => ( ))}
Tree Started Completed Outcome
{s.tree_name ?? '—'} {fmtFull(s.started_at)} {fmtFull(s.completed_at)} {s.outcome ? ( {s.outcome} ) : ( )}
) : (
No sessions yet
) )} {activeTab === 'audit' && ( user.recent_audit_logs.length > 0 ? ( {user.recent_audit_logs.map(a => ( ))}
Action Resource Time
{a.action} {a.resource_type ?? '—'} {fmtFull(a.created_at)}
) : (
No audit logs yet
) )}
{/* Change Plan Modal */} setPlanModalOpen(false)} title="Change Subscription Plan" size="sm" footer={
} >
{/* Reset Password Modal */} setResetModalOpen(false)} title="Reset User Password" size="sm" footer={
} >

Choose how to reset the password for {user.full_name || user.email}.

{/* Temp Password Result Modal */} { setResetTempPassword(null); setResetModalOpen(false) }} title="Temporary Password" size="sm" footer={
} >
This password will not be shown again. Copy it now.
{resetTempPassword}

The user will be required to change this password on next login.

{/* Extend Trial Modal */} setTrialModalOpen(false)} title={user.subscription?.status === 'trialing' ? 'Extend Trial' : 'Start Trial'} size="sm" footer={
} >
setTrialDays(e.target.value)} min={1} max={90} />

1-90 days. Will convert to trialing status if not already.

{/* Super Admin Modal */} setSuperAdminModalOpen(false)} title={user.is_super_admin ? 'Remove Super Admin Access' : 'Promote to Super Admin'} size="sm" footer={
} >
{user.is_super_admin ? (
This will remove system-wide admin access from {user.full_name || user.email}. They will revert to their account role permissions.
) : (
This will grant {user.full_name || user.email} full system-wide admin access, including access to the admin panel and all accounts.
)}
{/* Hard Delete Modal */} setHardDeleteModalOpen(false)} title="Permanently Delete User" size="sm" footer={
{hardDeleteBlockers && Object.keys(hardDeleteBlockers).length === 0 && ( )}
} >
{hardDeleteBlockers && Object.keys(hardDeleteBlockers).length > 0 ? ( <>
This user cannot be deleted because they have dependencies:
    {Object.entries(hardDeleteBlockers).map(([key, count]) => (
  • {key.replace(/_/g, ' ')} {count}
  • ))}
) : (

This action is irreversible.

The user {user?.full_name || user?.email} and all their technical data (tokens, reset tokens) will be permanently removed.

)}
) } export default UserDetailPage