import { useCallback, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { ArrowLeft, Building2, CalendarClock, Check, Copy, Crown, Loader2, Mail, Pencil, UserCheck, UserPlus, UserX, X, } from 'lucide-react' import { Button } from '@/components/ui/Button' import { Input } from '@/components/ui/Input' import { Modal } from '@/components/common/Modal' import { EmptyState, StatusBadge } from '@/components/admin' import { ConfirmButton } from '@/components/common/ConfirmButton' import { adminApi } from '@/api/admin' import { toast } from '@/lib/toast' import { cn } from '@/lib/utils' import type { AdminAccountDetailResponse, AdminAccountMember } from '@/types/admin' function formatDate(value: string | null) { if (!value) return 'Never' return new Date(value).toLocaleDateString() } export function AccountDetailPage() { const { accountId } = useParams<{ accountId: string }>() const navigate = useNavigate() const [account, setAccount] = useState(null) const [loading, setLoading] = useState(true) const [isEditingName, setIsEditingName] = useState(false) const [editedName, setEditedName] = useState('') const [savingName, setSavingName] = useState(false) const [showCreateUserModal, setShowCreateUserModal] = useState(false) const [createForm, setCreateForm] = useState({ email: '', name: '', account_role: 'engineer' as 'owner' | 'admin' | 'engineer' | 'viewer', send_email: true, }) const [createLoading, setCreateLoading] = useState(false) const [tempPassword, setTempPassword] = useState(null) const [copiedPassword, setCopiedPassword] = useState(false) const [showInviteModal, setShowInviteModal] = useState(false) const [inviteForm, setInviteForm] = useState({ email: '', role: 'engineer' as 'engineer' | 'viewer', }) const [inviteLoading, setInviteLoading] = useState(false) const [editingPlan, setEditingPlan] = useState(false) const [selectedPlan, setSelectedPlan] = useState('free') const [planSaving, setPlanSaving] = useState(false) const [editingTrial, setEditingTrial] = useState(false) const [trialDays, setTrialDays] = useState('14') const [trialSaving, setTrialSaving] = useState(false) const loadAccount = useCallback(async () => { if (!accountId) return setLoading(true) try { const data = await adminApi.getAccountDetail(accountId) setAccount(data) setEditedName(data.name) setSelectedPlan(data.subscription?.plan ?? 'free') } catch { toast.error('Failed to load account') } finally { setLoading(false) } }, [accountId]) useEffect(() => { loadAccount() }, [loadAccount]) const handleSaveName = async () => { if (!account || !editedName.trim() || editedName.trim() === account.name) { setIsEditingName(false) return } setSavingName(true) try { const updated = await adminApi.updateAccount(account.id, { name: editedName.trim() }) setAccount(updated) setEditedName(updated.name) setIsEditingName(false) toast.success('Account updated') } catch { toast.error('Failed to update account') } finally { setSavingName(false) } } const handleCreateUser = async () => { if (!account || !createForm.email || !createForm.name) return setCreateLoading(true) try { const result = await adminApi.createUser({ email: createForm.email, name: createForm.name, account_mode: 'existing', account_display_code: account.display_code, account_role: createForm.account_role, send_email: createForm.send_email, }) setShowCreateUserModal(false) setCreateForm({ email: '', name: '', account_role: 'engineer' as 'owner' | 'admin' | 'engineer' | 'viewer', send_email: true }) setTempPassword(result.temporary_password) setCopiedPassword(false) toast.success(result.email_sent ? 'User created and welcome email sent' : 'User created') loadAccount() } 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 create user') } else { toast.error('Failed to create user') } } finally { setCreateLoading(false) } } const handleInviteUser = async () => { if (!account || !inviteForm.email) return setInviteLoading(true) try { await adminApi.createInvite({ email: inviteForm.email, account_display_code: account.display_code, role: inviteForm.role, }) toast.success('Invite sent') setInviteForm({ email: '', role: 'engineer' }) setShowInviteModal(false) loadAccount() } 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 send invite') } else { toast.error('Failed to send invite') } } finally { setInviteLoading(false) } } const handleUpdateMemberRole = async (member: AdminAccountMember, nextRole: string) => { try { await adminApi.updateAccountRole(member.id, nextRole) toast.success(`Updated ${member.name}`) loadAccount() } catch { toast.error('Failed to update account role') } } const handleToggleActive = async (member: AdminAccountMember) => { try { if (member.is_active) { await adminApi.deactivateUser(member.id) toast.success('User deactivated') } else { await adminApi.activateUser(member.id) toast.success('User activated') } loadAccount() } catch { toast.error('Failed to update user status') } } const handleUpdatePlan = async () => { if (!account) return setPlanSaving(true) try { await adminApi.updateAccountSubscriptionPlan(account.id, selectedPlan) toast.success(`Plan updated to ${selectedPlan}`) setEditingPlan(false) loadAccount() } catch { toast.error('Failed to update plan') } finally { setPlanSaving(false) } } const handleExtendTrial = async () => { if (!account || !trialDays) return setTrialSaving(true) try { await adminApi.extendAccountTrial(account.id, parseInt(trialDays, 10)) toast.success(`Trial updated by ${trialDays} days`) setEditingTrial(false) loadAccount() } catch { toast.error('Failed to update trial') } finally { setTrialSaving(false) } } const copyDisplayCode = async () => { if (!account) return await navigator.clipboard.writeText(account.display_code) toast.success('Display code copied') } const copyTempPassword = async () => { if (!tempPassword) return await navigator.clipboard.writeText(tempPassword) setCopiedPassword(true) setTimeout(() => setCopiedPassword(false), 2000) } if (loading) { return (
) } if (!account) { return ( navigate('/admin/accounts')}>Back to Accounts} /> ) } return (

{account.name}

{account.display_code}

Manage account settings, subscription, invites, and users from one place.

Account Settings

{isEditingName ? (
setEditedName(e.target.value)} />
) : (
{account.name}
)}

Owner

{account.owner?.name ?? 'Unassigned'}

{account.owner?.email ?? 'No owner user yet'}

Created

{formatDate(account.created_at)}

Users

{account.member_count} members
{account.members.length > 0 ? ( account.members.map((member) => (

{member.name}

{member.email}

{member.role} {member.account_role && {member.account_role}} {member.is_active ? 'Active' : 'Inactive'}
{member.is_active ? ( handleToggleActive(member)} confirmLabel="Confirm deactivate?" className="inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition-colors hover:bg-elevated" confirmClassName="inline-flex items-center rounded-md border border-danger/30 bg-danger-dim px-3 py-1.5 text-sm font-medium text-danger transition-colors" > Deactivate ) : ( )}
)) ) : (

No users yet.

Use Create User or Invite User above to add members.

)}
setShowCreateUserModal(false)} title="Create User in Account" size="sm" footer={(
)} >
setCreateForm((f) => ({ ...f, name: e.target.value }))} />
setCreateForm((f) => ({ ...f, email: e.target.value }))} />
setCreateForm((f) => ({ ...f, send_email: e.target.checked }))} className="rounded border-border bg-card" />
setShowInviteModal(false)} title="Invite User to Account" size="sm" footer={(
)} >
setInviteForm((f) => ({ ...f, email: e.target.value }))} />
setTempPassword(null)} title="User Created" size="sm" footer={
} >
This password will not be shown again. Copy it now.
{tempPassword}
) } export default AccountDetailPage