messages implemented
This commit is contained in:
192
app/Http/Controllers/Api/ReactionController.php
Normal file
192
app/Http/Controllers/Api/ReactionController.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enums\ReactionType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ArtworkComment;
|
||||
use App\Models\ArtworkReaction;
|
||||
use App\Models\CommentReaction;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Handles reaction toggling for artworks and comments.
|
||||
*
|
||||
* POST /api/artworks/{id}/reactions → toggle artwork reaction
|
||||
* POST /api/comments/{id}/reactions → toggle comment reaction
|
||||
* GET /api/artworks/{id}/reactions → list artwork reactions
|
||||
* GET /api/comments/{id}/reactions → list comment reactions
|
||||
*/
|
||||
class ReactionController extends Controller
|
||||
{
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Artwork reactions
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
public function artworkReactions(Request $request, int $artworkId): JsonResponse
|
||||
{
|
||||
return $this->listReactions('artwork', $artworkId, $request->user()?->id);
|
||||
}
|
||||
|
||||
public function toggleArtworkReaction(Request $request, int $artworkId): JsonResponse
|
||||
{
|
||||
$this->validateExists('artworks', $artworkId);
|
||||
$slug = $this->validateReactionSlug($request);
|
||||
|
||||
return $this->toggle(
|
||||
model: new ArtworkReaction(),
|
||||
where: ['artwork_id' => $artworkId, 'user_id' => $request->user()->id, 'reaction' => $slug],
|
||||
countWhere: ['artwork_id' => $artworkId],
|
||||
entityId: $artworkId,
|
||||
entityType: 'artwork',
|
||||
userId: $request->user()->id,
|
||||
slug: $slug,
|
||||
);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Comment reactions
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
public function commentReactions(Request $request, int $commentId): JsonResponse
|
||||
{
|
||||
return $this->listReactions('comment', $commentId, $request->user()?->id);
|
||||
}
|
||||
|
||||
public function toggleCommentReaction(Request $request, int $commentId): JsonResponse
|
||||
{
|
||||
// Make sure comment exists and belongs to a public artwork
|
||||
$comment = ArtworkComment::with('artwork')
|
||||
->where('id', $commentId)
|
||||
->whereHas('artwork', fn ($q) => $q->public()->published())
|
||||
->firstOrFail();
|
||||
|
||||
$slug = $this->validateReactionSlug($request);
|
||||
|
||||
return $this->toggle(
|
||||
model: new CommentReaction(),
|
||||
where: ['comment_id' => $commentId, 'user_id' => $request->user()->id, 'reaction' => $slug],
|
||||
countWhere: ['comment_id' => $commentId],
|
||||
entityId: $commentId,
|
||||
entityType: 'comment',
|
||||
userId: $request->user()->id,
|
||||
slug: $slug,
|
||||
);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Shared internals
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private function toggle(
|
||||
\Illuminate\Database\Eloquent\Model $model,
|
||||
array $where,
|
||||
array $countWhere,
|
||||
int $entityId,
|
||||
string $entityType,
|
||||
int $userId,
|
||||
string $slug,
|
||||
): JsonResponse {
|
||||
$table = $model->getTable();
|
||||
$existing = DB::table($table)->where($where)->first();
|
||||
|
||||
if ($existing) {
|
||||
// Toggle off
|
||||
DB::table($table)->where($where)->delete();
|
||||
$active = false;
|
||||
} else {
|
||||
// Toggle on
|
||||
DB::table($table)->insertOrIgnore(array_merge($where, [
|
||||
'created_at' => now(),
|
||||
]));
|
||||
$active = true;
|
||||
}
|
||||
|
||||
// Return fresh totals per reaction type
|
||||
$totals = $this->getTotals($table, $countWhere, $userId);
|
||||
|
||||
return response()->json([
|
||||
'entity_type' => $entityType,
|
||||
'entity_id' => $entityId,
|
||||
'reaction' => $slug,
|
||||
'active' => $active,
|
||||
'totals' => $totals,
|
||||
]);
|
||||
}
|
||||
|
||||
private function listReactions(string $entityType, int $entityId, ?int $userId): JsonResponse
|
||||
{
|
||||
if ($entityType === 'artwork') {
|
||||
$table = 'artwork_reactions';
|
||||
$where = ['artwork_id' => $entityId];
|
||||
} else {
|
||||
$table = 'comment_reactions';
|
||||
$where = ['comment_id' => $entityId];
|
||||
}
|
||||
|
||||
$totals = $this->getTotals($table, $where, $userId);
|
||||
|
||||
return response()->json([
|
||||
'entity_type' => $entityType,
|
||||
'entity_id' => $entityId,
|
||||
'totals' => $totals,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return per-slug totals and whether the current user has each reaction.
|
||||
*/
|
||||
private function getTotals(string $table, array $where, ?int $userId): array
|
||||
{
|
||||
$rows = DB::table($table)
|
||||
->where($where)
|
||||
->selectRaw('reaction, COUNT(*) as total')
|
||||
->groupBy('reaction')
|
||||
->get()
|
||||
->keyBy('reaction');
|
||||
|
||||
$totals = [];
|
||||
foreach (ReactionType::cases() as $type) {
|
||||
$slug = $type->value;
|
||||
$count = (int) ($rows[$slug]->total ?? 0);
|
||||
|
||||
// Check if current user has this reaction
|
||||
$mine = false;
|
||||
if ($userId && $count > 0) {
|
||||
$mine = DB::table($table)
|
||||
->where($where)
|
||||
->where('reaction', $slug)
|
||||
->where('user_id', $userId)
|
||||
->exists();
|
||||
}
|
||||
|
||||
$totals[$slug] = [
|
||||
'emoji' => $type->emoji(),
|
||||
'label' => $type->label(),
|
||||
'count' => $count,
|
||||
'mine' => $mine,
|
||||
];
|
||||
}
|
||||
|
||||
return $totals;
|
||||
}
|
||||
|
||||
private function validateReactionSlug(Request $request): string
|
||||
{
|
||||
$request->validate([
|
||||
'reaction' => ['required', 'string', 'in:' . implode(',', ReactionType::values())],
|
||||
]);
|
||||
|
||||
return $request->input('reaction');
|
||||
}
|
||||
|
||||
private function validateExists(string $table, int $id): void
|
||||
{
|
||||
if (! DB::table($table)->where('id', $id)->exists()) {
|
||||
throw new ModelNotFoundException("No [{$table}] record found with id [{$id}].");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user