b2in/resources/views/livewire/admin/cms/display-dashboard.blade.php

298 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Enums\DisplayVersionType;
use App\Models\CabinetTabletSetting;
use App\Models\Display;
use App\Models\DisplayMedia;
use App\Models\DisplayVersion;
use App\Models\DisplayVersionItem;
use function Livewire\Volt\{layout, title, computed};
layout('components.layouts.app');
title('Store Displays');
$stats = computed(fn () => [
'displays' => Display::count(),
'displays_active' => Display::where('is_active', true)->count(),
'modules' => DisplayVersion::count(),
'modules_active' => DisplayVersion::active()->count(),
'items' => DisplayVersionItem::count(),
'items_active' => DisplayVersionItem::where('is_active', true)->count(),
'type_video' => DisplayVersion::ofType(DisplayVersionType::VideoDisplay)->count(),
'type_b2in' => DisplayVersion::ofType(DisplayVersionType::B2in)->count(),
'type_offers' => DisplayVersion::ofType(DisplayVersionType::Offers)->count(),
'media_total' => DisplayMedia::count(),
'media_uploads' => DisplayMedia::uploads()->count(),
'media_externals' => DisplayMedia::externals()->count(),
]);
$tabletStatus = computed(function () {
try {
$settings = CabinetTabletSetting::current();
return $settings->computeStatus()['status'];
} catch (\Throwable) {
return null;
}
});
?>
<div>
<div class="mb-6">
<flux:heading size="xl">Store Displays</flux:heading>
<flux:text class="mt-1">Displays, Inhalts-Module und Info-Tablet im Cabinet Showroom verwalten.</flux:text>
</div>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-5">
<a href="{{ route('admin.cms.display-media') }}" wire:navigate>
<flux:card class="hover:border-violet-500 transition-colors">
<div class="flex items-center gap-3">
<flux:icon name="photo" class="text-violet-500" />
<div>
<flux:heading size="lg">{{ $this->stats['media_total'] }}</flux:heading>
<flux:text class="text-sm">Medien ({{ $this->stats['media_uploads'] }} Uploads, {{ $this->stats['media_externals'] }} extern)</flux:text>
</div>
</div>
</flux:card>
</a>
<a href="{{ route('admin.cms.display-modules') }}" wire:navigate>
<flux:card class="hover:border-purple-500 transition-colors">
<div class="flex items-center gap-3">
<flux:icon name="rectangle-group" class="text-purple-500" />
<div>
<flux:heading size="lg">{{ $this->stats['modules'] }}</flux:heading>
<flux:text class="text-sm">Module ({{ $this->stats['modules_active'] }} aktiv)</flux:text>
</div>
</div>
</flux:card>
</a>
<a href="{{ route('admin.cms.displays') }}" wire:navigate>
<flux:card class="hover:border-blue-500 transition-colors">
<div class="flex items-center gap-3">
<flux:icon name="tv" class="text-blue-500" />
<div>
<flux:heading size="lg">{{ $this->stats['displays'] }}</flux:heading>
<flux:text class="text-sm">Displays ({{ $this->stats['displays_active'] }} aktiv)</flux:text>
</div>
</div>
</flux:card>
</a>
<a href="{{ route('admin.cms.cabinet-tablet') }}" wire:navigate>
<flux:card class="hover:border-teal-500 transition-colors">
<div class="flex items-center gap-3">
<flux:icon name="device-tablet" class="text-teal-500" />
<div>
<flux:heading size="lg">Info-Tablet</flux:heading>
<flux:text class="text-sm">
@if($this->tabletStatus)
Status:
<flux:badge size="sm" :color="match($this->tabletStatus) {
'open' => 'green',
'closed' => 'red',
'notice' => 'amber',
'warning' => 'orange',
default => 'zinc',
}">
{{ match($this->tabletStatus) {
'open' => 'Geöffnet',
'closed' => 'Geschlossen',
'notice' => 'Hinweis',
'warning' => 'Warnung',
default => $this->tabletStatus,
} }}
</flux:badge>
@else
Öffnungszeiten & Status
@endif
</flux:text>
</div>
</div>
</flux:card>
</a>
<flux:card>
<div class="flex items-center gap-3">
<flux:icon name="queue-list" class="text-zinc-400" />
<div>
<flux:heading size="lg">{{ $this->stats['items'] }}</flux:heading>
<flux:text class="text-sm">Inhalte gesamt ({{ $this->stats['items_active'] }} aktiv)</flux:text>
</div>
</div>
</flux:card>
</div>
{{-- Modul-Typen Übersicht --}}
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3 mt-4">
<flux:card>
<div class="flex items-center gap-3">
<flux:icon name="film" class="text-purple-400" />
<div>
<flux:text class="text-sm font-medium text-zinc-800 dark:text-zinc-200">Video-Display</flux:text>
<flux:text class="text-xs">{{ $this->stats['type_video'] }} {{ $this->stats['type_video'] === 1 ? 'Modul' : 'Module' }}</flux:text>
</div>
</div>
</flux:card>
<flux:card>
<div class="flex items-center gap-3">
<flux:icon name="photo" class="text-blue-400" />
<div>
<flux:text class="text-sm font-medium text-zinc-800 dark:text-zinc-200">B2in Display</flux:text>
<flux:text class="text-xs">{{ $this->stats['type_b2in'] }} {{ $this->stats['type_b2in'] === 1 ? 'Modul' : 'Module' }}</flux:text>
</div>
</div>
</flux:card>
<flux:card>
<div class="flex items-center gap-3">
<flux:icon name="tag" class="text-amber-400" />
<div>
<flux:text class="text-sm font-medium text-zinc-800 dark:text-zinc-200">Angebote</flux:text>
<flux:text class="text-xs">{{ $this->stats['type_offers'] }} {{ $this->stats['type_offers'] === 1 ? 'Modul' : 'Module' }}</flux:text>
</div>
</div>
</flux:card>
</div>
{{-- Beschreibung --}}
<flux:card class="mt-6 max-w-4xl">
<flux:heading size="lg" class="mb-4">So funktioniert das Display-System</flux:heading>
<div class="space-y-5 text-sm text-zinc-600 dark:text-zinc-400">
<div>
<flux:heading size="sm" class="mb-1 flex items-center gap-2">
<flux:icon name="squares-2x2" class="size-4 text-zinc-500" />
Überblick
</flux:heading>
<p>
Das Display-System steuert alle Bildschirme im Cabinet Showroom Bielefeld.
Es besteht aus drei Bereichen, die Sie über die Kacheln oben erreichen:
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Mediathek</strong> - Zentrale Verwaltung aller Bilder, SVG-Logos und Videos fuer die Displays. Dateien bis 200 MB direkt hochladen oder groessere Videos als externe URL (Google Drive, OneDrive) einbinden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Module</strong> Wiederverwendbare Content-Pakete, die auf den Displays abgespielt werden. Jedes Modul hat einen bestimmten Typ, passende Inhalte und eigene Meta-Einstellungen fuer Logo, Claim, Footer, QR-Code oder Theme.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Displays</strong> Die physischen Bildschirme im Showroom. Pro Display gibt es einen Live-Stand und optional einen Entwurf, der separat vorbereitet, getestet und bewusst veröffentlicht wird.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Info-Tablet</strong> Das Tablet an der Eingangstür des Showrooms. Hier verwalten Sie Öffnungszeiten, den aktuellen Store-Status und Hinweise für Besucher.</li>
</ul>
</div>
<flux:separator />
<div>
<flux:heading size="sm" class="mb-1 flex items-center gap-2">
<flux:icon name="photo" class="size-4 text-violet-500" />
Mediathek
</flux:heading>
<p>
Die <strong class="font-medium text-zinc-800 dark:text-zinc-200">Display-Mediathek</strong> verwaltet alle Bilder und Videos, die auf den Displays im Showroom angezeigt werden.
Sie ist unabhängig von der Website-Mediathek (Flux CMS) und speziell auf die Anforderungen der Displays zugeschnitten.
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Direkt-Upload:</strong> Bilder, SVG-Dateien und Videos bis 200 MB direkt per Drag-and-drop oder Dateiauswahl hochladen. Die Dateien werden auf dem Server gespeichert und stehen sofort zur Verfügung.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Externe URLs:</strong> Für Videos über 200 MB (z.&nbsp;B. 4K-Showroom-Rundgänge) können Sie einen Freigabe-Link von Google Drive, OneDrive oder anderen Cloud-Diensten hinterlegen. Diese URL wird wie ein normales Medium in der Mediathek verwaltet und kann genauso in Module eingebunden werden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Sammlungen:</strong> Ordnen Sie Medien in Sammlungen wie <em>immobilien</em>, <em>moebel</em> oder <em>brand</em>, um bei vielen Dateien den Überblick zu behalten.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Medienauswahl im Editor:</strong> Beim Bearbeiten eines Moduls erscheint ein „Aus Mediathek"-Button. Darüber öffnen Sie die Medienauswahl und können bestehende Medien wählen oder direkt neue Dateien inklusive SVG-Logos hochladen.</li>
</ul>
</div>
<flux:separator />
<div>
<flux:heading size="sm" class="mb-1 flex items-center gap-2">
<flux:icon name="rectangle-group" class="size-4 text-purple-500" />
Module & Modul-Typen
</flux:heading>
<p>
Ein <strong class="font-medium text-zinc-800 dark:text-zinc-200">Modul</strong> ist ein Content-Paket mit einem bestimmten Typ.
Der Typ bestimmt, welche Art von Inhalten hinzugefügt werden können:
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Video-Display</strong>
Für Video-Playlists mit optionalem Footer. Inhalte: <em>Videos</em> aus der Mediathek oder Legacy-Dateinamen, Position/Ausschnitt und <em>Footer-Zeilen</em> (Überschrift, Unterzeile, optionaler QR-Code-Link). Mediathek-URLs wie <code class="text-xs bg-zinc-100 dark:bg-zinc-800 px-1 py-0.5 rounded">/storage/...</code> werden direkt abgespielt.
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">B2in Display</strong>
Für Medien-Rotation (Bilder und Videos) im Marken-Design. Inhalte: <em>Media-Items</em> mit Kategorie (Immobilien / Möbel), Überschrift, Unterzeile und Anzeigedauer. Unterstützt Light-/Dark-Theme sowie zentrale Meta-Einstellungen für Header-Logo, Claim, Footer-Domain und QR-Code.
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Angebote</strong>
Für Produkt-Slides im Angebotsformat. Verschiedene Slide-Layouts: Intro, Produkt-Hero, Produkt-Details und Impuls-Slides mit Preisen, Badges und QR-Codes. Logo, Brand-Text, Footer-Claim und Web-/QR-URL werden einmal am Modul gepflegt und automatisch von allen Slides übernommen.
</li>
</ul>
<p class="mt-2">
Innerhalb eines Moduls können Sie beliebig viele Inhalte anlegen, die Reihenfolge per Hoch/Runter-Sortierung festlegen und einzelne Einträge aktivieren oder deaktivieren. Der Modul-Editor zeigt Inline-Vorschaubilder, eine 9:16-Player-Vorschau und eine Vollbild-Vorschau. Im Slide-Bearbeiten-Dialog wird nur der aktuell bearbeitete Slide als Einzel-Vorschau gerendert.
</p>
</div>
<flux:separator />
<div>
<flux:heading size="sm" class="mb-1 flex items-center gap-2">
<flux:icon name="tv" class="size-4 text-blue-500" />
Displays & Playlists
</flux:heading>
<p>
Ein <strong class="font-medium text-zinc-800 dark:text-zinc-200">Display</strong> repräsentiert einen physischen Bildschirm im Showroom.
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Live und Entwurf:</strong> Jedes Display zeigt den veröffentlichten Live-Stand und optional einen Entwurf. Entwürfe können aus Live angelegt, separat bearbeitet, verworfen oder veröffentlicht werden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Modul-Zuweisung:</strong> Jedem Live- oder Entwurfsstand können Sie eine oder mehrere Module zuordnen. Die Module werden in der festgelegten Reihenfolge als Playlist abgespielt.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Vorschau:</strong> Live- und Entwurfs-URLs sind direkt kopierbar. Entwürfe und Module können zusätzlich im 9:16-Iframe oder im Vollbild geprüft werden.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Aktiv/Inaktiv:</strong> Über den Aktiv-Status können Sie einzelne Displays vorübergehend deaktivieren, ohne die Konfiguration zu verlieren.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">API-Anbindung:</strong> Jedes Display ruft seine Live-Inhalte über eine JSON-API ab (<code class="text-xs bg-zinc-100 dark:bg-zinc-800 px-1 py-0.5 rounded">/api/display/{id}/config</code>). Entwürfe laufen über Preview-Tokens, Module über eigene Preview-Endpunkte.</li>
</ul>
</div>
<flux:separator />
<div>
<flux:heading size="sm" class="mb-1 flex items-center gap-2">
<flux:icon name="device-tablet" class="size-4 text-teal-500" />
Info-Tablet
</flux:heading>
<p>
Das Info-Tablet zeigt Besuchern am Showroom-Eingang den aktuellen Status und die Öffnungszeiten.
</p>
<ul class="mt-2 ml-5 list-disc space-y-1">
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Store-Status:</strong>
Vier Modi stehen zur Verfügung <em>Automatisch</em> (berechnet den Status aus den Öffnungszeiten), <em>Geschlossen</em> (manuell), <em>Hinweis</em> (eigene Nachricht) und <em>Warnung</em> (dringende Nachricht).
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Öffnungszeiten:</strong>
Für jeden Wochentag (MontagSonntag) können individuelle Öffnungs- und Schließzeiten gepflegt werden. Tage ohne Zeiten gelten als geschlossen.
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Tages-Overrides:</strong>
Für Sonderfälle (z.&nbsp;B. früher schließen) können Sie die Zeiten für den heutigen Tag überschreiben. Diese Überschreibungen werden automatisch um Mitternacht zurückgesetzt.
</li>
<li>
<strong class="font-medium text-zinc-800 dark:text-zinc-200">Kontaktdaten & Termine:</strong>
Telefonnummer, E-Mail-Adresse und der nächste Termin werden auf dem Tablet angezeigt und können hier zentral gepflegt werden.
</li>
</ul>
</div>
<flux:separator />
<div>
<flux:heading size="sm" class="mb-1 flex items-center gap-2">
<flux:icon name="arrow-path" class="size-4 text-zinc-500" />
Typischer Workflow
</flux:heading>
<ol class="mt-2 ml-5 list-decimal space-y-1">
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Medien hochladen</strong> Bilder, SVG-Logos oder Videos in der Display-Mediathek ablegen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Modul erstellen</strong> Unter „Module" ein neues Modul mit passendem Typ anlegen (z.&nbsp;B. „Frühling 2026 Video").</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Meta-Einstellungen pflegen</strong> Logo, Claim, Footer, QR-Code, Theme oder Anzeigezeiten einmal auf Modulebene setzen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Inhalte hinzufügen</strong> Im Modul Videos, Medien oder Slides anlegen, Reihenfolge festlegen, aktivieren und per Vorschau prüfen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Display-Entwurf erstellen</strong> Unter „Displays" aus dem Live-Stand einen Entwurf erzeugen und dort Module hinzufügen, sortieren oder entfernen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Prüfen und veröffentlichen</strong> Entwurf in der 9:16-Vorschau oder im Vollbild testen und anschließend bewusst veröffentlichen.</li>
</ol>
</div>
</div>
</flux:card>
</div>