- Add CalendarSlotService methods for slot order calculation - Update PlannedItemController to create slots from datetime - Update CalendarSlotController with proper eager loading - Create timeline UI components (TripTimeline, DaySection, HourRow, ScheduleItemModal) - Add comprehensive PHPUnit tests (PlannedItemTest, CalendarSlotServiceTest) - Add comprehensive Selenium E2E tests (timeline-scheduling.test.js) - Update PlannablesList to support onItemsChange callback
81 lines
No EOL
2.7 KiB
PHP
81 lines
No EOL
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Infrastructure\Http\Controllers\API\CalendarSlot;
|
|
|
|
use App\Domain\CalendarSlot\Policies\CalendarSlotPolicy;
|
|
use App\Infrastructure\Http\Controllers\Controller;
|
|
use App\Models\CalendarSlot;
|
|
use App\Models\Trip;
|
|
use App\Models\PlannedItem;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\JsonResponse;
|
|
|
|
class CalendarSlotController extends Controller
|
|
{
|
|
public function __construct(
|
|
private CalendarSlotPolicy $policy
|
|
) {}
|
|
public function index(Trip $trip): JsonResponse
|
|
{
|
|
if (!$this->policy->viewAny(auth()->user(), $trip)) {
|
|
return response()->json(['message' => 'Forbidden'], 403);
|
|
}
|
|
|
|
$calendarSlots = $trip->calendarSlots()
|
|
->with(['plannedItems.plannableItem'])
|
|
->orderBy('slot_date')
|
|
->orderBy('datetime_start')
|
|
->get();
|
|
|
|
return response()->json(['data' => $calendarSlots]);
|
|
}
|
|
|
|
public function update(Request $request, CalendarSlot $calendarSlot): JsonResponse
|
|
{
|
|
if (!$this->policy->update(auth()->user(), $calendarSlot)) {
|
|
return response()->json(['message' => 'Forbidden'], 403);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'name' => 'sometimes|required|string|max:255',
|
|
]);
|
|
|
|
$calendarSlot->update($validated);
|
|
|
|
return response()->json(['data' => $calendarSlot]);
|
|
}
|
|
|
|
public function reorder(Request $request, CalendarSlot $calendarSlot): JsonResponse
|
|
{
|
|
if (!$this->policy->reorder(auth()->user(), $calendarSlot)) {
|
|
return response()->json(['message' => 'Forbidden'], 403);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'items' => 'required|array',
|
|
'items.*.plannable_item_id' => 'required|exists:plannable_items,id',
|
|
'items.*.sort_order' => 'required|integer',
|
|
]);
|
|
|
|
// Validate all plannable items belong to the same trip
|
|
$trip = $calendarSlot->trip;
|
|
$validPlannableItemIds = $trip->plannableItems()->pluck('id')->toArray();
|
|
|
|
foreach ($validated['items'] as $item) {
|
|
if (!in_array($item['plannable_item_id'], $validPlannableItemIds)) {
|
|
return response()->json(['message' => 'Invalid plannable item for this trip'], 422);
|
|
}
|
|
}
|
|
|
|
// Update sort orders in transaction
|
|
\DB::transaction(function () use ($validated, $calendarSlot) {
|
|
foreach ($validated['items'] as $item) {
|
|
PlannedItem::where('calendar_slot_id', $calendarSlot->id)
|
|
->where('plannable_item_id', $item['plannable_item_id'])
|
|
->update(['sort_order' => $item['sort_order']]);
|
|
}
|
|
});
|
|
|
|
return response()->json(['message' => 'Items reordered successfully']);
|
|
}
|
|
} |