UNPKG

naim-firebase-auth-wrapper

Version:

React components and hooks for Firebase Authentication and Firestore with Mantine UI

94 lines 6.51 kB
'use client'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect } from 'react'; import { Table, Button, Paper, Title, TextInput, Group, Text, Badge, ActionIcon, Menu, Loader, Modal, Stack, Select } from '@mantine/core'; import { IconSearch, IconDotsVertical, IconEdit, IconTrash, IconUserOff, IconUserCheck } from '@tabler/icons-react'; import { getAllUsers, updateUserProfile, deleteUser } from '../services/firestore'; export const UserAdminDashboard = ({ onError }) => { const [users, setUsers] = useState([]); const [filteredUsers, setFilteredUsers] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [editingUser, setEditingUser] = useState(null); const [isEditModalOpen, setIsEditModalOpen] = useState(false); useEffect(() => { const loadUsers = async () => { try { const allUsers = await getAllUsers(); setUsers(allUsers); setFilteredUsers(allUsers); } catch (error) { console.error('Error loading users:', error); onError?.(error); } finally { setLoading(false); } }; loadUsers(); }, [onError]); useEffect(() => { if (searchQuery) { const filtered = users.filter(user => user.displayName?.toLowerCase().includes(searchQuery.toLowerCase()) || user.email.toLowerCase().includes(searchQuery.toLowerCase())); setFilteredUsers(filtered); } else { setFilteredUsers(users); } }, [searchQuery, users]); const handleEditUser = (user) => { setEditingUser(user); setIsEditModalOpen(true); }; const handleSaveUser = async () => { if (!editingUser) return; try { await updateUserProfile(editingUser.uid, editingUser); // Update local state setUsers(users.map(u => u.uid === editingUser.uid ? editingUser : u)); setIsEditModalOpen(false); } catch (error) { console.error('Error updating user:', error); onError?.(error); } }; const handleDeleteUser = async (userId) => { if (!confirm('Are you sure you want to delete this user? This action cannot be undone.')) { return; } try { await deleteUser(userId); // Update local state setUsers(users.filter(u => u.uid !== userId)); } catch (error) { console.error('Error deleting user:', error); onError?.(error); } }; const handleToggleUserStatus = async (user) => { const newStatus = user.disabled ? false : true; try { await updateUserProfile(user.uid, { disabled: newStatus }); // Update local state setUsers(users.map(u => u.uid === user.uid ? { ...u, disabled: newStatus } : u)); } catch (error) { console.error('Error updating user status:', error); onError?.(error); } }; if (loading) { return _jsx(Loader, {}); } return (_jsxs(Paper, { radius: "md", p: "xl", withBorder: true, children: [_jsxs(Group, { justify: "apart", mb: "md", children: [_jsx(Title, { order: 2, children: "User Management" }), _jsx(TextInput, { placeholder: "Search users...", leftSection: _jsx(IconSearch, { size: 14 }), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), style: { width: 300 } })] }), _jsxs(Text, { size: "sm", color: "dimmed", children: [filteredUsers.length, " users found"] }), _jsxs(Table, { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Name" }), _jsx("th", { children: "Email" }), _jsx("th", { children: "Role" }), _jsx("th", { children: "Status" }), _jsx("th", { children: "Organizations" }), _jsx("th", { children: "Actions" })] }) }), _jsx("tbody", { children: filteredUsers.map((user) => (_jsxs("tr", { children: [_jsx("td", { children: user.displayName || 'No name' }), _jsx("td", { children: user.email }), _jsx("td", { children: user.role || 'User' }), _jsx("td", { children: _jsx(Badge, { color: user.disabled ? 'red' : 'green', children: user.disabled ? 'Disabled' : 'Active' }) }), _jsx("td", { children: user.organizations?.length || 0 }), _jsx("td", { children: _jsxs(Menu, { position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { children: _jsx(IconDotsVertical, { size: 16 }) }) }), _jsxs(Menu.Dropdown, { children: [_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 16 }), onClick: () => handleEditUser(user), children: "Edit User" }), _jsx(Menu.Item, { leftSection: user.disabled ? _jsx(IconUserCheck, { size: 16 }) : _jsx(IconUserOff, { size: 16 }), onClick: () => handleToggleUserStatus(user), color: user.disabled ? 'green' : 'orange', children: user.disabled ? 'Enable User' : 'Disable User' }), _jsx(Menu.Item, { leftSection: _jsx(IconTrash, { size: 16 }), onClick: () => handleDeleteUser(user.uid), color: "red", children: "Delete User" })] })] }) })] }, user.uid))) })] }), _jsx(Modal, { opened: isEditModalOpen, onClose: () => setIsEditModalOpen(false), title: "Edit User", children: editingUser && (_jsxs(Stack, { children: [_jsx(TextInput, { label: "Display Name", value: editingUser.displayName || '', onChange: (e) => setEditingUser({ ...editingUser, displayName: e.target.value }) }), _jsx(TextInput, { label: "Email", value: editingUser.email, disabled: true }), _jsx(TextInput, { label: "Phone Number", value: editingUser.phoneNumber || '', onChange: (e) => setEditingUser({ ...editingUser, phoneNumber: e.target.value }) }), _jsx(Select, { label: "Role", value: editingUser.role || 'user', onChange: (value) => setEditingUser({ ...editingUser, role: value || 'user' }), data: [ { value: 'user', label: 'User' }, { value: 'admin', label: 'Admin' }, { value: 'moderator', label: 'Moderator' } ] }), _jsxs(Group, { justify: "right", mt: "md", children: [_jsx(Button, { variant: "outline", onClick: () => setIsEditModalOpen(false), children: "Cancel" }), _jsx(Button, { onClick: handleSaveUser, children: "Save Changes" })] })] })) })] })); }; //# sourceMappingURL=UserAdminDashboard.js.map