id = $id; $pr = $this->getMyPR(); $this->authorize('view', $pr); } public function submitForReview(): void { $pr = $this->getMyPR(); $this->authorize('submitForReview', $pr); try { app(PressReleaseService::class)->submitForReview($pr); } catch (BlacklistViolationException $e) { Flux::modal('confirm-submit-review')->close(); Flux::toast( heading: __('Automatisch abgelehnt'), text: __('Unzulässiges Wort gefunden: ":word". Bitte überarbeiten.', ['word' => $e->word]), variant: 'danger', duration: 8000, ); return; } catch (BookingRequiredException|QuotaExceededException $e) { Flux::modal('confirm-submit-review')->close(); Flux::toast( heading: __('Nicht eingereicht'), text: $e->getMessage(), variant: 'warning', duration: 8000, ); return; } Flux::modal('confirm-submit-review')->close(); Flux::toast( heading: __('Eingereicht'), text: __('Die Redaktion prüft die Pressemitteilung typischerweise innerhalb von 24 h.'), variant: 'success', ); } public function generateShareLink(MagicLinkGenerator $generator): void { $pr = $this->getMyPR(); $this->authorize('view', $pr); $share = $generator->createPressReleaseShareLink($pr, auth()->user()); $this->shareUrl = $share['url']; $this->shareExpiresAt = $share['expires_at']->format('d.m.Y H:i'); Flux::toast(text: __('Vorschau-Link wurde erzeugt.'), variant: 'success'); } public function with(): array { $pr = $this->getMyPR(); $this->authorize('view', $pr); $categoryName = $pr->category?->translations->firstWhere('locale', 'de')?->name ?? '–'; $latestRejection = null; if ($pr->status->value === 'rejected') { $latestRejection = $pr->statusLogs ->firstWhere(fn ($log) => $log->to_status?->value === 'rejected'); } $cover = app(PressReleaseCoverImage::class); $user = auth()->user(); return [ 'pr' => $pr, 'categoryName' => $categoryName, 'coverUrl' => $cover->coverUrl($pr, 'cover'), 'coverIsPlaceholder' => $cover->coverIsPlaceholder($pr), 'titleImage' => $pr->images()->orderByDesc('is_preview')->orderBy('sort_order')->orderBy('id')->first(), 'quotaTotal' => $user->pressReleaseQuotaTotal(), 'quotaRemaining' => $user->pressReleaseQuotaRemaining(), 'canEdit' => auth()->user()->can('update', $pr) && in_array($pr->status->value, ['draft', 'rejected']), 'latestRejection' => $latestRejection, 'contacts' => $pr->contacts, 'statusLogs' => $pr->statusLogs, 'statusColor' => match($pr->status->value) { 'published' => 'green', 'review' => 'yellow', 'rejected' => 'red', 'archived' => 'blue', default => 'zinc', }, ]; } private function getMyPR(): PressRelease { return PressRelease::withoutGlobalScopes() ->where('user_id', auth()->id()) ->with([ 'company:id,name,email,phone', 'category.translations', 'contacts' => fn ($query) => $query ->withoutGlobalScopes() ->orderBy('last_name') ->orderBy('first_name') ->select(['contacts.id', 'contacts.company_id', 'contacts.first_name', 'contacts.last_name', 'contacts.responsibility', 'contacts.email', 'contacts.phone']), 'statusLogs.changedBy:id,name,email', ]) ->findOrFail($this->id); } }; ?>
@php $statusClass = match ($pr->status->value) { 'published' => 'ok', 'review' => 'warn', 'rejected' => 'err', default => 'hub', }; @endphp {{-- Flash-Banner ersetzt durch im Layout. --}} {{-- ============== PAGE HEADER ============== --}} {{-- ============== SHARE-LINK ERFOLG ============== --}} @if ($shareUrl)
{{ __('Öffentlicher Vorschau-Link erstellt') }} {{ __('gültig bis :date', ['date' => $shareExpiresAt]) }}
@endif {{-- ============== REJECTION-HINWEIS ============== --}} @if ($pr->status === PressReleaseStatus::Rejected && $latestRejection)
{{ __('Diese Pressemitteilung wurde abgelehnt') }} {{ __('Handlung erforderlich') }}
@if ($latestRejection->reason) {{ __('Begründung') }}: {{ $latestRejection->reason }} @else {{ __('Bitte überarbeiten Sie den Inhalt und reichen Sie die Pressemitteilung erneut ein.') }} @endif {{ __('Abgelehnt am') }} {{ $latestRejection->created_at->format('d.m.Y H:i') }}
@endif {{-- ============== STATUS-WORKFLOW (oben, farblich abgehoben) ============== --}} @if ($pr->status === PressReleaseStatus::Draft || $pr->status === PressReleaseStatus::Rejected)
{{ __('Status-Workflow') }} status === PressReleaseStatus::Rejected ? 'err' : 'hub'])> {{ $pr->status === PressReleaseStatus::Rejected ? __('Überarbeiten') : __('Entwurf') }}

{{ $pr->status === PressReleaseStatus::Rejected ? __('Sie können den Text bearbeiten und erneut zur Prüfung einreichen.') : __('Reichen Sie den Entwurf ein, sobald er vollständig ist.') }}

