@burdenoff/microfe-atheletebridge 2026.624.1 → 2026.625.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atheletebridge/components/EmptyState.js +18 -11
- package/dist/atheletebridge/components/EmptyState.js.map +1 -1
- package/dist/atheletebridge/components/InvestmentCard.js +7 -7
- package/dist/atheletebridge/components/InvestmentCard.js.map +1 -1
- package/dist/atheletebridge/components/MetricsCard.js +20 -14
- package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
- package/dist/atheletebridge/components/PageLayout.js +30 -19
- package/dist/atheletebridge/components/PageLayout.js.map +1 -1
- package/dist/atheletebridge/pages/HomePage.js +210 -195
- package/dist/atheletebridge/pages/HomePage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/AdminAnalyticsPage.js +90 -82
- package/dist/atheletebridge/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/AdminDashboard.js +76 -44
- package/dist/atheletebridge/pages/admin/AdminDashboard.js.map +1 -1
- package/dist/atheletebridge/pages/admin/AdminFinancialPage.js +63 -55
- package/dist/atheletebridge/pages/admin/AdminFinancialPage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/AdminOrdersPage.js +244 -237
- package/dist/atheletebridge/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/AdminProfilePage.js +59 -57
- package/dist/atheletebridge/pages/admin/AdminProfilePage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/AdminSettingsPage.js +110 -106
- package/dist/atheletebridge/pages/admin/AdminSettingsPage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/CartManagementPage.js +166 -159
- package/dist/atheletebridge/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/atheletebridge/pages/admin/UserManagementPage.js +310 -303
- package/dist/atheletebridge/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/AnalyticsDashboard.js +86 -81
- package/dist/atheletebridge/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/BusinessSettingsPage.js +170 -166
- package/dist/atheletebridge/pages/cart-owner/BusinessSettingsPage.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/CartOwnerDashboard.js +141 -109
- package/dist/atheletebridge/pages/cart-owner/CartOwnerDashboard.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/CartOwnerProfilePage.js +139 -134
- package/dist/atheletebridge/pages/cart-owner/CartOwnerProfilePage.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/CartServiceConfigPage.js +109 -107
- package/dist/atheletebridge/pages/cart-owner/CartServiceConfigPage.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/InventoryManagementPage.js +318 -318
- package/dist/atheletebridge/pages/cart-owner/InventoryManagementPage.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/OrderManagementPage.js +262 -262
- package/dist/atheletebridge/pages/cart-owner/OrderManagementPage.js.map +1 -1
- package/dist/atheletebridge/pages/cart-owner/StaffManagementPage.js +170 -162
- package/dist/atheletebridge/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/atheletebridge/pages/common/HelpSupportPage.js +292 -298
- package/dist/atheletebridge/pages/common/HelpSupportPage.js.map +1 -1
- package/dist/atheletebridge/pages/common/NotificationCenterPage.js +100 -91
- package/dist/atheletebridge/pages/common/NotificationCenterPage.js.map +1 -1
- package/dist/atheletebridge/pages/common/SettingsPage.js +742 -734
- package/dist/atheletebridge/pages/common/SettingsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/BookingDetailsPage.js +365 -356
- package/dist/atheletebridge/pages/customer/BookingDetailsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CartDetailPage.js +277 -241
- package/dist/atheletebridge/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js +261 -250
- package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CheckoutPage.js +93 -89
- package/dist/atheletebridge/pages/customer/CheckoutPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CustomerDashboard.js +430 -387
- package/dist/atheletebridge/pages/customer/CustomerDashboard.js.map +1 -1
- package/dist/atheletebridge/pages/customer/CustomerProfilePage.js +526 -490
- package/dist/atheletebridge/pages/customer/CustomerProfilePage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js +524 -512
- package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/FavoritesPage.js +84 -75
- package/dist/atheletebridge/pages/customer/FavoritesPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/OrderHistoryPage.js +117 -108
- package/dist/atheletebridge/pages/customer/OrderHistoryPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/OrderTrackingPage.js +66 -61
- package/dist/atheletebridge/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js +81 -75
- package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/ReviewsPage.js +81 -72
- package/dist/atheletebridge/pages/customer/ReviewsPage.js.map +1 -1
- package/dist/atheletebridge/pages/customer/SavedAddressesPage.js +63 -55
- package/dist/atheletebridge/pages/customer/SavedAddressesPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestmentDetailsPage.js +93 -61
- package/dist/atheletebridge/pages/investor/InvestmentDetailsPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js +90 -84
- package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestorAnalyticsPage.js +60 -55
- package/dist/atheletebridge/pages/investor/InvestorAnalyticsPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestorDashboard.js +345 -311
- package/dist/atheletebridge/pages/investor/InvestorDashboard.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js +38 -32
- package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestorPortfolioPage.js +75 -67
- package/dist/atheletebridge/pages/investor/InvestorPortfolioPage.js.map +1 -1
- package/dist/atheletebridge/pages/investor/InvestorProfilePage.js +385 -381
- package/dist/atheletebridge/pages/investor/InvestorProfilePage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/TaskDetailsPage.js +353 -319
- package/dist/atheletebridge/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/WorkerDashboard.js +353 -318
- package/dist/atheletebridge/pages/worker/WorkerDashboard.js.map +1 -1
- package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js +134 -128
- package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/WorkerProfilePage.js +81 -77
- package/dist/atheletebridge/pages/worker/WorkerProfilePage.js.map +1 -1
- package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js +352 -342
- package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserManagementPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/admin/UserManagementPage.tsx"],"sourcesContent":["/**\n * User Management Page\n * @module atheletebridge/pages/admin\n *\n * Full-featured user management with 8 stats cards, 5 filter controls,\n * dual layout (mobile cards + desktop table), user action modal\n * (edit form + delete confirmation), pagination, and loading state.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport {\n Search,\n Users,\n UserCheck,\n UserX,\n Shield,\n Eye,\n Edit3,\n Trash2,\n CheckCircle2,\n XCircle,\n Loader2,\n ChevronLeft,\n ChevronRight,\n Smartphone,\n Mail,\n Phone,\n X,\n} from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { cn } from '../../utils/cn';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\ninterface ExtendedUser {\n id: string;\n email: string;\n phone: string;\n firstName: string;\n lastName: string;\n role: 'customer' | 'cart_owner' | 'worker' | 'investor' | 'admin';\n isEmailVerified: boolean;\n isPhoneVerified: boolean;\n profilePicture: string;\n status: 'active' | 'inactive' | 'suspended' | 'pending';\n lastLoginTime?: string;\n totalOrders?: number;\n totalSpent?: number;\n totalEarnings?: number;\n kycStatus?: 'pending' | 'verified' | 'rejected';\n riskScore?: number;\n registrationDate: string;\n deviceInfo?: string;\n}\n\ninterface UserFilters {\n role: string;\n status: string;\n searchQuery: string;\n sortBy: string;\n registrationDate: string;\n}\n\ninterface UserStats {\n totalUsers: number;\n activeUsers: number;\n newUsers: number;\n verifiedUsers: number;\n customers: number;\n cartOwners: number;\n workers: number;\n investors: number;\n}\n\n/* ------------------------------------------------------------------ */\n/* Mock data */\n/* ------------------------------------------------------------------ */\n\nconst mockUsers: ExtendedUser[] = [\n {\n id: 'user-001',\n email: 'rahul.sharma@gmail.com',\n phone: '+91 98765 43210',\n firstName: 'Rahul',\n lastName: 'Sharma',\n role: 'customer',\n isEmailVerified: true,\n isPhoneVerified: true,\n profilePicture: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100',\n status: 'active',\n lastLoginTime: '2024-06-23T16:45:00Z',\n totalOrders: 45,\n totalSpent: 12350,\n registrationDate: '2024-01-15T08:30:00Z',\n deviceInfo: 'iPhone 14 Pro',\n },\n {\n id: 'user-002',\n email: 'priya.patel@gmail.com',\n phone: '+91 98765 43211',\n firstName: 'Priya',\n lastName: 'Patel',\n role: 'cart_owner',\n isEmailVerified: true,\n isPhoneVerified: true,\n profilePicture: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100',\n status: 'active',\n lastLoginTime: '2024-06-24T09:15:00Z',\n totalEarnings: 285000,\n kycStatus: 'verified',\n registrationDate: '2023-08-20T10:15:00Z',\n deviceInfo: 'Android Samsung',\n },\n {\n id: 'user-003',\n email: 'amit.kumar@gmail.com',\n phone: '+91 98765 43212',\n firstName: 'Amit',\n lastName: 'Kumar',\n role: 'worker',\n isEmailVerified: true,\n isPhoneVerified: false,\n profilePicture: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100',\n status: 'suspended',\n lastLoginTime: '2024-06-15T14:30:00Z',\n totalEarnings: 45000,\n kycStatus: 'pending',\n registrationDate: '2024-02-10T12:45:00Z',\n deviceInfo: 'Web Browser',\n },\n {\n id: 'user-004',\n email: 'sneha.investor@gmail.com',\n phone: '+91 98765 43213',\n firstName: 'Sneha',\n lastName: 'Reddy',\n role: 'investor',\n isEmailVerified: true,\n isPhoneVerified: true,\n profilePicture: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100',\n status: 'active',\n lastLoginTime: '2024-06-24T10:30:00Z',\n kycStatus: 'verified',\n riskScore: 2.1,\n registrationDate: '2023-12-01T15:20:00Z',\n deviceInfo: 'MacBook Pro',\n },\n {\n id: 'user-005',\n email: 'new.user@gmail.com',\n phone: '+91 98765 43214',\n firstName: 'New',\n lastName: 'User',\n role: 'customer',\n isEmailVerified: false,\n isPhoneVerified: false,\n profilePicture: '',\n status: 'pending',\n registrationDate: '2024-06-24T09:00:00Z',\n deviceInfo: 'iPhone 15',\n },\n];\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function UserManagementPage() {\n const { navigateTo } = useAthleteBridge();\n\n const [users, setUsers] = useState<ExtendedUser[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedUser, setSelectedUser] = useState<ExtendedUser | null>(null);\n const [showUserModal, setShowUserModal] = useState(false);\n const [actionType, setActionType] = useState<'edit' | 'delete'>('edit');\n const [editForm, setEditForm] = useState({\n firstName: '',\n lastName: '',\n email: '',\n phone: '',\n role: '',\n });\n const [currentPage, setCurrentPage] = useState(1);\n const itemsPerPage = 10;\n\n const [filters, setFilters] = useState<UserFilters>({\n role: '',\n status: '',\n searchQuery: '',\n sortBy: 'recent',\n registrationDate: '',\n });\n\n const [stats] = useState<UserStats>({\n totalUsers: 2456,\n activeUsers: 2134,\n newUsers: 89,\n verifiedUsers: 2021,\n customers: 1845,\n cartOwners: 342,\n workers: 156,\n investors: 113,\n });\n\n const loadUsers = useCallback(() => {\n setLoading(true);\n setTimeout(() => {\n let filtered = [...mockUsers];\n\n if (filters.searchQuery) {\n const q = filters.searchQuery.toLowerCase();\n filtered = filtered.filter(\n (u) =>\n u.firstName.toLowerCase().includes(q) ||\n u.lastName.toLowerCase().includes(q) ||\n u.email.toLowerCase().includes(q) ||\n u.phone.includes(q)\n );\n }\n if (filters.role) filtered = filtered.filter((u) => u.role === filters.role);\n if (filters.status) filtered = filtered.filter((u) => u.status === filters.status);\n if (filters.registrationDate) {\n const days = parseInt(filters.registrationDate);\n const cutoff = new Date(Date.now() - days * 86400000);\n filtered = filtered.filter((u) => new Date(u.registrationDate) >= cutoff);\n }\n\n switch (filters.sortBy) {\n case 'name':\n filtered.sort((a, b) => a.firstName.localeCompare(b.firstName));\n break;\n case 'activity':\n filtered.sort((a, b) => {\n const aT = a.lastLoginTime ? new Date(a.lastLoginTime).getTime() : 0;\n const bT = b.lastLoginTime ? new Date(b.lastLoginTime).getTime() : 0;\n return bT - aT;\n });\n break;\n default:\n filtered.sort(\n (a, b) =>\n new Date(b.registrationDate).getTime() - new Date(a.registrationDate).getTime()\n );\n }\n\n setUsers(filtered);\n setLoading(false);\n }, 800);\n }, [filters]);\n\n useEffect(() => {\n loadUsers();\n }, [loadUsers]);\n\n const handleFilterChange = (key: keyof UserFilters, value: string) => {\n setFilters((prev) => ({ ...prev, [key]: value }));\n setCurrentPage(1);\n };\n\n const handleUserAction = (\n user: ExtendedUser,\n action: 'edit' | 'suspend' | 'activate' | 'delete' | 'verify'\n ) => {\n if (action === 'suspend' || action === 'activate' || action === 'verify') {\n const msg =\n action === 'suspend'\n ? `User ${user.firstName} ${user.lastName} suspended`\n : action === 'activate'\n ? `User ${user.firstName} ${user.lastName} activated`\n : `User ${user.firstName} ${user.lastName} verified`;\n alert(msg);\n loadUsers();\n return;\n }\n setSelectedUser(user);\n setActionType(action);\n setEditForm({\n firstName: user.firstName,\n lastName: user.lastName,\n email: user.email,\n phone: user.phone,\n role: user.role,\n });\n setShowUserModal(true);\n };\n\n const handleDeleteConfirm = () => {\n if (selectedUser) {\n alert(`User ${selectedUser.firstName} ${selectedUser.lastName} deleted`);\n setShowUserModal(false);\n loadUsers();\n }\n };\n\n const handleSaveEdit = () => {\n alert('User updated successfully');\n setShowUserModal(false);\n loadUsers();\n };\n\n const formatDate = (d: string) =>\n new Date(d).toLocaleDateString('en-IN', { year: 'numeric', month: 'short', day: 'numeric' });\n\n const formatCurrency = (amount: number) => `₹${amount.toLocaleString('en-IN')}`;\n\n const pagedUsers = useMemo(() => {\n const start = (currentPage - 1) * itemsPerPage;\n return users.slice(start, start + itemsPerPage);\n }, [users, currentPage]);\n\n const roleBadge = (role: string) => {\n const c: Record<string, string> = {\n customer: 'bg-blue-500/20 text-blue-600 dark:text-blue-400',\n cart_owner: 'bg-green-500/20 text-green-600 dark:text-green-400',\n worker: 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400',\n investor: 'bg-purple-500/20 text-purple-600 dark:text-purple-400',\n admin: 'bg-red-500/20 text-red-600 dark:text-red-400',\n };\n const l: Record<string, string> = {\n customer: 'Customer',\n cart_owner: 'Cart Owner',\n worker: 'Worker',\n investor: 'Investor',\n admin: 'Admin',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',\n c[role]\n )}\n >\n {l[role] ?? role}\n </span>\n );\n };\n\n const statusBadge = (status: string) => {\n const c: Record<string, string> = {\n active: 'bg-green-500/20 text-green-600 dark:text-green-400',\n inactive: 'bg-secondary text-secondary-foreground',\n suspended: 'bg-red-500/20 text-red-600 dark:text-red-400',\n pending: 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize',\n c[status]\n )}\n >\n {status}\n </span>\n );\n };\n\n /* ---- Loading ---- */\n if (loading) {\n return (\n <PageLayout title=\"User Management\" description=\"Loading users...\">\n <div className=\"flex flex-col items-center justify-center py-20\">\n <Loader2 className=\"h-10 w-10 animate-spin text-text-secondary mb-4\" />\n <p className=\"text-text-secondary\">Loading users...</p>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"User Management\"\n description={`${stats.totalUsers.toLocaleString('en-IN')} registered users on the platform`}\n >\n {/* 8 Stats Cards */}\n <div className=\"grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-8 gap-3 mb-6\">\n {[\n { label: 'Total Users', value: stats.totalUsers.toLocaleString('en-IN'), cls: '' },\n {\n label: 'Active',\n value: stats.activeUsers.toLocaleString('en-IN'),\n cls: 'bg-green-500/10 border-green-500/30',\n },\n {\n label: 'New (30d)',\n value: stats.newUsers.toString(),\n cls: 'bg-blue-500/10 border-blue-500/30',\n },\n {\n label: 'Verified',\n value: stats.verifiedUsers.toLocaleString('en-IN'),\n cls: 'bg-purple-500/10 border-purple-500/30',\n },\n { label: 'Customers', value: stats.customers.toLocaleString('en-IN'), cls: '' },\n { label: 'Cart Owners', value: stats.cartOwners.toString(), cls: '' },\n { label: 'Workers', value: stats.workers.toString(), cls: '' },\n { label: 'Investors', value: stats.investors.toString(), cls: '' },\n ].map((s) => (\n <div key={s.label} className={cn('rounded-lg border border-border-subtle bg-bg-surface p-3', s.cls)}>\n <p className=\"text-xs text-text-secondary\">{s.label}</p>\n <p className=\"text-lg font-bold text-text-primary\">{s.value}</p>\n </div>\n ))}\n </div>\n\n {/* 5 Filter Controls */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 mb-6\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search users...\"\n value={filters.searchQuery}\n onChange={(e) => handleFilterChange('searchQuery', e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-4 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <select\n value={filters.role}\n onChange={(e) => handleFilterChange('role', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Roles</option>\n <option value=\"customer\">Customers</option>\n <option value=\"cart_owner\">Cart Owners</option>\n <option value=\"worker\">Workers</option>\n <option value=\"investor\">Investors</option>\n </select>\n <select\n value={filters.status}\n onChange={(e) => handleFilterChange('status', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Status</option>\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n <option value=\"suspended\">Suspended</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={filters.registrationDate}\n onChange={(e) => handleFilterChange('registrationDate', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Time</option>\n <option value=\"1\">Last 24 hours</option>\n <option value=\"7\">Last 7 days</option>\n <option value=\"30\">Last 30 days</option>\n <option value=\"90\">Last 90 days</option>\n </select>\n <select\n value={filters.sortBy}\n onChange={(e) => handleFilterChange('sortBy', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"recent\">Most Recent</option>\n <option value=\"name\">Name A-Z</option>\n <option value=\"activity\">Last Activity</option>\n </select>\n </div>\n </div>\n\n {/* Dual Layout */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface overflow-hidden\">\n {/* Mobile Card View */}\n <div className=\"block md:hidden space-y-4 p-4\">\n {pagedUsers.map((user) => (\n <div key={user.id} className=\"rounded-lg border border-border-subtle bg-bg-sunken/30 p-4\">\n <div className=\"flex items-center mb-3\">\n {user.profilePicture ? (\n <img\n src={user.profilePicture}\n alt={`${user.firstName} ${user.lastName}`}\n className=\"w-12 h-12 rounded-full object-cover mr-3\"\n />\n ) : (\n <div className=\"w-12 h-12 rounded-full bg-bg-sunken flex items-center justify-center mr-3\">\n <Users className=\"h-6 w-6 text-text-secondary\" />\n </div>\n )}\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-medium text-text-primary\">\n {user.firstName} {user.lastName}\n </h3>\n <p className=\"text-sm text-text-secondary truncate\">{user.email}</p>\n <p className=\"text-sm text-text-secondary\">{user.phone}</p>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-2 mb-3\">\n {roleBadge(user.role)}\n {statusBadge(user.status)}\n </div>\n <div className=\"grid grid-cols-2 gap-4 text-sm mb-3\">\n <div>\n <p className=\"text-text-secondary\">Registered</p>\n <p className=\"text-text-primary\">{formatDate(user.registrationDate)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Last Login</p>\n <p className=\"text-text-primary\">\n {user.lastLoginTime ? formatDate(user.lastLoginTime) : 'Never'}\n </p>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-3 mb-3\">\n <div className=\"flex items-center\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-2',\n user.isEmailVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Email</span>\n </div>\n <div className=\"flex items-center\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-2',\n user.isPhoneVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Phone</span>\n </div>\n {user.kycStatus && (\n <div className=\"flex items-center\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-2',\n user.kycStatus === 'verified'\n ? 'bg-green-500'\n : user.kycStatus === 'pending'\n ? 'bg-yellow-500'\n : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">KYC</span>\n </div>\n )}\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'edit')}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Edit\n </button>\n {user.status === 'active' ? (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'suspend')}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-sm font-medium text-red-600 hover:bg-red-500/10 transition-colors\"\n >\n Suspend\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'activate')}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-sm font-medium text-green-600 hover:bg-green-500/10 transition-colors\"\n >\n Activate\n </button>\n )}\n {user.kycStatus === 'pending' && (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'verify')}\n className=\"rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Verify\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n\n {/* Desktop Table View */}\n <div className=\"hidden md:block overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-sunken/50\">\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n User\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Role & Status\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Activity\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Performance\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Verification\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {pagedUsers.map((user) => (\n <tr key={user.id} className=\"hover:bg-accent/50 transition-colors\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n {user.profilePicture ? (\n <img\n src={user.profilePicture}\n alt={`${user.firstName}`}\n className=\"w-10 h-10 rounded-full object-cover\"\n />\n ) : (\n <div className=\"w-10 h-10 rounded-full bg-bg-sunken flex items-center justify-center\">\n <Users className=\"h-5 w-5 text-text-secondary\" />\n </div>\n )}\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {user.firstName} {user.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">{user.email}</p>\n <p className=\"text-xs text-text-secondary\">{user.phone}</p>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"space-y-1\">\n {roleBadge(user.role)}\n <br />\n {statusBadge(user.status)}\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm\">\n <p className=\"text-text-primary\">\n Registered: {formatDate(user.registrationDate)}\n </p>\n {user.lastLoginTime && (\n <p className=\"text-text-secondary\">\n Last login: {formatDate(user.lastLoginTime)}\n </p>\n )}\n {user.deviceInfo && (\n <p className=\"text-text-secondary flex items-center gap-1\">\n <Smartphone className=\"h-3 w-3\" />\n {user.deviceInfo}\n </p>\n )}\n </td>\n <td className=\"px-4 py-3 text-sm\">\n {user.role === 'customer' && user.totalOrders != null && (\n <>\n <p className=\"text-text-primary\">{user.totalOrders} orders</p>\n <p className=\"text-text-secondary\">\n {formatCurrency(user.totalSpent ?? 0)} spent\n </p>\n </>\n )}\n {(user.role === 'cart_owner' || user.role === 'worker') &&\n user.totalEarnings != null && (\n <p className=\"text-text-primary\">\n {formatCurrency(user.totalEarnings)} earned\n </p>\n )}\n {user.role === 'investor' && user.riskScore != null && (\n <p className=\"text-text-primary\">Risk: {user.riskScore}/5</p>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full',\n user.isEmailVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Email</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full',\n user.isPhoneVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Phone</span>\n </div>\n {user.kycStatus && (\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full',\n user.kycStatus === 'verified'\n ? 'bg-green-500'\n : user.kycStatus === 'pending'\n ? 'bg-yellow-500'\n : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">KYC</span>\n </div>\n )}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'edit')}\n title=\"Edit\"\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-accent transition-colors\"\n >\n <Edit3 className=\"h-4 w-4\" />\n </button>\n {user.status === 'active' ? (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'suspend')}\n title=\"Suspend\"\n className=\"rounded p-1.5 text-text-secondary hover:text-red-600 hover:bg-red-500/10 transition-colors\"\n >\n <UserX className=\"h-4 w-4\" />\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'activate')}\n title=\"Activate\"\n className=\"rounded p-1.5 text-text-secondary hover:text-green-600 hover:bg-green-500/10 transition-colors\"\n >\n <UserCheck className=\"h-4 w-4\" />\n </button>\n )}\n {user.kycStatus === 'pending' && (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'verify')}\n title=\"Verify\"\n className=\"rounded p-1.5 text-text-secondary hover:text-blue-600 hover:bg-blue-500/10 transition-colors\"\n >\n <Shield className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {users.length === 0 && (\n <div className=\"flex flex-col items-center justify-center py-12 px-4\">\n <Users className=\"h-10 w-10 text-text-secondary/50 mb-3\" />\n <p className=\"text-sm text-text-secondary\">No users found matching your criteria</p>\n </div>\n )}\n </div>\n\n {/* Pagination */}\n <div className=\"mt-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4\">\n <p className=\"text-sm text-text-secondary text-center sm:text-left\">\n Showing{' '}\n <span className=\"font-medium\">\n {Math.min((currentPage - 1) * itemsPerPage + 1, users.length)}\n </span>{' '}\n to{' '}\n <span className=\"font-medium\">{Math.min(currentPage * itemsPerPage, users.length)}</span>{' '}\n of <span className=\"font-medium\">{users.length}</span> results\n </p>\n <div className=\"flex justify-center sm:justify-end gap-2\">\n <button\n type=\"button\"\n disabled={currentPage === 1}\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n Previous\n </button>\n <button\n type=\"button\"\n disabled={currentPage * itemsPerPage >= users.length}\n onClick={() => setCurrentPage((p) => p + 1)}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Next\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n\n {/* User Action Modal */}\n {showUserModal && selectedUser && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-border-subtle bg-bg-surface shadow-lg max-h-[90vh] overflow-y-auto\">\n <div className=\"flex items-center justify-between p-4 border-b border-border-subtle\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {actionType === 'edit' ? 'Edit User' : 'Delete User'}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowUserModal(false)}\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-accent transition-colors\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <div className=\"p-4\">\n {actionType === 'delete' ? (\n <div>\n <p className=\"text-text-secondary mb-4\">\n Are you sure you want to delete user "{selectedUser.firstName}{' '}\n {selectedUser.lastName}"? This action cannot be undone.\n </p>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={() => setShowUserModal(false)}\n className=\"flex-1 rounded-lg border border-border-subtle py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleDeleteConfirm}\n className=\"flex-1 rounded-lg bg-red-600 hover:bg-red-700 py-2 text-sm font-medium text-white transition-colors\"\n >\n Delete User\n </button>\n </div>\n </div>\n ) : (\n <div>\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n First Name\n </label>\n <input\n type=\"text\"\n value={editForm.firstName}\n onChange={(e) =>\n setEditForm((f) => ({ ...f, firstName: e.target.value }))\n }\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Last Name\n </label>\n <input\n type=\"text\"\n value={editForm.lastName}\n onChange={(e) => setEditForm((f) => ({ ...f, lastName: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Email\n </label>\n <input\n type=\"email\"\n value={editForm.email}\n onChange={(e) => setEditForm((f) => ({ ...f, email: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Phone\n </label>\n <input\n type=\"tel\"\n value={editForm.phone}\n onChange={(e) => setEditForm((f) => ({ ...f, phone: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Role\n </label>\n <select\n value={editForm.role}\n onChange={(e) => setEditForm((f) => ({ ...f, role: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"customer\">Customer</option>\n <option value=\"cart_owner\">Cart Owner</option>\n <option value=\"worker\">Worker</option>\n <option value=\"investor\">Investor</option>\n </select>\n </div>\n </div>\n <div className=\"flex gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowUserModal(false)}\n className=\"flex-1 rounded-lg border border-border-subtle py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSaveEdit}\n className=\"flex-1 rounded-lg bg-action-primary-bg py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Save Changes\n </button>\n <button\n type=\"button\"\n onClick={() => setActionType('delete')}\n className=\"rounded-lg border border-border-subtle py-2 px-3 text-sm font-medium text-red-600 hover:bg-red-500/10 transition-colors\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UserManagementPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/admin/UserManagementPage.tsx"],"sourcesContent":["/**\n * User Management Page\n * @module atheletebridge/pages/admin\n *\n * Full-featured user management with 8 stats cards, 5 filter controls,\n * dual layout (mobile cards + desktop table), user action modal\n * (edit form + delete confirmation), pagination, and loading state.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport {\n Search,\n Users,\n UserCheck,\n UserX,\n Shield,\n Eye,\n Edit3,\n Trash2,\n CheckCircle2,\n XCircle,\n Loader2,\n ChevronLeft,\n ChevronRight,\n Smartphone,\n Mail,\n Phone,\n X,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { cn } from '../../utils/cn';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\ninterface ExtendedUser {\n id: string;\n email: string;\n phone: string;\n firstName: string;\n lastName: string;\n role: 'customer' | 'cart_owner' | 'worker' | 'investor' | 'admin';\n isEmailVerified: boolean;\n isPhoneVerified: boolean;\n profilePicture: string;\n status: 'active' | 'inactive' | 'suspended' | 'pending';\n lastLoginTime?: string;\n totalOrders?: number;\n totalSpent?: number;\n totalEarnings?: number;\n kycStatus?: 'pending' | 'verified' | 'rejected';\n riskScore?: number;\n registrationDate: string;\n deviceInfo?: string;\n}\n\ninterface UserFilters {\n role: string;\n status: string;\n searchQuery: string;\n sortBy: string;\n registrationDate: string;\n}\n\ninterface UserStats {\n totalUsers: number;\n activeUsers: number;\n newUsers: number;\n verifiedUsers: number;\n customers: number;\n cartOwners: number;\n workers: number;\n investors: number;\n}\n\n/* ------------------------------------------------------------------ */\n/* Mock data */\n/* ------------------------------------------------------------------ */\n\nconst mockUsers: ExtendedUser[] = [\n {\n id: 'user-001',\n email: 'rahul.sharma@gmail.com',\n phone: '+91 98765 43210',\n firstName: 'Rahul',\n lastName: 'Sharma',\n role: 'customer',\n isEmailVerified: true,\n isPhoneVerified: true,\n profilePicture: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100',\n status: 'active',\n lastLoginTime: '2024-06-23T16:45:00Z',\n totalOrders: 45,\n totalSpent: 12350,\n registrationDate: '2024-01-15T08:30:00Z',\n deviceInfo: 'iPhone 14 Pro',\n },\n {\n id: 'user-002',\n email: 'priya.patel@gmail.com',\n phone: '+91 98765 43211',\n firstName: 'Priya',\n lastName: 'Patel',\n role: 'cart_owner',\n isEmailVerified: true,\n isPhoneVerified: true,\n profilePicture: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100',\n status: 'active',\n lastLoginTime: '2024-06-24T09:15:00Z',\n totalEarnings: 285000,\n kycStatus: 'verified',\n registrationDate: '2023-08-20T10:15:00Z',\n deviceInfo: 'Android Samsung',\n },\n {\n id: 'user-003',\n email: 'amit.kumar@gmail.com',\n phone: '+91 98765 43212',\n firstName: 'Amit',\n lastName: 'Kumar',\n role: 'worker',\n isEmailVerified: true,\n isPhoneVerified: false,\n profilePicture: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100',\n status: 'suspended',\n lastLoginTime: '2024-06-15T14:30:00Z',\n totalEarnings: 45000,\n kycStatus: 'pending',\n registrationDate: '2024-02-10T12:45:00Z',\n deviceInfo: 'Web Browser',\n },\n {\n id: 'user-004',\n email: 'sneha.investor@gmail.com',\n phone: '+91 98765 43213',\n firstName: 'Sneha',\n lastName: 'Reddy',\n role: 'investor',\n isEmailVerified: true,\n isPhoneVerified: true,\n profilePicture: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100',\n status: 'active',\n lastLoginTime: '2024-06-24T10:30:00Z',\n kycStatus: 'verified',\n riskScore: 2.1,\n registrationDate: '2023-12-01T15:20:00Z',\n deviceInfo: 'MacBook Pro',\n },\n {\n id: 'user-005',\n email: 'new.user@gmail.com',\n phone: '+91 98765 43214',\n firstName: 'New',\n lastName: 'User',\n role: 'customer',\n isEmailVerified: false,\n isPhoneVerified: false,\n profilePicture: '',\n status: 'pending',\n registrationDate: '2024-06-24T09:00:00Z',\n deviceInfo: 'iPhone 15',\n },\n];\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function UserManagementPage() {\n const { navigateTo } = useAthleteBridge();\n\n const [users, setUsers] = useState<ExtendedUser[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedUser, setSelectedUser] = useState<ExtendedUser | null>(null);\n const [showUserModal, setShowUserModal] = useState(false);\n const [actionType, setActionType] = useState<'edit' | 'delete'>('edit');\n const [editForm, setEditForm] = useState({\n firstName: '',\n lastName: '',\n email: '',\n phone: '',\n role: '',\n });\n const [currentPage, setCurrentPage] = useState(1);\n const itemsPerPage = 10;\n\n const [filters, setFilters] = useState<UserFilters>({\n role: '',\n status: '',\n searchQuery: '',\n sortBy: 'recent',\n registrationDate: '',\n });\n\n const [stats] = useState<UserStats>({\n totalUsers: 2456,\n activeUsers: 2134,\n newUsers: 89,\n verifiedUsers: 2021,\n customers: 1845,\n cartOwners: 342,\n workers: 156,\n investors: 113,\n });\n\n const loadUsers = useCallback(() => {\n setLoading(true);\n setTimeout(() => {\n let filtered = [...mockUsers];\n\n if (filters.searchQuery) {\n const q = filters.searchQuery.toLowerCase();\n filtered = filtered.filter(\n (u) =>\n u.firstName.toLowerCase().includes(q) ||\n u.lastName.toLowerCase().includes(q) ||\n u.email.toLowerCase().includes(q) ||\n u.phone.includes(q)\n );\n }\n if (filters.role) filtered = filtered.filter((u) => u.role === filters.role);\n if (filters.status) filtered = filtered.filter((u) => u.status === filters.status);\n if (filters.registrationDate) {\n const days = parseInt(filters.registrationDate);\n const cutoff = new Date(Date.now() - days * 86400000);\n filtered = filtered.filter((u) => new Date(u.registrationDate) >= cutoff);\n }\n\n switch (filters.sortBy) {\n case 'name':\n filtered.sort((a, b) => a.firstName.localeCompare(b.firstName));\n break;\n case 'activity':\n filtered.sort((a, b) => {\n const aT = a.lastLoginTime ? new Date(a.lastLoginTime).getTime() : 0;\n const bT = b.lastLoginTime ? new Date(b.lastLoginTime).getTime() : 0;\n return bT - aT;\n });\n break;\n default:\n filtered.sort(\n (a, b) =>\n new Date(b.registrationDate).getTime() - new Date(a.registrationDate).getTime()\n );\n }\n\n setUsers(filtered);\n setLoading(false);\n }, 800);\n }, [filters]);\n\n useEffect(() => {\n loadUsers();\n }, [loadUsers]);\n\n const handleFilterChange = (key: keyof UserFilters, value: string) => {\n setFilters((prev) => ({ ...prev, [key]: value }));\n setCurrentPage(1);\n };\n\n const handleUserAction = (\n user: ExtendedUser,\n action: 'edit' | 'suspend' | 'activate' | 'delete' | 'verify'\n ) => {\n if (action === 'suspend' || action === 'activate' || action === 'verify') {\n const msg =\n action === 'suspend'\n ? `User ${user.firstName} ${user.lastName} suspended`\n : action === 'activate'\n ? `User ${user.firstName} ${user.lastName} activated`\n : `User ${user.firstName} ${user.lastName} verified`;\n alert(msg);\n loadUsers();\n return;\n }\n setSelectedUser(user);\n setActionType(action);\n setEditForm({\n firstName: user.firstName,\n lastName: user.lastName,\n email: user.email,\n phone: user.phone,\n role: user.role,\n });\n setShowUserModal(true);\n };\n\n const handleDeleteConfirm = () => {\n if (selectedUser) {\n alert(`User ${selectedUser.firstName} ${selectedUser.lastName} deleted`);\n setShowUserModal(false);\n loadUsers();\n }\n };\n\n const handleSaveEdit = () => {\n alert('User updated successfully');\n setShowUserModal(false);\n loadUsers();\n };\n\n const formatDate = (d: string) =>\n new Date(d).toLocaleDateString('en-IN', { year: 'numeric', month: 'short', day: 'numeric' });\n\n const formatCurrency = (amount: number) => `₹${amount.toLocaleString('en-IN')}`;\n\n const pagedUsers = useMemo(() => {\n const start = (currentPage - 1) * itemsPerPage;\n return users.slice(start, start + itemsPerPage);\n }, [users, currentPage]);\n\n const roleBadge = (role: string) => {\n const c: Record<string, string> = {\n customer: 'bg-blue-500/20 text-blue-600 dark:text-blue-400',\n cart_owner: 'bg-green-500/20 text-green-600 dark:text-green-400',\n worker: 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400',\n investor: 'bg-purple-500/20 text-purple-600 dark:text-purple-400',\n admin: 'bg-red-500/20 text-red-600 dark:text-red-400',\n };\n const l: Record<string, string> = {\n customer: 'Customer',\n cart_owner: 'Cart Owner',\n worker: 'Worker',\n investor: 'Investor',\n admin: 'Admin',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',\n c[role]\n )}\n >\n {l[role] ?? role}\n </span>\n );\n };\n\n const statusBadge = (status: string) => {\n const c: Record<string, string> = {\n active: 'bg-green-500/20 text-green-600 dark:text-green-400',\n inactive: 'bg-secondary text-secondary-foreground',\n suspended: 'bg-red-500/20 text-red-600 dark:text-red-400',\n pending: 'bg-yellow-500/20 text-yellow-600 dark:text-yellow-400',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize',\n c[status]\n )}\n >\n {status}\n </span>\n );\n };\n\n /* ---- Loading ---- */\n if (loading) {\n return (\n <PageLayout title=\"User Management\" description=\"Loading users...\">\n <div className=\"flex flex-col items-center justify-center py-20\">\n <Loader2 className=\"h-10 w-10 animate-spin text-text-secondary mb-4\" />\n <p className=\"text-text-secondary\">Loading users...</p>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"User Management\"\n description={`${stats.totalUsers.toLocaleString('en-IN')} registered users on the platform`}\n >\n <PagePurpose className=\"mb-6\">\n Manage everyone on the platform — customers, cart owners, workers and investors. Search and\n filter the user base, review verification and activity, and take action on individual\n accounts. Use this page to keep the community healthy and roles correct.\n </PagePurpose>\n\n {/* 8 Stats Cards */}\n <EmphasisPanel className=\"mb-6\">\n <div className=\"grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-8 gap-3\">\n {[\n { label: 'Total Users', value: stats.totalUsers.toLocaleString('en-IN'), cls: '' },\n {\n label: 'Active',\n value: stats.activeUsers.toLocaleString('en-IN'),\n cls: 'bg-green-500/10 border-green-500/30',\n },\n {\n label: 'New (30d)',\n value: stats.newUsers.toString(),\n cls: 'bg-blue-500/10 border-blue-500/30',\n },\n {\n label: 'Verified',\n value: stats.verifiedUsers.toLocaleString('en-IN'),\n cls: 'bg-purple-500/10 border-purple-500/30',\n },\n { label: 'Customers', value: stats.customers.toLocaleString('en-IN'), cls: '' },\n { label: 'Cart Owners', value: stats.cartOwners.toString(), cls: '' },\n { label: 'Workers', value: stats.workers.toString(), cls: '' },\n { label: 'Investors', value: stats.investors.toString(), cls: '' },\n ].map((s) => (\n <div key={s.label} className={cn('rounded-lg border border-border-subtle bg-bg-surface p-3', s.cls)}>\n <p className=\"text-xs text-text-secondary\">{s.label}</p>\n <p className=\"text-lg font-bold text-text-primary\">{s.value}</p>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* 5 Filter Controls */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 mb-6\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search users...\"\n value={filters.searchQuery}\n onChange={(e) => handleFilterChange('searchQuery', e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-4 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <select\n value={filters.role}\n onChange={(e) => handleFilterChange('role', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Roles</option>\n <option value=\"customer\">Customers</option>\n <option value=\"cart_owner\">Cart Owners</option>\n <option value=\"worker\">Workers</option>\n <option value=\"investor\">Investors</option>\n </select>\n <select\n value={filters.status}\n onChange={(e) => handleFilterChange('status', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Status</option>\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n <option value=\"suspended\">Suspended</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={filters.registrationDate}\n onChange={(e) => handleFilterChange('registrationDate', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Time</option>\n <option value=\"1\">Last 24 hours</option>\n <option value=\"7\">Last 7 days</option>\n <option value=\"30\">Last 30 days</option>\n <option value=\"90\">Last 90 days</option>\n </select>\n <select\n value={filters.sortBy}\n onChange={(e) => handleFilterChange('sortBy', e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"recent\">Most Recent</option>\n <option value=\"name\">Name A-Z</option>\n <option value=\"activity\">Last Activity</option>\n </select>\n </div>\n </div>\n\n {/* Dual Layout */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface overflow-hidden\">\n {/* Mobile Card View */}\n <div className=\"block md:hidden space-y-4 p-4\">\n {pagedUsers.map((user) => (\n <div key={user.id} className=\"rounded-lg border border-border-subtle bg-bg-sunken/30 p-4\">\n <div className=\"flex items-center mb-3\">\n {user.profilePicture ? (\n <img\n src={user.profilePicture}\n alt={`${user.firstName} ${user.lastName}`}\n className=\"w-12 h-12 rounded-full object-cover mr-3\"\n />\n ) : (\n <div className=\"w-12 h-12 rounded-full bg-bg-sunken flex items-center justify-center mr-3\">\n <Users className=\"h-6 w-6 text-text-secondary\" />\n </div>\n )}\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-medium text-text-primary\">\n {user.firstName} {user.lastName}\n </h3>\n <p className=\"text-sm text-text-secondary truncate\">{user.email}</p>\n <p className=\"text-sm text-text-secondary\">{user.phone}</p>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-2 mb-3\">\n {roleBadge(user.role)}\n {statusBadge(user.status)}\n </div>\n <div className=\"grid grid-cols-2 gap-4 text-sm mb-3\">\n <div>\n <p className=\"text-text-secondary\">Registered</p>\n <p className=\"text-text-primary\">{formatDate(user.registrationDate)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Last Login</p>\n <p className=\"text-text-primary\">\n {user.lastLoginTime ? formatDate(user.lastLoginTime) : 'Never'}\n </p>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-3 mb-3\">\n <div className=\"flex items-center\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-2',\n user.isEmailVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Email</span>\n </div>\n <div className=\"flex items-center\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-2',\n user.isPhoneVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Phone</span>\n </div>\n {user.kycStatus && (\n <div className=\"flex items-center\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-2',\n user.kycStatus === 'verified'\n ? 'bg-green-500'\n : user.kycStatus === 'pending'\n ? 'bg-yellow-500'\n : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">KYC</span>\n </div>\n )}\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'edit')}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Edit\n </button>\n {user.status === 'active' ? (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'suspend')}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-sm font-medium text-red-600 hover:bg-red-500/10 transition-colors\"\n >\n Suspend\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'activate')}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-sm font-medium text-green-600 hover:bg-green-500/10 transition-colors\"\n >\n Activate\n </button>\n )}\n {user.kycStatus === 'pending' && (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'verify')}\n className=\"rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Verify\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n\n {/* Desktop Table View */}\n <div className=\"hidden md:block overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-sunken/50\">\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n User\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Role & Status\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Activity\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Performance\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Verification\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {pagedUsers.map((user) => (\n <tr key={user.id} className=\"hover:bg-accent/50 transition-colors\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n {user.profilePicture ? (\n <img\n src={user.profilePicture}\n alt={`${user.firstName}`}\n className=\"w-10 h-10 rounded-full object-cover\"\n />\n ) : (\n <div className=\"w-10 h-10 rounded-full bg-bg-sunken flex items-center justify-center\">\n <Users className=\"h-5 w-5 text-text-secondary\" />\n </div>\n )}\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {user.firstName} {user.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">{user.email}</p>\n <p className=\"text-xs text-text-secondary\">{user.phone}</p>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"space-y-1\">\n {roleBadge(user.role)}\n <br />\n {statusBadge(user.status)}\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm\">\n <p className=\"text-text-primary\">\n Registered: {formatDate(user.registrationDate)}\n </p>\n {user.lastLoginTime && (\n <p className=\"text-text-secondary\">\n Last login: {formatDate(user.lastLoginTime)}\n </p>\n )}\n {user.deviceInfo && (\n <p className=\"text-text-secondary flex items-center gap-1\">\n <Smartphone className=\"h-3 w-3\" />\n {user.deviceInfo}\n </p>\n )}\n </td>\n <td className=\"px-4 py-3 text-sm\">\n {user.role === 'customer' && user.totalOrders != null && (\n <>\n <p className=\"text-text-primary\">{user.totalOrders} orders</p>\n <p className=\"text-text-secondary\">\n {formatCurrency(user.totalSpent ?? 0)} spent\n </p>\n </>\n )}\n {(user.role === 'cart_owner' || user.role === 'worker') &&\n user.totalEarnings != null && (\n <p className=\"text-text-primary\">\n {formatCurrency(user.totalEarnings)} earned\n </p>\n )}\n {user.role === 'investor' && user.riskScore != null && (\n <p className=\"text-text-primary\">Risk: {user.riskScore}/5</p>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full',\n user.isEmailVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Email</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full',\n user.isPhoneVerified ? 'bg-green-500' : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">Phone</span>\n </div>\n {user.kycStatus && (\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\n 'w-2 h-2 rounded-full',\n user.kycStatus === 'verified'\n ? 'bg-green-500'\n : user.kycStatus === 'pending'\n ? 'bg-yellow-500'\n : 'bg-red-500'\n )}\n />\n <span className=\"text-sm text-text-secondary\">KYC</span>\n </div>\n )}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'edit')}\n title=\"Edit\"\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-accent transition-colors\"\n >\n <Edit3 className=\"h-4 w-4\" />\n </button>\n {user.status === 'active' ? (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'suspend')}\n title=\"Suspend\"\n className=\"rounded p-1.5 text-text-secondary hover:text-red-600 hover:bg-red-500/10 transition-colors\"\n >\n <UserX className=\"h-4 w-4\" />\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'activate')}\n title=\"Activate\"\n className=\"rounded p-1.5 text-text-secondary hover:text-green-600 hover:bg-green-500/10 transition-colors\"\n >\n <UserCheck className=\"h-4 w-4\" />\n </button>\n )}\n {user.kycStatus === 'pending' && (\n <button\n type=\"button\"\n onClick={() => handleUserAction(user, 'verify')}\n title=\"Verify\"\n className=\"rounded p-1.5 text-text-secondary hover:text-blue-600 hover:bg-blue-500/10 transition-colors\"\n >\n <Shield className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {users.length === 0 && (\n <EmptyState\n illustration=\"empty-people\"\n title=\"No users found\"\n description=\"No users match your current filters. Try adjusting your search, role or status filter.\"\n />\n )}\n </div>\n\n {/* Pagination */}\n <div className=\"mt-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4\">\n <p className=\"text-sm text-text-secondary text-center sm:text-left\">\n Showing{' '}\n <span className=\"font-medium\">\n {Math.min((currentPage - 1) * itemsPerPage + 1, users.length)}\n </span>{' '}\n to{' '}\n <span className=\"font-medium\">{Math.min(currentPage * itemsPerPage, users.length)}</span>{' '}\n of <span className=\"font-medium\">{users.length}</span> results\n </p>\n <div className=\"flex justify-center sm:justify-end gap-2\">\n <button\n type=\"button\"\n disabled={currentPage === 1}\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n Previous\n </button>\n <button\n type=\"button\"\n disabled={currentPage * itemsPerPage >= users.length}\n onClick={() => setCurrentPage((p) => p + 1)}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Next\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n\n {/* User Action Modal */}\n {showUserModal && selectedUser && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-border-subtle bg-bg-surface shadow-lg max-h-[90vh] overflow-y-auto\">\n <div className=\"flex items-center justify-between p-4 border-b border-border-subtle\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {actionType === 'edit' ? 'Edit User' : 'Delete User'}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowUserModal(false)}\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-accent transition-colors\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <div className=\"p-4\">\n {actionType === 'delete' ? (\n <div>\n <p className=\"text-text-secondary mb-4\">\n Are you sure you want to delete user "{selectedUser.firstName}{' '}\n {selectedUser.lastName}"? This action cannot be undone.\n </p>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={() => setShowUserModal(false)}\n className=\"flex-1 rounded-lg border border-border-subtle py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleDeleteConfirm}\n className=\"flex-1 rounded-lg bg-red-600 hover:bg-red-700 py-2 text-sm font-medium text-white transition-colors\"\n >\n Delete User\n </button>\n </div>\n </div>\n ) : (\n <div>\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n First Name\n </label>\n <input\n type=\"text\"\n value={editForm.firstName}\n onChange={(e) =>\n setEditForm((f) => ({ ...f, firstName: e.target.value }))\n }\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Last Name\n </label>\n <input\n type=\"text\"\n value={editForm.lastName}\n onChange={(e) => setEditForm((f) => ({ ...f, lastName: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Email\n </label>\n <input\n type=\"email\"\n value={editForm.email}\n onChange={(e) => setEditForm((f) => ({ ...f, email: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Phone\n </label>\n <input\n type=\"tel\"\n value={editForm.phone}\n onChange={(e) => setEditForm((f) => ({ ...f, phone: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n Role\n </label>\n <select\n value={editForm.role}\n onChange={(e) => setEditForm((f) => ({ ...f, role: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"customer\">Customer</option>\n <option value=\"cart_owner\">Cart Owner</option>\n <option value=\"worker\">Worker</option>\n <option value=\"investor\">Investor</option>\n </select>\n </div>\n </div>\n <div className=\"flex gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowUserModal(false)}\n className=\"flex-1 rounded-lg border border-border-subtle py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSaveEdit}\n className=\"flex-1 rounded-lg bg-action-primary-bg py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n Save Changes\n </button>\n <button\n type=\"button\"\n onClick={() => setActionType('delete')}\n className=\"rounded-lg border border-border-subtle py-2 px-3 text-sm font-medium text-red-600 hover:bg-red-500/10 transition-colors\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,8 +6,9 @@ import { mockAdminAnalytics as i } from "../../mocks/data.js";
|
|
|
6
6
|
import { useState as a } from "react";
|
|
7
7
|
import { ArrowDownRight as o, ArrowUpRight as s, BarChart3 as c, CalendarDays as l, Clock as u, Download as d, IndianRupee as f, Percent as p, ShoppingCart as m, Star as h, Target as g, ThumbsUp as _, TrendingUp as v, Users as y } from "lucide-react";
|
|
8
8
|
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
9
|
+
import { EmphasisPanel as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
|
|
9
10
|
//#region src/atheletebridge/pages/cart-owner/AnalyticsDashboard.tsx
|
|
10
|
-
var
|
|
11
|
+
var T = {
|
|
11
12
|
revenue: {
|
|
12
13
|
today: 12450,
|
|
13
14
|
week: 87150,
|
|
@@ -249,16 +250,16 @@ var C = {
|
|
|
249
250
|
}
|
|
250
251
|
]
|
|
251
252
|
}
|
|
252
|
-
},
|
|
253
|
-
let { navigateTo:
|
|
253
|
+
}, E = () => {
|
|
254
|
+
let { navigateTo: E } = e(), [D, O] = a("week"), k = Math.max(...T.orders.popularTimes.map((e) => e.orders)), A = Math.max(...T.offerings.categories.map((e) => e.revenue)), j = Math.max(...T.performance.peakHours.map((e) => e.orders)), M = Math.max(...T.performance.peakDays.map((e) => e.orders)), N = (e) => `${e > 0 ? "+" : ""}${e}%`;
|
|
254
255
|
return /* @__PURE__ */ x(n, {
|
|
255
256
|
title: "Analytics Dashboard",
|
|
256
257
|
description: "Business performance insights and data",
|
|
257
258
|
actions: /* @__PURE__ */ S("div", {
|
|
258
259
|
className: "flex items-center gap-2",
|
|
259
260
|
children: [/* @__PURE__ */ S("select", {
|
|
260
|
-
value:
|
|
261
|
-
onChange: (e) =>
|
|
261
|
+
value: D,
|
|
262
|
+
onChange: (e) => O(e.target.value),
|
|
262
263
|
className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
|
|
263
264
|
children: [
|
|
264
265
|
/* @__PURE__ */ x("option", {
|
|
@@ -288,56 +289,60 @@ var C = {
|
|
|
288
289
|
children: /* @__PURE__ */ S("div", {
|
|
289
290
|
className: "space-y-6",
|
|
290
291
|
children: [
|
|
291
|
-
/* @__PURE__ */
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
value: C.revenue.today,
|
|
300
|
-
growth: C.revenue.growth.daily
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
label: "This Week",
|
|
304
|
-
value: C.revenue.week,
|
|
305
|
-
growth: C.revenue.growth.weekly
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
label: "This Month",
|
|
309
|
-
value: C.revenue.month,
|
|
310
|
-
growth: C.revenue.growth.monthly
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
label: "This Year",
|
|
314
|
-
value: C.revenue.year,
|
|
315
|
-
growth: null
|
|
316
|
-
}
|
|
317
|
-
].map((e) => /* @__PURE__ */ S("div", {
|
|
318
|
-
className: "rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm",
|
|
292
|
+
/* @__PURE__ */ x(w, { children: "Understand what's working in your business. Track revenue across today, the week, month and year, see order patterns and your busiest times, and spot trends so you can stock, staff and price smarter. Export the data whenever you need it." }),
|
|
293
|
+
/* @__PURE__ */ S(C, {
|
|
294
|
+
className: "p-5",
|
|
295
|
+
children: [/* @__PURE__ */ x("h2", {
|
|
296
|
+
className: "text-base font-semibold text-text-primary mb-3",
|
|
297
|
+
children: "Revenue Overview"
|
|
298
|
+
}), /* @__PURE__ */ x("div", {
|
|
299
|
+
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
319
300
|
children: [
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
301
|
+
{
|
|
302
|
+
label: "Today's Revenue",
|
|
303
|
+
value: T.revenue.today,
|
|
304
|
+
growth: T.revenue.growth.daily
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
label: "This Week",
|
|
308
|
+
value: T.revenue.week,
|
|
309
|
+
growth: T.revenue.growth.weekly
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
label: "This Month",
|
|
313
|
+
value: T.revenue.month,
|
|
314
|
+
growth: T.revenue.growth.monthly
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
label: "This Year",
|
|
318
|
+
value: T.revenue.year,
|
|
319
|
+
growth: null
|
|
320
|
+
}
|
|
321
|
+
].map((e) => /* @__PURE__ */ S("div", {
|
|
322
|
+
className: "rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm",
|
|
323
|
+
children: [
|
|
324
|
+
/* @__PURE__ */ S("div", {
|
|
325
|
+
className: "flex items-center justify-between",
|
|
326
|
+
children: [/* @__PURE__ */ x("div", {
|
|
327
|
+
className: "rounded-md bg-accent p-2",
|
|
328
|
+
children: /* @__PURE__ */ x(f, { className: "h-5 w-5 text-text-secondary" })
|
|
329
|
+
}), e.growth !== null && /* @__PURE__ */ S("div", {
|
|
330
|
+
className: t("flex items-center gap-1 text-xs font-medium", e.growth >= 0 ? "text-green-600 dark:text-green-400" : "text-red-600 dark:text-red-400"),
|
|
331
|
+
children: [e.growth >= 0 ? /* @__PURE__ */ x(s, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ x(o, { className: "h-3.5 w-3.5" }), N(e.growth)]
|
|
332
|
+
})]
|
|
333
|
+
}),
|
|
334
|
+
/* @__PURE__ */ x("p", {
|
|
335
|
+
className: "mt-3 text-2xl font-bold text-text-primary",
|
|
336
|
+
children: r(e.value, { minimumFractionDigits: 0 })
|
|
337
|
+
}),
|
|
338
|
+
/* @__PURE__ */ x("p", {
|
|
339
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
340
|
+
children: e.label
|
|
341
|
+
})
|
|
342
|
+
]
|
|
343
|
+
}, e.label))
|
|
344
|
+
})]
|
|
345
|
+
}),
|
|
341
346
|
/* @__PURE__ */ S("div", {
|
|
342
347
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
343
348
|
children: [/* @__PURE__ */ S("div", {
|
|
@@ -358,28 +363,28 @@ var C = {
|
|
|
358
363
|
children: "Total Orders"
|
|
359
364
|
}), /* @__PURE__ */ x("p", {
|
|
360
365
|
className: "text-2xl font-bold text-text-primary",
|
|
361
|
-
children:
|
|
366
|
+
children: T.orders.total
|
|
362
367
|
})] }),
|
|
363
368
|
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
364
369
|
className: "text-xs text-text-secondary",
|
|
365
370
|
children: "Avg. Order Value"
|
|
366
371
|
}), /* @__PURE__ */ x("p", {
|
|
367
372
|
className: "text-2xl font-bold text-text-primary",
|
|
368
|
-
children: r(
|
|
373
|
+
children: r(T.orders.averageValue, { minimumFractionDigits: 0 })
|
|
369
374
|
})] }),
|
|
370
375
|
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
371
376
|
className: "text-xs text-text-secondary",
|
|
372
377
|
children: "Completed"
|
|
373
378
|
}), /* @__PURE__ */ x("p", {
|
|
374
379
|
className: "text-xl font-bold text-green-600 dark:text-green-400",
|
|
375
|
-
children:
|
|
380
|
+
children: T.orders.completed
|
|
376
381
|
})] }),
|
|
377
382
|
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
378
383
|
className: "text-xs text-text-secondary",
|
|
379
384
|
children: "Cancelled"
|
|
380
385
|
}), /* @__PURE__ */ x("p", {
|
|
381
386
|
className: "text-xl font-bold text-red-600 dark:text-red-400",
|
|
382
|
-
children:
|
|
387
|
+
children: T.orders.cancelled
|
|
383
388
|
})] })
|
|
384
389
|
]
|
|
385
390
|
}), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
@@ -387,7 +392,7 @@ var C = {
|
|
|
387
392
|
children: "Avg. Preparation Time"
|
|
388
393
|
}), /* @__PURE__ */ S("p", {
|
|
389
394
|
className: "text-sm font-medium text-text-primary",
|
|
390
|
-
children: [
|
|
395
|
+
children: [T.orders.averagePreparationTime, " minutes"]
|
|
391
396
|
})] })]
|
|
392
397
|
})]
|
|
393
398
|
}), /* @__PURE__ */ S("div", {
|
|
@@ -400,8 +405,8 @@ var C = {
|
|
|
400
405
|
})
|
|
401
406
|
}), /* @__PURE__ */ x("div", {
|
|
402
407
|
className: "p-5 space-y-2",
|
|
403
|
-
children:
|
|
404
|
-
let n = e.orders /
|
|
408
|
+
children: T.orders.popularTimes.map((e) => {
|
|
409
|
+
let n = e.orders / k * 100;
|
|
405
410
|
return /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ S("div", {
|
|
406
411
|
className: "flex items-center justify-between text-xs mb-0.5",
|
|
407
412
|
children: [/* @__PURE__ */ x("span", {
|
|
@@ -430,25 +435,25 @@ var C = {
|
|
|
430
435
|
children: [
|
|
431
436
|
{
|
|
432
437
|
label: "Acceptance Rate",
|
|
433
|
-
value: `${
|
|
438
|
+
value: `${T.performance.acceptanceRate}%`,
|
|
434
439
|
icon: g,
|
|
435
440
|
color: "text-green-600 dark:text-green-400"
|
|
436
441
|
},
|
|
437
442
|
{
|
|
438
443
|
label: "Cancellation Rate",
|
|
439
|
-
value: `${
|
|
444
|
+
value: `${T.performance.cancellationRate}%`,
|
|
440
445
|
icon: p,
|
|
441
446
|
color: "text-red-600 dark:text-red-400"
|
|
442
447
|
},
|
|
443
448
|
{
|
|
444
449
|
label: "On-Time Delivery",
|
|
445
|
-
value: `${
|
|
450
|
+
value: `${T.performance.onTimeDeliveryRate}%`,
|
|
446
451
|
icon: u,
|
|
447
452
|
color: "text-blue-600 dark:text-blue-400"
|
|
448
453
|
},
|
|
449
454
|
{
|
|
450
455
|
label: "Average Rating",
|
|
451
|
-
value: `${
|
|
456
|
+
value: `${T.performance.averageRating}`,
|
|
452
457
|
icon: h,
|
|
453
458
|
color: "text-yellow-600 dark:text-yellow-400"
|
|
454
459
|
}
|
|
@@ -483,7 +488,7 @@ var C = {
|
|
|
483
488
|
}),
|
|
484
489
|
/* @__PURE__ */ x("div", {
|
|
485
490
|
className: "divide-y divide-border",
|
|
486
|
-
children:
|
|
491
|
+
children: T.offerings.topSelling.map((e, t) => /* @__PURE__ */ S("div", {
|
|
487
492
|
className: "flex items-center justify-between px-5 py-3",
|
|
488
493
|
children: [/* @__PURE__ */ S("div", {
|
|
489
494
|
className: "flex items-center gap-3",
|
|
@@ -513,7 +518,7 @@ var C = {
|
|
|
513
518
|
children: [/* @__PURE__ */ x("p", {
|
|
514
519
|
className: "text-xs font-medium text-text-secondary mb-2",
|
|
515
520
|
children: "Least Selling"
|
|
516
|
-
}),
|
|
521
|
+
}), T.offerings.leastSelling.map((e) => /* @__PURE__ */ S("div", {
|
|
517
522
|
className: "flex items-center justify-between py-1.5",
|
|
518
523
|
children: [/* @__PURE__ */ x("span", {
|
|
519
524
|
className: "text-xs text-text-secondary",
|
|
@@ -540,8 +545,8 @@ var C = {
|
|
|
540
545
|
})
|
|
541
546
|
}), /* @__PURE__ */ x("div", {
|
|
542
547
|
className: "p-5 space-y-4",
|
|
543
|
-
children:
|
|
544
|
-
let t = e.revenue /
|
|
548
|
+
children: T.offerings.categories.map((e) => {
|
|
549
|
+
let t = e.revenue / A * 100;
|
|
545
550
|
return /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ S("div", {
|
|
546
551
|
className: "flex items-center justify-between text-sm mb-1",
|
|
547
552
|
children: [/* @__PURE__ */ x("span", {
|
|
@@ -589,28 +594,28 @@ var C = {
|
|
|
589
594
|
children: "Total Customers"
|
|
590
595
|
}), /* @__PURE__ */ x("p", {
|
|
591
596
|
className: "text-xl font-bold text-text-primary",
|
|
592
|
-
children:
|
|
597
|
+
children: T.customers.total
|
|
593
598
|
})] }),
|
|
594
599
|
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
595
600
|
className: "text-xs text-text-secondary",
|
|
596
601
|
children: "New This Month"
|
|
597
602
|
}), /* @__PURE__ */ x("p", {
|
|
598
603
|
className: "text-xl font-bold text-blue-600 dark:text-blue-400",
|
|
599
|
-
children:
|
|
604
|
+
children: T.customers.new
|
|
600
605
|
})] }),
|
|
601
606
|
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
602
607
|
className: "text-xs text-text-secondary",
|
|
603
608
|
children: "Returning"
|
|
604
609
|
}), /* @__PURE__ */ x("p", {
|
|
605
610
|
className: "text-xl font-bold text-green-600 dark:text-green-400",
|
|
606
|
-
children:
|
|
611
|
+
children: T.customers.returning
|
|
607
612
|
})] }),
|
|
608
613
|
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
|
|
609
614
|
className: "text-xs text-text-secondary",
|
|
610
615
|
children: "Satisfaction"
|
|
611
616
|
}), /* @__PURE__ */ S("p", {
|
|
612
617
|
className: "text-xl font-bold text-yellow-600 dark:text-yellow-400 flex items-center gap-1",
|
|
613
|
-
children: [/* @__PURE__ */ x(h, { className: "h-4 w-4 fill-yellow-400 text-yellow-400" }),
|
|
618
|
+
children: [/* @__PURE__ */ x(h, { className: "h-4 w-4 fill-yellow-400 text-yellow-400" }), T.customers.satisfaction.rating]
|
|
614
619
|
})] })
|
|
615
620
|
]
|
|
616
621
|
}),
|
|
@@ -642,7 +647,7 @@ var C = {
|
|
|
642
647
|
children: "Total Spent"
|
|
643
648
|
})
|
|
644
649
|
]
|
|
645
|
-
}) }), /* @__PURE__ */ x("tbody", { children:
|
|
650
|
+
}) }), /* @__PURE__ */ x("tbody", { children: T.customers.topCustomers.map((e, t) => /* @__PURE__ */ S("tr", {
|
|
646
651
|
className: "border-b border-border-subtle last:border-0",
|
|
647
652
|
children: [
|
|
648
653
|
/* @__PURE__ */ x("td", {
|
|
@@ -672,9 +677,9 @@ var C = {
|
|
|
672
677
|
children: [/* @__PURE__ */ x(_, { className: "h-4 w-4 text-green-600 dark:text-green-400" }), /* @__PURE__ */ S("span", {
|
|
673
678
|
className: "text-text-secondary",
|
|
674
679
|
children: [
|
|
675
|
-
|
|
680
|
+
T.customers.satisfaction.positiveReviews,
|
|
676
681
|
"/",
|
|
677
|
-
|
|
682
|
+
T.customers.satisfaction.reviews,
|
|
678
683
|
" positive reviews"
|
|
679
684
|
]
|
|
680
685
|
})]
|
|
@@ -694,8 +699,8 @@ var C = {
|
|
|
694
699
|
})
|
|
695
700
|
}), /* @__PURE__ */ x("div", {
|
|
696
701
|
className: "p-5 space-y-3",
|
|
697
|
-
children:
|
|
698
|
-
let n = e.orders /
|
|
702
|
+
children: T.performance.peakHours.map((e) => {
|
|
703
|
+
let n = e.orders / j * 100;
|
|
699
704
|
return /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ S("div", {
|
|
700
705
|
className: "flex items-center justify-between text-xs mb-1",
|
|
701
706
|
children: [/* @__PURE__ */ x("span", {
|
|
@@ -724,8 +729,8 @@ var C = {
|
|
|
724
729
|
})
|
|
725
730
|
}), /* @__PURE__ */ x("div", {
|
|
726
731
|
className: "p-5 space-y-3",
|
|
727
|
-
children:
|
|
728
|
-
let t = e.orders /
|
|
732
|
+
children: T.performance.peakDays.map((e) => {
|
|
733
|
+
let t = e.orders / M * 100;
|
|
729
734
|
return /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ S("div", {
|
|
730
735
|
className: "flex items-center justify-between text-xs mb-1",
|
|
731
736
|
children: [/* @__PURE__ */ x("span", {
|
|
@@ -829,6 +834,6 @@ var C = {
|
|
|
829
834
|
});
|
|
830
835
|
};
|
|
831
836
|
//#endregion
|
|
832
|
-
export {
|
|
837
|
+
export { E as AnalyticsDashboard };
|
|
833
838
|
|
|
834
839
|
//# sourceMappingURL=AnalyticsDashboard.js.map
|