user(); $relation = $user->profileRelation(); if (! $relation) { return $this->fail('Admins have no role profile', null, 422); } $user->load($relation); return $this->ok([ 'role' => $user->role, 'profile' => $user->{$relation}?->toArray(), ]); } public function update(Request $request): JsonResponse { $user = $request->user(); $relation = $user->profileRelation(); if (! $relation) { return $this->fail('Admins have no role profile to update', null, 422); } $rules = $this->rulesFor($user->role); $validated = Validator::make($request->all(), $rules)->validate(); $profile = $user->{$relation}; if (! $profile) { $profileClass = User::profileModelForRole($user->role); $profile = $profileClass::create(array_merge(['user_id' => $user->id], $validated)); } else { // Self-update should not allow changing verification fields. unset( $validated['verification_status'], $validated['verified_at'], $validated['verified_by_admin_id'], $validated['rejection_reason'], ); // Resubmitting a rejected profile resets it to pending. if ( method_exists($profile, 'markVerified') && property_exists($profile, 'attributes') && ($profile->verification_status ?? null) === 'rejected' ) { $validated['verification_status'] = 'pending'; $validated['rejection_reason'] = null; } $profile->update($validated); } return $this->ok([ 'role' => $user->role, 'profile' => $profile->fresh()->toArray(), ], 'Profile updated'); } private function rulesFor(string $role): array { return match ($role) { User::ROLE_RESIDENT => [ 'date_of_birth' => ['nullable', 'date', 'before:today'], 'gender' => ['nullable', 'in:male,female,other,prefer_not_to_say'], 'occupation' => ['nullable', 'string', 'max:100'], 'emergency_contact_name' => ['nullable', 'string', 'max:191'], 'emergency_contact_phone' => ['nullable', 'string', 'max:20'], ], User::ROLE_DRIVER => [ 'license_number' => ['nullable', 'string', 'max:32'], 'license_class' => ['nullable', 'string', 'max:16'], 'license_expires_at' => ['nullable', 'date'], 'license_photo_path' => ['nullable', 'string', 'max:255'], 'years_of_experience' => ['nullable', 'integer', 'min:0', 'max:80'], 'date_of_birth' => ['nullable', 'date', 'before:today'], 'gender' => ['nullable', 'in:male,female,other,prefer_not_to_say'], 'emergency_contact_name' => ['nullable', 'string', 'max:191'], 'emergency_contact_phone' => ['nullable', 'string', 'max:20'], ], User::ROLE_HELPER => [ 'date_of_birth' => ['nullable', 'date', 'before:today'], 'gender' => ['nullable', 'in:male,female,other,prefer_not_to_say'], 'emergency_contact_name' => ['nullable', 'string', 'max:191'], 'emergency_contact_phone' => ['nullable', 'string', 'max:20'], ], User::ROLE_SCANNER => [ 'shift_preference' => ['nullable', 'in:morning,afternoon,night,flexible'], 'date_of_birth' => ['nullable', 'date', 'before:today'], 'gender' => ['nullable', 'in:male,female,other,prefer_not_to_say'], 'emergency_contact_name' => ['nullable', 'string', 'max:191'], 'emergency_contact_phone' => ['nullable', 'string', 'max:20'], ], User::ROLE_STORE_PARTNER => [ 'business_name' => ['nullable', 'string', 'max:191'], 'business_permit_number' => ['nullable', 'string', 'max:64'], 'contact_phone' => ['nullable', 'string', 'max:20'], ], default => [], }; } }