/** * @ai-summary Mobile admin screen for user management * @ai-context List users, search, filter, change tiers, deactivate/reactivate */ import React, { useState, useCallback } from 'react'; import { Navigate } from 'react-router-dom'; import { GlassCard } from '../../../shared-minimal/components/mobile/GlassCard'; import { MobileContainer } from '../../../shared-minimal/components/mobile/MobileContainer'; import { useAdminAccess } from '../../../core/auth/useAdminAccess'; import { useUsers, useUpdateUserTier, useDeactivateUser, useReactivateUser, useUpdateUserProfile, usePromoteToAdmin, useHardDeleteUser, useAdminStats, useUserVehicles, } from '../hooks/useUsers'; import { ManagedUser, SubscriptionTier, ListUsersParams, } from '../types/admin.types'; // Modal component for dialogs interface ModalProps { isOpen: boolean; onClose: () => void; title: string; children: React.ReactNode; actions?: React.ReactNode; } const Modal: React.FC = ({ isOpen, onClose, title, children, actions }) => { if (!isOpen) return null; return (

{title}

{children}
{actions || ( )}
); }; // Tier badge component const TierBadge: React.FC<{ tier: SubscriptionTier }> = ({ tier }) => { const colors: Record = { free: 'bg-gray-100 text-gray-700', pro: 'bg-blue-100 text-blue-700', enterprise: 'bg-purple-100 text-purple-700', }; return ( {tier.charAt(0).toUpperCase() + tier.slice(1)} ); }; // Status badge component const StatusBadge: React.FC<{ active: boolean }> = ({ active }) => ( {active ? 'Active' : 'Deactivated'} ); // Vehicle count badge component const VehicleCountBadge: React.FC<{ count: number; onClick?: () => void }> = ({ count, onClick }) => ( ); // Expandable vehicle list component const UserVehiclesList: React.FC<{ auth0Sub: string; isOpen: boolean }> = ({ auth0Sub, isOpen }) => { const { data, isLoading, error } = useUserVehicles(auth0Sub); if (!isOpen) return null; return (

Vehicles

