Rebrand Hub+Flux
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run

This commit is contained in:
Kevin Adametz 2026-05-20 15:44:15 +02:00
parent 0a3e52d603
commit 9b47296cea
130 changed files with 9357 additions and 3345 deletions

View file

@ -1,18 +1,19 @@
<?php
use App\Enums\Portal;
use App\Enums\PressReleaseStatus;
use App\Models\PressRelease;
use App\Services\Customer\CustomerCompanyContext;
use App\Services\PressRelease\BlacklistViolationException;
use App\Services\PressRelease\PressReleaseService;
use App\Services\Customer\CustomerCompanyContext;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Volt\Component;
use Livewire\WithPagination;
new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class extends Component
{
new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class extends Component {
use WithPagination;
public string $search = '';
@ -22,6 +23,8 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
#[Url(as: 'company', except: 'all')]
public string $companyFilter = 'all';
public string $portalFilter = 'all';
public string $sortBy = 'created_at';
public string $sortDir = 'desc';
@ -37,16 +40,49 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
$this->resetPage();
}
public function updatedSearch(): void { $this->resetPage(); }
public function setView(string $view): void
{
$this->statusFilter = $view;
$this->resetPage();
}
public function updatedStatusFilter(): void { $this->resetPage(); }
public function resetFilters(): void
{
$this->search = '';
$this->statusFilter = 'all';
$this->portalFilter = 'all';
if ($this->companyFilter !== 'all') {
$this->companyFilter = 'all';
}
$this->resetPage();
}
public function updatedCompanyFilter(): void { $this->resetPage(); }
public function updatedSearch(): void
{
$this->resetPage();
}
public function updatedStatusFilter(): void
{
$this->resetPage();
}
public function updatedCompanyFilter(): void
{
$this->resetPage();
}
public function updatedPortalFilter(): void
{
$this->resetPage();
}
public function submitForReview(int $id): void
{
$pr = $this->findMyPR($id);
if (! $pr) { return; }
if (!$pr) {
return;
}
try {
app(PressReleaseService::class)->submitForReview($pr);
@ -64,25 +100,41 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
$context = app(CustomerCompanyContext::class);
$selectedCompanyId = $context->selectedCompanyId(auth()->user());
$prs = PressRelease::withoutGlobalScopes()
$base = PressRelease::withoutGlobalScopes()
->where('user_id', $userId)
->when($selectedCompanyId !== null, fn($q) => $q->where('company_id', $selectedCompanyId))
->when($selectedCompanyId === null && $this->companyFilter === 'assigned', fn($q) => $q->whereNotNull('company_id'))
->when($selectedCompanyId === null && $this->companyFilter === 'unassigned', fn($q) => $q->whereNull('company_id'));
$statusCountsRaw = (clone $base)->toBase()->selectRaw('status, COUNT(*) as aggregate')->groupBy('status')->pluck('aggregate', 'status');
$statusCounts = [
'all' => (int) $statusCountsRaw->sum(),
PressReleaseStatus::Published->value => (int) ($statusCountsRaw[PressReleaseStatus::Published->value] ?? 0),
PressReleaseStatus::Draft->value => (int) ($statusCountsRaw[PressReleaseStatus::Draft->value] ?? 0),
PressReleaseStatus::Review->value => (int) ($statusCountsRaw[PressReleaseStatus::Review->value] ?? 0),
PressReleaseStatus::Rejected->value => (int) ($statusCountsRaw[PressReleaseStatus::Rejected->value] ?? 0),
PressReleaseStatus::Archived->value => (int) ($statusCountsRaw[PressReleaseStatus::Archived->value] ?? 0),
];
$prs = (clone $base)
->with('company:id,name')
->when($selectedCompanyId !== null, fn ($q) => $q->where('company_id', $selectedCompanyId))
->when($selectedCompanyId === null && $this->companyFilter === 'assigned', fn ($q) => $q->whereNotNull('company_id'))
->when($selectedCompanyId === null && $this->companyFilter === 'unassigned', fn ($q) => $q->whereNull('company_id'))
->when(filled($this->search), function ($q): void {
$term = $this->search;
$q->where('title', 'like', '%'.$term.'%');
$q->where('title', 'like', '%' . $term . '%');
})
->when($this->statusFilter !== 'all', fn ($q) => $q->where('status', $this->statusFilter))
->when($this->statusFilter !== 'all', fn($q) => $q->where('status', $this->statusFilter))
->when($this->portalFilter !== 'all', fn($q) => $q->where('portal', $this->portalFilter))
->orderBy(in_array($this->sortBy, ['title', 'status', 'created_at']) ? $this->sortBy : 'created_at', $this->sortDir)
->paginate(100);
->paginate(25);
return [
'pressReleases' => $prs,
'statusOptions' => PressReleaseStatus::cases(),
'portalOptions' => Portal::cases(),
'selectedCompany' => $context->selectedCompany(auth()->user()),
'hasGlobalCompanyContext' => $selectedCompanyId === null,
'statusCounts' => $statusCounts,
];
}
@ -95,16 +147,27 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
}
}; ?>
@php
$hasAnyFilter =
$search !== '' ||
$statusFilter !== 'all' ||
$portalFilter !== 'all' ||
($hasGlobalCompanyContext && $companyFilter !== 'all');
$hasAnyPR = $statusCounts['all'] > 0;
@endphp
<div class="space-y-8">
@if(session('success'))
<div class="px-4 py-3 rounded-[5px] border text-[12.5px]
bg-[color:var(--color-ok-soft)] border-[color:var(--color-ok)]/30 text-[color:var(--color-gain-deep)]">
{{-- ============== FLASH ============== --}}
@if (session('success'))
<div class="px-4 py-3 rounded-[5px] border-l-[3px] text-[12.5px]"
style="border-color: var(--color-ok); background: color-mix(in oklab, var(--color-ok) 10%, var(--color-bg)); color: var(--color-ink);">
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="px-4 py-3 rounded-[5px] border text-[12.5px]
bg-[color:var(--color-err-soft)] border-[color:var(--color-err)]/30 text-[color:var(--color-loss)]">
@if (session('error'))
<div class="px-4 py-3 rounded-[5px] border-l-[3px] text-[12.5px]"
style="border-color: var(--color-err); background: color-mix(in oklab, var(--color-err) 12%, var(--color-bg)); color: var(--color-ink);">
{{ session('error') }}
</div>
@endif
@ -119,118 +182,491 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
<h1 class="text-[34px] font-bold tracking-[-0.7px] leading-[1.1] m-0 text-[color:var(--color-ink)]">
{{ __('Meine Pressemitteilungen') }}
</h1>
<p class="text-[13.5px] leading-[1.55] mt-2 m-0 max-w-[640px] text-[color:var(--color-ink-2)]">
@if ($selectedCompany)
{{-- Counter-Strip + Kontext-Hinweis --}}
@if ($hasAnyPR)
<div class="counter-strip mt-3">
<span class="seg"><b>{{ $statusCounts['all'] }}</b> {{ __('Mitteilungen') }}</span>
@if ($statusCounts[\App\Enums\PressReleaseStatus::Published->value] > 0)
<span class="sep"></span>
<span
class="seg is-ok"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Published->value] }}</b>
{{ __('veröffentlicht') }}</span>
@endif
@if ($statusCounts[\App\Enums\PressReleaseStatus::Review->value] > 0)
<span class="sep"></span>
<span
class="seg is-warn"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Review->value] }}</b>
{{ __('in Prüfung') }}</span>
@endif
@if ($statusCounts[\App\Enums\PressReleaseStatus::Draft->value] > 0)
<span class="sep"></span>
<span
class="seg is-muted"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Draft->value] }}</b>
{{ __('Entwürfe') }}</span>
@endif
@if ($statusCounts[\App\Enums\PressReleaseStatus::Rejected->value] > 0)
<span class="sep"></span>
<span
class="seg is-err"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Rejected->value] }}</b>
{{ __('abgelehnt') }}</span>
@endif
</div>
@endif
@if ($selectedCompany)
<p class="text-[12.5px] leading-[1.55] mt-2 m-0 text-[color:var(--color-ink-3)]">
{{ __('Gefiltert auf :company', ['company' => $selectedCompany->name]) }}
@else
</p>
@elseif (!$hasAnyPR)
<p class="text-[13.5px] leading-[1.55] mt-2 m-0 max-w-[640px] text-[color:var(--color-ink-2)]">
{{ __('Übersicht aller PMs Ihres Kundenkontos, mit Filter und Schnellaktionen.') }}
@endif
</p>
</p>
@endif
</div>
<div class="flex items-center gap-3 flex-shrink-0">
<div class="flex items-center gap-2 flex-shrink-0">
<flux:button variant="primary" icon="plus" href="{{ route('me.press-releases.create') }}" wire:navigate>
{{ __('Neue Pressemitteilung') }}
</flux:button>
</div>
</header>
{{-- ============== FILTER-PANEL ============== --}}
<article class="panel">
<div class="panel-head">
<span class="section-eyebrow">{{ __('Filter & Suche') }}</span>
</div>
<div class="p-5 flex flex-col gap-3 sm:flex-row">
<flux:input wire:model.live.debounce.300ms="search" placeholder="{{ __('Titel suchen…') }}" icon="magnifying-glass" class="flex-1" />
<flux:select wire:model.live="statusFilter" class="sm:w-44">
<option value="all">{{ __('Alle Status') }}</option>
@foreach($statusOptions as $s)
<option value="{{ $s->value }}">{{ $s->label() }}</option>
@endforeach
</flux:select>
@if($hasGlobalCompanyContext)
<flux:select wire:model.live="companyFilter" class="sm:w-48">
<option value="all">{{ __('Alle Firmenzuordnungen') }}</option>
<option value="assigned">{{ __('Mit Firma') }}</option>
<option value="unassigned">{{ __('Ohne Firma') }}</option>
{{-- ============== SAVED-VIEWS-TABS ============== --}}
@if ($hasAnyPR)
<nav class="view-tabs" aria-label="{{ __('Gespeicherte Ansichten') }}">
<button type="button" wire:click="setView('all')" @class(['view-tab', 'is-active' => $statusFilter === 'all'])>
{{ __('Alle') }} <span class="cnt">{{ $statusCounts['all'] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Published->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Published->value,
])>
{{ __('Veröffentlicht') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Published->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Draft->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Draft->value,
])>
{{ __('Entwürfe') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Draft->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Review->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Review->value,
])>
{{ __('In Prüfung') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Review->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Rejected->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Rejected->value,
])>
{{ __('Abgelehnt') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Rejected->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Archived->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Archived->value,
])>
{{ __('Archiv') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Archived->value] }}</span>
</button>
</nav>
@endif
{{-- ============== FILTER + SUCHE ============== --}}
@if ($hasAnyPR)
<section class="space-y-3">
<div class="flex items-center gap-2 flex-wrap">
<flux:input wire:model.live.debounce.300ms="search" placeholder="{{ __('Titel suchen…') }}"
icon="magnifying-glass" class="max-w-[340px]" />
<span class="w-px h-6 bg-[color:var(--color-bg-rule)] mx-1"></span>
<flux:select wire:model.live="portalFilter" class="sm:w-44">
<option value="all">{{ __('Portal: Alle') }}</option>
@foreach ($portalOptions as $p)
<option value="{{ $p->value }}">{{ __('Portal:') }} {{ $p->label() }}</option>
@endforeach
</flux:select>
@if ($hasGlobalCompanyContext)
<flux:select wire:model.live="companyFilter" class="sm:w-56">
<option value="all">{{ __('Firma: Alle') }}</option>
<option value="assigned">{{ __('Firma: Mit Firma') }}</option>
<option value="unassigned">{{ __('Firma: Ohne Firma') }}</option>
</flux:select>
@endif
</div>
{{-- Active-Chips --}}
@if ($hasAnyFilter)
<div class="flex items-center gap-2 flex-wrap text-[11.5px]">
<span class="eyebrow muted" style="margin-right:2px;">{{ __('Aktiv') }}</span>
@if ($statusFilter !== 'all')
@php $statusEnum = \App\Enums\PressReleaseStatus::tryFrom($statusFilter); @endphp
<span class="active-chip">
<span>{{ __('Status') }}:
<strong>{{ $statusEnum?->label() ?? $statusFilter }}</strong></span>
<button type="button" class="x" wire:click="setView('all')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
@if ($portalFilter !== 'all')
@php $portalEnum = \App\Enums\Portal::tryFrom($portalFilter); @endphp
<span class="active-chip">
<span>{{ __('Portal') }}:
<strong>{{ $portalEnum?->label() ?? $portalFilter }}</strong></span>
<button type="button" class="x" wire:click="$set('portalFilter', 'all')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
@if ($hasGlobalCompanyContext && $companyFilter !== 'all')
<span class="active-chip">
<span>{{ __('Firma') }}:
<strong>{{ $companyFilter === 'assigned' ? __('Mit Firma') : __('Ohne Firma') }}</strong></span>
<button type="button" class="x" wire:click="$set('companyFilter', 'all')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
@if ($search !== '')
<span class="active-chip">
<span>{{ __('Suche') }}:
<strong>{{ \Illuminate\Support\Str::limit($search, 40) }}"</strong></span>
<button type="button" class="x" wire:click="$set('search', '')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
<button type="button" wire:click="resetFilters"
class="text-[11.5px] font-semibold text-[color:var(--color-ink-3)] hover:text-[color:var(--color-hub)] underline-offset-[3px] hover:underline">
{{ __('Alle zurücksetzen') }}
</button>
</div>
@endif
</div>
</article>
</section>
@endif
{{-- ============== TABELLE-PANEL ============== --}}
{{-- ============== TABELLE / EMPTY ============== --}}
<article class="panel overflow-hidden">
<div class="panel-head">
<span class="section-eyebrow">{{ __('Alle Pressemitteilungen') }}</span>
<span class="text-[11.5px] text-[color:var(--color-ink-3)]">
{{ __(':count Einträge', ['count' => $pressReleases->count()]) }}
</span>
</div>
<div class="p-4">
<flux:table>
<flux:table.columns>
<flux:table.column sortable :sorted="$sortBy==='title'" :direction="$sortDir" wire:click="sort('title')">{{ __('Titel') }}</flux:table.column>
<flux:table.column>{{ __('Firma') }}</flux:table.column>
<flux:table.column sortable :sorted="$sortBy==='status'" :direction="$sortDir" wire:click="sort('status')">{{ __('Status') }}</flux:table.column>
<flux:table.column sortable :sorted="$sortBy==='created_at'" :direction="$sortDir" wire:click="sort('created_at')">{{ __('Erstellt') }}</flux:table.column>
<flux:table.column>{{ __('Aktionen') }}</flux:table.column>
</flux:table.columns>
@forelse($pressReleases as $pr)
<flux:table.row wire:key="{{ $pr->id }}">
<flux:table.cell>
<p class="max-w-xs truncate font-medium">{{ $pr->title }}</p>
</flux:table.cell>
<flux:table.cell>
<flux:text class="text-sm">{{ $pr->company?->name ?? '' }}</flux:text>
</flux:table.cell>
<flux:table.cell>
<span @class([
'badge',
'ok' => $pr->status->value === 'published',
'warn' => $pr->status->value === 'review',
'err' => $pr->status->value === 'rejected',
'hub' => in_array($pr->status->value, ['archived', 'draft'], true),
])>{{ $pr->status->label() }}</span>
</flux:table.cell>
<flux:table.cell>
<flux:text class="text-sm text-zinc-500">{{ $pr->created_at->format('d.m.Y') }}</flux:text>
</flux:table.cell>
<flux:table.cell>
<div class="flex items-center gap-1">
<flux:button size="sm" variant="ghost" icon="eye" href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate />
@if(in_array($pr->status->value, ['draft', 'rejected']))
<flux:button size="sm" variant="ghost" icon="pencil" href="{{ route('me.press-releases.edit', $pr->id) }}" wire:navigate />
<flux:button size="sm" variant="ghost" icon="paper-airplane" wire:click="submitForReview({{ $pr->id }})"
wire:confirm="{{ __('Pressemitteilung zur Prüfung einreichen?') }}" />
@endif
</div>
</flux:table.cell>
</flux:table.row>
@empty
<flux:table.row>
<flux:table.cell colspan="5">
<div class="flex flex-col items-center justify-center px-4 py-12 text-center">
<div class="w-14 h-14 rounded-[6px] flex items-center justify-center mb-4
bg-[color:var(--color-hub-soft)] border border-[color:var(--color-hub-soft-2)] text-[color:var(--color-hub)]">
<flux:icon.newspaper class="size-6" />
</div>
<div class="text-[14px] font-semibold text-[color:var(--color-ink)] mb-1">
{{ __('Keine Pressemitteilungen gefunden') }}
</div>
<p class="text-[12px] text-[color:var(--color-ink-3)] max-w-md m-0 mb-4">
{{ __('Passen Sie die Filter an oder erstellen Sie eine neue Pressemitteilung.') }}
</p>
<flux:button size="sm" variant="primary" icon="plus" href="{{ route('me.press-releases.create') }}" wire:navigate>
{{ __('Neue Pressemitteilung') }}
</flux:button>
</div>
</flux:table.cell>
</flux:table.row>
@endforelse
</flux:table>
</div>
@if ($pressReleases->isNotEmpty())
<div class="panel-head">
<span class="section-eyebrow">
@if ($statusFilter !== 'all')
@php $sEnum = \App\Enums\PressReleaseStatus::tryFrom($statusFilter); @endphp
{{ $sEnum?->label() ?? __('Pressemitteilungen') }}
@else
{{ __('Alle Pressemitteilungen') }}
@endif
</span>
<span class="text-[11.5px] text-[color:var(--color-ink-3)]">
{{ __(':count Einträge', ['count' => $pressReleases->total()]) }}
</span>
</div>
<flux:table>
<flux:table.columns>
<flux:table.column class="w-[140px]">{{ __('Status') }}</flux:table.column>
<flux:table.column sortable :sorted="$sortBy === 'title'" :direction="$sortDir"
wire:click="sort('title')">
{{ __('Titel') }}
</flux:table.column>
<flux:table.column class="w-[180px]">{{ __('Portal') }}</flux:table.column>
<flux:table.column class="w-[180px]">{{ __('Firma') }}</flux:table.column>
<flux:table.column class="w-[140px]" sortable :sorted="$sortBy === 'created_at'"
:direction="$sortDir" wire:click="sort('created_at')">
{{ __('Datum') }}
</flux:table.column>
<flux:table.column class="w-[80px]">{{ __('Aktionen') }}</flux:table.column>
</flux:table.columns>
@foreach ($pressReleases as $pr)
@php
$status = $pr->status->value;
$rowClass = match ($status) {
'review' => 'is-row-warn',
'rejected' => 'is-row-err',
default => '',
};
$badgeClass = match ($status) {
'published' => 'ok',
'review' => 'warn',
'rejected' => 'err',
'archived', 'draft' => 'muted',
default => 'hub',
};
$portal = $pr->portal?->value ?? 'both';
$showPe = in_array($portal, ['presseecho', 'both'], true);
$showBp = in_array($portal, ['businessportal24', 'both'], true);
$dateSubLabel = match ($status) {
'published' => __('veröffentlicht'),
'review' => __('eingereicht'),
'rejected' => __('abgelehnt'),
'draft' => __('erstellt'),
'archived' => __('archiviert'),
default => __('erstellt'),
};
$primaryDate = match (true) {
$status === 'published' && $pr->published_at => $pr->published_at,
default => $pr->created_at,
};
@endphp
<flux:table.row wire:key="{{ $pr->id }}" class="{{ $rowClass }}">
<flux:table.cell>
<div class="flex items-center gap-1 flex-wrap">
<span class="badge {{ $badgeClass }} dot">{{ $pr->status->label() }}</span>
@if ($status === 'draft')
<button type="button" class="inline-action"
wire:click="submitForReview({{ $pr->id }})"
wire:confirm="{{ __('Pressemitteilung zur Prüfung einreichen?') }}"
title="{{ __('Zur redaktionellen Prüfung senden') }}">
{{ __('Zur Prüfung →') }}
</button>
@endif
</div>
</flux:table.cell>
<flux:table.cell>
<a href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate
class="block font-semibold text-[13.5px] leading-[1.35] text-[color:var(--color-ink)] hover:text-[color:var(--color-hub)] hover:underline underline-offset-[3px] decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
{{ $pr->title }}
</a>
<div class="text-[11.5px] text-[color:var(--color-ink-3)] mt-0.5 leading-[1.4]">
PM-{{ $pr->id }}
</div>
</flux:table.cell>
<flux:table.cell>
<div class="flex flex-wrap gap-1">
@if ($showPe)
<span class="portal-pill pe"><span class="pdot"></span>presseecho</span>
@endif
@if ($showBp)
<span class="portal-pill bp"><span
class="pdot"></span>businessportal24</span>
@endif
</div>
</flux:table.cell>
<flux:table.cell>
@if ($pr->company)
<span class="text-[12.5px] text-[color:var(--color-ink-2)] font-medium">
{{ $pr->company->name }}
</span>
@else
<span
class="text-[11.5px] text-[color:var(--color-ink-4)] italic">{{ __('— keine —') }}</span>
@endif
</flux:table.cell>
<flux:table.cell>
<div class="font-mono text-[12px] text-[color:var(--color-ink-2)] tabular-nums">
{{ $primaryDate?->format('d.m.Y') }}
</div>
<div class="text-[10.5px] text-[color:var(--color-ink-4)] mt-0.5">
{{ $dateSubLabel }} · {{ $primaryDate?->format('H:i') }}
</div>
</flux:table.cell>
<flux:table.cell>
<div class="flex items-center gap-1">
<flux:button size="sm" variant="ghost" icon="eye"
href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate />
@if (in_array($status, ['draft', 'rejected']))
<flux:button size="sm" variant="ghost" icon="pencil"
href="{{ route('me.press-releases.edit', $pr->id) }}" wire:navigate />
@endif
</div>
</flux:table.cell>
</flux:table.row>
@endforeach
</flux:table>
<div class="border-t border-[color:var(--color-bg-rule)] p-4">
{{ $pressReleases->links() }}
</div>
@elseif ($hasAnyPR && $search !== '')
{{-- Empty: Suche ohne Treffer --}}
<div class="empty-stage">
<div class="empty-ico">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none">
<circle cx="10.5" cy="10.5" r="6" stroke="currentColor" stroke-width="1.6" />
<path d="M15.5 15.5L20 20" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" />
</svg>
</div>
<h3 class="empty-title">{{ __('Keine Treffer für „:term"', ['term' => $search]) }}</h3>
<p class="empty-sub">
{{ __('Wir konnten zu Ihrer Suche nichts finden. Prüfen Sie die Schreibweise oder schränken Sie den Suchbegriff ein.') }}
</p>
<div class="flex items-center gap-2.5 mt-6">
<flux:button variant="primary" wire:click="$set('search', '')">
{{ __('Suche zurücksetzen') }}
</flux:button>
</div>
</div>
@elseif ($hasAnyPR && $hasAnyFilter)
{{-- Empty: Filter ohne Treffer --}}
<div class="empty-stage">
<div class="empty-ico warm">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none">
<path d="M4 6h16M7 12h10M10 18h4" stroke="currentColor" stroke-width="1.8"
stroke-linecap="round" />
</svg>
</div>
<h3 class="empty-title">{{ __('Keine Mitteilungen mit diesen Filtern') }}</h3>
<p class="empty-sub">
{{ __('Aktive Filter passen auf keine Einträge. Setzen Sie einen Filter zurück oder probieren Sie eine breitere Auswahl.') }}
</p>
<div class="flex items-center gap-2.5 mt-6">
<flux:button variant="primary" wire:click="resetFilters">{{ __('Alle Filter zurücksetzen') }}
</flux:button>
</div>
</div>
@else
{{-- Empty: gar keine PMs überhaupt --}}
<div class="empty-stage">
<div class="empty-ico">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none">
<rect x="3" y="4" width="14" height="16" stroke="currentColor" stroke-width="1.5" />
<path d="M17 7h4v13H6" stroke="currentColor" stroke-width="1.5" />
<path d="M6 8h8M6 11h8M6 14h5" stroke="currentColor" stroke-width="1.3"
stroke-linecap="round" />
</svg>
</div>
<h3 class="empty-title">{{ __('Noch keine Pressemitteilungen') }}</h3>
<p class="empty-sub">
{{ __('Starten Sie mit Ihrer ersten Mitteilung. Nach redaktioneller Prüfung erscheint sie i. d. R. binnen 4 Stunden werktags auf beiden Portalen.') }}
</p>
<div class="flex items-center gap-2.5 mt-6">
<flux:button variant="primary" icon="plus" href="{{ route('me.press-releases.create') }}"
wire:navigate>
{{ __('Erste Pressemitteilung erstellen') }}
</flux:button>
</div>
<div class="mt-9 grid gap-3 w-full max-w-[560px]" style="grid-template-columns:repeat(3,1fr);">
<div
class="text-left px-3 py-2.5 bg-[color:var(--color-bg-elev)] border border-[color:var(--color-bg-rule)] rounded-[3px]">
<div
class="font-mono text-[9.5px] tracking-[0.16em] text-[color:var(--color-accent-deep)] font-bold mb-1">
01</div>
<div class="text-[11.5px] font-semibold text-[color:var(--color-ink)] leading-tight">
{{ __('Firma zuordnen') }}</div>
</div>
<div
class="text-left px-3 py-2.5 bg-[color:var(--color-bg-elev)] border border-[color:var(--color-bg-rule)] rounded-[3px]">
<div
class="font-mono text-[9.5px] tracking-[0.16em] text-[color:var(--color-accent-deep)] font-bold mb-1">
02</div>
<div class="text-[11.5px] font-semibold text-[color:var(--color-ink)] leading-tight">
{{ __('Mitteilung verfassen') }}</div>
</div>
<div
class="text-left px-3 py-2.5 bg-[color:var(--color-bg-elev)] border border-[color:var(--color-bg-rule)] rounded-[3px]">
<div
class="font-mono text-[9.5px] tracking-[0.16em] text-[color:var(--color-accent-deep)] font-bold mb-1">
03</div>
<div class="text-[11.5px] font-semibold text-[color:var(--color-ink)] leading-tight">
{{ __('Zur Prüfung senden') }}</div>
</div>
</div>
</div>
@endif
</article>
{{ $pressReleases->links() }}
{{-- ============== STATUS-AKTIONEN-LEGENDE ============== --}}
@if ($hasAnyPR)
<article class="panel-warm p-5">
<div class="grid items-start gap-6" style="grid-template-columns:auto 1fr;">
<div class="min-w-[180px]">
<div class="section-eyebrow">{{ __('Aktionen je Status') }}</div>
<p class="text-[12px] text-[color:var(--color-ink-3)] leading-[1.55] mt-3 m-0 max-w-[200px]">
{{ __('Welche Aktionen pro Status verfügbar sind.') }}
</p>
</div>
<div class="grid gap-4" style="grid-template-columns:repeat(5,minmax(0,1fr));">
<div>
<span class="badge muted dot" style="margin-bottom:8px;">{{ __('Entwurf') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Bearbeiten') }}</li>
<li>{{ __('Vorschau') }}</li>
<li class="text-[color:var(--color-accent-deep)] font-semibold">
{{ __('→ Zur Prüfung senden') }}</li>
</ul>
</div>
<div>
<span class="badge warn dot" style="margin-bottom:8px;">{{ __('In Prüfung') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Vorschau') }}</li>
<li class="text-[color:var(--color-ink-3)] italic">{{ __('Warten auf Redaktion') }}</li>
</ul>
</div>
<div>
<span class="badge ok dot" style="margin-bottom:8px;">{{ __('Veröffentlicht') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Vorschau') }}</li>
<li class="text-[color:var(--color-ink-3)] italic">{{ __('Statistik (bald)') }}</li>
</ul>
</div>
<div>
<span class="badge err dot" style="margin-bottom:8px;">{{ __('Abgelehnt') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Bearbeiten') }}</li>
<li class="text-[color:var(--color-accent-deep)] font-semibold">
{{ __('→ Erneut einreichen') }}</li>
</ul>
</div>
<div>
<span class="badge muted dot" style="margin-bottom:8px;">{{ __('Archiviert') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Vorschau') }}</li>
</ul>
</div>
</div>
</div>
</article>
@endif
</div>