chat icon indicating copy to clipboard operation
chat copied to clipboard

[Need help by everyone]: 📬How to create an Inbox with the newest update?

Open pmochine opened this issue 4 years ago • 3 comments

So before the big update, my inbox worked quite fine. However, now I'm struggling to create an inbox method :( I need everyone's help. My code gets quite ugly.

I show you the "old" code before patch 4.x.x. and explain what needs to be done.

    /**
     * Fetch all inbox for currently loggedin user with pagination.
     *
     * @param  User        $auth
     * @param  int $offset
     * @param  int $take
     * @param  string      $order
     * @return LengthAwarePaginator
     */
    protected function inbox(User $auth, int $offset = 0, int $take = 20, string $order = 'desc'): LengthAwarePaginator
    {
        $conversations = \Chat::conversations()
            ->setPaginationParams([
                'sorting' => $order,
            ])
            ->for($auth)
            ->limit($take)
            ->page(($offset + $take) / $take)
            ->get();

        //eager load users to the table
        $withUsers = $conversations
            ->load(['users' => function ($query) {
                $query->withTrashed();
            }]);

        //filters empty last_messages out
        $collection = $withUsers->filter(function ($value) {
            return !is_null($value->last_message);
        })->values();

        //swap out
        return $conversations->setCollection($collection);
    }

Explination

  1. First I'm loading all conversation a user has via pagination
  2. I'm eager loading all users, even deleted ones (they appear as "anonymous" so the user still has the option to read the messages of a deleted user)
  3. Sometimes they are conversations where all messages have been deleted or it's empty, so the last_message resulted null. So I needed to filter those out.
  4. The modified collection is set back, so I can work with the data.

Currently

Now with the new update, this is not that easy anymore. And I'm struggling to create an inbox method again.

This is my current code (not working):

protected function inbox(User $auth, int $offset = 0, int $take = 20, string $order = 'desc'): LengthAwarePaginator
    {
        $conversations = ChatChat::conversations()
            ->setPaginationParams([
                'sorting' => $order,
            ])
            ->setParticipant($auth)
            ->limit($take)
            ->page(($offset + $take) / $take)
            ->get();

        // Since the new update >4.x.x, it gives me unfortunately the Participation Model back
        $withUsers = $conversations
            ->load(['conversation.participants.messageable' => function ($query) {
                $query->withTrashed();
            }]);

        //filters empty last_messages out
        $collection = $withUsers->filter(function ($value) {
            return !is_null($value->conversation->last_message);
        })->values();

        //swap out
        return $conversations->setCollection($collection);
    }

Problems I face:

  • [x] - The pagination does not result in Conversation Collection but to the Participation Model (I'm using Laravel API Resources, so I can hack this away, ugly but it's ok).
  • [x] - I fixed the eager load problem with loading several relationships like 'conversation.participants.messageable'
  • [ ] - This gives me the biggest problem. I don't know how to filter out the "last_message". Because even if I delete messages, the messages are still returned for the user, even though it should be deleted. Addiontally, I face the problem that when I try to use $this->getNotification(auth()->user()) it fails, because it cannot find the notification table. I guess because it's deleted?

Testing

I'm super close to migrating the code, however, this test still fails hard because I cannot filter out the last_message

    /** @test */
    public function no_inbox_is_loaded_when_messages_is_deleted_by_authenticed_user()
    {
        $this->deleteMessageWithId(1)
            ->assertStatus(202);

        $this->deleteMessageWithId(2)
            ->assertStatus(202);

        $this->fetchInbox()
            ->assertJsonCount(0, 'data')
            ->assertStatus(200);
    }

Any tips for me? Thank you!

pmochine avatar Jan 17 '20 07:01 pmochine

I will take a look over the weekend. Thanks for detailed explanation

musonza avatar Jan 17 '20 23:01 musonza

It would be lovely 😊There must be a way to create a simple inbox.

