naim-firebase-auth-wrapper
Version:
React components and hooks for Firebase Authentication and Firestore with Mantine UI
143 lines • 8.95 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, ActionIcon, Menu, Loader, Modal, Stack, Tabs, Avatar, Badge, Select } from '@mantine/core';
import { IconDotsVertical, IconEdit, IconTrash, IconUserPlus, IconUsers } from '@tabler/icons-react';
import { useAuth } from '../hooks/useAuth';
import { updateOrganization, deleteOrganization, addUserToOrganization, removeUserFromOrganization, getOrganizationMembers } from '../services/firestore';
import { CreateOrganization } from './CreateOrganization';
export const OrganizationManagement = ({ onError }) => {
const { user, organizations, loadOrganizations } = useAuth();
const [loading, setLoading] = useState(true);
const [editingOrg, setEditingOrg] = useState(null);
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [selectedOrgId, setSelectedOrgId] = useState(null);
const [orgMembers, setOrgMembers] = useState([]);
const [inviteEmail, setInviteEmail] = useState('');
const [inviteRole, setInviteRole] = useState('member');
useEffect(() => {
const loadOrgs = async () => {
if (!user) {
setLoading(false);
return;
}
setLoading(true);
try {
if (loadOrganizations) {
await loadOrganizations();
if (organizations.length > 0 && !selectedOrgId) {
setSelectedOrgId(organizations[0].id);
}
}
}
catch (error) {
console.error('Error loading organizations:', error);
onError?.(error);
}
finally {
setLoading(false);
}
};
loadOrgs();
}, [user, onError, selectedOrgId, loadOrganizations, organizations]);
useEffect(() => {
const loadMembers = async () => {
if (!selectedOrgId)
return;
try {
const members = await getOrganizationMembers(selectedOrgId);
setOrgMembers(members);
}
catch (error) {
console.error('Error loading organization members:', error);
onError?.(error);
}
};
loadMembers();
}, [selectedOrgId, onError]);
const handleEditOrg = (org) => {
setEditingOrg(org);
setIsEditModalOpen(true);
};
const handleSaveOrg = async () => {
if (!editingOrg)
return;
try {
await updateOrganization(editingOrg.id, { name: editingOrg.name });
// Update local state
await loadOrganizations();
setIsEditModalOpen(false);
}
catch (error) {
console.error('Error updating organization:', error);
onError?.(error);
}
};
const handleDeleteOrg = async (orgId) => {
if (!confirm('Are you sure you want to delete this organization? This action cannot be undone.')) {
return;
}
try {
await deleteOrganization(orgId);
// Update local state
await loadOrganizations();
if (selectedOrgId === orgId) {
setSelectedOrgId(organizations.length > 1 ? organizations[0].id : null);
}
}
catch (error) {
console.error('Error deleting organization:', error);
onError?.(error);
}
};
const handleInviteUser = async () => {
if (!selectedOrgId || !inviteEmail || !inviteRole)
return;
try {
// In a real implementation, you would send an email invitation
// For now, we'll just add the user directly
await addUserToOrganization(selectedOrgId, inviteEmail, inviteRole);
// Refresh members
await loadOrganizations();
// Clear form
setInviteEmail('');
setInviteRole('member');
}
catch (error) {
console.error('Error inviting user:', error);
onError?.(error);
}
};
const handleRemoveMember = async (userId) => {
if (!selectedOrgId)
return;
if (!confirm('Are you sure you want to remove this member?')) {
return;
}
try {
await removeUserFromOrganization(selectedOrgId, userId);
// Refresh members
await loadOrganizations();
}
catch (error) {
console.error('Error removing member:', error);
onError?.(error);
}
};
const handleCreateOrgSuccess = async (orgId) => {
// Refresh organizations
if (!user)
return;
await loadOrganizations();
setSelectedOrgId(orgId);
};
if (loading) {
return _jsx(Loader, {});
}
return (_jsxs(Paper, { radius: "md", p: "xl", withBorder: true, children: [_jsx(Title, { order: 2, mb: "md", children: "Organization Management" }), organizations.length === 0 ? (_jsx(CreateOrganization, { onSuccess: handleCreateOrgSuccess, onError: onError })) : (_jsxs(Tabs, { value: selectedOrgId || undefined, onChange: (value) => setSelectedOrgId(value), children: [_jsx(Tabs.List, { children: organizations.map(org => (_jsx(Tabs.Tab, { value: org.id, children: org.name }, org.id))) }), organizations.map(org => (_jsxs(Tabs.Panel, { value: org.id, pt: "md", children: [_jsxs(Group, { justify: "apart", mb: "md", children: [_jsx(Title, { order: 3, children: org.name }), _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: () => handleEditOrg(org), children: "Edit Organization" }), _jsx(Menu.Item, { leftSection: _jsx(IconTrash, { size: 16 }), onClick: () => handleDeleteOrg(org.id), color: "red", children: "Delete Organization" })] })] })] }), _jsxs(Paper, { withBorder: true, p: "md", mb: "md", children: [_jsx(Title, { order: 4, mb: "md", children: _jsxs(Group, { children: [_jsx(IconUserPlus, { size: 20 }), _jsx(Text, { children: "Invite Member" })] }) }), _jsxs(Group, { align: "end", children: [_jsx(TextInput, { label: "Email Address", placeholder: "user@example.com", value: inviteEmail, onChange: (e) => setInviteEmail(e.target.value), style: { flex: 1 } }), _jsx(Select, { label: "Role", value: inviteRole, onChange: (value) => setInviteRole(value || 'member'), data: [
{ value: 'admin', label: 'Admin' },
{ value: 'member', label: 'Member' },
{ value: 'guest', label: 'Guest' }
], style: { width: 150 } }), _jsx(Button, { onClick: handleInviteUser, children: "Invite" })] })] }), _jsxs(Paper, { withBorder: true, p: "md", children: [_jsx(Title, { order: 4, mb: "md", children: _jsxs(Group, { children: [_jsx(IconUsers, { size: 20 }), _jsxs(Text, { children: ["Members (", orgMembers.length, ")"] })] }) }), _jsxs(Table, { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "User" }), _jsx("th", { children: "Email" }), _jsx("th", { children: "Role" }), _jsx("th", { children: "Joined" }), _jsx("th", { children: "Actions" })] }) }), _jsx("tbody", { children: orgMembers.map((member) => (_jsxs("tr", { children: [_jsx("td", { children: _jsxs(Group, { children: [_jsx(Avatar, { src: member.photoURL, radius: "xl", size: "sm" }), _jsx(Text, { children: member.displayName || 'No name' })] }) }), _jsx("td", { children: member.email }), _jsx("td", { children: _jsx(Badge, { children: member.organizations?.find(o => o.orgId === org.id)?.role || 'Member' }) }), _jsx("td", { children: new Date(member.createdAt).toLocaleDateString() }), _jsx("td", { children: member.uid !== org.ownerId && (_jsx(ActionIcon, { color: "red", onClick: () => handleRemoveMember(member.uid), children: _jsx(IconTrash, { size: 16 }) })) })] }, member.uid))) })] })] })] }, org.id)))] })), _jsx(Modal, { opened: isEditModalOpen, onClose: () => setIsEditModalOpen(false), title: "Edit Organization", children: editingOrg && (_jsxs(Stack, { children: [_jsx(TextInput, { label: "Organization Name", value: editingOrg.name, onChange: (e) => setEditingOrg({ ...editingOrg, name: e.target.value }) }), _jsxs(Group, { justify: "right", mt: "md", children: [_jsx(Button, { variant: "outline", onClick: () => setIsEditModalOpen(false), children: "Cancel" }), _jsx(Button, { onClick: handleSaveOrg, children: "Save Changes" })] })] })) })] }));
};
//# sourceMappingURL=OrganizationManagement.js.map