Skip to content

Commit f242675

Browse files
authored
Improvements and Bug Fixes: Definition of Closures (#29)
[Improvements and Bug Fixes: Definition of Closures](0191c22) - Moved closures for getting the user name, avatar and mention items to the commentable model - Override getUserAvatar and getUserName in the commentable model to customize these. - Override getMentionsQuery to modify the query used to get mentions in the commentable model - Removed closures from the config to allow optimization through cache. - Bug Fix: Mentions item name was using the currently logged in user - New Component: Comment Card view component - New Component: Comment Card Entry
2 parents fd04daa + 76f7d49 commit f242675

File tree

12 files changed

+209
-46
lines changed

12 files changed

+209
-46
lines changed

config/nested-comments.php

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php
22

3-
use Illuminate\Contracts\Auth\Authenticatable;
43
use Illuminate\Database\Eloquent\Model;
54

65
return [
@@ -36,17 +35,6 @@
3635
'allow-multiple-reactions' => env('ALLOW_MULTIPLE_REACTIONS', false), // Allow multiple reactions from the same user
3736
'allow-guest-reactions' => env('ALLOW_GUEST_REACTIONS', false), // Allow guest users to react
3837
'allow-guest-comments' => env('ALLOW_GUEST_COMMENTS', false), // Allow guest users to comment
39-
'closures' => [
40-
'getUserNameUsing' => fn (Authenticatable | Model $user) => $user->getAttribute('name'),
41-
'getUserAvatarUsing' => fn (
42-
Authenticatable | Model | string $user
43-
) => app(\Coolsam\NestedComments\NestedComments::class)->geDefaultUserAvatar($user),
44-
// 'getMentionsUsing' => fn (string $query) => app(\Coolsam\NestedComments\NestedComments::class)->getUserMentions($query), // Get mentions of all users in the DB
45-
'getMentionsUsing' => fn (
46-
string $query,
47-
Model $commentable
48-
) => app(\Coolsam\NestedComments\NestedComments::class)->getCurrentThreadUsers($query, $commentable),
49-
],
5038
'mentions' => [
5139
'items-placeholder' => 'Search users by name or email address',
5240
'empty-items-message' => 'No users found',
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@props([
2+
'comment' => null,
3+
])
4+
@if ($comment?->getKey())
5+
<livewire:nested-comments::comment-card
6+
:key="$comment->getKey()"
7+
:comment="$comment"
8+
/>
9+
@else
10+
<p class="text-gray-500 dark:text-gray-400">
11+
{{ __('No comment provided.') }}
12+
</p>
13+
@endif
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<x-dynamic-component :component="$getEntryWrapperView()" :entry="$entry">
2+
<livewire:nested-comments::comment-card
3+
:key="$entry->getKey()"
4+
:comment="$getRecord()"
5+
:user-avatar="$evaluateUserAvatar()"
6+
:user-name="$evaluateUserName()"
7+
/>
8+
</x-dynamic-component>

resources/views/livewire/comment-card.blade.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
<div x-data="{showFullDate: false}" class="flex items-center space-x-2">
55
<x-filament::avatar
66
:src="$this->getAvatar()"
7-
:alt="$this->comment->commentator"
8-
:name="$this->comment->commentator"
7+
:alt="$this->getCommentator()"
8+
:name="$this->getCommentator()"
99
size="md"
1010
:circular="false"
1111
/>
1212
<div x-on:mouseover="showFullDate = true" x-on:mouseout="showFullDate = false" class="cursor-pointer">
1313
<p class="text-sm font-semibold text-gray-900 dark:text-white">
14-
{{ $this->comment->commentator }}
14+
{{ $this->getCommentator() }}
1515
</p>
1616
<p x-show="!showFullDate"
1717
class="text-xs text-gray-500 dark:text-gray-400">

resources/views/livewire/comments.blade.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
@foreach($this->comments as $comment)
1818
<livewire:nested-comments::comment-card
1919
:key="$comment->getKey()"
20-
:comment="$comment" />
20+
:comment="$comment"
21+
/>
2122
@endforeach
2223
<livewire:nested-comments::add-comment :commentable="$this->record" />
2324
</x-filament::section>

src/Concerns/HasComments.php

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55
use Coolsam\NestedComments\Models\Comment;
66
use Coolsam\NestedComments\NestedComments;
77
use Exception;
8+
use FilamentTiptapEditor\Data\MentionItem;
9+
use Illuminate\Contracts\Auth\Authenticatable;
10+
use Illuminate\Database\Eloquent\Builder;
811
use Illuminate\Database\Eloquent\Model;
912
use Illuminate\Database\Eloquent\Relations\MorphMany;
1013
use Illuminate\Support\Collection;
1114

15+
use function auth;
16+
1217
/**
1318
* @mixin Model
1419
*/
@@ -97,7 +102,7 @@ public function editComment(Comment $comment, string $body, ?string $name = null
97102
app(NestedComments::class)->setGuestName($name);
98103
}
99104

100-
if (\auth()->check() && $comment->getAttribute('user_id') !== auth()->id()) {
105+
if (auth()->check() && $comment->getAttribute('user_id') !== auth()->id()) {
101106
throw new Exception('You are not authorized to edit this comment.');
102107
}
103108

@@ -123,7 +128,7 @@ public function deleteComment(Comment $comment): ?bool
123128
throw new Exception('You must be logged in to edit your comment.');
124129
}
125130

126-
if (\auth()->check() && $comment->getAttribute('user_id') !== auth()->id()) {
131+
if (auth()->check() && $comment->getAttribute('user_id') !== auth()->id()) {
127132
throw new Exception('You are not authorized to edit this comment.');
128133
}
129134

@@ -136,4 +141,50 @@ public function deleteComment(Comment $comment): ?bool
136141

137142
return $comment->delete();
138143
}
144+
145+
final public function getUserNameUsing(Comment $comment): string
146+
{
147+
return $this->getUserName($comment->getAttribute('user'));
148+
}
149+
150+
final public function getUserAvatarUsing(Comment $comment): ?string
151+
{
152+
$user = $comment->user ?? $comment->guest_name ?? 'Guest';
153+
154+
return $this->getUserAvatar($user);
155+
}
156+
157+
public function getUserName(Model | Authenticatable | null $user): string
158+
{
159+
return app(NestedComments::class)->getUserName($user);
160+
}
161+
162+
public function getUserAvatar(Model | Authenticatable | string | null $user): ?string
163+
{
164+
return app(NestedComments::class)->getDefaultUserAvatar($user);
165+
}
166+
167+
/**
168+
* @return array<int, MentionItem>
169+
*/
170+
public function getMentionsUsing(string $query): array
171+
{
172+
return $this->getMentionsQuery($query)
173+
// ->where('username', 'like', "%{$query}%")
174+
->take(50)
175+
->get()
176+
->map(function ($user) {
177+
return new MentionItem(
178+
id: $user->getKey(),
179+
label: $this->getUserName($user),
180+
image: $this->getUserAvatar($user),
181+
roundedImage: true,
182+
);
183+
})->toArray();
184+
}
185+
186+
public function getMentionsQuery(string $query): Builder
187+
{
188+
return app(NestedComments::class)->getUserMentionsQuery($query);
189+
}
139190
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Coolsam\NestedComments\Filament\Infolists;
4+
5+
use Closure;
6+
use Coolsam\NestedComments\Models\Comment;
7+
use Coolsam\NestedComments\NestedComments;
8+
use Filament\Infolists\Components\Entry;
9+
use Illuminate\Database\Eloquent\Model;
10+
11+
class CommentCardEntry extends Entry
12+
{
13+
/** @phpstan-ignore-next-line */
14+
protected string $view = 'nested-comments::filament.infolists.comment-card-entry';
15+
16+
protected bool | Closure $isLabelHidden = true;
17+
18+
protected string | Closure | null $userNameUsingClosure = null;
19+
20+
protected string | Closure | null $userAvatarUsingClosure = null;
21+
22+
protected array $columnSpan = ['default' => 'full'];
23+
24+
public static function make(?string $name = null): static
25+
{
26+
$name = $name ?? 'body';
27+
28+
return parent::make($name); // TODO: Change the autogenerated stub
29+
}
30+
31+
public function getUserNameUsing(Closure | string | null $callback = null): static
32+
{
33+
$this->userNameUsingClosure = $callback;
34+
35+
return $this;
36+
}
37+
38+
public function getUserAvatarUsing(Closure | string | null $callback = null): static
39+
{
40+
$this->userAvatarUsingClosure = $callback;
41+
42+
return $this;
43+
}
44+
45+
public function evaluateUserAvatar(): ?string
46+
{
47+
return $this->evaluate($this->userAvatarUsingClosure
48+
?? fn (Comment | Model $record) => app(NestedComments::class)
49+
->getDefaultUserAvatar($record->getAttribute('user')
50+
?? $record->getAttribute('guest_name') ?? 'Guest'));
51+
}
52+
53+
public function evaluateUserName(): ?string
54+
{
55+
return $this->evaluate($this->userNameUsingClosure
56+
?? fn (Comment | Model | null $record) => $record?->getAttribute('user')?->getAttribute('name')
57+
?? $record->getAttribute('guest_name'));
58+
}
59+
}

src/Livewire/AddComment.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace Coolsam\NestedComments\Livewire;
44

5+
use Coolsam\NestedComments\Concerns\HasComments;
56
use Coolsam\NestedComments\Models\Comment;
6-
use Coolsam\NestedComments\NestedComments;
77
use Coolsam\NestedComments\NestedCommentsServiceProvider;
8+
use Error;
9+
use Exception;
810
use Filament\Forms\Concerns\InteractsWithForms;
911
use Filament\Forms\Contracts\HasForms;
1012
use Filament\Forms\Form;
@@ -30,10 +32,10 @@ class AddComment extends Component implements HasForms
3032

3133
public ?Comment $replyTo = null;
3234

33-
public function mount(?Model $commentable = null, ?Comment $replyTo = null): void
35+
public function mount(?Model $commentable, ?Comment $replyTo): void
3436
{
3537
if (! $commentable) {
36-
throw new \Error('The $commentable property is required.');
38+
throw new Error('The $commentable property is required.');
3739
}
3840
$this->commentable = $commentable;
3941
$this->replyTo = $replyTo;
@@ -43,15 +45,20 @@ public function mount(?Model $commentable = null, ?Comment $replyTo = null): voi
4345
public function getCommentable(): Model
4446
{
4547
if (! $this->commentable) {
46-
throw new \Error('The $commentable property is required.');
48+
throw new Error('The $commentable property is required.');
4749
}
4850

4951
return $this->commentable;
5052
}
5153

5254
public function form(Form $form): Form
5355
{
54-
$mentionsClosure = config('nested-comments.closures.getMentionsUsing', fn (string $query, Model $commentable) => app(NestedComments::class)->getUserMentions($query));
56+
/**
57+
* @var Model<HasComments>|HasComments $commentable
58+
*
59+
* @phpstan-ignore-next-line
60+
*/
61+
$commentable = $this->getCommentable();
5562

5663
return $form
5764
->schema([
@@ -61,7 +68,11 @@ public function form(Form $form): Form
6168
->extraInputAttributes(['style' => 'min-height: 12rem;'])
6269
->mentionItemsPlaceholder(config('nested-comments.mentions.items-placeholder', __('Search users by name or email address')))
6370
->emptyMentionItemsMessage(config('nested-comments.mentions.empty-items-message', __('No users found')))
64-
->getMentionItemsUsing(fn (string $query) => $mentionsClosure($query, $this->getCommentable()))
71+
/**
72+
* @phpstan-ignore-next-line
73+
*/
74+
->getMentionItemsUsing(fn (string $query) => $commentable->getMentionsUsing($query))
75+
->maxContentWidth('full')
6576
->required()
6677
->autofocus(),
6778
])
@@ -70,12 +81,17 @@ public function form(Form $form): Form
7081
}
7182

7283
/**
73-
* @throws \Exception
84+
* @throws Exception
7485
*/
7586
public function create(): void
7687
{
7788
$data = $this->form->getState();
7889

90+
/**
91+
* @var Model<HasComments>|HasComments $commentable
92+
*
93+
* @phpstan-ignore-next-line
94+
*/
7995
$commentable = $this->getCommentable();
8096

8197
/**

src/Livewire/CommentCard.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,30 @@
44

55
use Coolsam\NestedComments\Models\Comment;
66
use Coolsam\NestedComments\NestedCommentsServiceProvider;
7+
use Error;
8+
use Filament\Support\Concerns\EvaluatesClosures;
79
use Livewire\Component;
810

911
class CommentCard extends Component
1012
{
13+
use EvaluatesClosures;
14+
1115
public ?Comment $comment = null;
1216

1317
public bool $showReplies = false;
1418

19+
public ?string $userAvatar = null;
20+
21+
public ?string $userName = null;
22+
1523
protected $listeners = [
1624
'refresh' => 'refreshReplies',
1725
];
1826

1927
public function mount(?Comment $comment = null): void
2028
{
2129
if (! $comment) {
22-
throw new \Error('The $comment property is required.');
30+
throw new Error('The $comment property is required.');
2331
}
2432

2533
$this->comment = $comment;
@@ -48,6 +56,21 @@ public function getAvatar()
4856
return '';
4957
}
5058

51-
return call_user_func(config('nested-comments.closures.getUserAvatarUsing'), $this->comment->commentator);
59+
/**
60+
* @phpstan-ignore-next-line
61+
*/
62+
return $this->comment->commentable?->getUserAvatarUsing($this->comment);
63+
}
64+
65+
public function getCommentator(): string
66+
{
67+
if (! $this->comment) {
68+
return '';
69+
}
70+
71+
/**
72+
* @phpstan-ignore-next-line
73+
*/
74+
return $this->comment->commentable?->getUserNameUsing($this->comment);
5275
}
5376
}

src/Livewire/Comments.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Comments extends Component
2929
public function mount(): void
3030
{
3131
$this->comments = collect();
32+
3233
if (! $this->record) {
3334
throw new \Error('Record model (Commentable) is required');
3435
}

0 commit comments

Comments
 (0)