feat: extend event toolkit and polish guest pwa
This commit is contained in:
@@ -4,7 +4,9 @@ namespace App\Http\Controllers\Api\Tenant;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Tenant\EventStoreRequest;
|
||||
use App\Http\Resources\Tenant\EventJoinTokenResource;
|
||||
use App\Http\Resources\Tenant\EventResource;
|
||||
use App\Http\Resources\Tenant\PhotoResource;
|
||||
use App\Models\Event;
|
||||
use App\Models\EventPackage;
|
||||
use App\Models\Package;
|
||||
@@ -228,6 +230,10 @@ class EventController extends Controller
|
||||
unset($validated[$unused]);
|
||||
}
|
||||
|
||||
if (isset($validated['settings']) && is_array($validated['settings'])) {
|
||||
$validated['settings'] = array_merge($event->settings ?? [], $validated['settings']);
|
||||
}
|
||||
|
||||
$event->update($validated);
|
||||
$event->load(['eventType', 'tenant']);
|
||||
|
||||
@@ -277,6 +283,141 @@ class EventController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function toolkit(Request $request, Event $event): JsonResponse
|
||||
{
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
}
|
||||
|
||||
$event->load(['eventType', 'eventPackage.package']);
|
||||
|
||||
$photoQuery = Photo::query()->where('event_id', $event->id);
|
||||
$pendingPhotos = (clone $photoQuery)
|
||||
->where('status', 'pending')
|
||||
->latest('created_at')
|
||||
->take(6)
|
||||
->get();
|
||||
|
||||
$recentUploads = (clone $photoQuery)
|
||||
->where('status', 'approved')
|
||||
->latest('created_at')
|
||||
->take(8)
|
||||
->get();
|
||||
|
||||
$pendingCount = (clone $photoQuery)->where('status', 'pending')->count();
|
||||
$uploads24h = (clone $photoQuery)->where('created_at', '>=', now()->subDay())->count();
|
||||
$totalUploads = (clone $photoQuery)->count();
|
||||
|
||||
$tasks = $event->tasks()
|
||||
->orderBy('tasks.sort_order')
|
||||
->orderBy('tasks.created_at')
|
||||
->get(['tasks.id', 'tasks.title', 'tasks.description', 'tasks.priority', 'tasks.is_completed']);
|
||||
|
||||
$taskSummary = [
|
||||
'total' => $tasks->count(),
|
||||
'completed' => $tasks->where('is_completed', true)->count(),
|
||||
];
|
||||
$taskSummary['pending'] = max(0, $taskSummary['total'] - $taskSummary['completed']);
|
||||
|
||||
$translate = static function ($value, string $fallback = '') {
|
||||
if (is_array($value)) {
|
||||
$locale = app()->getLocale();
|
||||
$candidates = array_filter([
|
||||
$locale,
|
||||
$locale && str_contains($locale, '-') ? explode('-', $locale)[0] : null,
|
||||
'de',
|
||||
'en',
|
||||
]);
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if ($candidate && isset($value[$candidate]) && $value[$candidate] !== '') {
|
||||
return $value[$candidate];
|
||||
}
|
||||
}
|
||||
|
||||
$first = reset($value);
|
||||
|
||||
return $first !== false ? $first : $fallback;
|
||||
}
|
||||
|
||||
if (is_string($value) && $value !== '') {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $fallback;
|
||||
};
|
||||
|
||||
$taskPreview = $tasks
|
||||
->take(6)
|
||||
->map(fn ($task) => [
|
||||
'id' => $task->id,
|
||||
'title' => $translate($task->title, 'Task'),
|
||||
'description' => $translate($task->description, null),
|
||||
'is_completed' => (bool) $task->is_completed,
|
||||
'priority' => $task->priority,
|
||||
])
|
||||
->values();
|
||||
|
||||
$joinTokenQuery = $event->joinTokens();
|
||||
$totalInvites = (clone $joinTokenQuery)->count();
|
||||
$activeInvites = (clone $joinTokenQuery)
|
||||
->whereNull('revoked_at')
|
||||
->where(function ($query) {
|
||||
$query->whereNull('expires_at')
|
||||
->orWhere('expires_at', '>', now());
|
||||
})
|
||||
->where(function ($query) {
|
||||
$query->whereNull('usage_limit')
|
||||
->orWhereColumn('usage_limit', '>', 'usage_count');
|
||||
})
|
||||
->count();
|
||||
|
||||
$recentInvites = (clone $joinTokenQuery)
|
||||
->orderByDesc('created_at')
|
||||
->take(3)
|
||||
->get();
|
||||
|
||||
$alerts = [];
|
||||
if (($event->settings['engagement_mode'] ?? 'tasks') !== 'photo_only' && $taskSummary['total'] === 0) {
|
||||
$alerts[] = 'no_tasks';
|
||||
}
|
||||
if ($activeInvites === 0) {
|
||||
$alerts[] = 'no_invites';
|
||||
}
|
||||
if ($pendingCount > 0) {
|
||||
$alerts[] = 'pending_photos';
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'event' => new EventResource($event),
|
||||
'metrics' => [
|
||||
'uploads_total' => $totalUploads,
|
||||
'uploads_24h' => $uploads24h,
|
||||
'pending_photos' => $pendingCount,
|
||||
'active_invites' => $activeInvites,
|
||||
'engagement_mode' => $event->settings['engagement_mode'] ?? 'tasks',
|
||||
],
|
||||
'tasks' => [
|
||||
'summary' => $taskSummary,
|
||||
'items' => $taskPreview,
|
||||
],
|
||||
'photos' => [
|
||||
'pending' => PhotoResource::collection($pendingPhotos)->resolve($request),
|
||||
'recent' => PhotoResource::collection($recentUploads)->resolve($request),
|
||||
],
|
||||
'invites' => [
|
||||
'summary' => [
|
||||
'total' => $totalInvites,
|
||||
'active' => $activeInvites,
|
||||
],
|
||||
'items' => EventJoinTokenResource::collection($recentInvites)->resolve($request),
|
||||
],
|
||||
'alerts' => $alerts,
|
||||
]);
|
||||
}
|
||||
|
||||
public function toggle(Request $request, Event $event): JsonResponse
|
||||
{
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
Reference in New Issue
Block a user