UNPKG

naim-firebase-auth-wrapper

Version:

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

143 lines 8.95 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, 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