Skip to content

Commit de808c2

Browse files
ItsMalikJoneslisa-fehr
authored andcommitted
Add comment ratings feature with per-component configuration
1 parent 456d17a commit de808c2

18 files changed

Lines changed: 307 additions & 47 deletions

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,36 @@ By default, Commentions ships with the following reactions: `['👍', '❤️',
351351
],
352352
```
353353

354+
#### Comment Ratings
355+
356+
Commentions can attach an optional star rating to a comment, review-style. Ratings are **disabled by default**.
357+
358+
Enable them globally in your `config/commentions.php` file (or via the matching environment variables):
359+
360+
```php
361+
'ratings' => [
362+
'enabled' => env('COMMENTIONS_RATINGS_ENABLED', false),
363+
364+
'max' => (int) env('COMMENTIONS_RATINGS_MAX', 5),
365+
],
366+
```
367+
368+
You can also enable ratings per component, which overrides the global config. This works on `CommentsEntry`, `CommentsAction`, and `CommentsTableAction`:
369+
370+
```php
371+
CommentsEntry::make('comments')
372+
->enableRatings()
373+
->maxRating(10)
374+
```
375+
376+
Available methods:
377+
378+
- `enableRatings(bool|Closure $condition = true)` — enable the rating input for this component.
379+
- `disableRatings()` — disable the rating input, even if enabled globally.
380+
- `maxRating(int|Closure $max)` — set the highest selectable rating (defaults to `ratings.max`).
381+
382+
When ratings are enabled, commenters can pick a rating while writing or editing a comment, and each rated comment renders its score as filled stars. The rating is stored in a nullable `rating` column added by the package's `add_rating_to_commentions_comments_table` migration.
383+
354384
### Configuring the Commenter name
355385

356386
By default, the `name` property will be used to render the mention names. You can customize it either by implementing the Filament `HasName` interface OR by implementing the optional `getCommenterName` method.

phpstan.neon

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ parameters:
99
- tests/
1010

1111
excludePaths:
12-
- src/Filament/Actions/CommentsTableAction.php
1312
- src/Filament/Actions/SubscriptionTableAction.php
1413

1514
# Level 10 is the highest level

resources/lang/en/comments.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
'add_reaction' => 'Add Reaction',
2222
'show_more' => 'Show More',
2323

24+
'rating_input_label' => 'Rating',
25+
'rate_stars' => 'Rate :count star|Rate :count stars',
26+
'rating_display_label' => 'Rated :rating out of :max',
27+
2428
'notifications' => 'Notifications',
2529
'unsubscribe' => 'Unsubscribe',
2630
'subscribe' => 'Subscribe',

resources/views/comment-list.blade.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class="comm:w-8 comm:h-8 comm:text-gray-400 comm:dark:text-gray-500"
2121
:comment="$comment"
2222
:mentionables="$mentionables"
2323
:tip-tap-css-classes="$tipTapCssClasses"
24+
:ratings-enabled="$ratingsEnabled"
25+
:max-rating="$maxRating"
2426
/>
2527
@endforeach
2628

resources/views/comment.blade.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ class="comm:text-xs comm:text-gray-300 comm:ml-1"
9191

