*/ public $selectedVersionIds = []; public $displayIsActive = true; public $displayIsTest = false; public $addVersionSelect = null; 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(['livePlaylist.modules', 'draftPlaylist.modules', 'versions'])->findOrFail($id); $this->displayId = $display->id; $this->displayName = $display->name; $this->displayLocation = $display->location ?? ''; $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(); } $this->showModal = true; } public function addVersion(?int $versionId = null): void { $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 { $newIndex = $direction === 'up' ? $index - 1 : $index + 1; if ($newIndex < 0 || $newIndex >= count($this->selectedVersionIds)) { return; } $temp = $this->selectedVersionIds[$index]; $this->selectedVersionIds[$index] = $this->selectedVersionIds[$newIndex]; $this->selectedVersionIds[$newIndex] = $temp; $this->persistDraftPreviewIfNeeded(); } public function save(): void { $this->validate([ 'displayName' => 'required|string|max:255', 'displayLocation' => 'nullable|string|max:255', 'selectedVersionIds' => 'array', 'selectedVersionIds.*' => 'exists:display_versions,id', ], [ 'displayName.required' => 'Bitte geben Sie einen Namen ein.', ]); $data = [ 'name' => $this->displayName, 'location' => $this->displayLocation ?: null, 'is_active' => $this->displayIsActive, 'is_test' => $this->displayIsTest, ]; if ($this->displayId) { $display = Display::findOrFail($this->displayId); $display->update($data); session()->flash('success', 'Display erfolgreich aktualisiert!'); } else { $display = Display::create($data); session()->flash('success', 'Display erfolgreich erstellt!'); } 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); } $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 $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 $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 */ private function moduleIdsForPlaylist(?DisplayPlaylist $playlist): array { if (! $playlist) { return []; } $playlist->loadMissing('modules'); return $playlist->modules->pluck('id')->all(); } /** * @return array */ 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); $name = $display->name; $display->delete(); session()->flash('success', 'Display "'.$name.'" wurde gelöscht!'); } public function toggleActive(int $id): void { $display = Display::findOrFail($id); $display->update(['is_active' => ! $display->is_active]); } public function closeModal(): void { $this->showModal = false; $this->resetForm(); } public function resetForm(): void { $this->displayId = null; $this->displayName = ''; $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(): View { $displays = Display::with(['livePlaylist.modules', 'draftPlaylist.modules']) ->orderByDesc('is_test') ->orderBy('name') ->get(); $versions = DisplayVersion::active() ->orderBy('name') ->get(); return view('livewire.admin.cms.display-list', [ 'displays' => $displays, 'versions' => $versions, ]); } }