portal: Firmenseiten verlinken den öffentlichen Newsroom

Im Backend heißt der Datensatz weiter „Firma“, öffentlich ist er der
Newsroom. Kunden- und Admin-Firmenseite heißen „Firma & Newsroom“ und zeigen
unter dem Namen die Newsroom-Links je Portal oder den Hinweis, dass der
Newsroom erst mit der ersten Meldung erscheint (Company::publicNewsroomLinks).

Changelog: Verbessert
Public: Die Firmenseite im Kundenbereich verlinkt jetzt direkt auf den öffentlichen Newsroom.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-13 15:26:08 +00:00
parent 2c332052ce
commit 33fcde5558
4 changed files with 135 additions and 4 deletions

View file

@ -0,0 +1,23 @@
@props([
// Company::publicNewsroomLinks(): je Portal, auf dem der Newsroom schon erscheint.
'links' => [],
])
{{-- Verknüpfung Firma ↔ Newsroom (Roadmap 6.17): Im Backend heißt der
Datensatz „Firma“, öffentlich ist er der Newsroom. Ohne sichtbare Meldung
gibt es noch keine öffentliche Seite (Roadmap 1b.1) — das steht dann da,
statt dass der Link fehlt. --}}
<div {{ $attributes->class(['flex flex-wrap items-center gap-x-3 gap-y-1 text-[12px]']) }} data-newsroom-links>
@if ($links === [])
<span class="text-[color:var(--color-ink-3)]">{{ __('Newsroom noch nicht öffentlich – er erscheint mit der ersten veröffentlichten Meldung.') }}</span>
@else
<span class="text-[color:var(--color-ink-3)]">{{ __('Öffentlicher Newsroom:') }}</span>
@foreach ($links as $link)
<a href="{{ $link['url'] }}" target="_blank" rel="noopener"
class="inline-flex items-center gap-1 font-semibold text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
{{ $link['label'] }}
<flux:icon.arrow-top-right-on-square class="size-3.5" />
</a>
@endforeach
@endif
</div>

View file

