org team management section in org Settings module

This commit is contained in:
Satyam Rastogi
2026-05-13 18:55:09 +05:30
parent 315191c01b
commit 2299cda11d
3 changed files with 1070 additions and 17 deletions
File diff suppressed because it is too large Load Diff
+30 -14
View File
@@ -5054,19 +5054,19 @@ export const MockStoreProvider = ({ children }) => {
]);
const [orgMembers, setOrgMembers] = useState([
{ id: 'om_001', userId: 'owner_001', name: 'Justin Johnson', email: 'justin@lynkeduppro.com', roleKey: 'OWNER', status: 'active', joinedAt: '2024-01-15' },
{ id: 'om_002', userId: 'owner_002', name: 'Maria Garcia', email: 'maria@lynkeduppro.com', roleKey: 'OWNER', status: 'active', joinedAt: '2024-01-15' },
{ id: 'om_003', userId: 'ADM01', name: 'Admin One', email: 'admin1@lynkeduppro.com', roleKey: 'ADMIN', status: 'active', joinedAt: '2024-02-10' },
{ id: 'om_004', userId: 'ADM02', name: 'Admin Two', email: 'admin2@lynkeduppro.com', roleKey: 'ADMIN', status: 'active', joinedAt: '2024-03-01' },
{ id: 'om_005', userId: 'ADM03', name: 'Admin Three', email: 'admin3@lynkeduppro.com', roleKey: 'ADMIN', status: 'active', joinedAt: '2024-04-20' },
{ id: 'om_006', userId: 'p1', name: 'Jesus Gonzales', email: 'jesus@lynkeduppro.com', roleKey: 'SALES_REP', status: 'active', joinedAt: '2024-03-15', individualCommission: { enabled: true, type: 'percent_gross', rate: 12 } },
{ id: 'om_007', userId: 'p2', name: 'Sarah Sales', email: 'sarah@lynkeduppro.com', roleKey: 'SALES_REP', status: 'active', joinedAt: '2024-04-01', individualCommission: { enabled: true, type: 'flat', rate: 2000 } },
{ id: 'om_008', userId: 'FA001', name: 'Frank Agent', email: 'agent1@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-05-10' },
{ id: 'om_009', userId: 'FA002', name: 'Fiona Field', email: 'agent2@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-05-15' },
{ id: 'om_010', userId: 'FA003', name: 'Fred Flyer', email: 'agent3@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-06-01' },
{ id: 'om_011', userId: 'FA004', name: 'Felicity Fast', email: 'agent4@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-06-10' },
{ id: 'om_012', userId: 'FA005', name: 'Felix Fixer', email: 'agent5@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-07-01' },
{ id: 'om_013', userId: 'sub_001', name: 'Carlos Subcontractor', email: 'carlos@electricpro.com', roleKey: 'SUBCONTRACTOR', status: 'active', joinedAt: '2024-08-01' },
{ id: 'om_001', userId: 'owner_001', name: 'Justin Johnson', email: 'justin@lynkeduppro.com', roleKey: 'OWNER', status: 'active', joinedAt: '2024-01-15', lastActivity: '2025-05-12', assignedJobsCount: 14 },
{ id: 'om_002', userId: 'owner_002', name: 'Maria Garcia', email: 'maria@lynkeduppro.com', roleKey: 'OWNER', status: 'active', joinedAt: '2024-01-15', lastActivity: '2025-05-10', assignedJobsCount: 8 },
{ id: 'om_003', userId: 'ADM01', name: 'Admin One', email: 'admin1@lynkeduppro.com', roleKey: 'ADMIN', status: 'active', joinedAt: '2024-02-10', lastActivity: '2025-05-11', assignedJobsCount: 6 },
{ id: 'om_004', userId: 'ADM02', name: 'Admin Two', email: 'admin2@lynkeduppro.com', roleKey: 'ADMIN', status: 'active', joinedAt: '2024-03-01', lastActivity: '2025-05-09', assignedJobsCount: 4 },
{ id: 'om_005', userId: 'ADM03', name: 'Admin Three', email: 'admin3@lynkeduppro.com', roleKey: 'ADMIN', status: 'active', joinedAt: '2024-04-20', lastActivity: '2025-05-08', assignedJobsCount: 3 },
{ id: 'om_006', userId: 'p1', name: 'Jesus Gonzales', email: 'jesus@lynkeduppro.com', roleKey: 'SALES_REP', status: 'active', joinedAt: '2024-03-15', lastActivity: '2025-05-12', assignedJobsCount: 9, individualCommission: { enabled: true, type: 'percent_gross', rate: 12 } },
{ id: 'om_007', userId: 'p2', name: 'Sarah Sales', email: 'sarah@lynkeduppro.com', roleKey: 'SALES_REP', status: 'active', joinedAt: '2024-04-01', lastActivity: '2025-05-11', assignedJobsCount: 7, individualCommission: { enabled: true, type: 'flat', rate: 2000 } },
{ id: 'om_008', userId: 'FA001', name: 'Frank Agent', email: 'agent1@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-05-10', lastActivity: '2025-05-12', assignedJobsCount: 2 },
{ id: 'om_009', userId: 'FA002', name: 'Fiona Field', email: 'agent2@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-05-15', lastActivity: '2025-05-07', assignedJobsCount: 3 },
{ id: 'om_010', userId: 'FA003', name: 'Fred Flyer', email: 'agent3@plano.com', roleKey: 'CANVASSER', status: 'invited', joinedAt: '2024-06-01', lastActivity: null, assignedJobsCount: 0 },
{ id: 'om_011', userId: 'FA004', name: 'Felicity Fast', email: 'agent4@plano.com', roleKey: 'CANVASSER', status: 'active', joinedAt: '2024-06-10', lastActivity: '2025-05-06', assignedJobsCount: 1 },
{ id: 'om_012', userId: 'FA005', name: 'Felix Fixer', email: 'agent5@plano.com', roleKey: 'CANVASSER', status: 'suspended', joinedAt: '2024-07-01', lastActivity: '2025-03-20', assignedJobsCount: 0 },
{ id: 'om_013', userId: 'sub_001', name: 'Carlos Subcontractor', email: 'carlos@electricpro.com', roleKey: 'SUBCONTRACTOR', status: 'active', joinedAt: '2024-08-01', lastActivity: '2025-05-10', assignedJobsCount: 5 },
]);
// Initialize properties once
@@ -5322,13 +5322,29 @@ export const MockStoreProvider = ({ children }) => {
setOrgMembers(prev => prev.map(m => m.id === memberId ? { ...m, ...data } : m));
},
addOrgMember: (member) => {
const newMember = { ...member, id: `om_${Date.now()}`, joinedAt: new Date().toISOString().slice(0, 10) };
const newMember = {
...member,
id: `om_${Date.now()}`,
joinedAt: new Date().toISOString().slice(0, 10),
lastActivity: null,
assignedJobsCount: 0,
status: member.status || 'invited',
};
setOrgMembers(prev => [...prev, newMember]);
return newMember;
},
removeOrgMember: (memberId) => {
setOrgMembers(prev => prev.filter(m => m.id !== memberId));
},
suspendOrgMember: (memberId) => {
setOrgMembers(prev => prev.map(m => m.id === memberId ? { ...m, status: 'suspended' } : m));
},
reactivateOrgMember: (memberId) => {
setOrgMembers(prev => prev.map(m => m.id === memberId ? { ...m, status: 'active' } : m));
},
resendOrgInvite: (memberId) => {
toast.success('Invite resent successfully');
},
}}>
{children}
</MockStoreContext.Provider>
+31 -3
View File
@@ -5,12 +5,14 @@ import {
Search, Check, X, Plus, Trash2, Edit3, Save, User, Crown,
ToggleLeft, ToggleRight, Info, ArrowRight, Mail, Phone, MapPin, Clock,
AlertTriangle, UserPlus, UserMinus, Eye, Pencil, Lock,
RotateCcw, Filter, CheckSquare, Square, BarChart3, History
RotateCcw, Filter, CheckSquare, Square, BarChart3, History, UsersRound
} from 'lucide-react';
import { useMockStore } from '../../data/mockStore';
import { useAuth } from '../../context/AuthContext';
import { usePermissions } from '../../hooks/usePermissions';
import { toast } from 'sonner';
import { computeRolePermissionStats } from '../../utils/permissions';
import OrgTeamManagement from '../../components/owner/OrgTeamManagement';
const COMMISSION_TYPES = [
{ value: 'flat', label: 'Flat Amount', hint: 'Fixed dollar amount' },
@@ -984,9 +986,11 @@ const UserOverridesSection = ({ members, roles, orgDefaults, roleOverrides, user
const OrgSettings = () => {
const { user } = useAuth();
const store = useMockStore();
const { orgRoleKey } = usePermissions();
const [openSections, setOpenSections] = useState({
org: true,
team: false,
roles: false,
access: false,
commission: false,
@@ -1009,6 +1013,29 @@ const OrgSettings = () => {
/>
),
},
{
id: 'team',
icon: UsersRound,
title: 'Organization Team Management',
subtitle: `${store.orgMembers.length} members — invite, manage roles, and administer your team`,
color: '#8b5cf6',
content: (
<OrgTeamManagement
members={store.orgMembers}
roles={store.orgRoles}
users={store.users}
permissions={store.orgPermissions}
permissionModules={store.PERMISSION_MODULES}
currentUserRoleKey={orgRoleKey}
onAddMember={store.addOrgMember}
onUpdateMember={store.updateOrgMember}
onRemoveMember={store.removeOrgMember}
onSuspendMember={store.suspendOrgMember}
onReactivateMember={store.reactivateOrgMember}
onResendInvite={store.resendOrgInvite}
/>
),
},
{
id: 'roles',
icon: Crown,
@@ -1093,11 +1120,12 @@ const OrgSettings = () => {
</div>
{/* Quick Stats */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mt-6">
<div className="grid grid-cols-2 md:grid-cols-5 gap-3 mt-6">
{[
{ label: 'Roles', value: store.orgRoles.length, color: '#fda913' },
{ label: 'Members', value: store.orgMembers.length, color: '#3b82f6' },
{ label: 'Modules', value: Object.keys(store.PERMISSION_MODULES).length, color: '#10b981' },
{ label: 'Active', value: store.orgMembers.filter(m => m.status === 'active').length, color: '#10b981' },
{ label: 'Modules', value: Object.keys(store.PERMISSION_MODULES).length, color: '#8b5cf6' },
{ label: 'Commission Overrides', value: store.roleCommissionOverrides.length + store.userCommissionOverrides.length, color: '#a855f7' },
].map(stat => (
<div key={stat.label} className="px-4 py-3 rounded-xl bg-white dark:bg-white/[0.03] border border-zinc-200 dark:border-white/5 shadow-sm dark:shadow-none">