Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/Enums/LivewireEventEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
enum LivewireEventEnum: string
{
case CommentDeleted = 'comment-deleted';
case CommentFlagCancelled = 'comment-flag-cancelled';
case CommentFlagDeleted = 'comment-flag-deleted';
case CommentFlagged = 'comment-flagged';
case CommentStored = 'comment-stored';
Expand All @@ -19,6 +20,7 @@ enum LivewireEventEnum: string
case FlagDeleted = 'flag-deleted';
case HideFlagCommentForm = 'hide-flag-comment-form';
case PostDeleted = 'post-deleted';
case PostFlagCancelled = 'post-flag-cancelled';
case PostFlagDeleted = 'post-flag-deleted';
case PostFlagged = 'post-flagged';
case PostStored = 'post-stored';
Expand Down
57 changes: 19 additions & 38 deletions app/Livewire/Comments/CommentComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use App\Models\User;
use App\Traits\CommentComponentTrait;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\On;
use Livewire\Component;

Expand All @@ -24,13 +23,12 @@ final class CommentComponent extends Component
public string $body = '';
public ?int $parentId = null;
public int $flagCount = 0;
public string $flagIconFilename = 'flag';
public string $flagButtonText = '';
public bool $userFlagged = false;

// State
public bool $isEditing = false;
public bool $isFlagging = false;
public bool $isFlagLoading = false;
public bool $isReplying = false;

public Comment $comment;
Expand All @@ -52,42 +50,16 @@ public function mount(Comment $comment, Post $post): void
$this->user = auth()->user() ?? null;

$this->updateFlagCount();
$this->hasUserFlagged();

$this->flagIconFilename = $this->getFlagIconFilename();
$this->flagButtonText = $this->getFlagTitleText();
}

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

private function getFlagIconFilename(): string
{
return $this->userFlagged ? 'flag-fill' : 'flag';
}

private function getFlagTitleText(): string
{
return $this->userFlagged ? trans('Remove flag') : trans('Flag this comment');
}

private function hasUserFlagged(): void
{
$userFlagCount = DB::table(table: 'markable_flags')
->where(column: 'user_id', operator: '=', value: auth()->id())
->where(column: 'markable_id', operator: '=', value: $this->comment->id)
->where(column: 'markable_type', operator: 'LIKE', value: '%Comment%')
->count();

$this->userFlagged = $userFlagCount > 0;
}

#[On([
LivewireEventEnum::CommentStored->value,
LivewireEventEnum::CommentDeleted->value,
LivewireEventEnum::CommentFlagged->value,
LivewireEventEnum::CommentUpdated->value,
LivewireEventEnum::EscapeKeyClicked->value,
])]
Expand All @@ -98,27 +70,36 @@ public function closeForm(): void
]);

$this->stopEditing();
$this->stopFlagging();
$this->stopReplying();
}

private function updateFlagCount(): void
{
$this->flagCount = Flag::count($this->comment);
$this->flagCount = $this->comment->flagCount();
$this->userFlagged = $this->comment->userFlagged();
}

#[On('comment-flagged.{comment.id}')]
public function addUserFlag(): void
public function addUserFlag(int $id): void
{
\Log::debug('CommentComponent::addUserFlag');
if ($id !== $this->comment->id) {
return;
}

$this->userFlagged = true;
$this->flagCount++;
// Requery as flag may have just been edited, not added
$this->updateFlagCount();
$this->stopFlagging();
}

#[On('comment-flag-deleted.{comment.id}')]
public function removeUserFlag(): void
public function removeUserFlag(int $id): void
{
if ($id !== $this->comment->id) {
return;
}

$this->userFlagged = false;
$this->flagCount--;
// Requery as technically multiple flags could exist (though they shouldn't)
$this->updateFlagCount();
$this->stopFlagging();
}
}
138 changes: 88 additions & 50 deletions app/Livewire/Flags/FlagComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
use App\Traits\AuthStatusTrait;
use App\Traits\LoggingTrait;
use App\Traits\TypeTrait;
use Exception;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\Locked;
use Livewire\Component;
use Maize\Markable\Exceptions\InvalidMarkValueException;

Expand All @@ -26,25 +26,42 @@ final class FlagComponent extends Component
private const string MODEL_PATH = 'app\\models\\';

public Comment|Post $model;
public Flag|null $userFlag = null;

#[Locked]
public int $modelId;
#[Locked]
public string $type;
#[Locked]
public int $flagCount = 0;
#[Locked]
public string $iconFilename = 'flag';
public string $note = '';
#[Locked]
public string $titleText;
#[Locked]
public array $flagReasons = [];

// Actual values we interact with
public string $note = '';
public string $selectedReason = '';
public bool $showForm = false;
public bool $showNoteField = false;
public string $titleText;
public string $type;
public bool $userFlagged = false;
public bool $formClosed = false;

public function mount(
Comment|Post $model,
): void {
$configReasons = config('markable.allowed_values.flag', []);
$this->flagReasons = is_array($configReasons) ? $configReasons : [];

$this->flagReasons = is_array($configReasons) ? array_combine(
array_map(fn($reason) => mb_strtolower(preg_replace('/[^\w]+/', '-', $reason)), $configReasons),
$configReasons,
) : [];

$this->formClosed = false;
$this->model = $model;
$this->modelId = $model->id;
$this->type = $this->getType();
$this->userFlag = $this->getUserFlag();
$this->updateFlagData();
}

Expand All @@ -53,77 +70,98 @@ public function render(): View
return view('livewire.flags.flag-component');
}

