diff --git a/app/Enums/ContactMessageTopic.php b/app/Enums/ContactMessageTopic.php index c220f979..f246ec09 100644 --- a/app/Enums/ContactMessageTopic.php +++ b/app/Enums/ContactMessageTopic.php @@ -5,6 +5,7 @@ namespace App\Enums; enum ContactMessageTopic: string { case Contact = 'contact'; + case Advertising = 'advertising'; case BugReport = 'bug_report'; case PressReleaseReport = 'press_release_report'; case Feedback = 'feedback'; @@ -16,6 +17,7 @@ enum ContactMessageTopic: string { return match ($this) { self::Contact => 'Kontaktaufnahme', + self::Advertising => 'Werbeanfrage', self::BugReport => 'Fehlermeldung', self::PressReleaseReport => 'PM-Meldung', self::Feedback => 'Feedback', diff --git a/lang/de/web.php b/lang/de/web.php index 2bc0089a..503bcf07 100644 --- a/lang/de/web.php +++ b/lang/de/web.php @@ -92,6 +92,15 @@ return [ 'title' => 'Meistgelesen', ], + 'ad_slot' => [ + 'label' => 'Anzeige', + 'end_label' => 'Ende Anzeige', + 'eyebrow' => 'Werbeplatz verfügbar', + 'title' => 'Hier könnte Ihre Werbung stehen', + 'text' => 'Erreichen Sie Entscheider aus dem DACH-Raum — direkt im redaktionellen Umfeld.', + 'cta' => 'Jetzt Werbeplatz anfragen', + ], + 'newsrooms' => [ 'title' => 'Aktive Newsrooms', 'today' => 'Heute', @@ -189,6 +198,8 @@ return [ 'intro' => 'Wählen Sie Ihr Anliegen — wir melden uns werktags schnellstmöglich zurück.', 'topic_contact' => 'Kontaktaufnahme', 'topic_contact_desc' => 'Allgemeine Frage oder Anfrage an uns', + 'topic_advertising' => 'Werbung buchen', + 'topic_advertising_desc' => 'Werbeplätze und Konditionen anfragen', 'topic_bug' => 'Fehler melden', 'topic_bug_desc' => 'Etwas funktioniert nicht wie erwartet', 'topic_press' => 'Pressemitteilung melden', diff --git a/lang/en/web.php b/lang/en/web.php index 1ad93d98..bf1c78a8 100644 --- a/lang/en/web.php +++ b/lang/en/web.php @@ -87,6 +87,15 @@ return [ 'title' => 'Most read', ], + 'ad_slot' => [ + 'label' => 'Advertisement', + 'end_label' => 'End of advertisement', + 'eyebrow' => 'Ad space available', + 'title' => 'Your advertising could be here', + 'text' => 'Reach decision-makers across the DACH region — right within the editorial environment.', + 'cta' => 'Enquire about this ad space', + ], + 'newsrooms' => [ 'title' => 'Active newsrooms', 'today' => 'Today', @@ -184,6 +193,8 @@ return [ 'intro' => 'Choose your topic — we will get back to you as soon as possible on business days.', 'topic_contact' => 'Get in touch', 'topic_contact_desc' => 'General question or inquiry', + 'topic_advertising' => 'Book advertising', + 'topic_advertising_desc' => 'Ask about ad placements and rates', 'topic_bug' => 'Report a bug', 'topic_bug_desc' => 'Something is not working as expected', 'topic_press' => 'Report a press release', diff --git a/resources/views/components/web/ad-slot.blade.php b/resources/views/components/web/ad-slot.blade.php new file mode 100644 index 00000000..c4ff8449 --- /dev/null +++ b/resources/views/components/web/ad-slot.blade.php @@ -0,0 +1,47 @@ +{{-- + Werbeplatz-Hinweis (Eigenwerbung): dezenter „Anzeige"-Rahmen im Stil der + früheren Ad-Slots (focus-ad/feed-ad), solange die Fläche nicht vermarktet + ist. Klick öffnet das schwebende Kontakt-Widget mit vorgewähltem Thema + „Werbeanfrage" (Window-Event `open-contact-modal` + topic-Detail). + + Varianten steuern nur die Außenabstände der jeweiligen Einbauorte: + - sidebar → Hero-Sidebar der Startseiten + - feed → Meldungs-Feed + - inline → Fließtext der PM-Detailseite +--}} + +@props(['variant' => 'sidebar']) + +
$variant === 'sidebar', + 'my-6' => $variant === 'feed', + 'my-8 max-w-[680px]' => $variant === 'inline', +])> +
+ + {{ __('web.ad_slot.label') }} + +
+ + + +
+ + {{ __('web.ad_slot.end_label') }} + +
+
diff --git a/resources/views/components/web/contact-launcher.blade.php b/resources/views/components/web/contact-launcher.blade.php index 4b3d5fad..79d209e4 100644 --- a/resources/views/components/web/contact-launcher.blade.php +++ b/resources/views/components/web/contact-launcher.blade.php @@ -25,6 +25,11 @@ 'label' => __('web.launcher.topic_contact'), 'description' => __('web.launcher.topic_contact_desc'), ], + [ + 'value' => \App\Enums\ContactMessageTopic::Advertising->value, + 'label' => __('web.launcher.topic_advertising'), + 'description' => __('web.launcher.topic_advertising_desc'), + ], [ 'value' => \App\Enums\ContactMessageTopic::BugReport->value, 'label' => __('web.launcher.topic_bug'), @@ -50,7 +55,8 @@ topic: @js(old('topic')), topicLabels: @js($launcherTopicLabels), }" - @open-contact-modal.window="open = true" + {{-- Optionales Event-Detail `topic` wählt das Anliegen direkt vor (z. B. Werbeplätze). --}} + @open-contact-modal.window="open = true; if ($event.detail?.topic && topicLabels[$event.detail.topic]) { topic = $event.detail.topic }" @keydown.escape.window="open = false" class="fixed bottom-5 right-5 z-50 flex flex-col items-end gap-3 print:hidden" > diff --git a/resources/views/components/web/focus-hero.blade.php b/resources/views/components/web/focus-hero.blade.php index ac960d85..6edd48b2 100644 --- a/resources/views/components/web/focus-hero.blade.php +++ b/resources/views/components/web/focus-hero.blade.php @@ -88,6 +88,8 @@ @foreach ($sideReleases as $index => $release) @endforeach + + diff --git a/resources/views/livewire/web/press-release-feed.blade.php b/resources/views/livewire/web/press-release-feed.blade.php index 31772d09..2e6add98 100644 --- a/resources/views/livewire/web/press-release-feed.blade.php +++ b/resources/views/livewire/web/press-release-feed.blade.php @@ -127,6 +127,11 @@ new class extends Component @foreach ($rest as $release) + + @if ($loop->index === 2) + {{-- Werbeplatz nach der dritten Feed-Meldung (Position der früheren feed-ad). --}} + + @endif @endforeach @if ($releases->hasMorePages()) diff --git a/resources/views/web/release-detail.blade.php b/resources/views/web/release-detail.blade.php index 417d2b66..cb49099f 100644 --- a/resources/views/web/release-detail.blade.php +++ b/resources/views/web/release-detail.blade.php @@ -353,6 +353,11 @@ @endif + {{-- Inline-Werbeplatz (Position der früheren Inline-Ad); in der privaten Vorschau ausgeblendet --}} + @unless ($isPreview) + + @endunless + {{-- Pressekontakt --}} @if ($contact)
diff --git a/tests/Feature/PressReleasePreviewTest.php b/tests/Feature/PressReleasePreviewTest.php index dce50fe7..6527853e 100644 --- a/tests/Feature/PressReleasePreviewTest.php +++ b/tests/Feature/PressReleasePreviewTest.php @@ -62,7 +62,9 @@ test('preview renders the public release detail layout with preview banner and n ->assertSeeText('Vorschau') ->assertSeeText('So erscheint die Pressemitteilung nach der Veröffentlichung.') ->assertSeeText('Status: Entwurf') - ->assertSeeText('Entwurf im Portal-Design'); + ->assertSeeText('Entwurf im Portal-Design') + // Der Werbeplatz-Hinweis erscheint nur auf der öffentlichen Seite. + ->assertDontSeeText('Hier könnte Ihre Werbung stehen'); }); test('preview applies the theme of the target portal', function () { diff --git a/tests/Feature/Web/ContactFormTest.php b/tests/Feature/Web/ContactFormTest.php index 236d8308..b2d7a610 100644 --- a/tests/Feature/Web/ContactFormTest.php +++ b/tests/Feature/Web/ContactFormTest.php @@ -150,6 +150,34 @@ test('a widget submission stores topic and page url', function () { }); }); +test('an advertising enquiry from the ad slot stores the advertising topic', function () { + /** @var TestCase $this */ + Mail::fake(); + + $this->post('https://presseecho.test/de/kontakt', [ + 'name' => 'Willi Werbung', + 'email' => 'willi@example.test', + 'message' => 'Ich interessiere mich für Werbeplätze auf Ihrem Portal.', + 'topic' => 'advertising', + 'page_url' => 'https://presseecho.test/de', + ])->assertSessionHas('contact-status'); + + $message = ContactMessage::query()->sole(); + + expect($message->topic)->toBe(ContactMessageTopic::Advertising) + ->and($message->portal)->toBe('presseecho'); + + Mail::assertSent(ContactRequestSubmitted::class, fn (ContactRequestSubmitted $mail) => $mail->topicLabel === 'Werbeanfrage'); +}); + +test('the spoke pages offer the advertising topic in the contact launcher', function () { + /** @var TestCase $this */ + $this->get('https://businessportal24.test/de/faq') + ->assertSuccessful() + ->assertSee('Werbung buchen') + ->assertSee('Werbeplätze und Konditionen anfragen'); +}); + test('an unknown topic is rejected', function () { /** @var TestCase $this */ Mail::fake(); diff --git a/tests/Feature/Web/PresseechoHomeTest.php b/tests/Feature/Web/PresseechoHomeTest.php index 286c81db..3030bb96 100644 --- a/tests/Feature/Web/PresseechoHomeTest.php +++ b/tests/Feature/Web/PresseechoHomeTest.php @@ -50,6 +50,39 @@ test('presseecho homepage renders the editorial shell with real data', function ->assertSeeText('Heute im Fokus'); }); +test('presseecho homepage shows the ad slot self-promotion in the hero sidebar', function () { + /** @var TestCase $this */ + $category = Category::factory()->create([ + 'portal' => Portal::Presseecho, + ]); + $category->translations()->create([ + 'locale' => 'de', + 'name' => 'Energie & Klima', + 'slug' => 'energie-klima', + ]); + + $company = Company::factory()->presseecho()->create(); + + PressRelease::factory() + ->published() + ->forPortal(Portal::Presseecho) + ->for($category) + ->for($company) + ->create([ + 'title' => 'Ad-Slot Hero Meldung', + 'slug' => 'ad-slot-hero-meldung', + 'published_at' => now()->subHour(), + ]); + + $this->get('https://presseecho.test/de') + ->assertSuccessful() + ->assertSeeText('Hier könnte Ihre Werbung stehen') + ->assertSeeText('Jetzt Werbeplatz anfragen') + // Klick öffnet das Kontakt-Widget mit vorgewähltem Thema „Werbeanfrage". + ->assertSee('open-contact-modal', false) + ->assertSee("{ topic: 'advertising' }", false); +}); + test('presseecho homepage hides data sections and shows the empty feed state without content', function () { /** @var TestCase $this */ $this->get('https://presseecho.test/de') diff --git a/tests/Feature/Web/ReleaseDetailTest.php b/tests/Feature/Web/ReleaseDetailTest.php index 3e5b6a54..740f84b3 100644 --- a/tests/Feature/Web/ReleaseDetailTest.php +++ b/tests/Feature/Web/ReleaseDetailTest.php @@ -128,6 +128,26 @@ test('release detail without chosen placeholder falls back to the generic hero', ->assertDontSee('images/press-release-placeholders/', false); }); +test('release detail shows the ad slot self-promotion inline', function () { + /** @var TestCase $this */ + // Werbeplatz-Hinweis (Eigenwerbung): Klick öffnet das Kontakt-Widget + // mit vorgewähltem Thema „Werbeanfrage". + [$category, $company] = detailCategoryAndCompany(Portal::Businessportal24); + + $release = PressRelease::factory() + ->published() + ->forPortal(Portal::Businessportal24) + ->for($category) + ->for($company) + ->create(['slug' => 'meldung-mit-werbeplatz', 'published_at' => now()->subDay()]); + + $this->get('https://businessportal24.test/de/press-release/'.$release->slug) + ->assertSuccessful() + ->assertSeeText('Hier könnte Ihre Werbung stehen') + ->assertSeeText('Jetzt Werbeplatz anfragen') + ->assertSee("{ topic: 'advertising' }", false); +}); + test('release detail shows prominent report links below the article', function () { /** @var TestCase $this */ // T13 (Meldeverfahren): Die Melde-Links stehen sichtbar unter jeder