user(); $context = app(CustomerCompanyContext::class); $selectedCompanyId = $context->selectedCompanyId($user); $selectedCompany = $selectedCompanyId === null ? null : $context->findFor($user, $selectedCompanyId); $pressReleaseQuery = PressRelease::withoutGlobalScopes() ->where('user_id', $user->id) ->when($selectedCompanyId !== null, fn ($query) => $query->where('company_id', $selectedCompanyId)); $now = Carbon::now(); $currentStart = $now->copy()->startOfMonth(); $previousStart = $now->copy()->subMonthNoOverflow()->startOfMonth(); $previousEnd = $now->copy()->subMonthNoOverflow()->endOfMonth(); $stats = (clone $pressReleaseQuery) ->toBase() ->selectRaw('COUNT(*) as total') ->selectRaw('SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as published', [PressReleaseStatus::Published->value]) ->selectRaw('SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as review', [PressReleaseStatus::Review->value]) ->selectRaw('SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as draft', [PressReleaseStatus::Draft->value]) ->selectRaw('SUM(CASE WHEN created_at >= ? THEN 1 ELSE 0 END) as current_month', [$currentStart]) ->selectRaw('SUM(CASE WHEN created_at BETWEEN ? AND ? THEN 1 ELSE 0 END) as previous_month', [$previousStart, $previousEnd]) ->first(); $recent = (clone $pressReleaseQuery) ->with('company:id,name') ->latest() ->limit(5) ->get(['id', 'title', 'status', 'portal', 'company_id', 'created_at', 'published_at']); $profile = $user->profile; $billingAddress = $user->billingAddress; return [ 'user' => $user, 'selectedCompany' => $selectedCompany, 'stats' => [ 'total' => (int) ($stats->total ?? 0), 'published' => (int) ($stats->published ?? 0), 'review' => (int) ($stats->review ?? 0), 'draft' => (int) ($stats->draft ?? 0), 'deltaMonth' => (int) ($stats->current_month ?? 0) - (int) ($stats->previous_month ?? 0), ], 'profileCompleteness' => $this->profileCompleteness($profile), 'billingCompleteness' => $this->billingCompleteness($billingAddress), 'qualityHints' => $this->qualityHints( $user, $profile, $billingAddress, $selectedCompany, $pressReleaseQuery, ), 'recent' => $recent, 'companies' => $context->latestCompaniesFor($user), 'companiesTotal' => $context->companyCountFor($user), 'bridgeStatus' => [ /* Heute hardcoded — perspektivisch aus echtem Sync-Service. */ 'presseecho' => ['state' => 'connected', 'subline' => __('Archiv · Branchen-Tiefe')], 'businessportal24' => ['state' => 'connected', 'subline' => __('Wirtschaft · Live')], ], ]; } /** * Heuristische Profil-Vollständigkeit in %. * 6 Kernfelder, jedes ~17 %. */ private function profileCompleteness(?Profile $profile): int { if (! $profile) { return 0; } $fields = [ 'salutation_key', 'first_name', 'last_name', 'phone', 'address', 'country_code', ]; $filled = collect($fields)->filter(fn (string $field) => filled($profile->{$field}))->count(); return (int) round(($filled / count($fields)) * 100); } /** * Rechnungsadressen-Vollständigkeit in %. * Ohne hinterlegte Adresse: 0; sonst je nach gefüllten Pflichtfeldern. */ private function billingCompleteness(?BillingAddress $address): int { if (! $address) { return 0; } $fields = ['name', 'address1', 'postal_code', 'city', 'country_code']; $filled = collect($fields)->filter(fn (string $field) => filled($address->{$field}))->count(); return (int) round(($filled / count($fields)) * 100); } /** * @return list */ private function qualityHints( User $user, ?Profile $profile, ?BillingAddress $billingAddress, ?Company $selectedCompany, Builder $pressReleaseQuery, ): array { $hints = []; $profilePercent = $this->profileCompleteness($profile); if ($profilePercent < 100) { $hints[] = [ 'icon' => 'user', 'title' => __('Profil unvollständig'), 'description' => __('Ergänzen Sie Salutation, Telefon und Adresse für eine saubere Kundenakte.'), 'href' => route('me.profile').'#profil', 'action' => __('Profil öffnen'), 'percent' => $profilePercent, ]; } $billingPercent = $this->billingCompleteness($billingAddress); if ($billingPercent < 100) { $hints[] = [ 'icon' => 'archive-box', 'title' => $billingAddress ? __('Rechnungsadresse unvollständig') : __('Rechnungsadresse fehlt'), 'description' => __('Hinterlegen Sie eine Rechnungsadresse, damit spätere Buchungen sauber abgerechnet werden können.'), 'href' => route('me.profile').'#rechnungsadresse', 'action' => __('Rechnungsadresse ergänzen'), 'percent' => $billingPercent, ]; } if ($selectedCompany) { $contactsCount = Contact::withoutGlobalScopes() ->where('company_id', $selectedCompany->id) ->count(); if ($contactsCount === 0) { $hints[] = [ 'icon' => 'user-group', 'title' => __('Keine Pressekontakte hinterlegt'), 'description' => __('Ergänzen Sie Pressekontakte für diese Firma.'), 'href' => route('me.press-kits.show', $selectedCompany->id), 'action' => __('Firma öffnen'), ]; } } else { $unassignedPressReleasesCount = (clone $pressReleaseQuery) ->whereNull('company_id') ->count(); if ($unassignedPressReleasesCount > 0) { $hints[] = [ 'icon' => 'newspaper', 'title' => trans_choice( ':count Pressemitteilung ohne Firma|:count Pressemitteilungen ohne Firma', $unassignedPressReleasesCount, ['count' => $unassignedPressReleasesCount], ), 'description' => __('Ordnen Sie Legacy-Pressemitteilungen einer Firma zu, damit Portal und Pressekontakte eindeutig sind.'), 'href' => route('me.press-releases.index', ['company' => 'unassigned']), 'action' => __('Pressemitteilungen prüfen'), ]; } } return $hints; } }; ?>
{{-- ============== PAGE HEADER ============== --}}
{{ __('User Backend') }} {{ __('Mein Bereich · A · 01') }}