public function flagReasonSelected(string $selectedReason): void
public function isNoteVisibleForReason(string $reason): bool
{
if ($selectedReason === self::FLAG_WITH_NOTE) {
$this->showNoteField = true;
} else {
$this->showNoteField = false;
$this->reset('note');
}
return $reason === self::FLAG_WITH_NOTE;
}

$this->selectedReason = $selectedReason;
public function getUserFlag(): Flag | null
{
return Flag::where([
'user_id' => auth()->id(),
'markable_id' => $this->model->getKey(),
'markable_type' => $this->model->getMorphClass(),
])->first();
}

public function updateFlagData(): void
protected function updateFlagData(): void
{
$value = $this->userFlag?->value ?? '';
$this->selectedReason = in_array($value, $this->flagReasons) ? $value : '';
$this->note = $this->userFlag?->metadata['note'] ?? '';
$this->showNoteField = $this->isNoteVisibleForReason($this->selectedReason);
$this->setTitleText();
}

public function store(): void
protected function deleteUserFlag(): void
{
// $rules = (new StoreFlagRequest())->rules();
Flag::where([
'user_id' => auth()->id(),
'markable_id' => $this->model->getKey(),
'markable_type' => $this->model->getMorphClass(),
])->get()->each->delete();
}

// $this->validate($rules);
public function store(): void
{
$metadata = [];

$selectedReason = mb_trim($this->selectedReason);
$noteText = mb_trim($this->note);

try {
if ($selectedReason === self::FLAG_WITH_NOTE && mb_strlen($this->note) > 0) {
$metadata = ['note' => $this->note];
}

$event = $this->type === 'comment' ?
LivewireEventEnum::CommentFlagged->value :
LivewireEventEnum::PostFlagged->value;

$this->dispatchEvent($event);
if ($this->isNoteVisibleForReason($selectedReason) && mb_strlen($noteText) > 0) {
$metadata = ['note' => $noteText];
}

Flag::add($this->model, auth()->user(), $selectedReason, $metadata);
// Just cancel the change if the form is unmodified
if ($selectedReason === ($this->userFlag?->value ?? '') && $metadata === $this->userFlag?->metadata) {
$this->cancel();
return;
}

$this->showForm = false;
$event = $this->type === 'comment' ?
LivewireEventEnum::CommentFlagged :
LivewireEventEnum::PostFlagged;

$this->userFlagged = false;
// Stop rendering while we are modifying data
$this->formClosed = true;

$this->updateFlagData();
$this->deleteUserFlag();
try {
$this->userFlag = Flag::add($this->model, auth()->user(), $selectedReason, $metadata);
} catch (InvalidMarkValueException $exception) {
$this->logError($exception);
}
$this->updateFlagData();

$this->dispatchEvent($event);
}

public function delete(): void
{
try {
$event = $this->type === 'comment' ?
LivewireEventEnum::CommentFlagDeleted->value :
LivewireEventEnum::PostFlagDeleted->value;

$this->dispatchEvent($event);

Flag::remove($this->model, auth()->user());
// Stop rendering while we are modifying data
$this->formClosed = true;
$event = $this->type === 'comment' ?
LivewireEventEnum::CommentFlagDeleted :
LivewireEventEnum::PostFlagDeleted;

$this->userFlagged = false;
$this->deleteUserFlag();
$this->userFlag = null;
$this->updateFlagData();

$this->updateFlagData();
} catch (Exception $exception) {
$this->logError($exception);
}
$this->dispatchEvent($event);
}

public function toggleForm(): void
public function cancel(): void
{
$this->showForm = !$this->showForm;
$this->formClosed = true;

$event = $this->type === 'comment' ?
LivewireEventEnum::CommentFlagCancelled :
LivewireEventEnum::PostFlagCancelled;

$this->dispatchEvent($event);
}

private function getType(): string
Expand All @@ -137,11 +175,11 @@ private function setTitleText(): void
{
$flagText = 'Flag this ' . $this->type;

$this->titleText = $this->userFlagged ? trans('Remove flag') : trans($flagText);
$this->titleText = $this->userFlag ? trans('Remove or edit flag') : trans($flagText);
}

private function dispatchEvent(string $event): void
private function dispatchEvent(LivewireEventEnum $event): void
{
$this->dispatch($event, id: $this->model->id);
$this->dispatch($event->value, id: $this->model->id);
}
}
14 changes: 13 additions & 1 deletion app/Models/Comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,19 @@ public function favoriteCount(): int

public function flagCount(): int
{
return Flag::count($this);
return Flag::where([
'markable_id' => $this->getKey(),
'markable_type' => $this->getMorphClass(),
])->count();
}

public function userFlagged(): bool
{
return Flag::where([
'user_id' => auth()->id(),
'markable_id' => $this->getKey(),
'markable_type' => $this->getMorphClass(),
])->exists();
}

public function post(): BelongsTo
Expand Down
14 changes: 13 additions & 1 deletion app/Models/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,19 @@ public function favoriteCount(): int

public function flagCount(): int
{
return Flag::count($this);
return Flag::where([
'markable_id' => $this->getKey(),
'markable_type' => $this->getMorphClass(),
])->count();
}

public function userFlagged(): bool
{
return Flag::where([
'user_id' => auth()->id(),
'markable_id' => $this->getKey(),
'markable_type' => $this->getMorphClass(),
])->exists();
}

public function next(): Post|null
Expand Down
2 changes: 2 additions & 0 deletions app/Traits/CommentComponentTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ public function stopEditing(): void
public function startFlagging(): void
{
$this->isFlagging = true;
$this->isFlagLoading = false;
$this->stopEditing();
$this->stopReplying();
}

public function stopFlagging(): void
{
$this->isFlagging = false;
$this->isFlagLoading = false;
}

public function startReplying(): void
Expand Down
Loading