b2in/app/Livewire/Web/Components/Ui/ContactForm.php
Kevin Adametz a661a68913 Hotfix: Livewire-UI-Komponenten im Ordner Ui (wie der Namespace)
Der Ordner hieß im Repository UI, der Namespace App\Livewire\Web\Components\Ui. Auf dem
Mac fällt das nicht auf, auf Linux findet der Autoloader die Klassen nicht: Header,
Footer usw. rendern ohne Klasse (500, Undefined variable $logoPath). Wächtertest prüft
Pfad und Namespace auf gleiche Schreibweise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:11:39 +00:00

205 lines
6.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Livewire\Web\Components\Ui;
use Acme\ContactForm\ContactFormService;
use Acme\ContactForm\SpamDetector;
use App\Models\CmsBrand;
use Illuminate\Validation\Rule;
use Livewire\Component;
class ContactForm extends Component
{
public string $firstName = '';
public string $lastName = '';
public string $company = '';
public string $email = '';
public string $phone = '';
public string $subject = '';
public string $message = '';
public bool $privacy = false;
public bool $success = false;
/** @var string Hidden honeypot field */
public string $website = '';
public ?int $formLoadedAt = null;
/** @var array<string, mixed> */
public array $content = [];
/** Farbwelt der Seite (`interior` | `immobilien`). */
public string $world = 'interior';
public function mount(string $world = 'interior'): void
{
$this->world = $world === 'immobilien' ? 'immobilien' : 'interior';
$this->content = $this->loadContent();
$this->formLoadedAt = time();
}
/**
* Inhalte der Welt. Die Immobilien-Welt liegt als Overlay über der Interior-Sektion:
* `contact_form_immobilien` trägt nur, was abweicht (Einstieg, Betreffe) – Adresse,
* Beschriftungen und Social Media erbt sie von `contact_form`.
*
* @return array<string, mixed>
*/
private function loadContent(): array
{
$base = cms_theme_section('contact_form');
$base = is_array($base) ? $base : [];
if ($this->world !== 'immobilien') {
return $base;
}
$overlay = cms_theme_section('contact_form_immobilien');
if (! is_array($overlay)) {
return $base;
}
return array_replace_recursive($base, $overlay);
}
/**
* Betreffe in Gruppen: Interior (mit den gepflegten Kernmarken vorneweg), Immobilien, B2in.
* Die Welt der Seite bestimmt die Reihenfolge – ihre Gruppe steht oben.
*
* Ohne `subject_groups` (aeltere CMS-Staende) faellt das Formular auf die flache Liste zurueck.
*
* @return array<string, array{label: string, subjects: array<string, string>}>
*/
public function getSubjectGroupsProperty(): array
{
$groups = $this->content['form']['subject_groups'] ?? null;
if (! is_array($groups) || $groups === []) {
$flat = $this->content['form']['subjects'] ?? [];
unset($flat['']);
return $flat === [] ? [] : ['all' => ['label' => '', 'subjects' => $flat]];
}
$brands = [];
foreach (CmsBrand::forFrontend() as $slug => $brand) {
$brands[$slug] = (string) ($brand['name'] ?? $slug);
}
$out = [];
foreach ($groups as $key => $group) {
$subjects = is_array($group['subjects'] ?? null) ? $group['subjects'] : [];
if ($key === 'interior') {
$subjects = $brands + $subjects;
}
$out[$key] = [
'label' => (string) ($group['label'] ?? ''),
'subjects' => $subjects,
];
}
$first = $this->world === 'immobilien' ? 'immobilien' : 'interior';
if (isset($out[$first])) {
$out = [$first => $out[$first]] + $out;
}
return $out;
}
/**
* Alle waehlbaren Betreffe als flache Liste (Schluessel → Beschriftung).
*
* @return array<string, string>
*/
public function getSubjectsProperty(): array
{
$flat = [];
foreach ($this->getSubjectGroupsProperty() as $group) {
$flat += $group['subjects'];
}
return $flat;
}
public function getSubjectPlaceholderProperty(): string
{
return (string) ($this->content['form']['subjects'][''] ?? $this->content['form']['subject_placeholder'] ?? __('ui.contact_form.subject_placeholder'));
}
/** @return array<int, array<string, mixed>> */
public function getContactInfoProperty(): array
{
return $this->content['contact_info'] ?? [];
}
public function submit(ContactFormService $service): void
{
$this->validate([
'firstName' => ['required', 'string', 'max:255'],
'lastName' => ['required', 'string', 'max:255'],
'email' => ['required', 'email:rfc', 'max:255'],
'subject' => ['required', 'string', Rule::in(array_keys($this->subjects))],
'message' => ['required', 'string', 'max:2000'],
'company' => ['nullable', 'string', 'max:255'],
'phone' => ['nullable', 'string', 'max:255'],
'privacy' => ['accepted'],
'website' => ['nullable', 'string', 'max:0'],
]);
$spamDetector = SpamDetector::fromConfig();
$payload = [
'first_name' => $this->firstName,
'last_name' => $this->lastName,
'email' => $this->email,
'subject' => $this->subject,
'message' => $this->message,
'company' => $this->company,
'phone' => $this->phone,
'website' => $this->website,
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
'is_spam' => false,
];
$payload['is_spam'] = $spamDetector->detect($payload, $this->formLoadedAt);
$subjectLabel = $this->getSubjectsProperty()[$this->subject] ?? $this->subject;
$prefix = $this->world === 'immobilien' ? 'Kontaktanfrage B2in Immobilien' : 'Kontaktanfrage B2in';
$subjectLine = $subjectLabel
? $prefix.': '.$subjectLabel
: __('contact-form::contact-form.default_subject');
$service->handle($payload, $subjectLine, 'contact-form');
$this->success = true;
$this->firstName = '';
$this->lastName = '';
$this->company = '';
$this->email = '';
$this->phone = '';
$this->subject = '';
$this->message = '';
$this->privacy = false;
$this->website = '';
$this->formLoadedAt = time();
}
public function render(): \Illuminate\View\View
{
return view('livewire.web.components.ui.contact-form');
}
}