Requirements are super easy (perspective from the authenticated user and only two people are chatting):

  1. Able to paginate
  2. See the last message
  3. See if it was read or not
  4. Fetch user's data

There are two catches though:

  1. There might be conversations where all messages have been deleted -> filter them out
  2. There might be conversations where the other user has deleted his account, but still load to all conversation even the trashed users

pmochine avatar Feb 04 '20 11:02 pmochine

It would be lovely 😊There must be a way to create a simple inbox.

Requirements are super easy (perspective from the authenticated user and only two people are chatting):

  1. Able to paginate
  2. See the last message
  3. See if it was read or not
  4. Fetch user's data

There are two catches though:

  1. There might be conversations where all messages have been deleted -> filter them out
  2. There might be conversations where the other user has deleted his account, but still load to all conversation even the trashed users

@pmochine Hi, i do this on my project and i thing it can help you

protected function inbox(User $auth, int $offset = 0, int $take = 20, string $order = 'desc'): LengthAwarePaginator
{
    $conversations = ChatChat::conversations()
        ->setPaginationParams([
            'sorting' => $order,
        ])
        ->setParticipant($auth)
        ->limit($take)
        ->page(($offset + $take) / $take)
        ->get();
    return $conversations;
}

All You Need To Do:

Clone library and replace getConversationsList function in Musonza\Chat\Models\Conversation file

/**
 * @param Model $participant
 * @param $options
 *
 * @return mixed
 **/
private function getConversationsList(Model $participant, $options)
{
    /** @var Builder $paginator */
    $paginator = $participant->participation()
        ->join($this->tablePrefix . 'conversations as c', $this->tablePrefix . 'participation.conversation_id', '=', 'c.id')
        ->with([
            'conversation.last_message' => function ($query) use ($participant) {
                $query->join($this->tablePrefix . 'message_notifications', $this->tablePrefix . 'message_notifications.message_id', '=', $this->tablePrefix . 'messages.id')
                    ->select($this->tablePrefix . 'message_notifications.*', $this->tablePrefix . 'messages.*')
                    ->where($this->tablePrefix . 'message_notifications.messageable_id', $participant->getKey())
                    ->where($this->tablePrefix . 'message_notifications.messageable_type', get_class($participant))
                    ->whereNull($this->tablePrefix . 'message_notifications.deleted_at');
            },
            'conversation.participants.messageable' => function ($query) {
                $query->withTrashed();
            },
        ])
        ->whereHas('conversation.last_message', function ($query) use ($participant) {
            $query->join($this->tablePrefix . 'message_notifications', $this->tablePrefix . 'message_notifications.message_id', '=', $this->tablePrefix . 'messages.id')
                ->select($this->tablePrefix . 'message_notifications.*', $this->tablePrefix . 'messages.*')
                ->where($this->tablePrefix . 'message_notifications.messageable_id', $participant->getKey())
                ->where($this->tablePrefix . 'message_notifications.messageable_type', get_class($participant))
                ->whereNull($this->tablePrefix . 'message_notifications.deleted_at');
        });

    if (isset($options['filters']['private'])) {
        $paginator = $paginator->where('c.private', (bool)$options['filters']['private']);
    }

    if (isset($options['filters']['direct_message'])) {
        $paginator = $paginator->where('c.direct_message', (bool)$options['filters']['direct_message']);
    }
    return $paginator
        ->orderBy('c.updated_at', 'DESC')
        ->orderBy('c.id', 'DESC')
        ->distinct('c.id')
        ->paginate($options['perPage'], [$this->tablePrefix . 'participation.*', $this->tablePrefix . 'participation.id as participation_id', 'c.*'], $options['pageName'], $options['page']);
}

And in view loop, get another participation

$anotherUser = $row->conversation->participants->where('id', '!=', $row->participation_id)->first()->messageable;

$conversaions:

Screenshot (36)_LI

aren1989 avatar Feb 07 '20 17:02 aren1989