import { useState, useEffect } from 'react'; import { Layout } from '../components/Layout'; import { api } from '../lib/api'; import { useAuthStore } from '../store/authStore'; import { Users as UsersIcon, Plus, Pencil, Trash2, X, Check, AlertCircle, Search, Globe, Phone, Mail } from 'lucide-react'; interface User { id: number; email: string; role: string; first_name: string | null; last_name: string | null; phone: string | null; domain: string; created_at: string; updated_at: string; } interface UserFormData { email: string; password: string; role: string; first_name: string; last_name: string; phone: string; domain: string; } const DOMAINS = [ { value: 'cannaiq.co', label: 'CannaIQ' }, { value: 'findagram.co', label: 'Find a Gram' }, { value: 'findadispo.com', label: 'Find a Dispo' }, ]; export function Users() { const { user: currentUser } = useAuthStore(); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showCreateModal, setShowCreateModal] = useState(false); const [editingUser, setEditingUser] = useState(null); const [formData, setFormData] = useState({ email: '', password: '', role: 'viewer', first_name: '', last_name: '', phone: '', domain: 'cannaiq.co' }); const [formError, setFormError] = useState(null); const [saving, setSaving] = useState(false); // Search and filter states const [searchQuery, setSearchQuery] = useState(''); const [domainFilter, setDomainFilter] = useState(''); const fetchUsers = async () => { try { setLoading(true); const params = new URLSearchParams(); if (searchQuery) params.set('search', searchQuery); if (domainFilter) params.set('domain', domainFilter); const response = await api.getUsers(params.toString()); setUsers(response.users); setError(null); } catch (err: any) { setError(err.message || 'Failed to fetch users'); } finally { setLoading(false); } }; useEffect(() => { fetchUsers(); }, [searchQuery, domainFilter]); const handleCreate = async () => { if (!formData.email || !formData.password) { setFormError('Email and password are required'); return; } try { setSaving(true); setFormError(null); await api.createUser({ email: formData.email, password: formData.password, role: formData.role, first_name: formData.first_name || undefined, last_name: formData.last_name || undefined, phone: formData.phone || undefined, domain: formData.domain }); setShowCreateModal(false); resetForm(); fetchUsers(); } catch (err: any) { setFormError(err.message || 'Failed to create user'); } finally { setSaving(false); } }; const handleUpdate = async () => { if (!editingUser) return; const updateData: any = {}; if (formData.email && formData.email !== editingUser.email) { updateData.email = formData.email; } if (formData.password) { updateData.password = formData.password; } if (formData.role && formData.role !== editingUser.role) { updateData.role = formData.role; } if (formData.first_name !== (editingUser.first_name || '')) { updateData.first_name = formData.first_name || null; } if (formData.last_name !== (editingUser.last_name || '')) { updateData.last_name = formData.last_name || null; } if (formData.phone !== (editingUser.phone || '')) { updateData.phone = formData.phone || null; } if (formData.domain !== editingUser.domain) { updateData.domain = formData.domain; } if (Object.keys(updateData).length === 0) { setEditingUser(null); return; } try { setSaving(true); setFormError(null); await api.updateUser(editingUser.id, updateData); setEditingUser(null); resetForm(); fetchUsers(); } catch (err: any) { setFormError(err.message || 'Failed to update user'); } finally { setSaving(false); } }; const handleDelete = async (user: User) => { if (!confirm(`Are you sure you want to delete ${user.email}?`)) { return; } try { await api.deleteUser(user.id); fetchUsers(); } catch (err: any) { alert(err.message || 'Failed to delete user'); } }; const openEditModal = (user: User) => { setEditingUser(user); setFormData({ email: user.email, password: '', role: user.role, first_name: user.first_name || '', last_name: user.last_name || '', phone: user.phone || '', domain: user.domain }); setFormError(null); }; const resetForm = () => { setFormData({ email: '', password: '', role: 'viewer', first_name: '', last_name: '', phone: '', domain: 'cannaiq.co' }); }; const closeModal = () => { setShowCreateModal(false); setEditingUser(null); resetForm(); setFormError(null); }; const getRoleBadgeColor = (role: string) => { switch (role) { case 'superadmin': return 'bg-purple-100 text-purple-800'; case 'admin': return 'bg-blue-100 text-blue-800'; case 'analyst': return 'bg-green-100 text-green-800'; case 'viewer': return 'bg-gray-100 text-gray-700'; default: return 'bg-gray-100 text-gray-700'; } }; const getDomainBadgeColor = (domain: string) => { switch (domain) { case 'cannaiq.co': return 'bg-indigo-100 text-indigo-800'; case 'findagram.co': return 'bg-emerald-100 text-emerald-800'; case 'findadispo.com': return 'bg-amber-100 text-amber-800'; default: return 'bg-gray-100 text-gray-700'; } }; const canModifyUser = (user: User) => { if (currentUser?.id === user.id) return false; if (user.role === 'superadmin' && currentUser?.role !== 'superadmin') return false; return true; }; return (
{/* Header */}

User Management

Manage system users across all domains

{/* Search and Filters */}
setSearchQuery(e.target.value)} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
{/* Error Message */} {error && (

{error}

)} {/* Users Table */}
{loading ? (

Loading users...

) : users.length === 0 ? (
No users found
) : (
{users.map((user) => ( ))}
User Domain Role Contact Created Actions
{(user.first_name?.[0] || user.email[0]).toUpperCase()}

{user.first_name || user.last_name ? `${user.first_name || ''} ${user.last_name || ''}`.trim() : user.email.split('@')[0]}

{user.email}

{currentUser?.id === user.id && ( (you) )}
{DOMAINS.find(d => d.value === user.domain)?.label || user.domain} {user.role}
{user.phone && (
{user.phone}
)} {!user.phone && -}
{new Date(user.created_at).toLocaleDateString()} {canModifyUser(user) ? (
) : ( - )}
)}
{/* Domain Legend */}

Domains

{DOMAINS.map((domain) => (
{domain.label} {domain.value}
))}
{/* Create/Edit Modal */} {(showCreateModal || editingUser) && (

{editingUser ? 'Edit User' : 'Create New User'}

{formError && (

{formError}

)} {/* Profile Section */}
setFormData({ ...formData, first_name: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="John" />
setFormData({ ...formData, last_name: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Doe" />
setFormData({ ...formData, email: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="user@example.com" />
setFormData({ ...formData, password: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder={editingUser ? '********' : 'Enter password'} />
setFormData({ ...formData, phone: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="+1 555 123 4567" />
)}
); }