'datetime', 'password' => 'hashed', 'status' => UserStatus::class, ]; } protected static function newFactory(): Factory { return UserFactory::new(); } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logFillable() ->logExcept(['password']) ->logOnlyDirty() ->dontSubmitEmptyLogs(); } public function canAccessPanel(Panel $panel): bool { return match ($panel->getId()) { 'admin' => $this->hasRole('admin'), default => false, }; } public function listings() { return $this->hasMany(Listing::class); } public function profile() { return $this->hasOne(Profile::class); } public function favoriteListings() { return $this->belongsToMany(Listing::class, 'favorite_listings')->withTimestamps(); } public function favoriteSellers() { return $this->belongsToMany(self::class, 'favorite_sellers', 'user_id', 'seller_id')->withTimestamps(); } public function favoriteSearches() { return $this->hasMany(FavoriteSearch::class); } public function buyerConversations() { return $this->hasMany(Conversation::class, 'buyer_id'); } public function sellerConversations() { return $this->hasMany(Conversation::class, 'seller_id'); } public function sentConversationMessages() { return $this->hasMany(ConversationMessage::class, 'sender_id'); } public function canImpersonate(): bool { return $this->hasRole('admin'); } public function canBeImpersonated(): bool { return ! $this->hasRole('admin'); } public function getFilamentAvatarUrl(): ?string { if (! filled($this->avatar_url)) { return null; } $path = trim((string) $this->avatar_url); if (! LocalMedia::managesPath($path)) { return LocalMedia::url($path); } $disk = LocalMedia::disk(); if (Storage::disk($disk)->exists($path)) { return Storage::disk($disk)->url($path); } return LocalMedia::url($path); } public function getDisplayName(): string { return trim((string) ($this->name ?: $this->email ?: 'User')); } public function getEmail(): string { return trim((string) $this->email); } public function toggleFavoriteListing(Listing $listing): bool { $isFavorite = $this->favoriteListings()->whereKey($listing->getKey())->exists(); if ($isFavorite) { $this->favoriteListings()->detach($listing->getKey()); return false; } $this->favoriteListings()->syncWithoutDetaching([$listing->getKey()]); return true; } public function toggleFavoriteSeller(self $seller): bool { if ((int) $seller->getKey() === (int) $this->getKey()) { return false; } $isFavorite = $this->favoriteSellers()->whereKey($seller->getKey())->exists(); if ($isFavorite) { $this->favoriteSellers()->detach($seller->getKey()); return false; } $this->favoriteSellers()->syncWithoutDetaching([$seller->getKey()]); return true; } public function unreadInboxCount(): int { return Conversation::unreadCountForUser((int) $this->getKey()); } public function unreadNotificationCount(): int { try { return (int) $this->unreadNotifications()->count(); } catch (Throwable) { return 0; } } public function savedListingsCount(): int { try { return (int) $this->favoriteListings()->count(); } catch (Throwable) { return 0; } } public function headerBadgeCounts(): array { return [ 'messages' => $this->unreadInboxCount(), 'notifications' => $this->unreadNotificationCount(), 'favorites' => $this->savedListingsCount(), ]; } public static function totalCount(): int { return (int) static::query()->count(); } public function homeFavoriteListingIds(): array { return $this->favoriteListings() ->pluck('listings.id') ->map(fn ($id): int => (int) $id) ->all(); } public function panelListingOptions(): Collection { return $this->listings() ->latest('id') ->get(['id', 'title', 'status']); } public function loadPanelProfile(): self { return $this->loadCount([ 'listings', 'favoriteListings', 'favoriteSearches', 'favoriteSellers', ]); } }