presseportale/resources/views/web/melden-pm-anliegen.blade.php
Kevin Adametz 9afbedddeb 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>
2026-07-23 13:02:57 +00:00

166 lines
11 KiB
PHP

@extends('web.layouts.web-master')
@section('title', __('static.pm_report.concerns_title'))
@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')"
:breadcrumb="__('static.pm_report.breadcrumb')"
>
<div class="max-w-[640px]">
<div class="mb-6 px-4 py-3 border border-bg-rule bg-bg-elev text-[13px] text-ink-2">
<p class="font-semibold text-ink mb-1">{{ $pressRelease->title }}</p>
<p>{{ __('static.pm_report.verified_as', ['email' => $contactEmail]) }}</p>
</div>
@if (session('pm-report-status'))
<div class="mb-6 px-4 py-3 border border-bg-rule bg-bg-elev text-[13px] text-ink-2" role="status">
{{ session('pm-report-status') }}
</div>
@endif
@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>
<legend class="block text-[12px] font-semibold text-ink mb-2">{{ __('static.pm_report.concern_legend') }}</legend>
<div class="space-y-2">
@foreach ([
'correction' => ['label' => __('static.pm_report.track_correction'), 'desc' => __('static.pm_report.track_correction_desc'), 'cost' => __('static.pm_report.cost_free')],
'dsgvo' => ['label' => __('static.pm_report.track_dsgvo'), 'desc' => __('static.pm_report.track_dsgvo_desc'), 'cost' => __('static.pm_report.cost_free')],
'depublication' => ['label' => __('static.pm_report.track_depublication'), 'desc' => __('static.pm_report.track_depublication_desc'), 'cost' => '35 €'],
'change' => ['label' => __('static.pm_report.track_change'), 'desc' => __('static.pm_report.track_change_desc'), 'cost' => '10 €'],
] 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"
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>
<span class="block text-[12.5px] text-ink-2">{{ $track['desc'] }}</span>
</span>
</label>
@endforeach
</div>
@error('concern')
<p class="mt-1 text-[12px] text-red-600">{{ $message }}</p>
@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">{{ $prefilledMessage }}</textarea>
@error('message')
<p class="mt-1 text-[12px] text-red-600">{{ $message }}</p>
@enderror
</div>
<p class="text-[12.5px] text-ink-3 leading-relaxed">
{{ __('static.pm_report.concern_note') }}
</p>
<button type="submit"
class="inline-flex items-center px-5 py-2.5 bg-brand text-white text-[13px] font-semibold hover:opacity-90">
<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>
</x-web.static-page>
@endsection