diff --git a/Modules/UserManagement/app/Http/Controllers/UserController.php b/Modules/UserManagement/app/Http/Controllers/UserController.php index 4f49bad..a041b6b 100644 --- a/Modules/UserManagement/app/Http/Controllers/UserController.php +++ b/Modules/UserManagement/app/Http/Controllers/UserController.php @@ -58,9 +58,12 @@ class UserController extends Controller $nextNumber = $last ? ((int) substr($last, 4)) + 1 : 1; $nextCode = 'EMP-' . str_pad($nextNumber, 4, '0', STR_PAD_LEFT); + $roles = \Spatie\Permission\Models\Role::orderBy('name')->pluck('name'); + return Inertia::render('UserManagement::Users/Create', [ 'isSuperAdmin' => $isSuperAdmin, 'nextEmployeeCode' => $nextCode, + 'roles' => $roles, 'contractors' => $isSuperAdmin ? Contractor::where('status', 'active') ->orderBy('company_name') diff --git a/Modules/UserManagement/resources/js/Pages/Users/Create.tsx b/Modules/UserManagement/resources/js/Pages/Users/Create.tsx index 596dfe3..e6a1413 100644 --- a/Modules/UserManagement/resources/js/Pages/Users/Create.tsx +++ b/Modules/UserManagement/resources/js/Pages/Users/Create.tsx @@ -22,9 +22,10 @@ interface Props extends PageProps { contractors: Contractor[]; isSuperAdmin: boolean; nextEmployeeCode: string; + roles?: string[]; } -export default function Create({ contractors, isSuperAdmin, nextEmployeeCode }: Props) { +export default function Create({ contractors, isSuperAdmin, nextEmployeeCode, roles = [] }: Props) { const { auth } = usePage().props; const { data, setData, post, processing, errors } = useForm({ @@ -210,9 +211,13 @@ export default function Create({ contractors, isSuperAdmin, nextEmployeeCode }: value={data.spatie_role} onValueChange={(v) => { if (v) { + const lower = v.toLowerCase(); let targetType = 'employee'; - if (v === 'Super Admin' || v === 'admin') targetType = 'admin'; - if (v === 'Contractor Admin' || v === 'Contractor') targetType = 'contractor'; + if (lower.includes('contractor')) { + targetType = 'contractor'; + } else if (lower.includes('super admin') || lower === 'admin') { + targetType = 'admin'; + } setData(d => ({ ...d, @@ -226,10 +231,9 @@ export default function Create({ contractors, isSuperAdmin, nextEmployeeCode }: - Project Manager - Contractor Admin - Construction Supervisor - Site Technical + {(roles && roles.length > 0 ? roles : ['Super Admin', 'Admin', 'Project Manager', 'Contractor Admin', 'Construction Supervisor', 'Site Technical', 'Designer']).map((r) => ( + {r} + ))} {/* @ts-ignore */} diff --git a/resources/js/Pages/Dashboard.tsx b/resources/js/Pages/Dashboard.tsx index f14ec3e..6f1975a 100644 --- a/resources/js/Pages/Dashboard.tsx +++ b/resources/js/Pages/Dashboard.tsx @@ -43,9 +43,12 @@ export default function Dashboard({ }; const roleName = (roleAnalytics?.role || '').toLowerCase(); - const isExecutive = roleName.includes('admin') || roleName.includes('super'); - const isPM = roleName.includes('project manager'); - const isContractor = roleName.includes('contractor'); + const userType = (roleAnalytics?.user_type || '').toLowerCase(); + + // Executive dashboard is ONLY for system admins (user_type === 'admin' or role includes 'super' / 'admin' AND NOT contractor) + const isContractor = userType === 'contractor' || roleName.includes('contractor'); + const isExecutive = !isContractor && (userType === 'admin' || roleName.includes('super admin') || roleName === 'admin'); + const isPM = !isContractor && !isExecutive && roleName.includes('project manager'); return ( has('roleAnalytics.logistics') ); } + + /** @test */ + public function test_custom_or_newly_created_roles_dynamically_resolve_assigned_dashboard(): void + { + // 1. Custom Contractor Role -> Contractor Bidding & Financials Dashboard + $newContractorRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'Subcontractor Estimator']); + $contractorUser = \App\Models\User::factory()->create([ + 'user_type' => 'contractor', + 'status' => 'active', + ]); + $contractorUser->assignRole($newContractorRole); + + $response = $this->actingAs($contractorUser)->get(route('dashboard')); + $response->assertStatus(200) + ->assertInertia(fn ($page) => $page + ->component('Dashboard') + ->where('roleAnalytics.role', 'Subcontractor Estimator') + ->where('roleAnalytics.user_type', 'contractor') + ->has('roleAnalytics.bidding') + ); + + // 2. Custom Executive Admin Role -> Executive Governance Dashboard + $newExecutiveRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'Regional Admin Officer']); + $executiveUser = \App\Models\User::factory()->create([ + 'user_type' => 'admin', + 'status' => 'active', + ]); + $executiveUser->assignRole($newExecutiveRole); + + $response = $this->actingAs($executiveUser)->get(route('dashboard')); + $response->assertStatus(200) + ->assertInertia(fn ($page) => $page + ->component('Dashboard') + ->where('roleAnalytics.role', 'Regional Admin Officer') + ->where('roleAnalytics.user_type', 'admin') + ->has('roleAnalytics.financials') + ->has('roleAnalytics.approvals') + ); + + // 3. Custom Project Manager Role -> Project Operations Dashboard + $newPMRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'Senior Project Manager']); + $pmUser = \App\Models\User::factory()->create([ + 'user_type' => 'employee', + 'status' => 'active', + ]); + $pmUser->assignRole($newPMRole); + + $response = $this->actingAs($pmUser)->get(route('dashboard')); + $response->assertStatus(200) + ->assertInertia(fn ($page) => $page + ->component('Dashboard') + ->where('roleAnalytics.role', 'Senior Project Manager') + ->where('roleAnalytics.user_type', 'employee') + ->has('roleAnalytics.milestones') + ); + + // 4. Custom Site Officer Role -> Site Execution Dashboard + $newSiteRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'Chief Safety Officer']); + $siteUser = \App\Models\User::factory()->create([ + 'user_type' => 'employee', + 'status' => 'active', + ]); + $siteUser->assignRole($newSiteRole); + + $response = $this->actingAs($siteUser)->get(route('dashboard')); + $response->assertStatus(200) + ->assertInertia(fn ($page) => $page + ->component('Dashboard') + ->where('roleAnalytics.role', 'Chief Safety Officer') + ->where('roleAnalytics.user_type', 'employee') + ); + } }