@if ($canEdit) {{ __('Bearbeiten') }} @endif {{ $pr->status === PressReleaseStatus::Rejected ? __('Erneut einreichen') : __('Zur Prüfung einreichen') }}
@endif @if ($pr->status === PressReleaseStatus::Published)
{{ __('Status-Workflow') }} {{ __('Live') }}

{{ __('Diese Pressemitteilung ist veröffentlicht (seit :date).', ['date' => $pr->published_at?->format('d.m.Y H:i') ?? '–']) }}

@endif @if ($pr->status === PressReleaseStatus::Review)
{{ __('Status-Workflow') }} {{ __('Geduld bitte') }}

{{ __('Ihre Pressemitteilung wird gerade geprüft. Sie werden benachrichtigt, sobald eine Entscheidung vorliegt.') }}

@endif {{-- ============== KONTAKTE + STATUS/VERLAUF ============== --}}
{{ __('Zugeordnete Pressekontakte') }} @if ($pr->company) {{ __('Firma') }} @endif

{{ __('Kontakte, die dieser Pressemitteilung zugeordnet sind.') }}

@forelse ($contacts as $contact)
{{ trim(($contact->first_name ?? '').' '.($contact->last_name ?? '')) ?: __('Kontakt ohne Name') }}
{{ $contact->responsibility ?: __('Keine Rolle hinterlegt') }}
@if ($contact->email) {{ $contact->email }} @endif @if ($contact->phone) {{ $contact->phone }} @endif
@empty
{{ __('Dieser Pressemitteilung ist noch kein Pressekontakt zugeordnet.') }} @if ($pr->company) {{ __('Kontakte in der Firma prüfen.') }} @endif
@endforelse
{{ __('Status & Verlauf') }} {{ $pr->status->label() }}
{{ __('Aktueller Status') }}
{{ $pr->status->label() }}
{{ __('Erstellt') }}
{{ $pr->created_at?->format('d.m.Y H:i') ?? '–' }}
{{ __('Veröffentlicht') }}
{{ $pr->published_at?->format('d.m.Y H:i') ?? '–' }}
{{ __('Aufrufe') }}
{{ number_format($pr->hits, 0, ',', '.') }}
@if ($pr->scheduled_at)
{{ __('Geplante Veröffentlichung') }}
{{ $pr->scheduledAtLocal()->format('d.m.Y H:i') }}
@endif @if ($pr->embargo_at)
{{ __('Sperrfrist bis') }}
{{ $pr->embargoAtLocal()->format('d.m.Y H:i') }}
@endif
{{ __('Portal') }}
{{ $pr->portal?->label() ?? '–' }}
{{ __('Kategorie') }}
{{ $categoryName }}
{{ __('Sprache') }}
{{ strtoupper($pr->language) }}
@if (filled($pr->keywords))
{{ __('Themen') }}
@foreach (array_filter(array_map('trim', explode(',', $pr->keywords))) as $keyword) {{ $keyword }} @endforeach
@endif @if ($pr->backlink_url)
{{ __('Backlink') }}
{{ $pr->backlink_url }}
@endif @if ($pr->no_export)
{{ __('Kein Export aktiv (PM wird nicht über Feeds verteilt).') }}
@endif
@if ($statusLogs->isNotEmpty())
    @foreach ($statusLogs as $log)
  1. @php $logClass = match ($log->to_status?->value) { 'published' => 'ok', 'review' => 'warn', 'rejected' => 'err', default => 'hub', }; @endphp {{ $log->to_status?->label() }} {{ $log->created_at->format('d.m.Y H:i') }} @if ($log->changedBy) {{ __('durch :name', ['name' => $log->changedBy->name]) }} @endif
    @if ($log->reason)

    {{ $log->reason }}

    @endif
  2. @endforeach
@else

{{ __('Noch keine Statusänderungen protokolliert.') }}

@endif
{{-- ============== TITELBILD (Hero) ============== --}} {{-- Harte Obergrenze 1280x580 px: Container deckelt Breite und Seitenverhältnis, damit das Bild auf großen Screens nicht über die Detailgröße hinauswächst. --}}
{{ $pr->title }}
@if ($coverIsPlaceholder)
{{ __('Platzhalter-Titelbild — laden Sie im Editor ein eigenes Bild hoch.') }}
@elseif ($titleImage && ($titleImage->copyright || $titleImage->is_ai_generated)) {{-- Bildnachweis + KI-Kennzeichnung (Art. 50 EU AI Act) --}}
@if ($titleImage->is_ai_generated) {{ __('KI-generiert') }} @endif {{ $titleImage->copyright ?? __('Bild: KI-generiert') }}
@endif
{{-- ============== INHALT ============== --}}
{{ __('Inhalt') }}
{!! $pr->renderedText() !!}
{{-- ============== VERÖFFENTLICHUNGS-MODAL ============== --}} @if ($pr->status === PressReleaseStatus::Draft || $pr->status === PressReleaseStatus::Rejected) @endif {{-- ============== BOILERPLATE-OVERRIDE ============== --}} @if ($pr->boilerplate_override)
{{ __('Eigener Abbinder (Boilerplate)') }} {{ __('Override') }}

{{ __('Dieser Text wird für diese Pressemitteilung anstelle des Standard-Abbinders der Firma verwendet.') }}

{{ $pr->boilerplate_override }}
@endif