*/ use HasApiTokens, HasFactory, HasRoles, LogsActivity, Notifiable, SoftDeletes; public const ROLE_SUPER_ADMIN = 'super_admin'; public const ROLE_ADMIN = 'admin'; public const ROLE_RESIDENT = 'resident'; public const ROLE_DRIVER = 'driver'; public const ROLE_HELPER = 'helper'; public const ROLE_SCANNER = 'scanner'; public const ROLE_STORE_PARTNER = 'store_partner'; public const STATUS_ACTIVE = 'active'; public const STATUS_SUSPENDED = 'suspended'; public const STATUS_PENDING = 'pending'; protected $fillable = [ 'uuid', 'tenant_id', 'email', 'phone', 'password', 'role', 'status', 'first_name', 'middle_name', 'last_name', 'avatar_path', 'preferred_language', 'fcm_token', ]; protected $hidden = [ 'password', 'remember_token', ]; protected static function booted(): void { static::creating(function (self $user): void { if (empty($user->uuid)) { $user->uuid = (string) Str::uuid(); } }); } protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'phone_verified_at' => 'datetime', 'last_login_at' => 'datetime', 'password' => 'hashed', ]; } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['email', 'phone', 'role', 'status', 'first_name', 'last_name']) ->logOnlyDirty() ->dontSubmitEmptyLogs(); } public function getFullNameAttribute(): string { return trim(implode(' ', array_filter([ $this->first_name, $this->middle_name, $this->last_name, ]))); } public function sendEmailVerificationNotification(): void { $this->notify(new VerifyEmailNotification); } public function headedHousehold(): HasOne { return $this->hasOne(Household::class, 'head_user_id'); } public function householdMemberships() { return $this->hasMany(HouseholdMember::class); } public function residentProfile(): HasOne { return $this->hasOne(ResidentProfile::class); } public function driverProfile(): HasOne { return $this->hasOne(DriverProfile::class); } public function helperProfile(): HasOne { return $this->hasOne(HelperProfile::class); } public function scannerProfile(): HasOne { return $this->hasOne(ScannerProfile::class); } public function storePartnerProfile(): HasOne { return $this->hasOne(StorePartnerProfile::class); } public function driverTeam(): HasOne { return $this->hasOne(CollectionTeam::class, 'driver_id'); } public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } public function isSuperAdmin(): bool { return $this->role === self::ROLE_SUPER_ADMIN; } /** * Resolve the role-specific profile relation name. Admins have no profile. */ public function profileRelation(): ?string { return match ($this->role) { self::ROLE_RESIDENT => 'residentProfile', self::ROLE_DRIVER => 'driverProfile', self::ROLE_HELPER => 'helperProfile', self::ROLE_SCANNER => 'scannerProfile', self::ROLE_STORE_PARTNER => 'storePartnerProfile', default => null, }; } /** * Map of role => profile FQCN. Used for create-on-register. */ public static function profileModelForRole(string $role): ?string { return match ($role) { self::ROLE_RESIDENT => ResidentProfile::class, self::ROLE_DRIVER => DriverProfile::class, self::ROLE_HELPER => HelperProfile::class, self::ROLE_SCANNER => ScannerProfile::class, self::ROLE_STORE_PARTNER => StorePartnerProfile::class, default => null, }; } public function profile(): ?Model { $relation = $this->profileRelation(); return $relation ? $this->{$relation} : null; } /** * Get the household this user belongs to (either as head or member). */ public function getHouseholdAttribute(): ?Household { return Household::where('head_user_id', $this->id) ->orWhereHas('members', function ($q) { $q->where('user_id', $this->id); }) ->first(); } }