- Add UserRole type and AppUser interface to types.ts - Create UserContext with useUser() hook providing role-based permission booleans - Split App into App (auth wrapper) + AppContent (uses UserContext) - Update Sidebar to filter nav items by UserRole instead of boolean isAdmin - Add User Management nav item (super_admin only) - Add AgencyFilterBar component for oversight_admin/super_admin session-level filtering - Pass agencyId to getCampaigns, getAnalytics, audit endpoints in apiService - Add getMe, getUsers, updateUser, createAgency to apiService - Build UserManagement page with user table (role/agency dropdowns) and agency CRUD - Add readOnly prop to Campaigns (hides create/delete/status-toggle for oversight_admin) - Add readOnly prop to Settings (disables all ManagementCards, shows view-only banner) - Pass agencyId to Analytics component for filtered data - Update urlState with Knowledge Base and User Management views Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
36 lines
1.4 KiB
TypeScript
36 lines
1.4 KiB
TypeScript
type View = 'Home' | 'Analytics' | 'Campaigns' | 'WIP Reviewer' | 'CopyGenAI' | 'Settings' | 'Profile' | 'Auditing' | 'Knowledge Base' | 'User Management';
|
|
|
|
export interface UrlNavigationState {
|
|
view: View;
|
|
campaignName: string | null;
|
|
proofId: string | null;
|
|
}
|
|
|
|
const VALID_VIEWS: View[] = ['Home', 'Analytics', 'Campaigns', 'WIP Reviewer', 'CopyGenAI', 'Settings', 'Profile', 'Auditing', 'Knowledge Base', 'User Management'];
|
|
|
|
export function parseUrlState(): UrlNavigationState {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const view = params.get('view') as View;
|
|
return {
|
|
view: VALID_VIEWS.includes(view) ? view : 'Home',
|
|
campaignName: params.get('campaign'),
|
|
proofId: params.get('proof'),
|
|
};
|
|
}
|
|
|
|
export function buildUrl(state: Partial<UrlNavigationState>): string {
|
|
const params = new URLSearchParams();
|
|
if (state.view && state.view !== 'Home') params.set('view', state.view);
|
|
if (state.campaignName) params.set('campaign', state.campaignName);
|
|
if (state.proofId) params.set('proof', state.proofId);
|
|
const query = params.toString();
|
|
return query ? `?${query}` : '/';
|
|
}
|
|
|
|
export function pushUrlState(state: Partial<UrlNavigationState>): void {
|
|
const newUrl = buildUrl(state);
|
|
// Only push if URL actually changed to avoid duplicate history entries
|
|
if (newUrl !== window.location.pathname + window.location.search) {
|
|
window.history.pushState(state, '', newUrl);
|
|
}
|
|
}
|