246 lines
9.1 KiB
PHP
246 lines
9.1 KiB
PHP
<?php
|
||
|
||
use App\Enums\Portal;
|
||
use App\Models\Category;
|
||
use App\Models\FooterCode;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Livewire\Attributes\Layout;
|
||
use Livewire\Attributes\Title;
|
||
use Livewire\Attributes\Validate;
|
||
use Livewire\Volt\Component;
|
||
|
||
new #[Layout('components.layouts.app'), Title('Footer-Code bearbeiten')] class extends Component
|
||
{
|
||
public int $id = 0;
|
||
|
||
#[Validate('required|string|min:2|max:255')]
|
||
public string $title = '';
|
||
|
||
#[Validate('required|string|min:5')]
|
||
public string $content = '';
|
||
|
||
#[Validate('required|in:'.Portal::Both->value.','.Portal::Presseecho->value.','.Portal::Businessportal24->value)]
|
||
public string $portal = Portal::Both->value;
|
||
|
||
#[Validate('nullable|in:de,en')]
|
||
public ?string $language = null;
|
||
|
||
public bool $isGlobal = false;
|
||
|
||
public bool $isActive = true;
|
||
|
||
#[Validate('integer|min:0|max:1000')]
|
||
public int $priority = 0;
|
||
|
||
/** @var array<int, int> */
|
||
public array $categoryIds = [];
|
||
|
||
public function mount(int $id): void
|
||
{
|
||
$code = FooterCode::query()
|
||
->with('categories:id')
|
||
->findOrFail($id);
|
||
|
||
$this->id = $code->id;
|
||
$this->title = $code->title;
|
||
$this->content = $code->content;
|
||
$this->portal = $code->portal->value;
|
||
$this->language = $code->language;
|
||
$this->isGlobal = $code->is_global;
|
||
$this->isActive = $code->is_active;
|
||
$this->priority = $code->priority;
|
||
$this->categoryIds = $code->categories->pluck('id')->all();
|
||
}
|
||
|
||
public function save(): void
|
||
{
|
||
$this->validate();
|
||
|
||
$code = FooterCode::query()->findOrFail($this->id);
|
||
|
||
DB::transaction(function () use ($code): void {
|
||
$code->update([
|
||
'title' => $this->title,
|
||
'content' => $this->content,
|
||
'portal' => $this->portal,
|
||
'language' => $this->language,
|
||
'is_global' => $this->isGlobal,
|
||
'is_active' => $this->isActive,
|
||
'priority' => $this->priority,
|
||
]);
|
||
|
||
$code->categories()->sync(
|
||
$this->isGlobal ? [] : $this->categoryIds,
|
||
);
|
||
});
|
||
|
||
session()->flash('success', __('Footer-Code wurde aktualisiert.'));
|
||
|
||
$this->redirect(route('admin.footer-codes.index'), navigate: true);
|
||
}
|
||
|
||
public function delete(): void
|
||
{
|
||
$code = FooterCode::query()->findOrFail($this->id);
|
||
$code->delete();
|
||
|
||
session()->flash('success', __('Footer-Code wurde gelöscht.'));
|
||
|
||
$this->redirect(route('admin.footer-codes.index'), navigate: true);
|
||
}
|
||
|
||
public function with(): array
|
||
{
|
||
return [
|
||
'portalOptions' => Portal::cases(),
|
||
'categoryOptions' => Category::query()
|
||
->with(['translations' => fn ($q) => $q->where('locale', 'de')])
|
||
->orderBy('id')
|
||
->get()
|
||
->map(fn (Category $cat) => [
|
||
'id' => $cat->id,
|
||
'name' => $cat->translations->first()?->name ?? '#'.$cat->id,
|
||
'portal' => $cat->portal->value,
|
||
]),
|
||
];
|
||
}
|
||
}; ?>
|
||
|
||
<div class="space-y-8">
|
||
{{-- ============== PAGE HEADER ============== --}}
|
||
<header class="grid items-end gap-8" style="grid-template-columns:1fr auto;">
|
||
<div class="min-w-0">
|
||
<div class="flex items-center gap-3 mb-3 flex-wrap">
|
||
<span class="badge hub dot">{{ __('Admin Backend') }}</span>
|
||
<span class="eyebrow muted">{{ __('Administration · Footer-Codes') }}</span>
|
||
<span class="badge hub">ID #{{ $id }}</span>
|
||
@if ($isGlobal)
|
||
<span class="badge hub dot">{{ __('Global') }}</span>
|
||
@endif
|
||
@if ($isActive)
|
||
<span class="badge ok dot">{{ __('Aktiv') }}</span>
|
||
@else
|
||
<span class="badge dot">{{ __('Inaktiv') }}</span>
|
||
@endif
|
||
</div>
|
||
<h1 class="text-[30px] font-bold tracking-[-0.6px] leading-[1.15] m-0 text-[color:var(--color-ink)] break-words">
|
||
{{ __('Footer-Code bearbeiten') }}
|
||
</h1>
|
||
<p class="text-[13px] leading-[1.55] mt-2 m-0 max-w-[640px] text-[color:var(--color-ink-2)]">{{ $title }}</p>
|
||
</div>
|
||
|
||
<div class="flex items-center gap-2 flex-shrink-0">
|
||
<flux:button variant="ghost" icon="arrow-left" :href="route('admin.footer-codes.index')" wire:navigate>
|
||
{{ __('Zurück') }}
|
||
</flux:button>
|
||
</div>
|
||
</header>
|
||
|
||
<form wire:submit="save" class="space-y-6">
|
||
<article class="panel">
|
||
<div class="panel-head">
|
||
<span class="section-eyebrow">{{ __('Stammdaten') }}</span>
|
||
</div>
|
||
<div class="p-5 space-y-4">
|
||
<flux:input wire:model="title" :label="__('Titel')" />
|
||
|
||
<flux:textarea
|
||
wire:model="content"
|
||
:label="__('HTML-/Text-Inhalt')"
|
||
rows="10"
|
||
/>
|
||
|
||
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||
<flux:select wire:model="portal" :label="__('Portal')">
|
||
@foreach ($portalOptions as $option)
|
||
<option value="{{ $option->value }}">{{ $option->label() }}</option>
|
||
@endforeach
|
||
</flux:select>
|
||
|
||
<flux:select wire:model="language" :label="__('Sprache')">
|
||
<option value="">{{ __('Alle') }}</option>
|
||
<option value="de">{{ __('Deutsch') }}</option>
|
||
<option value="en">{{ __('Englisch') }}</option>
|
||
</flux:select>
|
||
|
||
<flux:input
|
||
wire:model="priority"
|
||
type="number"
|
||
min="0"
|
||
max="1000"
|
||
:label="__('Priorität')"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="panel">
|
||
<div class="panel-head">
|
||
<span class="section-eyebrow">{{ __('Sichtbarkeit') }}</span>
|
||
</div>
|
||
<div class="p-5 space-y-4">
|
||
<flux:switch
|
||
wire:model.live="isGlobal"
|
||
:label="__('Global ausspielen')"
|
||
:description="__('Wird unter allen Pressemitteilungen angezeigt – Kategorie-Zuordnung wird ignoriert.')"
|
||
/>
|
||
|
||
<flux:switch
|
||
wire:model="isActive"
|
||
:label="__('Aktiv')"
|
||
/>
|
||
</div>
|
||
</article>
|
||
|
||
@if (! $isGlobal)
|
||
<article class="panel">
|
||
<div class="panel-head">
|
||
<span class="section-eyebrow">{{ __('Kategorie-Zuordnung') }}</span>
|
||
</div>
|
||
<div class="p-5 grid grid-cols-1 gap-2 md:grid-cols-2 lg:grid-cols-3">
|
||
@forelse ($categoryOptions as $option)
|
||
<label class="flex items-center gap-2 rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] px-3 py-2 hover:border-[color:var(--color-hub)]/30 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
wire:model="categoryIds"
|
||
value="{{ $option['id'] }}"
|
||
class="rounded border-[color:var(--color-bg-rule)]"
|
||
/>
|
||
<span class="text-[12.5px] text-[color:var(--color-ink)]">{{ $option['name'] }}</span>
|
||
</label>
|
||
@empty
|
||
<p class="text-[12.5px] text-[color:var(--color-ink-3)] m-0">
|
||
{{ __('Keine Kategorien vorhanden.') }}
|
||
</p>
|
||
@endforelse
|
||
</div>
|
||
</article>
|
||
@endif
|
||
|
||
<article class="panel" style="border-left:3px solid var(--color-err);">
|
||
<div class="panel-head">
|
||
<span class="section-eyebrow" style="color:var(--color-err);">{{ __('Danger Zone & Aktionen') }}</span>
|
||
</div>
|
||
<div class="p-5 flex items-center justify-between gap-2 flex-wrap">
|
||
<flux:button
|
||
type="button"
|
||
variant="danger"
|
||
icon="trash"
|
||
wire:click="delete"
|
||
wire:confirm="{{ __('Footer-Code wirklich löschen?') }}"
|
||
>
|
||
{{ __('Löschen') }}
|
||
</flux:button>
|
||
|
||
<div class="flex items-center gap-2">
|
||
<flux:button variant="ghost" :href="route('admin.footer-codes.index')" wire:navigate>
|
||
{{ __('Abbrechen') }}
|
||
</flux:button>
|
||
<flux:button type="submit" variant="primary" icon="check">
|
||
{{ __('Speichern') }}
|
||
</flux:button>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</form>
|
||
</div>
|