Skip to content

Commit

Permalink
refactor: improve comments system
Browse files Browse the repository at this point in the history
  • Loading branch information
yilanboy committed Nov 4, 2024
1 parent c578bfb commit aed311b
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 94 deletions.
2 changes: 1 addition & 1 deletion app/Livewire/Shared/Comments/CommentCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class CommentCard extends Component

public string $body;

public object $createdAt;
public string $createdAt;

public bool $isEdited;

Expand Down
64 changes: 21 additions & 43 deletions app/Livewire/Shared/Comments/CommentGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,17 @@

namespace App\Livewire\Shared\Comments;

use App\Enums\CommentOrder;
use App\Models\Comment;
use App\Models\Post;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Locked;
use Livewire\Attributes\On;
use Livewire\Component;
use Throwable;

/**
* @property Collection<Comment> $comments
*/
class CommentGroup extends Component
{
use AuthorizesRequests;
Expand Down Expand Up @@ -52,20 +45,29 @@ class CommentGroup extends Component
#[Locked]
public string $commentGroupName;

#[Locked]
public CommentOrder $order = CommentOrder::LATEST;

/**
* Comment ids.
*
* @var array<int>
* Comments array, the format is like:
* [
* 1 => ["id" => 1, "body" => "hello" ...],
* 2 => ["id" => 2, "body" => "world" ...],
* ],
*/
public array $commentIds = [];
public array $comments = [];

#[On('append-new-id-to-{commentGroupName}')]
public function appendCommentIdInGroup(int $id): void
#[On('insert-new-comment-to-{commentGroupName}')]
public function insertComment(int $id): void
{
$this->commentIds[] = $id;
$comment = Comment::query()
->select(['id', 'user_id', 'body', 'created_at', 'updated_at'])
->withCount('children')
->where('id', $id)
->orderByDesc('children_count')
->with('user:id,name,email')
->with('children')
->first()
->toArray();

$this->comments = [$comment['id'] => $comment] + $this->comments;
}

/**
Expand Down Expand Up @@ -95,37 +97,13 @@ public function destroy(int $commentId): void
$post->decrement('comment_counts');
});

unset($this->comments[$commentId]);

$this->dispatch('update-comment-counts');

$this->dispatch('info-badge', status: 'success', message: '成功刪除留言!');
}

/**
* @return Collection<Comment>
*/
#[Computed]
public function comments(): Collection
{
return Comment::query()
->select(['id', 'body', 'user_id', 'created_at', 'updated_at'])
->withCount('children')
->when($this->order === CommentOrder::LATEST, function (Builder $query) {
$query->latest('id');
})
->when($this->order === CommentOrder::OLDEST, function (Builder $query) {
$query->oldest('id');
})
->when($this->order === CommentOrder::POPULAR, function (Builder $query) {
$query->orderByDesc('children_count');
})
->whereIn('id', $this->commentIds)
->where('post_id', $this->postId)
->where('parent_id', $this->parentId)
->with('user:id,name,email')
->with('children')
->get();
}

public function render(): View
{
return view('livewire.shared.comments.comment-group');
Expand Down
42 changes: 24 additions & 18 deletions app/Livewire/Shared/Comments/CommentList.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,19 @@ class CommentList extends Component
public CommentOrder $order = CommentOrder::LATEST;

/**
* Comment ids list, example:
* Comments list array, the format is like:
* [
* [1, 2, 3, 4, 5],
* [6, 7, 8, 9, 10],
* [11, 12, 13, 14, 15],
* [
* 1 => ["id" => 1, "body" => "hello" ...],
* 2 => ["id" => 2, "body" => "world" ...],
* ],
* [
* 3 => ["id" => 3, "body" => "foo" ...],
* 4 => ["id" => 4, "body" => "bar" ...],
* ],
* ]
*
* @var array<array<int>>
*/
public array $commentIdsList = [];
public array $commentsList = [];

public int $skipCounts = 0;

Expand All @@ -78,22 +81,22 @@ public function appendNewIdToNewCommentIds(int $id): void

public function showMoreComments(): void
{
$commentIds = $this->getCommentIds();
$comments = $this->getComments();

$this->updateSkipCounts();
$this->updateCommentIdsList($commentIds);
$this->updateShowMoreButtonStatus($commentIds);
$this->updateCommentsList($comments);
$this->updateShowMoreButtonStatus($comments);
}

public function render(): View
{
return view('livewire.shared.comments.comment-list');
}

private function getCommentIds(): array
private function getComments(): array
{
return Comment::query()
->select('id')
->select(['id', 'user_id', 'body', 'created_at', 'updated_at'])
// use a sub query to generate children_count column
->withCount('children')
->when($this->order === CommentOrder::LATEST, function (Builder $query) {
Expand All @@ -115,7 +118,10 @@ private function getCommentIds(): array
->skip($this->skipCounts)
// Plus one is needed here because we need to determine whether there is a next page.
->take($this->perPage + 1)
->pluck('id')
->with('user:id,name,email')
->with('children')
->get()
->keyBy('id')
->toArray();
}

Expand All @@ -124,16 +130,16 @@ private function updateSkipCounts(): void
$this->skipCounts += $this->perPage;
}

private function updateCommentIdsList(array $commentIds): void
private function updateCommentsList(array $comments): void
{
if (count($commentIds) > 0) {
$this->commentIdsList[] = array_slice($commentIds, 0, $this->perPage);
if (count($comments) > 0) {
$this->commentsList[] = array_slice($comments, 0, $this->perPage, true);
}
}

private function updateShowMoreButtonStatus(array $commentIds): void
private function updateShowMoreButtonStatus(array $comments): void
{
if (count($commentIds) <= $this->perPage) {
if (count($comments) <= $this->perPage) {
$this->showMoreButtonIsActive = false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/Livewire/Shared/Comments/CreateCommentModal.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public function store(?int $parentId = null): void
// Notify the article author of new comments.
$post->user->notifyNewComment(new NewComment($comment));

$this->dispatch('append-new-id-to-'.($parentId ?? 'root').'-new-comment-group', id: $comment->id);
$this->dispatch('insert-new-comment-to-'.($parentId ?? 'root').'-new-comment-group', id: $comment->id);

$this->dispatch('append-new-id-to-'.($parentId ?? 'root').'-comment-list', id: $comment->id);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class="size-10 rounded-full hover:ring-2 hover:ring-blue-400"

<time
class="hidden text-gray-400 md:block"
datetime="{{ $createdAt->toDateString() }}"
>{{ $createdAt->format('Y 年 m 月 d 日') }}</time>
datetime="{{ date('d-m-Y', strtotime($createdAt)) }}"
>{{ date('Y 年 m 月 d 日', strtotime($createdAt)) }}</time>

@if ($isEdited)
<span class="text-gray-400">(已編輯)</span>
Expand Down
40 changes: 19 additions & 21 deletions resources/views/livewire/shared/comments/comment-group.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,23 @@
class="w-full"
x-data="commentGroup"
>
@if (count($commentIds) > 0)
@foreach ($this->comments as $comment)
<livewire:shared.comments.comment-card
:$maxLayer
:$currentLayer
:$postId
:$postAuthorId
:comment-id="$comment->id"
:user-id="$comment->user_id ?? 0"
:user-gravatar-url="$comment->user ? get_gravatar($comment->user->email) : ''"
:user-name="$comment->user->name ?? ''"
:body="$comment->body"
:created-at="$comment->created_at"
:is-edited="$comment->created_at->ne($comment->updated_at)"
:has-children="$comment->children->count() > 0"
{{-- when the parent component is updated, the child component is updated together --}}
{{-- reference: https://github.com/livewire/livewire/discussions/1895 --}}
:key="'comment-' . $comment->id . '-has-' . $comment->children->count() . '-children'"
/>
@endforeach
@endif
@foreach ($comments as $comment)
<livewire:shared.comments.comment-card
:$maxLayer
:$currentLayer
:$postId
:$postAuthorId
:comment-id="$comment['id']"
:user-id="$comment['user_id'] ?? 0"
:user-gravatar-url="$comment['user'] ? get_gravatar($comment['user']['email']) : ''"
:user-name="$comment['user'] ? $comment['user']['name'] : ''"
:body="$comment['body']"
:created-at="$comment['created_at']"
:is-edited="$comment['created_at'] !== $comment['updated_at']"
:has-children="$comment['children_count'] > 0"
{{-- when the parent component is updated, the child component is updated together --}}
{{-- reference: https://github.com/livewire/livewire/discussions/1895 --}}
:key="'comment-' . $comment['id'] . '-has-' . $comment['children_count'] . '-children'"
/>
@endforeach
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,16 @@
class="w-full"
x-data="commentList"
>
@foreach ($commentIdsList as $commentIds)
@foreach ($commentsList as $comments)
<livewire:shared.comments.comment-group
:$maxLayer
:$currentLayer
:$postId
:$postAuthorId
:$parentId
:$commentIds
:comment-group-name="$commentIds[0] . '-comment-group'"
:$order
:key="$commentIds[0] . '-comment-group'"
:$comments
:comment-group-name="array_key_first($comments) . '-comment-group'"
:key="array_key_first($comments) . '-comment-group'"
/>
@endforeach

Expand Down
6 changes: 3 additions & 3 deletions tests/Feature/Comments/CreateCommentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
->set('body', $body)
->set('captchaToken', 'fake-captcha-response')
->call('store')
->assertDispatched('append-new-id-to-root-new-comment-group')
->assertDispatched('insert-new-comment-to-root-new-comment-group')
->assertDispatched('close-create-comment-modal')
->assertDispatched('update-comment-counts')
->assertDispatched('info-badge',
Expand All @@ -45,7 +45,7 @@
->set('body', $body)
->set('captchaToken', 'fake-captcha-response')
->call('store')
->assertDispatched('append-new-id-to-root-new-comment-group')
->assertDispatched('insert-new-comment-to-root-new-comment-group')
->assertDispatched('close-create-comment-modal')
->assertDispatched('update-comment-counts')
->assertDispatched('info-badge',
Expand Down Expand Up @@ -157,7 +157,7 @@
->set('body', 'Hello World!')
->set('captchaToken', 'fake-captcha-response')
->call('store', parentId: $comment->id)
->assertDispatched('append-new-id-to-'.$comment->id.'-new-comment-group')
->assertDispatched('insert-new-comment-to-'.$comment->id.'-new-comment-group')
->assertDispatched('close-create-comment-modal')
->assertDispatched('update-comment-counts')
->assertDispatched('info-badge',
Expand Down

0 comments on commit aed311b

Please sign in to comment.