{isLoading ? (
) : error ? (

Failed to load vehicles

) : !data?.vehicles?.length ? (

No vehicles registered

) : (
{data.vehicles.map((vehicle, idx) => (
{vehicle.year} {vehicle.make} {vehicle.model}
))}
)}
); }; export const AdminUsersMobileScreen: React.FC = () => { const { isAdmin, loading: adminLoading } = useAdminAccess(); // Filter state const [params, setParams] = useState({ page: 1, pageSize: 20, status: 'all', sortBy: 'createdAt', sortOrder: 'desc', }); const [searchInput, setSearchInput] = useState(''); const [showFilters, setShowFilters] = useState(false); // Query const { data, isLoading, error, refetch } = useUsers(params); // Admin stats const { data: statsData } = useAdminStats(); // Expanded user for vehicle list const [expandedUserId, setExpandedUserId] = useState(null); // Mutations const updateTierMutation = useUpdateUserTier(); const deactivateMutation = useDeactivateUser(); const reactivateMutation = useReactivateUser(); const updateProfileMutation = useUpdateUserProfile(); const promoteToAdminMutation = usePromoteToAdmin(); const hardDeleteMutation = useHardDeleteUser(); // Selected user for actions const [selectedUser, setSelectedUser] = useState(null); const [showUserActions, setShowUserActions] = useState(false); const [showTierPicker, setShowTierPicker] = useState(false); const [showDeactivateConfirm, setShowDeactivateConfirm] = useState(false); const [deactivateReason, setDeactivateReason] = useState(''); const [showEditModal, setShowEditModal] = useState(false); const [editEmail, setEditEmail] = useState(''); const [editDisplayName, setEditDisplayName] = useState(''); const [showPromoteModal, setShowPromoteModal] = useState(false); const [promoteRole, setPromoteRole] = useState<'admin' | 'super_admin'>('admin'); const [showHardDeleteModal, setShowHardDeleteModal] = useState(false); const [hardDeleteReason, setHardDeleteReason] = useState(''); const [hardDeleteConfirmText, setHardDeleteConfirmText] = useState(''); // Handlers const handleSearch = useCallback(() => { setParams(prev => ({ ...prev, search: searchInput || undefined, page: 1 })); }, [searchInput]); const handleClearSearch = useCallback(() => { setSearchInput(''); setParams(prev => ({ ...prev, search: undefined, page: 1 })); }, []); const handleTierFilterChange = useCallback((tier: SubscriptionTier | '') => { setParams(prev => ({ ...prev, tier: tier || undefined, page: 1, })); }, []); const handleStatusFilterChange = useCallback((status: 'active' | 'deactivated' | 'all') => { setParams(prev => ({ ...prev, status, page: 1 })); }, []); const handleUserClick = useCallback((user: ManagedUser) => { setSelectedUser(user); setShowUserActions(true); }, []); const handleTierChange = useCallback( (newTier: SubscriptionTier) => { if (selectedUser) { updateTierMutation.mutate( { auth0Sub: selectedUser.auth0Sub, data: { subscriptionTier: newTier } }, { onSuccess: () => { setShowTierPicker(false); setShowUserActions(false); setSelectedUser(null); }, } ); } }, [selectedUser, updateTierMutation] ); const handleDeactivate = useCallback(() => { if (selectedUser) { deactivateMutation.mutate( { auth0Sub: selectedUser.auth0Sub, data: { reason: deactivateReason || undefined } }, { onSuccess: () => { setShowDeactivateConfirm(false); setShowUserActions(false); setDeactivateReason(''); setSelectedUser(null); }, } ); } }, [selectedUser, deactivateReason, deactivateMutation]); const handleReactivate = useCallback(() => { if (selectedUser) { reactivateMutation.mutate(selectedUser.auth0Sub, { onSuccess: () => { setShowUserActions(false); setSelectedUser(null); }, }); } }, [selectedUser, reactivateMutation]); const handleEditClick = useCallback(() => { if (selectedUser) { setEditEmail(selectedUser.email); setEditDisplayName(selectedUser.displayName || ''); setShowUserActions(false); setShowEditModal(true); } }, [selectedUser]); const handleEditConfirm = useCallback(() => { if (selectedUser) { const updates: { email?: string; displayName?: string } = {}; if (editEmail !== selectedUser.email) { updates.email = editEmail; } if (editDisplayName !== (selectedUser.displayName || '')) { updates.displayName = editDisplayName; } if (Object.keys(updates).length > 0) { updateProfileMutation.mutate( { auth0Sub: selectedUser.auth0Sub, data: updates }, { onSuccess: () => { setShowEditModal(false); setEditEmail(''); setEditDisplayName(''); setSelectedUser(null); }, } ); } } }, [selectedUser, editEmail, editDisplayName, updateProfileMutation]); const handleEditCancel = useCallback(() => { setShowEditModal(false); setEditEmail(''); setEditDisplayName(''); setSelectedUser(null); }, []); const handlePromoteClick = useCallback(() => { setPromoteRole('admin'); setShowUserActions(false); setShowPromoteModal(true); }, []); const handlePromoteConfirm = useCallback(() => { if (selectedUser) { promoteToAdminMutation.mutate( { auth0Sub: selectedUser.auth0Sub, data: { role: promoteRole } }, { onSuccess: () => { setShowPromoteModal(false); setPromoteRole('admin'); setSelectedUser(null); }, } ); } }, [selectedUser, promoteRole, promoteToAdminMutation]); const handlePromoteCancel = useCallback(() => { setShowPromoteModal(false); setPromoteRole('admin'); setSelectedUser(null); }, []); const handleHardDeleteClick = useCallback(() => { setShowUserActions(false); setShowHardDeleteModal(true); }, []); const handleHardDeleteConfirm = useCallback(() => { if (selectedUser && hardDeleteConfirmText === 'DELETE') { hardDeleteMutation.mutate( { auth0Sub: selectedUser.auth0Sub, reason: hardDeleteReason || undefined }, { onSuccess: () => { setShowHardDeleteModal(false); setHardDeleteReason(''); setHardDeleteConfirmText(''); setSelectedUser(null); }, } ); } }, [selectedUser, hardDeleteReason, hardDeleteConfirmText, hardDeleteMutation]); const handleHardDeleteCancel = useCallback(() => { setShowHardDeleteModal(false); setHardDeleteReason(''); setHardDeleteConfirmText(''); setSelectedUser(null); }, []); const handleLoadMore = useCallback(() => { setParams(prev => ({ ...prev, page: (prev.page || 1) + 1 })); }, []); // Loading state if (adminLoading) { return (
Loading admin access...
); } // Not admin redirect if (!isAdmin) { return ; } const users = data?.users || []; const total = data?.total || 0; const hasMore = users.length < total; return (
{/* Header */}

User Management

{statsData?.totalUsers ?? total}

Users

{statsData?.totalVehicles ?? 0}

Vehicles

{/* Search Bar */}
setSearchInput(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleSearch()} className="w-full px-4 py-3 rounded-lg border border-slate-200 dark:border-silverstone dark:bg-scuro dark:text-avus focus:outline-none focus:ring-2 focus:ring-blue-500 min-h-[44px]" /> {searchInput && ( )}
{/* Filter Toggle */} {/* Filters */} {showFilters && (
{/* Tier Filter */}
{/* Status Filter */}
)}
{/* Loading State */} {isLoading && users.length === 0 && (
)} {/* Error State */} {error && (

Failed to load users. Please try again.

)} {/* Empty State */} {!isLoading && !error && users.length === 0 && (

No users found matching your criteria.

)} {/* User List */} {users.length > 0 && (
{users.map((user) => ( ))} {/* Load More */} {hasMore && ( )}
)}
{/* User Actions Modal */} { setShowUserActions(false); setSelectedUser(null); }} title="User Actions" actions={ } > {selectedUser && (

{selectedUser.email}

{!selectedUser.isAdmin && ( )} {selectedUser.deactivatedAt ? ( ) : ( )} {!selectedUser.isAdmin && ( )}
)}
{/* Tier Picker Modal */} setShowTierPicker(false)} title="Change Subscription Tier" actions={ } >
{(['free', 'pro', 'enterprise'] as SubscriptionTier[]).map((tier) => ( ))} {updateTierMutation.isPending && (

Updating...

)}
{/* Deactivate Confirmation Modal */} { setShowDeactivateConfirm(false); setDeactivateReason(''); }} title="Deactivate User" actions={ <> } >

Are you sure you want to deactivate{' '} {selectedUser?.email}?

The user will no longer be able to log in, but their data will be preserved.