Skip to content

Commit e372757

Browse files
Merge pull request #66 from MetaFilter/post-tools
Comment moderation variations
2 parents 7f70134 + f2fa631 commit e372757

48 files changed

Lines changed: 1447 additions & 321 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/Enums/CommentStateEnum.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Enums;
6+
7+
enum CommentStateEnum: string
8+
{
9+
case Viewing = 'viewing';
10+
case Editing = 'editing';
11+
case Flagging = 'flagging';
12+
case Replying = 'replying';
13+
case Moderating = 'moderating';
14+
}

app/Enums/LivewireEventEnum.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
enum LivewireEventEnum: string
88
{
99
case CommentDeleted = 'comment-deleted';
10+
case CommentFlagCancelled = 'comment-flag-cancelled';
1011
case CommentFlagDeleted = 'comment-flag-deleted';
1112
case CommentFlagged = 'comment-flagged';
1213
case CommentStored = 'comment-stored';
1314
case CommentUpdated = 'comment-updated';
15+
case CommentFormStateChanged = 'comment-form-state-changed';
1416
case EditorUpdated = 'editor-updated';
1517
case EscapeKeyClicked = 'escape-key-clicked';
1618
case FavoriteDeleted = 'favorite-deleted';
@@ -19,6 +21,7 @@ enum LivewireEventEnum: string
1921
case FlagDeleted = 'flag-deleted';
2022
case HideFlagCommentForm = 'hide-flag-comment-form';
2123
case PostDeleted = 'post-deleted';
24+
case PostFlagCancelled = 'post-flag-cancelled';
2225
case PostFlagDeleted = 'post-flag-deleted';
2326
case PostFlagged = 'post-flagged';
2427
case PostStored = 'post-stored';

app/Enums/ModerationTypeEnum.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Enums;
6+
7+
enum ModerationTypeEnum: string
8+
{
9+
case Blur = 'blur';
10+
case Comment = 'comment';
11+
case Edit = 'edit';
12+
case Remove = 'remove';
13+
case Replace = 'replace';
14+
case Wrap = 'wrap';
15+
16+
public function label(): string
17+
{
18+
return match ($this) {
19+
self::Blur => 'Blur',
20+
self::Comment => 'Comment',
21+
self::Edit => 'Edit',
22+
self::Remove => 'Remove',
23+
self::Replace => 'Replace',
24+
self::Wrap => 'Wrap',
25+
};
26+
}
27+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Livewire\Comments;
6+
7+
use App\Enums\ModerationTypeEnum;
8+
use App\Traits\CommentComponentTrait;
9+
use App\Traits\CommentComponentStateTrait;
10+
use Illuminate\Contracts\View\View;
11+
use Livewire\Component;
12+
13+
final class CommentBlur extends Component
14+
{
15+
use CommentComponentStateTrait;
16+
use CommentComponentTrait;
17+
18+
// State
19+
public bool $isBlurred = true;
20+
21+
public function render(): View
22+
{
23+
$moderatorComment = $this->moderatorCommentsByType?->get(ModerationTypeEnum::Blur->value);
24+
25+
return view('livewire.comments.comment-blur', [
26+
'comment' => $this->comment,
27+
'childComments' => $this->childComments,
28+
'blurMessage' => $moderatorComment?->body ?? '',
29+
]);
30+
}
31+
}

app/Livewire/Comments/CommentComponent.php

Lines changed: 78 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,121 +4,123 @@
44

55
namespace App\Livewire\Comments;
66

7+
use App\Enums\CommentStateEnum;
78
use App\Enums\LivewireEventEnum;
9+
use App\Enums\ModerationTypeEnum;
810
use App\Models\Comment;
9-
use App\Models\Flag;
10-
use App\Models\Post;
11-
use App\Models\User;
1211
use App\Traits\CommentComponentTrait;
1312
use Illuminate\Contracts\View\View;
14-
use Illuminate\Support\Facades\DB;
13+
use Illuminate\Support\Collection;
14+
use Livewire\Attributes\Computed;
1515
use Livewire\Attributes\On;
1616
use Livewire\Component;
1717

1818
final class CommentComponent extends Component
1919
{
2020
use CommentComponentTrait;
2121

22-
// Data
23-
public ?int $authorizedUserId;
24-
public string $body = '';
25-
public ?int $parentId = null;
26-
public int $flagCount = 0;
27-
public string $flagIconFilename = 'flag';
28-
public string $flagButtonText = '';
29-
public bool $userFlagged = false;
30-
3122
// State
32-
public bool $isEditing = false;
33-
public bool $isFlagging = false;
34-
public bool $isReplying = false;
35-
36-
public Comment $comment;
37-
public CommentForm $commentForm;
38-
public Post $post;
39-
public ?User $user;
23+
public CommentStateEnum $state = CommentStateEnum::Viewing;
4024

41-
public function mount(Comment $comment, Post $post): void
25+
#[Computed]
26+
public function isInitiallyBlurred(): bool
4227
{
43-
$this->authorizedUserId = auth()->id() ?? null;
44-
45-
$this->comment = $comment;
46-
$this->commentForm->setComment($comment);
47-
48-
$this->post = $post;
49-
50-
$this->body = $comment->body;
51-
52-
$this->user = auth()->user() ?? null;
53-
54-
$this->updateFlagCount();
55-
$this->hasUserFlagged();
56-
57-
$this->flagIconFilename = $this->getFlagIconFilename();
58-
$this->flagButtonText = $this->getFlagTitleText();
59-
}
60-
61-
public function render(): View
62-
{
63-
return view('livewire.comments.comment-component');
28+
return $this->moderatorCommentsByType?->get(ModerationTypeEnum::Blur->value) !== null;
6429
}
6530

66-
private function getFlagIconFilename(): string
31+
public function mount(int $commentId, ?Comment $comment, ?Collection $childComments): void
6732
{
68-
return $this->userFlagged ? 'flag-fill' : 'flag';
33+
// On mount we expect the comment list to provide the comment model
34+
// and the moderator comments collection.
35+
$this->commentId = $commentId;
36+
$this->comment = $comment ?? Comment::find($commentId);
37+
$this->childComments = $childComments;
38+
39+
// Decide whether to blur the component initially.
40+
$this->isBlurred = $this->isInitiallyBlurred;
6941
}
7042

71-
private function getFlagTitleText(): string
43+
public function render(): View
7244
{
73-
return $this->userFlagged ? trans('Remove flag') : trans('Flag this comment');
45+
// If the comment has been replaced, just render the moderation message.
46+
// TODO: if it is possible to have a top-level comment be marked with a
47+
// moderation type, we may want to render it via this view. But it may
48+
// also just be about changing the border for a regular rendering.
49+
$moderatorReplaceComment = $this->moderatorCommentsByType?->get(ModerationTypeEnum::Replace->value);
50+
$moderatorWrapComment = $this->moderatorCommentsByType?->get(ModerationTypeEnum::Wrap->value);
51+
$moderatorBlurComment = $this->moderatorCommentsByType?->get(ModerationTypeEnum::Blur->value);
52+
$moderationType = null;
53+
54+
if ($moderatorReplaceComment !== null &&
55+
($moderatorWrapComment === null || $moderatorReplaceComment->created_at > $moderatorWrapComment->created_at)) {
56+
$moderationType = ModerationTypeEnum::Replace;
57+
} elseif ($moderatorWrapComment !== null) {
58+
$moderationType = ModerationTypeEnum::Wrap;
59+
}
60+
61+
// If there are no decorations to apply, just render the basic comment component.
62+
return view('livewire.comments.comment-component', [
63+
'comment' => $this->comment,
64+
'childComments' => $this->childComments,
65+
'moderationType' => $moderationType,
66+
'isInitiallyBlurred' => $this->isInitiallyBlurred,
67+
'replacedByCommentId' => $moderatorReplaceComment?->id,
68+
'wrappedByCommentId' => $moderatorWrapComment?->id,
69+
'blurredByCommentId' => $moderatorBlurComment?->id,
70+
'isEditing' => $this->state === CommentStateEnum::Editing,
71+
'isFlagging' => $this->state === CommentStateEnum::Flagging,
72+
'isReplying' => $this->state === CommentStateEnum::Replying,
73+
'isModerating' => $this->state === CommentStateEnum::Moderating,
74+
]);
7475
}
7576

76-
private function hasUserFlagged(): void
77+
#[On([
78+
LivewireEventEnum::EscapeKeyClicked->value,
79+
])]
80+
public function closeForm(): void
7781
{
78-
$userFlagCount = DB::table(table: 'markable_flags')
79-
->where(column: 'user_id', operator: '=', value: auth()->id())
80-
->where(column: 'markable_id', operator: '=', value: $this->comment->id)
81-
->where(column: 'markable_type', operator: 'LIKE', value: '%Comment%')
82-
->count();
83-
84-
$this->userFlagged = $userFlagCount > 0;
82+
$this->state = CommentStateEnum::Viewing;
8583
}
8684

