recht: Meldeverfahren v2 Phasen 5+7 — DSGVO-Strukturformular, 10-€-Checkout mit KI-Vorprüfung, Triage & Panel-Modal
Phase 7 (Spur D, E2 revidiert): KI-Vorprüfung VOR der Zahlung im Modal — rot lehnt ohne Zahlung ab, gelb/grün führt zum Stripe-Checkout (SinglePurchaseType::Change, 10 € netto), nach Zahlungseingang übernimmt der Webhook die geprüfte Fassung sofort (applyPaid: Snapshot, Sperre, Verlauf). Nur einmal je PM; Obergrenze legal.change_max_distance_percent (50 %) verhindert die verdeckte Selbst-Depublizierung. Phase 5 (Spur B): strukturiertes Schwärzungsformular mit Pflicht-Vorschau im verifizierten Web-Bereich UND als Modal im Kunden-Panel; Admin-Editor wird aus payload.redaction vorbefüllt. Umsetzungsmail LegalRequestExecuted an Antragsteller, Bestätigungsmail PressReleaseChangeApplied (Spur A/D, neuer abbestellbarer Typ press_release_corrected). Außerdem: - Re-Sync-Sperre + Sitemap-Invalidierung fest in depublish() verankert (Lücke im bezahlten Webhook-Pfad geschlossen) - Öffentliche „Rechtliches"-Seite als zweistufige Triage: primär der Portal-Anmeldelink, Formular nur Fallback mit Identifizierungs-Hinweis; Store auf report/dsgvo/personal_rights gehärtet - Panel-Button „Ändern/Melden" öffnet Anliegen-Modal (4 Spuren) statt des Web-Formulars - Pressekontakt-Fallback für Legacy-Bestände (30k PMs ohne Verknüpfung): Detailseite + pressContactEmail() nutzen PM-Kontakt → Firmen-Kontakt → Firmendaten - Korrektur-Gate entity-fest (Editor-Normalisierung zählt nicht als Änderung), toEditorHtml() in Admin-Edit + Korrektur-Panel, Wochenlimit-Hinweis in Text und Bremsen-Meldung Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
04b49c567d
commit
e6eca9c85f
40 changed files with 2507 additions and 169 deletions
|
|
@ -5,16 +5,29 @@
|
|||
|
||||
@section('content')
|
||||
{{--
|
||||
Hinweistexte je Anfragetyp (R2.5, final 10.07.2026): Wortlaut folgt dem am
|
||||
06.07. inhaltlich freigegebenen Meldeverfahren v0.1 (/melden bzw.
|
||||
lang/de/static.php static.report.*) und dem tatsächlichen Flow
|
||||
(Vorgangsnummer M-{id}, unverzügliche Eingangsbestätigung nach DSA Art. 16
|
||||
Abs. 4 sofern E-Mail angegeben, kostenlose manuelle Prüfung). Die noch
|
||||
ausstehende anwaltliche Freigabe des Rechtstexte-Pakets [EXTERN] umfasst
|
||||
auch diese Texte.
|
||||
Zweistufige Triage (Meldeverfahren v2, 23.07.2026): Stufe 1 wählt das
|
||||
Anliegen, Stufe 2 zeigt den passenden Weg. Absender-Anliegen und
|
||||
DSGVO/Persönlichkeitsrechte werden primär auf den passwortlosen
|
||||
Anmeldelink ins Portal (pressekonto /anmeldelink) geleitet — dort werden
|
||||
die PMs der Kontaktadresse im Konto zusammengeführt und alle
|
||||
Selbstservice-Funktionen stehen bereit. Das Kontaktformular ist nur der
|
||||
Fallback und weist auf die notwendige persönliche Identifizierung hin.
|
||||
Meldungen rechtswidriger Inhalte gehen direkt ins Formular (DSA: jede
|
||||
dritte Person darf melden).
|
||||
Hinweistexte folgen dem am 06.07. freigegebenen Meldeverfahren v0.1;
|
||||
die anwaltliche Freigabe des Rechtstexte-Pakets [EXTERN] umfasst auch
|
||||
diese Texte.
|
||||
--}}
|
||||
<style>[x-cloak]{display:none!important}</style>
|
||||
<section
|
||||
x-data="{ type: @js(old('type', $type->value)), emailRequired() { return ['dsgvo', 'personal_rights'].includes(this.type); } }"
|
||||
x-data="{
|
||||
concern: @js(old('type', $initialConcern)),
|
||||
showFallback: @js(in_array(old('type'), ['dsgvo', 'personal_rights'], true)),
|
||||
pick(value) { this.concern = value; this.showFallback = false; },
|
||||
needsFallbackToggle() { return ['dsgvo', 'personal_rights'].includes(this.concern); },
|
||||
formVisible() { return this.concern === 'report' || (this.needsFallbackToggle() && this.showFallback); },
|
||||
emailRequired() { return ['dsgvo', 'personal_rights'].includes(this.concern); }
|
||||
}"
|
||||
class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-10"
|
||||
>
|
||||
<a href="{{ route('release.detail', ['slug' => $release->slug]) }}"
|
||||
|
|
@ -28,9 +41,9 @@
|
|||
Betrifft: <span class="text-ink-2 font-medium">{{ $release->title }}</span>
|
||||
</p>
|
||||
<p class="text-[12.5px] text-ink-3 leading-relaxed mb-6">
|
||||
Datenschutz (DSGVO), Persönlichkeitsrechte und Meldungen werden von unserem
|
||||
Team manuell geprüft. Bitte wählen Sie die Art Ihrer Anfrage – dazu erscheint
|
||||
ein Hinweis mit den genauen Regeln.
|
||||
Bitte wählen Sie zuerst Ihr Anliegen — dazu erscheint der passende Weg.
|
||||
Viele Anliegen können Sie nach einer kurzen Verifizierung direkt selbst
|
||||
anstoßen; alle Prüfungen sind kostenlos.
|
||||
</p>
|
||||
|
||||
@if (session('legal-status'))
|
||||
|
|
@ -39,63 +52,141 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('legal-request.store', ['slug' => $release->slug]) }}" class="space-y-5">
|
||||
@csrf
|
||||
|
||||
<div>
|
||||
<label for="type" class="block text-[12px] font-semibold text-ink mb-1.5">Art der Anfrage</label>
|
||||
<select id="type" name="type" x-model="type"
|
||||
class="w-full border border-bg-rule px-3 py-2.5 text-[13px] bg-white text-ink focus:outline-none focus:border-brand">
|
||||
@foreach ($types as $case)
|
||||
<option value="{{ $case->value }}" @selected(old('type', $type->value) === $case->value)>
|
||||
{{ $case->publicLabel() }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('type')
|
||||
<p class="mt-1 text-[12px] text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
{{-- ===== Stufe 1: Anliegen wählen ===== --}}
|
||||
<fieldset class="mb-6">
|
||||
<legend class="block text-[12px] font-semibold text-ink mb-2">Was möchten Sie tun?</legend>
|
||||
<div class="space-y-2">
|
||||
@foreach ([
|
||||
'owner' => ['label' => 'Korrektur, Änderung oder Depublizierung', 'desc' => 'Sie sind Absender oder hinterlegter Pressekontakt und möchten Inhalte korrigieren, ändern oder die Mitteilung offline nehmen.', 'badge' => 'Selbstservice'],
|
||||
'dsgvo' => ['label' => 'Entfernung persönlicher Daten (DSGVO)', 'desc' => 'Ihr Name oder Ihre Kontaktdaten erscheinen in dieser Mitteilung und sollen entfernt werden (Art. 17 DSGVO).', 'badge' => 'kostenlos'],
|
||||
'personal_rights' => ['label' => 'Verletzung von Persönlichkeitsrechten', 'desc' => 'Unwahre Tatsachenbehauptungen, Bild- oder Namensrechte — die Mitteilung betrifft Sie persönlich.', 'badge' => 'kostenlos'],
|
||||
'report' => ['label' => 'Rechtswidrige Inhalte melden', 'desc' => 'Urheberrechts- oder Markenverletzung, irreführende Inhalte, Spam — Meldung als dritte Person, auch ohne eigene Betroffenheit.', 'badge' => 'kostenlos'],
|
||||
] as $value => $card)
|
||||
<label class="flex items-start gap-3 border border-bg-rule px-3 py-2.5 cursor-pointer hover:bg-bg-elev"
|
||||
:class="concern === '{{ $value }}' ? 'border-brand bg-bg-elev' : ''">
|
||||
<input type="radio" name="concern_choice" value="{{ $value }}" class="mt-0.5"
|
||||
@change="pick('{{ $value }}')"
|
||||
:checked="concern === '{{ $value }}'" />
|
||||
<span class="text-[13px] text-ink">
|
||||
<span class="font-semibold">{{ $card['label'] }}</span>
|
||||
<span class="text-ink-3">· {{ $card['badge'] }}</span>
|
||||
<span class="block text-[12.5px] text-ink-2">{{ $card['desc'] }}</span>
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{-- Hinweistext je Anfragetyp (Wortlaut: siehe Kommentar am Seitenanfang). --}}
|
||||
<div x-cloak x-show="type === 'report'"
|
||||
class="px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Meldung:</strong>
|
||||
Melden Sie diese Pressemitteilung, wenn Sie sie für rechtswidrig halten
|
||||
oder sie Ihre Rechte verletzt — z. B. unwahre Tatsachenbehauptungen,
|
||||
Urheberrechts- oder Markenverletzungen, irreführende Inhalte oder Spam.
|
||||
Bitte benennen Sie konkret, welche Inhalte betroffen sind und warum.
|
||||
Jede Meldung wird von unserem Team manuell geprüft; die Meldung ist
|
||||
kostenlos. Wenn Sie eine E-Mail-Adresse angeben, erhalten Sie unverzüglich
|
||||
eine Eingangsbestätigung mit Vorgangsnummer und anschließend unsere
|
||||
Entscheidung mit Begründung.
|
||||
{{-- ===== Stufe 2a: Absender-Anliegen → passwortloser Portal-Login ===== --}}
|
||||
<div x-cloak x-show="concern === 'owner'" class="space-y-4">
|
||||
<div class="px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">So funktioniert es:</strong>
|
||||
Fordern Sie im Portal einen passwortlosen Anmeldelink an Ihre hinterlegte
|
||||
Pressekontakt- oder Firmenadresse an. Nach dem Klick sind Sie angemeldet und
|
||||
Ihre Pressemitteilungen werden in Ihrem Konto zusammengeführt — dort können
|
||||
Sie kleine Korrekturen kostenlos und sofort umsetzen, größere Änderungen
|
||||
(10 €) und die Depublizierung (35 €) direkt beauftragen.
|
||||
</div>
|
||||
<div x-cloak x-show="type === 'dsgvo'"
|
||||
class="px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<a href="{{ $portalMagicLinkUrl }}"
|
||||
class="inline-flex items-center px-5 py-2.5 bg-brand text-white text-[13px] font-semibold hover:opacity-90">
|
||||
Anmeldelink im Portal anfordern
|
||||
</a>
|
||||
<p class="text-[12px] text-ink-3 leading-relaxed">
|
||||
Keine erreichbare Pressekontaktadresse mehr? Dann nutzen Sie bitte das
|
||||
Formular unter „Entfernung persönlicher Daten" bzw. die manuelle Prüfung
|
||||
über das <a href="{{ route('melden') }}" class="underline hover:text-ink">Meldeverfahren</a> —
|
||||
wir verifizieren Ihre Berechtigung anhand eines Nachweises.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{-- ===== Stufe 2b: DSGVO ===== --}}
|
||||
<div x-cloak x-show="concern === 'dsgvo'" class="space-y-4">
|
||||
<div class="px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Datenschutz / DSGVO:</strong>
|
||||
Als natürliche Person können Sie die Entfernung, Ersetzung oder
|
||||
Anonymisierung Ihrer persönlichen Daten in dieser Pressemitteilung
|
||||
verlangen (Art. 17 DSGVO) — zum Beispiel Name, Telefonnummer oder
|
||||
E-Mail-Adresse. Bitte geben Sie an, welche Angaben Sie betreffen. Die
|
||||
Prüfung und Bearbeitung ist für Sie kostenlos. Zur Prüfung Ihrer
|
||||
Berechtigung benötigen wir Ihre E-Mail-Adresse; in der Regel senden wir
|
||||
einen Bestätigungslink an die betroffene Adresse, andernfalls können wir
|
||||
einen geeigneten Identitäts- oder Berechtigungsnachweis verlangen. Sie
|
||||
erhalten unverzüglich eine Eingangsbestätigung mit Vorgangsnummer. Die
|
||||
E-Mail-Adresse. Die Prüfung und Bearbeitung ist für Sie kostenlos. Die
|
||||
Pressemitteilung selbst bleibt nach der Entfernung Ihrer Daten
|
||||
grundsätzlich bestehen.
|
||||
</div>
|
||||
<div x-cloak x-show="type === 'personal_rights'"
|
||||
class="px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<div class="px-4 py-3 border border-bg-rule text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Empfohlener Weg — passwortloser Anmeldelink ins Portal:</strong>
|
||||
Sind Sie die in der Veröffentlichung hinterlegte Kontaktperson (oder haben
|
||||
Zugriff auf deren Postfach), melden Sie sich per Anmeldelink im Portal an —
|
||||
Ihre Mitteilungen werden dort in Ihrem Konto zusammengeführt und Sie geben
|
||||
die zu entfernenden Angaben direkt mit Vorschau an. Der schnellste Weg.
|
||||
</div>
|
||||
<a href="{{ $portalMagicLinkUrl }}"
|
||||
class="inline-flex items-center px-5 py-2.5 bg-brand text-white text-[13px] font-semibold hover:opacity-90">
|
||||
Anmeldelink im Portal anfordern
|
||||
</a>
|
||||
<p>
|
||||
<button type="button" @click="showFallback = true" x-show="!showFallback"
|
||||
class="text-[12.5px] text-ink-2 underline underline-offset-2 hover:text-ink">
|
||||
Ich bin nicht der hinterlegte Pressekontakt oder habe keinen Zugriff auf das Postfach
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{-- ===== Stufe 2c: Persönlichkeitsrechte ===== --}}
|
||||
<div x-cloak x-show="concern === 'personal_rights'" class="space-y-4">
|
||||
<div class="px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Persönlichkeitsrecht:</strong>
|
||||
Wenn diese Mitteilung Ihre Persönlichkeitsrechte verletzt — z. B.
|
||||
durch unwahre Tatsachenbehauptungen oder die Verletzung von Bild- oder
|
||||
Namensrechten —, schildern Sie bitte konkret, welche Inhalte betroffen
|
||||
sind und warum. Für die Eingangsbestätigung mit Vorgangsnummer und
|
||||
Rückfragen benötigen wir Ihre E-Mail-Adresse. Wir prüfen Ihre Anfrage
|
||||
sorgfältig und zeitnah und teilen Ihnen unsere Entscheidung mit
|
||||
Begründung mit; bei berechtigten Beanstandungen wird der Inhalt
|
||||
angepasst, gesperrt oder entfernt. Die Prüfung ist kostenlos.
|
||||
Namensrechten —, prüfen wir Ihre Anfrage sorgfältig und zeitnah und teilen
|
||||
Ihnen unsere Entscheidung mit Begründung mit; bei berechtigten
|
||||
Beanstandungen wird der Inhalt angepasst, gesperrt oder entfernt. Die
|
||||
Prüfung ist kostenlos.
|
||||
</div>
|
||||
<div class="px-4 py-3 border border-bg-rule text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Schnellster Weg — passwortloser Anmeldelink ins Portal:</strong>
|
||||
Sind Sie zugleich die hinterlegte Kontaktperson dieser Veröffentlichung,
|
||||
melden Sie sich per Anmeldelink im Portal an und stoßen die Anpassung
|
||||
direkt in Ihrem Konto an.
|
||||
</div>
|
||||
<a href="{{ $portalMagicLinkUrl }}"
|
||||
class="inline-flex items-center px-5 py-2.5 bg-brand text-white text-[13px] font-semibold hover:opacity-90">
|
||||
Anmeldelink im Portal anfordern
|
||||
</a>
|
||||
<p>
|
||||
<button type="button" @click="showFallback = true" x-show="!showFallback"
|
||||
class="text-[12.5px] text-ink-2 underline underline-offset-2 hover:text-ink">
|
||||
Ich bin nicht der hinterlegte Pressekontakt — Anfrage per Formular stellen
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{-- ===== Stufe 2d: Meldung → direkt zum Formular ===== --}}
|
||||
<div x-cloak x-show="concern === 'report'"
|
||||
class="mb-4 px-4 py-3 border border-bg-rule bg-bg-elev text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Meldung:</strong>
|
||||
Melden Sie diese Pressemitteilung, wenn Sie sie für rechtswidrig halten
|
||||
oder sie Ihre Rechte verletzt — z. B. unwahre Tatsachenbehauptungen,
|
||||
Urheberrechts- oder Markenverletzungen, irreführende Inhalte oder Spam.
|
||||
Bitte benennen Sie konkret, welche Inhalte betroffen sind und warum.
|
||||
Jede Meldung wird von unserem Team manuell geprüft; die Meldung ist
|
||||
kostenlos. Wenn Sie eine E-Mail-Adresse angeben, erhalten Sie unverzüglich
|
||||
eine Eingangsbestätigung mit Vorgangsnummer und anschließend unsere
|
||||
Entscheidung mit Begründung.
|
||||
</div>
|
||||
|
||||
{{-- ===== Formular: direkt (Meldung) bzw. Fallback (DSGVO/Persönlichkeitsrecht) ===== --}}
|
||||
<form x-cloak x-show="formVisible()" method="POST"
|
||||
action="{{ route('legal-request.store', ['slug' => $release->slug]) }}" class="space-y-5 mt-2">
|
||||
@csrf
|
||||
<input type="hidden" name="type" :value="concern" />
|
||||
|
||||
{{-- Identifizierungs-Hinweis nur im Fallback-Weg (DSGVO/Persönlichkeitsrecht). --}}
|
||||
<div x-cloak x-show="needsFallbackToggle()"
|
||||
class="px-4 py-3 border-l-2 border border-bg-rule text-[12.5px] text-ink-2 leading-relaxed">
|
||||
<strong class="text-ink">Wichtig — persönliche Identifizierung erforderlich:</strong>
|
||||
Da personenbezogene Daten bzw. Persönlichkeitsrechte betroffen sind, müssen
|
||||
wir Ihre Berechtigung prüfen. In der Regel senden wir einen Bestätigungslink
|
||||
an die betroffene Adresse; andernfalls können wir einen geeigneten
|
||||
Identitäts- oder Berechtigungsnachweis verlangen. Sie erhalten unverzüglich
|
||||
eine Eingangsbestätigung mit Vorgangsnummer.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -128,8 +219,6 @@
|
|||
verwirft der Controller die Anfrage still. Die Namen ('website',
|
||||
'homepage') sind bewusst „attraktiv" für Auto-Filler. Zusätzlich greift
|
||||
serverseitig ein Rate-Limit pro IP/PM.
|
||||
Mögliche Erweiterung später: zeitbasierte Falle (signierter Render-
|
||||
Zeitstempel, Ablehnung bei Absenden < 2s) oder Captcha bei Missbrauch.
|
||||
--}}
|
||||
<div class="hidden" aria-hidden="true">
|
||||
<label for="website">Website</label>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@section('meta_description', __('static.pm_report.meta'))
|
||||
|
||||
@section('content')
|
||||
<style>[x-cloak]{display:none!important}</style>
|
||||
<x-web.static-page
|
||||
:eyebrow="__('static.legal.eyebrow')"
|
||||
:title="__('static.pm_report.concerns_title')"
|
||||
|
|
@ -21,7 +22,73 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('melden.pm.anliegen.store') }}" class="space-y-5">
|
||||
@if (($dsgvoPreview ?? null) !== null)
|
||||
{{-- Pflicht-Diff (Spur B): Vorschau der Schwärzung bestätigen, bevor
|
||||
die Anfrage entsteht. Ausführung bleibt beim Admin. --}}
|
||||
@php
|
||||
$fieldLabels = [
|
||||
'title' => __('static.pm_report.dsgvo_field_title'),
|
||||
'subtitle' => __('static.pm_report.dsgvo_field_subtitle'),
|
||||
'text' => __('static.pm_report.dsgvo_field_text'),
|
||||
'boilerplate_override' => __('static.pm_report.dsgvo_field_boilerplate'),
|
||||
'keywords' => __('static.pm_report.dsgvo_field_keywords'),
|
||||
];
|
||||
@endphp
|
||||
<div class="mb-6 border border-bg-rule">
|
||||
<div class="px-4 py-3 bg-bg-elev border-b border-bg-rule">
|
||||
<p class="text-[13px] font-semibold text-ink">{{ __('static.pm_report.dsgvo_preview_title') }}</p>
|
||||
<p class="text-[12.5px] text-ink-2 mt-0.5">
|
||||
{{ trans_choice('static.pm_report.dsgvo_preview_hits', (int) $dsgvoPreview['total_hits'], ['hits' => (int) $dsgvoPreview['total_hits']]) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="px-4 py-3 space-y-4 text-[13px]">
|
||||
@forelse ($dsgvoPreview['fields'] as $field => $meta)
|
||||
<div>
|
||||
<p class="text-[12px] font-semibold text-ink mb-1">
|
||||
{{ $fieldLabels[$field] ?? $field }}
|
||||
<span class="font-normal text-ink-3">· {{ trans_choice('static.pm_report.dsgvo_preview_field_hits', (int) $meta['hits'], ['hits' => (int) $meta['hits']]) }}</span>
|
||||
</p>
|
||||
<p class="text-ink-2 leading-relaxed whitespace-pre-line border-l-2 border-bg-rule pl-3">{{ \Illuminate\Support\Str::limit(trim(strip_tags((string) $meta['after'])), 600) }}</p>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-ink-2">{{ __('static.pm_report.dsgvo_preview_no_text_hits') }}</p>
|
||||
@endforelse
|
||||
|
||||
@if ($dsgvoInput['detach_contacts'])
|
||||
<p class="text-ink-2">✓ {{ __('static.pm_report.dsgvo_preview_contacts') }}</p>
|
||||
@endif
|
||||
@if ($dsgvoInput['remove_images'])
|
||||
<p class="text-ink-2">✓ {{ __('static.pm_report.dsgvo_preview_images') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="px-4 py-3 border-t border-bg-rule bg-bg-elev">
|
||||
<form method="POST" action="{{ route('melden.pm.anliegen.store') }}" class="flex flex-wrap items-center gap-3">
|
||||
@csrf
|
||||
<input type="hidden" name="concern" value="dsgvo" />
|
||||
<input type="hidden" name="confirmed" value="1" />
|
||||
<input type="hidden" name="redaction_terms" value="{{ $dsgvoInput['redaction_terms'] }}" />
|
||||
<input type="hidden" name="detach_contacts" value="{{ $dsgvoInput['detach_contacts'] ? 1 : 0 }}" />
|
||||
<input type="hidden" name="remove_images" value="{{ $dsgvoInput['remove_images'] ? 1 : 0 }}" />
|
||||
<input type="hidden" name="message" value="{{ $dsgvoInput['message'] }}" />
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-5 py-2.5 bg-brand text-white text-[13px] font-semibold hover:opacity-90">
|
||||
{{ __('static.pm_report.dsgvo_preview_confirm') }}
|
||||
</button>
|
||||
<span class="text-[12.5px] text-ink-3">{{ __('static.pm_report.dsgvo_preview_edit_hint') }}</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@php
|
||||
$initialConcern = old('concern', isset($dsgvoInput) ? 'dsgvo' : '');
|
||||
$prefilledTerms = old('redaction_terms', $dsgvoInput['redaction_terms'] ?? '');
|
||||
$prefilledMessage = old('message', $dsgvoInput['message'] ?? '');
|
||||
$prefilledDetach = old('detach_contacts', ($dsgvoInput['detach_contacts'] ?? false) ? '1' : null);
|
||||
$prefilledRemoveImages = old('remove_images', ($dsgvoInput['remove_images'] ?? false) ? '1' : null);
|
||||
@endphp
|
||||
<form method="POST" action="{{ route('melden.pm.anliegen.store') }}" class="space-y-5"
|
||||
x-data="{ concern: '{{ $initialConcern }}' }">
|
||||
@csrf
|
||||
|
||||
<fieldset>
|
||||
|
|
@ -35,7 +102,8 @@
|
|||
] as $value => $track)
|
||||
<label class="flex items-start gap-3 border border-bg-rule px-3 py-2.5 cursor-pointer hover:bg-bg-elev">
|
||||
<input type="radio" name="concern" value="{{ $value }}" required class="mt-0.5"
|
||||
@checked(old('concern') === $value) />
|
||||
x-model="concern"
|
||||
@checked($initialConcern === $value) />
|
||||
<span class="text-[13px] text-ink">
|
||||
<span class="font-semibold">{{ $track['label'] }}</span>
|
||||
<span class="text-ink-3">· {{ $track['cost'] }}</span>
|
||||
|
|
@ -49,11 +117,35 @@
|
|||
@enderror
|
||||
</fieldset>
|
||||
|
||||
{{-- Spur B (Phase 5): strukturierter Schwärzungsauftrag statt nur Freitext.
|
||||
Wording bewusst „Schwärzung/Entfernung", nicht „Anonymisierung". --}}
|
||||
<div x-cloak x-show="concern === 'dsgvo'" class="space-y-4 border border-bg-rule bg-bg-elev px-4 py-4">
|
||||
<div>
|
||||
<label for="redaction_terms" class="block text-[12px] font-semibold text-ink mb-1.5">{{ __('static.pm_report.dsgvo_terms_label') }}</label>
|
||||
<textarea id="redaction_terms" name="redaction_terms" rows="4" maxlength="2000"
|
||||
placeholder="{{ __('static.pm_report.dsgvo_terms_placeholder') }}"
|
||||
class="w-full border border-bg-rule px-3 py-2.5 text-[13px] bg-white text-ink focus:outline-none focus:border-brand">{{ $prefilledTerms }}</textarea>
|
||||
<p class="mt-1 text-[12px] text-ink-3">{{ __('static.pm_report.dsgvo_terms_hint') }}</p>
|
||||
@error('redaction_terms')
|
||||
<p class="mt-1 text-[12px] text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<label class="flex items-start gap-2.5 text-[13px] text-ink cursor-pointer">
|
||||
<input type="checkbox" name="detach_contacts" value="1" class="mt-0.5" @checked($prefilledDetach) />
|
||||
<span>{{ __('static.pm_report.dsgvo_detach_contacts') }}</span>
|
||||
</label>
|
||||
<label class="flex items-start gap-2.5 text-[13px] text-ink cursor-pointer">
|
||||
<input type="checkbox" name="remove_images" value="1" class="mt-0.5" @checked($prefilledRemoveImages) />
|
||||
<span>{{ __('static.pm_report.dsgvo_remove_images') }}</span>
|
||||
</label>
|
||||
<p class="text-[12px] text-ink-3 leading-relaxed">{{ __('static.pm_report.dsgvo_note') }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="message" class="block text-[12px] font-semibold text-ink mb-1.5">{{ __('static.pm_report.label_message') }}</label>
|
||||
<textarea id="message" name="message" rows="6" required minlength="10" maxlength="5000"
|
||||
placeholder="{{ __('static.pm_report.placeholder_message') }}"
|
||||
class="w-full border border-bg-rule px-3 py-2.5 text-[13px] bg-white text-ink focus:outline-none focus:border-brand">{{ old('message') }}</textarea>
|
||||
class="w-full border border-bg-rule px-3 py-2.5 text-[13px] bg-white text-ink focus:outline-none focus:border-brand">{{ $prefilledMessage }}</textarea>
|
||||
@error('message')
|
||||
<p class="mt-1 text-[12px] text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
|
|
@ -65,7 +157,8 @@
|
|||
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-5 py-2.5 bg-brand text-white text-[13px] font-semibold hover:opacity-90">
|
||||
{{ __('static.pm_report.concern_submit') }}
|
||||
<span x-show="concern === 'dsgvo'" x-cloak>{{ __('static.pm_report.dsgvo_preview_button') }}</span>
|
||||
<span x-show="concern !== 'dsgvo'">{{ __('static.pm_report.concern_submit') }}</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
<div>
|
||||
<label for="reported_url" class="block text-[12px] font-semibold text-ink mb-1.5">{{ __('static.report_form.label_url') }}</label>
|
||||
<input id="reported_url" type="url" name="reported_url" value="{{ old('reported_url') }}" required
|
||||
<input id="reported_url" type="url" name="reported_url" value="{{ old('reported_url', request('reported_url')) }}" required
|
||||
placeholder="https://…"
|
||||
class="w-full border border-bg-rule px-3 py-2.5 text-[13px] bg-white text-ink focus:outline-none focus:border-brand" />
|
||||
@error('reported_url')
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@
|
|||
|
||||
$contact = $release->contacts->first();
|
||||
$contactName = $contact ? trim(implode(' ', array_filter([$contact->title, $contact->first_name, $contact->last_name]))) : null;
|
||||
// Legacy-Bestände ohne Kontakt-Datensatz: der Block erscheint trotzdem,
|
||||
// solange die Firma erreichbare Angaben hat (wie im Altsystem).
|
||||
$contactEmail = $contact?->email ?: $company?->email;
|
||||
$hasContactBlock = $contact || filled($contactEmail) || filled($company?->address) || filled($company?->website);
|
||||
|
||||
// Attributions-Zeile wie im Legacy-System: Urheber (Firma der PM) und
|
||||
// Übermittler (Profilfeld agency_name des einliefernden Accounts, z. B.
|
||||
|
|
@ -440,8 +444,8 @@
|
|||
<x-web.ad-slot variant="inline" />
|
||||
@endunless
|
||||
|
||||
{{-- Pressekontakt --}}
|
||||
@if ($contact)
|
||||
{{-- Pressekontakt (Fallback ohne Kontakt-Datensatz: Firmendaten) --}}
|
||||
@if ($hasContactBlock)
|
||||
<div class="mt-8 px-5 sm:px-7 py-6 bg-white border border-bg-rule-strong max-w-[680px]">
|
||||
<div class="eyebrow mb-3 text-[10.5px]">{{ __('web.detail.press_contact') }}</div>
|
||||
|
||||
|
|
@ -456,9 +460,9 @@
|
|||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@if ($contact->responsibility || $companyName)
|
||||
@if ($contact?->responsibility || $companyName)
|
||||
<div class="text-[12.5px] text-ink-3 mb-3.5 leading-[1.5]">
|
||||
@if ($contact->responsibility){{ $contact->responsibility }}<br />@endif
|
||||
@if ($contact?->responsibility){{ $contact->responsibility }}<br />@endif
|
||||
{{ $companyName }}
|
||||
</div>
|
||||
@endif
|
||||
|
|
@ -470,16 +474,16 @@
|
|||
<span class="text-ink-2">{{ $company->address }}</span>
|
||||
</span>
|
||||
@endif
|
||||
@if ($contact->phone)
|
||||
@if ($contact?->phone)
|
||||
<span class="flex items-center gap-2">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" class="text-ink-3 flex-shrink-0" aria-hidden="true"><path d="M2 3l3-1 1.5 3-1.5 1c.5 2 2 3.5 4 4l1-1.5L13 10l-1 3c-5 0-10-5-10-10z" fill="currentColor" /></svg>
|
||||
<a href="tel:{{ preg_replace('/[^0-9+]/', '', $contact->phone) }}" class="text-ink-2 hover:text-ink transition-colors">{{ $contact->phone }}</a>
|
||||
</span>
|
||||
@endif
|
||||
@if ($contact->email)
|
||||
@if ($contactEmail)
|
||||
<span class="flex items-center gap-2">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" class="text-ink-3 flex-shrink-0" aria-hidden="true"><path d="M1 3h12v8H1zM1 3l6 4 6-4" stroke="currentColor" stroke-width="1.2" fill="none" /></svg>
|
||||
<a href="mailto:{{ $contact->email }}" class="text-ink underline underline-offset-2 hover:text-brand transition-colors">{{ $contact->email }}</a>
|
||||
<a href="mailto:{{ $contactEmail }}" class="text-ink underline underline-offset-2 hover:text-brand transition-colors">{{ $contactEmail }}</a>
|
||||
</span>
|
||||
@endif
|
||||
@if ($company?->website)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue