'datetime', 'is_active' => 'boolean', ]; // ── Relationships ──────────────────────────────────────────────────────── public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); } public function participants(): BelongsToMany { return $this->belongsToMany(User::class, 'conversation_participants') ->withPivot(['role', 'last_read_at', 'is_muted', 'is_archived', 'is_pinned', 'pinned_at', 'joined_at', 'left_at']) ->wherePivotNull('left_at'); } public function allParticipants(): HasMany { return $this->hasMany(ConversationParticipant::class); } public function messages(): HasMany { return $this->hasMany(Message::class)->orderBy('created_at'); } public function latestMessage(): HasOne { return $this->hasOne(Message::class)->whereNull('deleted_at')->latestOfMany(); } // ── Helpers ───────────────────────────────────────────────────────────── public function isDirect(): bool { return $this->type === 'direct'; } public function isGroup(): bool { return $this->type === 'group'; } /** * Find an existing direct conversation between exactly two users, or null. */ public static function findDirect(int $userA, int $userB): ?self { return self::query() ->where('type', 'direct') ->where('is_active', true) ->whereHas('allParticipants', fn ($q) => $q->where('user_id', $userA)->whereNull('left_at')) ->whereHas('allParticipants', fn ($q) => $q->where('user_id', $userB)->whereNull('left_at')) ->whereRaw( '(select count(*) from conversation_participants' .' where conversation_participants.conversation_id = conversations.id' .' and left_at is null) = 2' ) ->first(); } /** * Compute unread count for a given participant. */ public function unreadCountFor(int $userId): int { $participant = $this->allParticipants() ->where('user_id', $userId) ->first(); if (! $participant) { return 0; } $query = $this->messages() ->whereNull('deleted_at') ->where('sender_id', '!=', $userId); if ($participant->last_read_message_id) { $query->where('id', '>', $participant->last_read_message_id); return $query->count(); } if ($participant->last_read_at) { $query->where('created_at', '>', $participant->last_read_at); } return $query->count(); } }