mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 08:11:10 -05:00
125 lines
3.6 KiB
PHP
125 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
use App\Models\Park;
|
|
use App\Models\ParkArea;
|
|
use Livewire\Component;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class ParkAreaReorderComponent extends Component
|
|
{
|
|
public Park $park;
|
|
public ?int $parentId = null;
|
|
public array $areas = [];
|
|
|
|
public function mount(Park $park, ?int $parentId = null): void
|
|
{
|
|
$this->park = $park;
|
|
$this->parentId = $parentId;
|
|
$this->loadAreas();
|
|
}
|
|
|
|
/**
|
|
* Load areas for the current context (either top-level or within a parent).
|
|
*/
|
|
protected function loadAreas(): void
|
|
{
|
|
$query = $this->park->areas()
|
|
->where('parent_id', $this->parentId)
|
|
->orderBy('position')
|
|
->select(['id', 'name', 'position', 'closing_date']);
|
|
|
|
$this->areas = $query->get()
|
|
->map(fn ($area) => [
|
|
'id' => $area->id,
|
|
'name' => $area->name,
|
|
'position' => $area->position,
|
|
'is_closed' => !is_null($area->closing_date),
|
|
'has_children' => $area->hasChildren(),
|
|
])
|
|
->toArray();
|
|
}
|
|
|
|
/**
|
|
* Handle reordering of areas.
|
|
*/
|
|
public function reorder(array $orderedIds): void
|
|
{
|
|
// Validate that all IDs belong to this park and parent context
|
|
$validIds = $this->park->areas()
|
|
->where('parent_id', $this->parentId)
|
|
->pluck('id')
|
|
->toArray();
|
|
|
|
$orderedIds = array_values(array_intersect($orderedIds, $validIds));
|
|
|
|
// Update positions
|
|
foreach ($orderedIds as $position => $id) {
|
|
ParkArea::where('id', $id)->update(['position' => $position]);
|
|
}
|
|
|
|
$this->loadAreas();
|
|
$this->dispatch('areas-reordered');
|
|
}
|
|
|
|
/**
|
|
* Move an area to a new parent.
|
|
*/
|
|
public function moveToParent(int $areaId, ?int $newParentId): void
|
|
{
|
|
$area = $this->park->areas()->findOrFail($areaId);
|
|
|
|
// Prevent circular references
|
|
if ($newParentId === $area->id) {
|
|
return;
|
|
}
|
|
|
|
// If moving to a new parent, validate it exists and belongs to this park
|
|
if ($newParentId) {
|
|
$newParent = $this->park->areas()->findOrFail($newParentId);
|
|
|
|
// Prevent moving to own descendant
|
|
$ancestorIds = Collection::make();
|
|
$current = $newParent;
|
|
while ($current) {
|
|
if ($ancestorIds->contains($current->id)) {
|
|
return; // Circular reference detected
|
|
}
|
|
$ancestorIds->push($current->id);
|
|
if ($current->id === $area->id) {
|
|
return; // Would create circular reference
|
|
}
|
|
$current = $current->parent;
|
|
}
|
|
}
|
|
|
|
// Get the next position in the new parent context
|
|
$maxPosition = $this->park->areas()
|
|
->where('parent_id', $newParentId)
|
|
->max('position');
|
|
|
|
$area->update([
|
|
'parent_id' => $newParentId,
|
|
'position' => ($maxPosition ?? -1) + 1,
|
|
]);
|
|
|
|
// Reorder the old parent's remaining areas to close gaps
|
|
$this->park->areas()
|
|
->where('parent_id', $this->parentId)
|
|
->where('position', '>', $area->position)
|
|
->decrement('position');
|
|
|
|
$this->loadAreas();
|
|
$this->dispatch('area-moved');
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.park-area-reorder-component', [
|
|
'parentArea' => $this->parentId
|
|
? $this->park->areas()->find($this->parentId)
|
|
: null,
|
|
]);
|
|
}
|
|
} |