Org settings module and user roles

This commit is contained in:
Satyam Rastogi
2026-05-12 20:36:44 +05:30
parent 3b1a77f500
commit fea4ad2d22
4 changed files with 998 additions and 19 deletions
+130 -18
View File
@@ -4971,6 +4971,104 @@ export const MockStoreProvider = ({ children }) => {
{ userId: 'p2', userName: 'Sarah Sales', enabled: true, type: 'flat', rate: 2000 },
]);
// Org Settings & Access Control
const [orgSettings, setOrgSettings] = useState({
orgName: 'LynkedUp Pro Roofing',
orgEmail: 'info@lynkeduppro.com',
orgPhone: '214-555-1000',
orgAddress: '5800 Legacy Dr, Plano, TX 75024',
timezone: 'America/Chicago',
});
const [orgRoles, setOrgRoles] = useState([
{
id: 'role_owner',
name: 'Org Owner',
key: 'OWNER',
description: 'Full access to all modules, settings, billing, and access control',
isSystem: true,
memberCount: 2,
color: '#fda913',
},
{
id: 'role_admin',
name: 'Admin / Manager',
key: 'ADMIN',
description: 'Manage jobs, view financials, assign team, verify leads, configure commissions',
isSystem: true,
memberCount: 3,
color: '#3b82f6',
},
{
id: 'role_sales',
name: 'Sales Rep',
key: 'SALES_REP',
description: 'View/manage assigned jobs, verify canvasser leads, view own commission',
isSystem: true,
memberCount: 2,
color: '#a855f7',
},
{
id: 'role_canvasser',
name: 'Canvasser',
key: 'CANVASSER',
description: 'Log door knocks, add leads, view leaderboard, view verified leads',
isSystem: true,
memberCount: 5,
color: '#10b981',
},
{
id: 'role_subcontractor',
name: 'Subcontractor',
key: 'SUBCONTRACTOR',
description: 'Receive tasks, update status, reply to tasks, log expenses',
isSystem: true,
memberCount: 1,
color: '#06b6d4',
},
]);
const [orgPermissions, setOrgPermissions] = useState({
jobs: { OWNER: ['view','edit','delete'], ADMIN: ['view','edit','delete'], SALES_REP: ['view','edit'], CANVASSER: [], SUBCONTRACTOR: [] },
financials: { OWNER: ['view','edit'], ADMIN: ['view','edit'], SALES_REP: ['view'], CANVASSER: [], SUBCONTRACTOR: [] },
commission: { OWNER: ['view','edit'], ADMIN: ['view','edit'], SALES_REP: ['view'], CANVASSER: [], SUBCONTRACTOR: [] },
team: { OWNER: ['view','invite','remove'], ADMIN: ['view','invite'], SALES_REP: ['view'], CANVASSER: [], SUBCONTRACTOR: [] },
leads: { OWNER: ['view','log','verify'], ADMIN: ['view','log','verify'], SALES_REP: ['view','verify'], CANVASSER: ['view','log'], SUBCONTRACTOR: [] },
leaderboard: { OWNER: ['view'], ADMIN: ['view'], SALES_REP: ['view'], CANVASSER: ['view'], SUBCONTRACTOR: [] },
subcontractor_tasks: { OWNER: ['view','assign'], ADMIN: ['view','assign'], SALES_REP: [], CANVASSER: [], SUBCONTRACTOR: ['view','receive'] },
});
const PERMISSION_MODULES = {
jobs: { label: 'Jobs', actions: ['view','edit','delete'] },
financials: { label: 'Financials', actions: ['view','edit'] },
commission: { label: 'Commission Settings', actions: ['view','edit'] },
team: { label: 'Team Members', actions: ['view','invite','remove'] },
leads: { label: 'Leads & Door Knocks', actions: ['view','log','verify'] },
leaderboard: { label: 'Leaderboard', actions: ['view'] },
subcontractor_tasks: { label: 'Subcontractor Tasks', actions: ['view','assign','receive'] },
};
const [roleCommissionOverrides, setRoleCommissionOverrides] = useState([
{ roleKey: 'SALES_REP', enabled: true, type: 'percent_net', rate: 5 },
{ roleKey: 'CANVASSER', enabled: true, type: 'flat', rate: 300 },
]);
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' },
]);
// Initialize properties once
useEffect(() => {
const data = generateProperties();
@@ -5048,8 +5146,6 @@ export const MockStoreProvider = ({ children }) => {
users,
meetings,
salesHistory, // Exported for Leaderboard
// New Data
owners,
personnel,
vendors,
@@ -5057,7 +5153,6 @@ export const MockStoreProvider = ({ children }) => {
projects,
orders,
vendorInvoices,
leads,
addLead: (lead) => {
const newLead = {
@@ -5180,24 +5275,41 @@ export const MockStoreProvider = ({ children }) => {
setProjects(prev => prev.map(p => p.id === projectId ? { ...p, ...data } : p));
},
// Team Management (job-scoped)
addJobTeamMember: (projectId, member) => {
setProjects(prev => prev.map(p => {
if (p.id !== projectId) return p;
return { ...p, teamMembers: [...(p.teamMembers || []), { ...member, id: `jtm_${Date.now()}_${Math.random().toString(36).slice(2, 6)}` }] };
// Org Settings & Access Control
orgSettings,
updateOrgSettings: (data) => setOrgSettings(prev => ({ ...prev, ...data })),
orgRoles,
updateOrgRole: (roleId, data) => setOrgRoles(prev => prev.map(r => r.id === roleId ? { ...r, ...data } : r)),
orgPermissions,
PERMISSION_MODULES,
updateOrgPermissions: (moduleKey, roleKey, actions) => {
setOrgPermissions(prev => ({
...prev,
[moduleKey]: { ...prev[moduleKey], [roleKey]: actions },
}));
},
removeJobTeamMember: (projectId, memberId) => {
setProjects(prev => prev.map(p => {
if (p.id !== projectId) return p;
return { ...p, teamMembers: (p.teamMembers || []).filter(m => m.id !== memberId) };
}));
roleCommissionOverrides,
setRoleCommissionOverride: (override) => {
setRoleCommissionOverrides(prev => {
const idx = prev.findIndex(o => o.roleKey === override.roleKey);
if (idx >= 0) return prev.map((o, i) => i === idx ? { ...o, ...override } : o);
return [...prev, override];
});
},
updateJobTeamMember: (projectId, memberId, updates) => {
setProjects(prev => prev.map(p => {
if (p.id !== projectId) return p;
return { ...p, teamMembers: (p.teamMembers || []).map(m => m.id === memberId ? { ...m, ...updates } : m) };
}));
removeRoleCommissionOverride: (roleKey) => {
setRoleCommissionOverrides(prev => prev.filter(o => o.roleKey !== roleKey));
},
orgMembers,
updateOrgMember: (memberId, data) => {
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) };
setOrgMembers(prev => [...prev, newMember]);
return newMember;
},
removeOrgMember: (memberId) => {
setOrgMembers(prev => prev.filter(m => m.id !== memberId));
},
}}>
{children}