495 lines
15 KiB
PHP
495 lines
15 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Admin\Cms;
|
|
|
|
use App\Enums\DisplayVersionType;
|
|
use App\Models\DisplayVersion;
|
|
use App\Models\DisplayVersionItem;
|
|
use App\Support\DisplayModuleSettings;
|
|
use Illuminate\Support\Facades\File;
|
|
use Livewire\Attributes\On;
|
|
use Livewire\Component;
|
|
|
|
class DisplayVersionEditor extends Component
|
|
{
|
|
public DisplayVersion $version;
|
|
|
|
public string $versionName = '';
|
|
|
|
// Item Modal
|
|
public bool $showItemModal = false;
|
|
|
|
public ?int $itemId = null;
|
|
|
|
public string $itemType = '';
|
|
|
|
// Video-Display: Video fields
|
|
public string $videoFilename = '';
|
|
|
|
public string $videoTitle = '';
|
|
|
|
public int $videoPosition = 25;
|
|
|
|
public bool $videoIsActive = true;
|
|
|
|
// Video-Display: Footer fields
|
|
public string $footerHeadline = '';
|
|
|
|
public string $footerSubline = '';
|
|
|
|
public string $footerUrl = '';
|
|
|
|
public bool $footerIsActive = true;
|
|
|
|
// B2in: Media fields
|
|
public string $mediaType = 'image';
|
|
|
|
public string $mediaCategory = 'immobilien';
|
|
|
|
public string $mediaUrl = '';
|
|
|
|
public string $mediaHeadline = '';
|
|
|
|
public string $mediaSubline = '';
|
|
|
|
public int $mediaDuration = 10;
|
|
|
|
public bool $mediaIsActive = true;
|
|
|
|
// Offers: Slide fields
|
|
public string $slideType = 'product-hero';
|
|
|
|
public int $slideDuration = 8000;
|
|
|
|
public string $slideImageUrl = '';
|
|
|
|
public string $slideBadge = '';
|
|
|
|
public string $slideEyebrow = '';
|
|
|
|
public string $slideTitle = '';
|
|
|
|
public string $slideSubline = '';
|
|
|
|
public string $slidePrice = '';
|
|
|
|
public string $slideOriginalPrice = '';
|
|
|
|
public string $slideTagText = '';
|
|
|
|
/** @var array<string> */
|
|
public array $slideBullets = [];
|
|
|
|
public string $slideDisclaimer = '';
|
|
|
|
public string $slideQrUrl = '';
|
|
|
|
public string $slideQrTitle = '';
|
|
|
|
public string $slideContact = '';
|
|
|
|
public bool $slideShowBrandText = false;
|
|
|
|
public string $slideBrandTagline = '';
|
|
|
|
public bool $slideIsActive = true;
|
|
|
|
// Settings Modal
|
|
public bool $showSettingsModal = false;
|
|
|
|
public array $settings = [];
|
|
|
|
/** @var array<string> */
|
|
public array $availableVideos = [];
|
|
|
|
public int $previewFrameRefreshCounter = 0;
|
|
|
|
public function mount(DisplayVersion $displayVersion): void
|
|
{
|
|
$this->version = $displayVersion;
|
|
$this->versionName = $displayVersion->name;
|
|
$this->settings = $this->settingsWithDefaults();
|
|
|
|
if ($this->version->type === DisplayVersionType::VideoDisplay) {
|
|
$this->loadAvailableVideos();
|
|
}
|
|
}
|
|
|
|
public function loadAvailableVideos(): void
|
|
{
|
|
$assetsPath = public_path('_cabinet/assets');
|
|
|
|
if (File::exists($assetsPath)) {
|
|
$this->availableVideos = collect(File::files($assetsPath))
|
|
->map(fn ($file) => $file->getFilename())
|
|
->filter(fn ($filename) => in_array(pathinfo($filename, PATHINFO_EXTENSION), ['mp4', 'webm', 'mov']))
|
|
->values()
|
|
->toArray();
|
|
}
|
|
}
|
|
|
|
public function toggleTheme(): void
|
|
{
|
|
$settings = $this->settingsWithDefaults();
|
|
$settings['theme'] = ($settings['theme'] ?? 'dark') === 'dark' ? 'light' : 'dark';
|
|
$this->version->update(['settings' => $settings]);
|
|
$this->settings = $settings;
|
|
$this->refreshModulePreview();
|
|
}
|
|
|
|
public function saveName(): void
|
|
{
|
|
$this->validate([
|
|
'versionName' => 'required|string|max:255',
|
|
]);
|
|
|
|
$this->version->update(['name' => $this->versionName]);
|
|
$this->refreshModulePreview();
|
|
session()->flash('success', 'Name aktualisiert!');
|
|
}
|
|
|
|
// ========================================
|
|
// SETTINGS
|
|
// ========================================
|
|
|
|
public function openSettingsModal(): void
|
|
{
|
|
$this->settings = $this->settingsWithDefaults();
|
|
$this->showSettingsModal = true;
|
|
}
|
|
|
|
public function saveSettings(): void
|
|
{
|
|
$this->version->update(['settings' => $this->settings]);
|
|
$this->showSettingsModal = false;
|
|
$this->refreshModulePreview();
|
|
session()->flash('success', 'Einstellungen gespeichert!');
|
|
}
|
|
|
|
// ========================================
|
|
// ITEM CRUD
|
|
// ========================================
|
|
|
|
public function openItemModal(?int $id = null, string $type = ''): void
|
|
{
|
|
$this->resetItemForm();
|
|
|
|
if ($id) {
|
|
$item = DisplayVersionItem::findOrFail($id);
|
|
$this->itemId = $item->id;
|
|
$this->itemType = $item->item_type;
|
|
$this->loadItemContent($item);
|
|
} else {
|
|
$this->itemType = $type ?: $this->defaultItemType();
|
|
}
|
|
|
|
$this->showItemModal = true;
|
|
}
|
|
|
|
public function saveItem(): void
|
|
{
|
|
$content = $this->buildItemContent();
|
|
$isActive = $this->getActiveFlag();
|
|
|
|
if ($this->itemId) {
|
|
$item = DisplayVersionItem::findOrFail($this->itemId);
|
|
$item->update([
|
|
'content' => $content,
|
|
'is_active' => $isActive,
|
|
]);
|
|
session()->flash('success', 'Inhalt aktualisiert!');
|
|
} else {
|
|
$maxSort = DisplayVersionItem::where('display_version_id', $this->version->id)
|
|
->where('item_type', $this->itemType)
|
|
->max('sort_order') ?? -1;
|
|
|
|
$item = DisplayVersionItem::create([
|
|
'display_version_id' => $this->version->id,
|
|
'item_type' => $this->itemType,
|
|
'content' => $content,
|
|
'sort_order' => $maxSort + 1,
|
|
'is_active' => $isActive,
|
|
]);
|
|
session()->flash('success', 'Inhalt hinzugefügt!');
|
|
}
|
|
|
|
$this->itemId = $item->id;
|
|
$this->itemType = $item->item_type;
|
|
$this->loadItemContent($item->fresh());
|
|
$this->showItemModal = true;
|
|
$this->refreshModulePreview();
|
|
}
|
|
|
|
public function deleteItem(int $id): void
|
|
{
|
|
DisplayVersionItem::findOrFail($id)->delete();
|
|
$this->refreshModulePreview();
|
|
session()->flash('success', 'Inhalt gelöscht!');
|
|
}
|
|
|
|
public function toggleItemStatus(int $id): void
|
|
{
|
|
$item = DisplayVersionItem::findOrFail($id);
|
|
$item->update(['is_active' => ! $item->is_active]);
|
|
$this->refreshModulePreview();
|
|
}
|
|
|
|
public function moveItem(int $id, string $direction): void
|
|
{
|
|
$item = DisplayVersionItem::findOrFail($id);
|
|
$currentOrder = $item->sort_order;
|
|
|
|
$swapItem = DisplayVersionItem::where('display_version_id', $this->version->id)
|
|
->where('item_type', $item->item_type)
|
|
->where('sort_order', $direction === 'up' ? $currentOrder - 1 : $currentOrder + 1)
|
|
->first();
|
|
|
|
if ($swapItem) {
|
|
$item->update(['sort_order' => $swapItem->sort_order]);
|
|
$swapItem->update(['sort_order' => $currentOrder]);
|
|
$this->refreshModulePreview();
|
|
}
|
|
}
|
|
|
|
public function modulePreviewUrl(): string
|
|
{
|
|
return url('/preview/module/'.$this->version->id).'?refresh='.$this->previewFrameRefreshCounter;
|
|
}
|
|
|
|
public function itemPreviewUrl(): string
|
|
{
|
|
if (! $this->itemId) {
|
|
return $this->modulePreviewUrl();
|
|
}
|
|
|
|
return url('/preview/module/'.$this->version->id.'/item/'.$this->itemId).'?refresh='.$this->previewFrameRefreshCounter;
|
|
}
|
|
|
|
#[On('display-media-selected')]
|
|
public function onDisplayMediaSelected(string $field, ?int $mediaId, ?string $url): void
|
|
{
|
|
if (! $url) {
|
|
return;
|
|
}
|
|
|
|
match ($field) {
|
|
'videoFilename' => $this->videoFilename = $url,
|
|
'mediaUrl' => $this->mediaUrl = $url,
|
|
'slideImageUrl' => $this->slideImageUrl = $url,
|
|
'settings.header_logo_url' => $this->settings['header_logo_url'] = $url,
|
|
'settings.logo_url' => $this->settings['logo_url'] = $url,
|
|
default => null,
|
|
};
|
|
}
|
|
|
|
public function addBullet(): void
|
|
{
|
|
$this->slideBullets[] = '';
|
|
}
|
|
|
|
public function removeBullet(int $index): void
|
|
{
|
|
unset($this->slideBullets[$index]);
|
|
$this->slideBullets = array_values($this->slideBullets);
|
|
}
|
|
|
|
public function closeItemModal(): void
|
|
{
|
|
$this->showItemModal = false;
|
|
$this->resetItemForm();
|
|
}
|
|
|
|
// ========================================
|
|
// HELPERS
|
|
// ========================================
|
|
|
|
private function loadItemContent(DisplayVersionItem $item): void
|
|
{
|
|
$content = $item->content;
|
|
|
|
match ($item->item_type) {
|
|
'video' => $this->loadVideoContent($content),
|
|
'footer' => $this->loadFooterContent($content),
|
|
'media' => $this->loadMediaContent($content),
|
|
'slide' => $this->loadSlideContent($content),
|
|
default => null,
|
|
};
|
|
}
|
|
|
|
private function loadVideoContent(array $content): void
|
|
{
|
|
$this->videoFilename = $content['filename'] ?? '';
|
|
$this->videoTitle = $content['title'] ?? '';
|
|
$this->videoPosition = $content['position'] ?? 25;
|
|
$this->videoIsActive = true;
|
|
}
|
|
|
|
private function loadFooterContent(array $content): void
|
|
{
|
|
$this->footerHeadline = $content['headline'] ?? '';
|
|
$this->footerSubline = $content['subline'] ?? '';
|
|
$this->footerUrl = $content['url'] ?? '';
|
|
$this->footerIsActive = true;
|
|
}
|
|
|
|
private function loadMediaContent(array $content): void
|
|
{
|
|
$this->mediaType = $content['media_type'] ?? 'image';
|
|
$this->mediaCategory = $content['category'] ?? 'immobilien';
|
|
$this->mediaUrl = $content['media_url'] ?? '';
|
|
$this->mediaHeadline = $content['headline'] ?? '';
|
|
$this->mediaSubline = $content['subline'] ?? '';
|
|
$this->mediaDuration = $content['duration_seconds'] ?? 10;
|
|
$this->mediaIsActive = true;
|
|
}
|
|
|
|
private function loadSlideContent(array $content): void
|
|
{
|
|
$this->slideType = $content['type'] ?? 'product-hero';
|
|
$this->slideDuration = $content['duration'] ?? 8000;
|
|
$this->slideImageUrl = $content['image_url'] ?? '';
|
|
$this->slideBadge = $content['badge_text'] ?? '';
|
|
$this->slideEyebrow = $content['eyebrow'] ?? '';
|
|
$this->slideTitle = $content['title'] ?? '';
|
|
$this->slideSubline = $content['subline'] ?? '';
|
|
$this->slidePrice = $content['price'] ?? '';
|
|
$this->slideOriginalPrice = $content['original_price'] ?? '';
|
|
$this->slideTagText = $content['tag_text'] ?? '';
|
|
$this->slideBullets = $content['bullets'] ?? [];
|
|
$this->slideDisclaimer = $content['disclaimer'] ?? '';
|
|
$this->slideQrUrl = $content['qr_url'] ?? '';
|
|
$this->slideQrTitle = $content['qr_title'] ?? '';
|
|
$this->slideContact = $content['contact'] ?? '';
|
|
$this->slideShowBrandText = $content['show_brand_text'] ?? false;
|
|
$this->slideBrandTagline = $content['brand_tagline'] ?? '';
|
|
$this->slideIsActive = true;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function buildItemContent(): array
|
|
{
|
|
return match ($this->itemType) {
|
|
'video' => [
|
|
'filename' => $this->videoFilename,
|
|
'title' => $this->videoTitle,
|
|
'position' => $this->videoPosition,
|
|
],
|
|
'footer' => [
|
|
'headline' => $this->footerHeadline,
|
|
'subline' => $this->footerSubline,
|
|
'url' => $this->footerUrl ?: null,
|
|
],
|
|
'media' => [
|
|
'media_type' => $this->mediaType,
|
|
'category' => $this->mediaCategory,
|
|
'media_url' => $this->mediaUrl,
|
|
'headline' => $this->mediaHeadline,
|
|
'subline' => $this->mediaSubline,
|
|
'duration_seconds' => $this->mediaDuration,
|
|
],
|
|
'slide' => [
|
|
'type' => $this->slideType,
|
|
'duration' => $this->slideDuration,
|
|
'image_url' => $this->slideImageUrl,
|
|
'badge_text' => $this->slideBadge,
|
|
'eyebrow' => $this->slideEyebrow,
|
|
'title' => $this->slideTitle,
|
|
'subline' => $this->slideSubline,
|
|
'price' => $this->slidePrice,
|
|
'original_price' => $this->slideOriginalPrice,
|
|
'tag_text' => $this->slideTagText,
|
|
'bullets' => $this->slideBullets,
|
|
'disclaimer' => $this->slideDisclaimer,
|
|
'qr_url' => $this->slideQrUrl,
|
|
'qr_title' => $this->slideQrTitle,
|
|
'contact' => $this->slideContact,
|
|
'show_brand_text' => $this->slideShowBrandText,
|
|
'brand_tagline' => $this->slideBrandTagline,
|
|
],
|
|
default => [],
|
|
};
|
|
}
|
|
|
|
private function getActiveFlag(): bool
|
|
{
|
|
return match ($this->itemType) {
|
|
'video' => $this->videoIsActive,
|
|
'footer' => $this->footerIsActive,
|
|
'media' => $this->mediaIsActive,
|
|
'slide' => $this->slideIsActive,
|
|
default => true,
|
|
};
|
|
}
|
|
|
|
private function defaultItemType(): string
|
|
{
|
|
return match ($this->version->type) {
|
|
DisplayVersionType::VideoDisplay => 'video',
|
|
DisplayVersionType::B2in => 'media',
|
|
DisplayVersionType::Offers => 'slide',
|
|
};
|
|
}
|
|
|
|
private function resetItemForm(): void
|
|
{
|
|
$this->itemId = null;
|
|
$this->itemType = '';
|
|
$this->videoFilename = '';
|
|
$this->videoTitle = '';
|
|
$this->videoPosition = 25;
|
|
$this->videoIsActive = true;
|
|
$this->footerHeadline = '';
|
|
$this->footerSubline = '';
|
|
$this->footerUrl = '';
|
|
$this->footerIsActive = true;
|
|
$this->mediaType = 'image';
|
|
$this->mediaCategory = 'immobilien';
|
|
$this->mediaUrl = '';
|
|
$this->mediaHeadline = '';
|
|
$this->mediaSubline = '';
|
|
$this->mediaDuration = 10;
|
|
$this->mediaIsActive = true;
|
|
$this->slideType = 'product-hero';
|
|
$this->slideDuration = 8000;
|
|
$this->slideImageUrl = '';
|
|
$this->slideBadge = '';
|
|
$this->slideEyebrow = '';
|
|
$this->slideTitle = '';
|
|
$this->slideSubline = '';
|
|
$this->slidePrice = '';
|
|
$this->slideOriginalPrice = '';
|
|
$this->slideTagText = '';
|
|
$this->slideBullets = [];
|
|
$this->slideDisclaimer = '';
|
|
$this->slideQrUrl = '';
|
|
$this->slideQrTitle = '';
|
|
$this->slideContact = '';
|
|
$this->slideShowBrandText = false;
|
|
$this->slideBrandTagline = '';
|
|
$this->slideIsActive = true;
|
|
}
|
|
|
|
private function refreshModulePreview(): void
|
|
{
|
|
$this->previewFrameRefreshCounter++;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function settingsWithDefaults(): array
|
|
{
|
|
return DisplayModuleSettings::merge($this->version->type, $this->version->settings);
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
$items = $this->version->items()->get()->groupBy('item_type');
|
|
|
|
return view('livewire.admin.cms.display-version-editor', [
|
|
'items' => $items,
|
|
]);
|
|
}
|
|
}
|