12-05-2026 admin, Panel Displays

This commit is contained in:
Kevin Adametz 2026-05-12 18:28:38 +02:00
parent 0762e3beac
commit 6a65354f4c
43 changed files with 3273 additions and 410 deletions

View file

@ -3,7 +3,12 @@
namespace App\Livewire\Admin\Cms;
use App\Models\Display;
use App\Models\DisplayPlaylist;
use App\Models\DisplayPlaylistItem;
use App\Models\DisplayVersion;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
class DisplayList extends Component
@ -21,17 +26,36 @@ class DisplayList extends Component
public $displayIsActive = true;
public $displayIsTest = false;
public $addVersionSelect = null;
public function openModal(?int $id = null): void
public $editingPlaylistStatus = DisplayPlaylist::STATUS_PUBLISHED;
public ?string $draftPreviewToken = null;
public int $previewFrameRefreshCounter = 0;
public function openModal(?int $id = null, string $playlistStatus = DisplayPlaylist::STATUS_PUBLISHED): void
{
$this->editingPlaylistStatus = in_array($playlistStatus, [
DisplayPlaylist::STATUS_PUBLISHED,
DisplayPlaylist::STATUS_DRAFT,
], true) ? $playlistStatus : DisplayPlaylist::STATUS_PUBLISHED;
if ($id) {
$display = Display::with('versions')->findOrFail($id);
$display = Display::with(['livePlaylist.modules', 'draftPlaylist.modules', 'versions'])->findOrFail($id);
$this->displayId = $display->id;
$this->displayName = $display->name;
$this->displayLocation = $display->location ?? '';
$this->selectedVersionIds = $display->versions->pluck('id')->toArray();
$this->selectedVersionIds = $this->selectedVersionIdsFor($display);
$this->displayIsActive = $display->is_active;
$this->displayIsTest = $display->is_test;
if ($this->editingPlaylistStatus === DisplayPlaylist::STATUS_DRAFT) {
$this->draftPreviewToken = $display->ensurePreviewToken();
$this->previewFrameRefreshCounter++;
}
} else {
$this->resetForm();
}
@ -41,18 +65,28 @@ class DisplayList extends Component
public function addVersion(?int $versionId = null): void
{
$id = $versionId ?? $this->addVersionSelect;
$id = $versionId ?? $this->addVersionSelect ?? $this->firstAvailableVersionId();
if ($id && ! in_array((int) $id, $this->selectedVersionIds)) {
$this->selectedVersionIds[] = (int) $id;
}
$this->addVersionSelect = null;
$this->persistDraftPreviewIfNeeded();
}
private function firstAvailableVersionId(): ?int
{
return DisplayVersion::active()
->whereNotIn('id', $this->selectedVersionIds)
->orderBy('name')
->value('id');
}
public function removeVersion(int $index): void
{
array_splice($this->selectedVersionIds, $index, 1);
$this->persistDraftPreviewIfNeeded();
}
public function moveVersion(int $index, string $direction): void
@ -66,6 +100,8 @@ class DisplayList extends Component
$temp = $this->selectedVersionIds[$index];
$this->selectedVersionIds[$index] = $this->selectedVersionIds[$newIndex];
$this->selectedVersionIds[$newIndex] = $temp;
$this->persistDraftPreviewIfNeeded();
}
public function save(): void
@ -83,6 +119,7 @@ class DisplayList extends Component
'name' => $this->displayName,
'location' => $this->displayLocation ?: null,
'is_active' => $this->displayIsActive,
'is_test' => $this->displayIsTest,
];
if ($this->displayId) {
@ -94,16 +131,176 @@ class DisplayList extends Component
session()->flash('success', 'Display erfolgreich erstellt!');
}
// Sync versions with sort_order
$syncData = [];
foreach ($this->selectedVersionIds as $sortOrder => $versionId) {
$syncData[$versionId] = ['sort_order' => $sortOrder];
if ($this->editingPlaylistStatus === DisplayPlaylist::STATUS_DRAFT && $this->displayId) {
$this->syncDraftPlaylist($display);
$this->draftPreviewToken = $display->ensurePreviewToken();
$this->previewFrameRefreshCounter++;
} else {
$this->syncPublishedPlaylist($display);
$this->syncLegacyPivot($display, $this->selectedVersionIds);
}
$display->versions()->sync($syncData);
$this->closeModal();
}
public function createDraft(int $displayId): void
{
$display = Display::with(['livePlaylist.modules', 'draftPlaylist'])->findOrFail($displayId);
if ($display->draftPlaylist) {
session()->flash('success', 'Für dieses Display existiert bereits ein Entwurf.');
return;
}
$draft = $display->playlists()->create([
'status' => DisplayPlaylist::STATUS_DRAFT,
'published_at' => null,
'published_by' => null,
]);
$this->syncPlaylistItems($draft, $this->moduleIdsForPlaylist($display->livePlaylist));
$display->ensurePreviewToken();
session()->flash('success', 'Entwurf wurde aus dem Live-Stand angelegt.');
}
public function discardDraft(int $displayId): void
{
$display = Display::with('draftPlaylist')->findOrFail($displayId);
if (! $display->draftPlaylist) {
session()->flash('success', 'Für dieses Display gibt es keinen Entwurf.');
return;
}
$display->draftPlaylist->delete();
session()->flash('success', 'Entwurf wurde verworfen.');
}
public function publishDraft(int $displayId): void
{
$display = Display::with(['draftPlaylist.modules'])->findOrFail($displayId);
if (! $display->draftPlaylist) {
session()->flash('success', 'Für dieses Display gibt es keinen Entwurf zum Veröffentlichen.');
return;
}
$publishedPlaylist = DB::transaction(function () use ($display): DisplayPlaylist {
$display->livePlaylist()->delete();
$display->draftPlaylist->update([
'status' => DisplayPlaylist::STATUS_PUBLISHED,
'published_at' => now(),
'published_by' => Auth::id(),
]);
return $display->draftPlaylist->fresh('modules');
});
$this->syncLegacyPivot($display, $this->moduleIdsForPlaylist($publishedPlaylist));
session()->flash('success', 'Entwurf wurde veröffentlicht.');
}
/**
* @param array<int> $versionIds
*/
private function syncLegacyPivot(Display $display, array $versionIds): void
{
$syncData = [];
foreach ($versionIds as $sortOrder => $versionId) {
$syncData[$versionId] = ['sort_order' => $sortOrder];
}
$display->versions()->sync($syncData);
}
private function syncPublishedPlaylist(Display $display): void
{
$playlist = $display->playlists()->firstOrCreate(
['status' => DisplayPlaylist::STATUS_PUBLISHED],
['published_at' => now(), 'published_by' => Auth::id()]
);
$playlist->update([
'published_at' => now(),
'published_by' => Auth::id(),
]);
$this->syncPlaylistItems($playlist, $this->selectedVersionIds);
}
private function syncDraftPlaylist(Display $display): void
{
$playlist = $display->playlists()->firstOrCreate(
['status' => DisplayPlaylist::STATUS_DRAFT],
['published_at' => null, 'published_by' => null]
);
$this->syncPlaylistItems($playlist, $this->selectedVersionIds);
}
private function persistDraftPreviewIfNeeded(): void
{
if ($this->editingPlaylistStatus !== DisplayPlaylist::STATUS_DRAFT || ! $this->displayId) {
return;
}
$display = Display::findOrFail($this->displayId);
$this->syncDraftPlaylist($display);
$this->draftPreviewToken = $display->ensurePreviewToken();
$this->previewFrameRefreshCounter++;
}
/**
* @param array<int> $versionIds
*/
private function syncPlaylistItems(DisplayPlaylist $playlist, array $versionIds): void
{
$playlist->items()->delete();
foreach (array_values($versionIds) as $sortOrder => $versionId) {
DisplayPlaylistItem::query()->create([
'display_playlist_id' => $playlist->id,
'display_version_id' => $versionId,
'sort_order' => $sortOrder,
]);
}
}
/**
* @return array<int>
*/
private function moduleIdsForPlaylist(?DisplayPlaylist $playlist): array
{
if (! $playlist) {
return [];
}
$playlist->loadMissing('modules');
return $playlist->modules->pluck('id')->all();
}
/**
* @return array<int>
*/
private function selectedVersionIdsFor(Display $display): array
{
if ($this->editingPlaylistStatus === DisplayPlaylist::STATUS_DRAFT) {
return $this->moduleIdsForPlaylist($display->draftPlaylist);
}
return $this->moduleIdsForPlaylist($display->livePlaylist)
?: $display->versions->pluck('id')->all();
}
public function deleteDisplay(int $id): void
{
$display = Display::findOrFail($id);
@ -132,12 +329,17 @@ class DisplayList extends Component
$this->displayLocation = '';
$this->selectedVersionIds = [];
$this->displayIsActive = true;
$this->displayIsTest = false;
$this->addVersionSelect = null;
$this->editingPlaylistStatus = DisplayPlaylist::STATUS_PUBLISHED;
$this->draftPreviewToken = null;
$this->previewFrameRefreshCounter = 0;
}
public function render()
public function render(): View
{
$displays = Display::with('versions')
$displays = Display::with(['livePlaylist.modules', 'draftPlaylist.modules'])
->orderByDesc('is_test')
->orderBy('name')
->get();