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

294 lines
17 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 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. Jede Modul hat einen bestimmten Typ und enthält passende Inhalte (Videos, Bilder oder Angebots-Slides).</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Displays</strong> Die physischen Bildschirme im Showroom. Jedem Display werden eine oder mehrere Module als Playlist zugewiesen.</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 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 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> (Dateiname, Titel, Position/Ausschnitt) und <em>Footer-Zeilen</em> (Überschrift, Unterzeile, optionaler QR-Code-Link).
</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.
</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.
</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.
</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">Modul-Zuweisung:</strong> Jedem Display 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">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 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>). Änderungen werden beim nächsten Abruf automatisch übernommen.</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">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">Inhalte hinzufügen</strong> Im Modul Videos, Medien oder Slides anlegen, Reihenfolge festlegen und aktivieren.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Display zuweisen</strong> Unter „Displays" das Modul einem physischen Bildschirm zuordnen.</li>
<li><strong class="font-medium text-zinc-800 dark:text-zinc-200">Fertig</strong> Das Display lädt die neuen Inhalte automatisch über die API.</li>
</ol>
</div>
</div>
</flux:card>
</div>