naim-firebase-auth-wrapper
Version:
React components and hooks for Firebase Authentication and Firestore with Mantine UI
94 lines • 6.51 kB
JavaScript
'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