9292
@if ($editing)
9393
<div class="comm:mt-2">
94+
@if ($this->ratingsAreEnabled())
95+
@include('commentions::partials.rating-input', ['maxRating' => $this->getMaxRating()])
96+
@endif
97+
9498
<div class="tip-tap-container comm:mb-2" wire:ignore>
9599
<div x-data="editor(@js($commentBody), @js($mentionables), 'comment', null, @js($this->getTipTapCssClasses()), @js($commentionsComponentPrefix . 'comment'))">
96100
<div x-ref="element"></div>
@@ -116,8 +120,13 @@ class="comm:text-xs comm:text-gray-300 comm:ml-1"
116120
</div>
117121
@else
118122
@if ($comment->isComment() && $comment->rating)
119-
<div class="comm:mt-1 comm:flex comm:items-center comm:gap-0.5" title="{{ $comment->rating }}/{{ \Kirschbaum\Commentions\Config::getMaxRating() }}">
120-
@for ($ratingStar = 1; $ratingStar <= \Kirschbaum\Commentions\Config::getMaxRating(); $ratingStar++)
123+
<div
124+
class="comm:mt-1 comm:flex comm:items-center comm:gap-0.5"
125+
role="img"
126+
title="{{ $comment->rating }}/{{ $this->getMaxRating() }}"
127+
aria-label="{{ __('commentions::comments.rating_display_label', ['rating' => $comment->rating, 'max' => $this->getMaxRating()]) }}"
128+
>
129+
@for ($ratingStar = 1; $ratingStar <= $this->getMaxRating(); $ratingStar++)
121130
<x-filament::icon
122131
icon="heroicon-s-star"
123132
@class([

resources/views/comments.blade.php

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,7 @@
66
@if (Config::resolveAuthenticatedUser()?->can('create', Config::getCommentModel()))
77
<form wire:submit.prevent="save" x-cloak>
88
@if ($this->ratingsAreEnabled())
9-
<div class="comm:mb-2 comm:flex comm:items-center comm:gap-0.5" x-data="{ hover: 0 }">
10-
@for ($ratingStar = 1; $ratingStar <= $this->getMaxRating(); $ratingStar++)
11-
<button
12-
type="button"
13-
wire:key="comment-rating-star-{{ $ratingStar }}"
14-
x-on:click="$wire.rating = ($wire.rating === {{ $ratingStar }} ? null : {{ $ratingStar }})"
15-
x-on:mouseenter="hover = {{ $ratingStar }}"
16-
x-on:mouseleave="hover = 0"
17-
class="commentions-rating-star"
18-
:class="{ 'commentions-rating-star-active': (hover || $wire.rating) >= {{ $ratingStar }} }"
19-
>
20-
<x-filament::icon icon="heroicon-s-star" class="comm:h-5 comm:w-5" />
21-
</button>
22-
@endfor
23-
</div>
24-
25-
@error('rating')
26-
<p class="comm:mb-2 comm:text-xs comm:text-red-600">{{ $message }}</p>
27-
@enderror
9+
@include('commentions::partials.rating-input', ['maxRating' => $this->getMaxRating()])
2810
@endif
2911

3012
{{-- tiptap editor --}}
@@ -64,6 +46,8 @@ class="commentions-rating-star"
6446
:load-more-label="$loadMoreLabel ?? __('commentions::comments.show_more')"
6547
:per-page-increment="$perPageIncrement ?? null"
6648
:tip-tap-css-classes="$tipTapCssClasses"
49+
:ratings-enabled="$this->ratingsAreEnabled()"
50+
:max-rating="$this->getMaxRating()"
6751
/>
6852
</div>
6953

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<div
2+
class="comm:mb-2 comm:flex comm:items-center comm:gap-0.5"
3+
x-data="{ hover: 0 }"
4+
role="group"
5+
aria-label="{{ __('commentions::comments.rating_input_label') }}"
6+
>
7+
@for ($ratingStar = 1; $ratingStar <= $maxRating; $ratingStar++)
8+
<button
9+
type="button"
10+
wire:key="comment-rating-star-{{ $ratingStar }}"
11+
x-on:click="$wire.rating = ($wire.rating === {{ $ratingStar }} ? null : {{ $ratingStar }})"
12+
x-on:mouseenter="hover = {{ $ratingStar }}"
13+
x-on:mouseleave="hover = 0"
14+
class="commentions-rating-star"
15+
:class="{ 'commentions-rating-star-active': (hover || $wire.rating) >= {{ $ratingStar }} }"
16+
:aria-pressed="($wire.rating === {{ $ratingStar }}).toString()"
17+
aria-label="{{ trans_choice('commentions::comments.rate_stars', $ratingStar, ['count' => $ratingStar]) }}"
18+
>
19+
<x-filament::icon icon="heroicon-s-star" class="comm:h-5 comm:w-5" />
20+
</button>
21+
@endfor
22+
</div>
23+
24+
@error('rating')
25+
<p class="comm:mb-2 comm:text-xs comm:text-red-600">{{ $message }}</p>
26+
@enderror

src/Comment.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ public function getContentHash(): string
188188
{
189189
return md5(json_encode([
190190
'body' => $this->body,
191+
'rating' => $this->rating,
191192
'reactions' => $this->reactions->pluck('id'),
192193
]));
193194
}

src/CommentionsServiceProvider.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Illuminate\Support\Facades\View;
1111
use Kirschbaum\Commentions\Comment as CommentModel;
1212
use Kirschbaum\Commentions\Events\UserWasMentionedEvent;
13+
use Kirschbaum\Commentions\Filament\Actions\TableAction;
1314
use Kirschbaum\Commentions\Listeners\SendUserMentionedNotification;
1415
use Kirschbaum\Commentions\Livewire\Comment;
1516
use Kirschbaum\Commentions\Livewire\CommentList;
@@ -44,6 +45,11 @@ public function configurePackage(Package $package): void
4445
]);
4546
}
4647

48+
public function packageRegistered(): void
49+
{
50+
$this->aliasTableAction();
51+
}
52+
4753
public function packageBooted(): void
4854
{
4955
$prefix = Config::getComponentPrefix();
@@ -83,4 +89,24 @@ public function packageBooted(): void
8389
Event::listen(UserWasMentionedEvent::class, $listenerClass);
8490
}
8591
}
92+
93+
/**
94+
* Bridge the package's {@see TableAction} to the correct Filament base class.
95+
*
96+
* Filament 4 unified actions under `Filament\Actions\Action`, removing the
97+
* `Filament\Tables\Actions\Action` base that table actions extend on
98+
* Filament 3. The bundled TableAction class already extends the unified base
99+
* (correct for Filament 4/5); on Filament 3 it must instead resolve to the
100+
* legacy table-action base, so alias it before CommentsTableAction loads.
101+
*/
102+
protected function aliasTableAction(): void
103+
{
104+
if (class_exists(TableAction::class, false)) {
105+
return;
106+
}
107+
108+
if (class_exists('Filament\Tables\Actions\Action')) {
109+
class_alias('Filament\Tables\Actions\Action', TableAction::class);
110+
}
111+
}
86112
}

src/Config.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ public static function getCommentSubscriptionTable(): string
4949
return config('commentions.tables.comment_subscriptions', 'comment_subscriptions');
5050
}
5151

52+
public static function ratingsAreEnabled(): bool
53+
{
54+
return (bool) config('commentions.ratings.enabled', false);
55+
}
56+
5257
public static function getMaxRating(): int
5358
{
5459
return (int) config('commentions.ratings.max', 5);

0 commit comments

Comments
 (0)