8785
#[On([
8886
LivewireEventEnum::CommentStored->value,
89-
LivewireEventEnum::CommentDeleted->value,
90-
LivewireEventEnum::CommentFlagged->value,
9187
LivewireEventEnum::CommentUpdated->value,
92-
LivewireEventEnum::EscapeKeyClicked->value,
9388
])]
94-
public function closeForm(): void
89+
public function reloadChildComments(int $id, ?int $parentId): void
9590
{
96-
$this->reset([
97-
'body',
98-
]);
91+
if ($parentId === $this->commentId) {
92+
$this->childComments = $this->commentRepository->getCommentsByParentId($parentId);
93+
unset($this->moderatorCommentsByType, $this->isInitiallyBlurred);
9994

100-
$this->stopEditing();
101-
$this->stopFlagging();
102-
$this->stopReplying();
95+
// Re-evaluate whether the comment should be blurred.
96+
$this->isBlurred = $this->isInitiallyBlurred;
97+
}
10398
}
10499

105-
private function updateFlagCount(): void
100+
public function setState(CommentStateEnum $state): void
106101
{
107-
$this->flagCount = Flag::count($this->comment);
102+
$this->state = $state;
108103
}
109104

110-
#[On('comment-flagged.{comment.id}')]
111-
public function addUserFlag(): void
105+
public function addUserFlag(int $id): void
112106
{
113-
\Log::debug('CommentComponent::addUserFlag');
114-
$this->userFlagged = true;
115-
$this->flagCount++;
107+
if ($id !== $this->comment->id) {
108+
return;
109+
}
110+
111+
unset($this->userFlagged, $this->flagCount);
112+
113+
$this->state = CommentStateEnum::Viewing;
116114
}
117115

