*/ public ?array $commentData = []; public string $sortDirection = 'asc'; /** @var array */ public array $attachments = []; public int $perPage = 10; public int $loadedCount = 10; public function mount(Model $model): void { $this->model = $model; $this->perPage = CommentsConfig::getPerPage(); $this->loadedCount = $this->perPage; $this->commentForm->fill(); } public function commentForm(Schema $schema): Schema { return $schema ->components([ RichEditor::make('body') ->hiddenLabel() ->required() ->placeholder(__('Write a comment...')) ->toolbarButtons(CommentsConfig::getEditorToolbar()) ->mentions([ CommentsConfig::makeMentionProvider(), ]), ]) ->statePath('commentData'); } /** @return Collection */ #[Computed] public function comments(): Collection { return $this->model ->topLevelComments() ->with(['commenter', 'mentions', 'attachments', 'reactions.commenter', 'replies.commenter', 'replies.mentions', 'replies.attachments', 'replies.reactions.commenter', 'replies.replies.commenter', 'replies.replies.mentions', 'replies.replies.attachments', 'replies.replies.reactions.commenter']) ->orderBy('created_at', $this->sortDirection) ->take($this->loadedCount) ->get(); } #[Computed] public function totalCount(): int { return $this->model->topLevelComments()->count(); } #[Computed] public function allCommentsCount(): int { return $this->model->commentCount(); } #[Computed] public function hasMore(): bool { return $this->totalCount > $this->loadedCount; } #[Computed] public function isSubscribed(): bool { $user = CommentsConfig::resolveAuthenticatedUser(); if (! $user) { return false; } return Subscription::isSubscribed($this->model, $user); } public function toggleSubscription(): void { $user = CommentsConfig::resolveAuthenticatedUser(); if (! $user) { return; } if ($this->isSubscribed) { Subscription::unsubscribe($this->model, $user); } else { Subscription::subscribe($this->model, $user); } unset($this->isSubscribed); } public function addComment(): void { $data = $this->commentForm->getState(); if (CommentsConfig::areAttachmentsEnabled()) { $maxSize = CommentsConfig::getAttachmentMaxSize(); $allowedTypes = implode(',', CommentsConfig::getAttachmentAllowedTypes()); $this->validate([ 'attachments.*' => ['nullable', 'file', "max:{$maxSize}", "mimetypes:{$allowedTypes}"], ]); } $this->authorize('create', CommentsConfig::getCommentModel()); $user = CommentsConfig::resolveAuthenticatedUser(); $comment = $this->model->comments()->create([ 'body' => $data['body'] ?? '', 'commenter_id' => $user->getKey(), 'commenter_type' => $user->getMorphClass(), ]); if (CommentsConfig::areAttachmentsEnabled() && ! empty($this->attachments)) { $disk = CommentsConfig::getAttachmentDisk(); foreach ($this->attachments as $file) { $path = $file->store("comments/attachments/{$comment->id}", $disk); $comment->attachments()->create([ 'file_path' => $path, 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getMimeType(), 'size' => $file->getSize(), 'disk' => $disk, ]); } } event(new CommentCreated($comment)); app(MentionParser::class)->syncMentions($comment); $this->commentForm->fill(); $this->reset('attachments'); } public function removeAttachment(int $index): void { $attachments = $this->attachments; unset($attachments[$index]); $this->attachments = array_values($attachments); } public function loadMore(): void { $this->loadedCount += $this->perPage; } public function toggleSort(): void { $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc'; } /** @return array */ public function getListeners(): array { $listeners = [ 'commentDeleted' => 'refreshComments', 'commentUpdated' => 'refreshComments', ]; if (CommentsConfig::isBroadcastingEnabled()) { $prefix = CommentsConfig::getBroadcastChannelPrefix(); $type = $this->model->getMorphClass(); $id = $this->model->getKey(); $channel = "echo-private:{$prefix}.{$type}.{$id}"; $listeners["{$channel},CommentCreated"] = 'refreshComments'; $listeners["{$channel},CommentUpdated"] = 'refreshComments'; $listeners["{$channel},CommentDeleted"] = 'refreshComments'; $listeners["{$channel},CommentReacted"] = 'refreshComments'; } return $listeners; } public function refreshComments(): void { unset($this->comments, $this->totalCount, $this->hasMore, $this->allCommentsCount); } public function render(): View { return view('comments::livewire.comments'); } }