{{ __('Mein Dashboard') }}

{{ __('Willkommen zurück, ') }}{{ $user->name }}. @if ($selectedCompany) {{ __('Übersicht für :company', ['company' => $selectedCompany->name]) }} — @endif {{ __('Hier sehen Sie Status und Reichweite Ihres Kundenkontos für presseecho und businessportal24.') }}

@if ($selectedCompany) {{ __('Aktive Firma:') }} {{ $selectedCompany->name }} @else {{ __('Keine Firma zugeordnet') }} {{ __('zuordnen') }} → @endif
{{-- ============== STAT-CARDS — KPI-Reihe ============== --}}
{{ now()->format('Y') }} @php $delta = $stats['deltaMonth']; $deltaLabel = $delta === 0 ? __('keine Veränderung ggü. Vormonat') : trans_choice(':sign:abs ggü. Vormonat', abs($delta), [ 'sign' => $delta > 0 ? '+' : '−', 'abs' => abs($delta), ]); @endphp @if ($delta > 0) @elseif ($delta < 0) @else @endif {{ $deltaLabel }} {{ __('live') }} {{ __('auf beiden Portalen') }} {{ __('Ø 4 h') }} {{ __('redaktionelle Prüfung') }} {{ __('privat') }} {{ __('gespeichert, nicht eingereicht') }}
{{-- ============== ZWEISPALTEN-GRID ============== --}}
{{-- LINKS: Pressemitteilungen-Liste / Empty-State --}}
{{ __('Meine letzten Pressemitteilungen') }}
{{ $recent->count() }} {{ __('von') }} {{ $stats['total'] }} {{ __('Alle anzeigen') }} →
@forelse ($recent as $pr) @php $badgeClass = match ($pr->status->value) { '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); $primaryDate = $pr->status === PressReleaseStatus::Published && $pr->published_at ? $pr->published_at : $pr->created_at; @endphp

{{ $pr->title }}

PM-{{ $pr->id }} · {{ $pr->company?->name ?? __('Ohne Firma') }} · {{ $primaryDate?->format('d.m.Y') }}

@if ($showPe) presseecho @endif @if ($showBp) businessportal24 @endif {{ $pr->status->label() }}
@empty
0
{{ __('Noch keine Pressemitteilungen') }}

{{ __('Starten Sie mit einer ersten Mitteilung für die aktive Firma oder Ihr Kundenkonto. Veröffentlichung erfolgt nach redaktioneller Prüfung auf beiden Portalen.') }}

{{ __('Erste Pressemitteilung erstellen') }}
@foreach ([ ['num' => '01', 'label' => __('Firma zuordnen')], ['num' => '02', 'label' => __('Mitteilung verfassen')], ['num' => '03', 'label' => __('Zur Prüfung senden')], ] as $step)
{{ $step['num'] }}
{{ $step['label'] }}
@endforeach
@endforelse
{{ __('Tipp: Geprüfte Mitteilungen erscheinen i. d. R. binnen') }} {{ __('4 Stunden') }} {{ __('werktags auf beiden Portalen.') }}
{{-- RECHTS: Datenqualität --}}
{{ __('Datenqualität') }} @if (count($qualityHints) > 0) {{ count($qualityHints) }} {{ __('offen') }} @else {{ __('vollständig') }} @endif

{{ __('Diese Hinweise helfen, Ihr User Backend vollständig und sauber zu halten.') }}

@if (count($qualityHints) > 0)
@foreach ($qualityHints as $hint) {{ $hint['description'] }} @endforeach
@else
{{ __('Alles im grünen Bereich') }}

{{ __('Profil, Rechnungsadresse und Firmen-Daten sind vollständig.') }}

@endif
{{-- ============== UNTERER GRID: FIRMEN + BRAND-BRIDGE ============== --}}
{{-- Firmen --}}
{{ __('Meine Firmen') }}
{{ $companiesTotal }} {{ __('zugeordnet') }} {{ __('Alle Firmen anzeigen') }} →
@if ($companies->isNotEmpty()) @if ($companiesTotal > $companies->count())
{{ __('Die zehn neuesten Firmen werden hier als Vorschau angezeigt.') }} {{ __('Zur vollständigen Firmenliste') }} →
@endif @else
{{ __('Firma hinzufügen') }}
{{ __('Slot frei') }}

{{ __('Pressestellen, für die Sie Mitteilungen erstellen — mit eigenem Logo, Kontaktperson und Themen-Tags.') }}

{{ __('Hinweis') }}
{{ __('Keine Firmen zugeordnet. Wenn hier eine Firma fehlen sollte, prüfen Sie bitte die Firmenverwaltung oder wenden Sie sich an den Support.') }}
{{ __('Firmen öffnen') }}
@endif
{{-- Brand-Bridge (dark) --}}
{{ __('Brand-Bridge') }} A · B
{{ __('Ein Konto, beide Portale — Veröffentlichungen werden parallel auf presseecho und businessportal24 ausgespielt.') }}
{{-- Konstantes dunkles Hub-Blau (Phase 5): bleibt in beiden Modi gleich. --}}
presseecho
{{ __($bridgeStatus['presseecho']['state']) }}
{{ $bridgeStatus['presseecho']['subline'] }}
businessportal24
{{ __($bridgeStatus['businessportal24']['state']) }}
{{ $bridgeStatus['businessportal24']['subline'] }}

{{ __('API-Status') }} {{ __('operational') }}
{{ __('Tarif') }} {{ __('Starter') }}
{{-- ============== FOOTER ============== --}}