118-
#[On('comment-flag-deleted.{comment.id}')]
119-
public function removeUserFlag(): void
116+
public function removeUserFlag(int $id): void
120117
{
121-
$this->userFlagged = false;
122-
$this->flagCount--;
118+
if ($id !== $this->comment->id) {
119+
return;
120+
}
121+
122+
unset($this->userFlagged, $this->flagCount);
123+
124+
$this->state = CommentStateEnum::Viewing;
123125
}
124126
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Livewire\Comments;
6+
7+
use App\Enums\CommentStateEnum;
8+
use App\Traits\CommentComponentTrait;
9+
use App\Traits\CommentComponentStateTrait;
10+
use Illuminate\Contracts\View\View;
11+
use Livewire\Component;
12+
13+
final class CommentContent extends Component
14+
{
15+
use CommentComponentStateTrait;
16+
use CommentComponentTrait;
17+
18+
public function render(): View
19+
{
20+
$data = [
21+
'authorizedUserId' => auth()->id() ?? null,
22+
'comment' => $this->comment,
23+
'body' => $this->comment->body,
24+
'flagCount' => $this->flagCount,
25+
'userFlagged' => $this->userFlagged,
26+
'isEditing' => $this->state === CommentStateEnum::Editing,
27+
'isFlagging' => $this->state === CommentStateEnum::Flagging,
28+
'isReplying' => $this->state === CommentStateEnum::Replying,
29+
'isModerating' => $this->state === CommentStateEnum::Moderating,
30+
];
31+
32+
// If there are no decorations to apply, just render the basic comment component.
33+
return view('livewire.comments.comment-content', $data);
34+
}
35+
}

0 commit comments

Comments
 (0)