@ -119,6 +119,7 @@ new #[Layout('components.layouts.app'), Title('Firma anzeigen')] class extends C
'recentPressReleases' => collect(),
'unreachableEmails' => [],
'domainCheck' => null,
'newsroomLinks' => [],
];
}
@ -192,6 +193,7 @@ new #[Layout('components.layouts.app'), Title('Firma anzeigen')] class extends C
return [
'company' => $company,
'newsroomLinks' => $company->publicNewsroomLinks(),
'domainCheck' => $domainCheck,
'unreachableEmails' => $unreachableEmails,
'filteredContacts' => $filteredContacts,
@ -228,7 +230,7 @@ new #[Layout('components.layouts.app'), Title('Firma anzeigen')] class extends C
<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">{{ __('Stammdaten · Firma') }}</span>
<span class="eyebrow muted">{{ __('Stammdaten · Firma & Newsroom') }}</span>
@if ($company->is_active)
<span class="badge ok">{{ __('Aktiv') }}</span>
@else
@ -266,6 +268,7 @@ new #[Layout('components.layouts.app'), Title('Firma anzeigen')] class extends C
{{ $company->website }}
</a>
@endif
<x-portal.newsroom-links :links="$newsroomLinks" class="mt-1.5" />
</div>
</div>
</div>

View file

@ -19,7 +19,7 @@ use Livewire\Attributes\Title;
use Livewire\Component;
use Livewire\WithFileUploads;
new #[Layout('components.layouts.app'), Title('Firma')] class extends Component {
new #[Layout('components.layouts.app'), Title('Firma & Newsroom')] class extends Component {
use WithFileUploads;
#[Locked]
@ -302,6 +302,7 @@ new #[Layout('components.layouts.app'), Title('Firma')] class extends Component
return [
'company' => $company,
'newsroomLinks' => $company->publicNewsroomLinks(),
'roleLabel' => $context->roleLabelFor($company, $user),
'canManageCompany' => $user->can('update', $company),
'canManageContacts' => $user->can('update', $company),
@ -377,7 +378,7 @@ new #[Layout('components.layouts.app'), Title('Firma')] class extends Component
<div class="min-w-0">
<div class="flex items-center gap-3 mb-3 flex-wrap">
<span class="badge hub dot">{{ __('User Backend') }}</span>
<span class="eyebrow muted">{{ __('Mein Bereich · Firma') }}</span>
<span class="eyebrow muted">{{ __('Mein Bereich · Firma & Newsroom') }}</span>
@if ($company->is_active)
<span class="badge ok">{{ __('Aktiv') }}</span>
@else
@ -403,7 +404,7 @@ new #[Layout('components.layouts.app'), Title('Firma')] class extends Component
<h1 class="text-[30px] font-bold tracking-[-0.6px] leading-[1.15] m-0 text-[color:var(--color-ink)] break-words">
{{ $company->name }}
</h1>
<div class="text-[12px] text-[color:var(--color-ink-3)] mt-1">{{ $company->slug }}</div>
<x-portal.newsroom-links :links="$newsroomLinks" class="mt-1.5" />
</div>
</div>
</div>

View file

@ -0,0 +1,104 @@
<?php
use App\Enums\Portal;
use App\Models\Company;
use App\Models\PressRelease;
use App\Models\User;
use Database\Seeders\RolesAndPermissionsSeeder;
use Livewire\Livewire;
use Tests\TestCase;
/**
* Firma ↔ Newsroom (Roadmap 6.17): Im Backend heißt der Datensatz „Firma“,
* öffentlich ist er der Newsroom. Beide Firmenseiten verlinken ihn, und die
* Newsroom-Seite zeigt den Verwaltungszugang als Kasten statt als Textzeile.
*/
test('a company has no public newsroom before its first visible release', function () {
/** @var TestCase $this */
$company = Company::factory()->presseecho()->create(['slug' => 'alpha-gmbh', 'is_active' => true]);
expect($company->publicNewsroomLinks())->toBe([]);
PressRelease::factory()->published()->forPortal(Portal::Presseecho)->create([
'company_id' => $company->id, 'published_at' => now()->subDay(), 'language' => 'de',
]);
$links = $company->publicNewsroomLinks();
expect($links)->toHaveCount(1)
->and($links[0]['portal'])->toBe(Portal::Presseecho)
->and($links[0]['url'])->toEndWith('/de/newsroom/alpha-gmbh');
});
test('a company on both portals links each portal where it already appears, english only without german releases', function () {
/** @var TestCase $this */
$company = Company::factory()->create(['portal' => Portal::Both, 'slug' => 'beta-ag', 'is_active' => true]);
PressRelease::factory()->published()->forPortal(Portal::Businessportal24)->create([
'company_id' => $company->id, 'published_at' => now()->subDay(), 'language' => 'en',
]);
$links = $company->publicNewsroomLinks();
expect($links)->toHaveCount(1)
->and($links[0]['portal'])->toBe(Portal::Businessportal24)
->and($links[0]['url'])->toEndWith('/en/newsroom/beta-ag');
});
test('the customer company page links the public newsroom or says why there is none', function () {
/** @var TestCase $this */
$this->seed(RolesAndPermissionsSeeder::class);
$customer = User::factory()->create(['is_active' => true]);
$customer->assignRole('customer');
$company = Company::factory()->presseecho()->create(['name' => 'Alpha GmbH', 'slug' => 'alpha-gmbh', 'is_active' => true]);
$customer->companies()->attach($company->id, ['role' => 'responsible']);
$this->actingAs($customer);
Livewire::test('customer.press-kits.show', ['id' => $company->id])
->assertSee('Firma & Newsroom')
->assertSee('Newsroom noch nicht öffentlich');
PressRelease::factory()->published()->forPortal(Portal::Presseecho)->create([
'company_id' => $company->id, 'published_at' => now()->subDay(), 'language' => 'de',
]);
Livewire::test('customer.press-kits.show', ['id' => $company->id])
->assertSee('Öffentlicher Newsroom:')
->assertSee('/de/newsroom/alpha-gmbh');
});
test('the admin company page links the public newsroom', function () {
/** @var TestCase $this */
$this->seed(RolesAndPermissionsSeeder::class);
$admin = User::factory()->create(['is_active' => true]);
$admin->assignRole('admin');
$company = Company::factory()->businessportal24()->create(['slug' => 'gamma-kg', 'is_active' => true]);
PressRelease::factory()->published()->forPortal(Portal::Businessportal24)->create([
'company_id' => $company->id, 'published_at' => now()->subDay(), 'language' => 'de',
]);
$this->actingAs($admin);
Livewire::test('admin.companies.show', ['id' => $company->id])
->assertSee('Öffentlicher Newsroom:')
->assertSee('/de/newsroom/gamma-kg');
});
test('the newsroom page shows the manage box with the masked address instead of a text line', function () {
/** @var TestCase $this */
$company = Company::factory()->businessportal24()->create([
'name' => 'Muster GmbH', 'slug' => 'muster-gmbh', 'email' => 'info@muster.de', 'is_active' => true,
]);
PressRelease::factory()->published()->forPortal(Portal::Businessportal24)->create([
'company_id' => $company->id, 'published_at' => now()->subDay(), 'language' => 'de',
]);
$this->get('https://businessportal24.test/de/newsroom/muster-gmbh')
->assertOk()
->assertSee('data-manage-newsroom', false)
->assertSeeText('Sie vertreten Muster GmbH?')
->assertSeeText('i***@muster.de')
->assertSeeText('Anmeldelink anfordern')
->assertDontSeeText('info@muster.de')
->assertDontSeeText('Eigenen Newsroom starten');
});