syncScheduledAt(); if ($this->publishMode === 'now') { $this->scheduledDate = null; $this->scheduledTime = null; $this->scheduledAt = null; $this->resetErrorBag(['scheduledDate', 'scheduledTime', 'scheduledAt']); } } public function updatedScheduledDate(): void { $this->syncScheduledAt(); $this->validateScheduledAtWhenReady(); } public function updatedScheduledTime(): void { $this->syncScheduledAt(); $this->validateScheduledAtWhenReady(); } /** * Live-Re-Validation: sobald für ein Property bereits ein Error im Bag * liegt, wird es bei jeder Änderung neu geprüft. Die Termin-Synchronisierung * liegt vollständig in den spezifischen `updated{PublishMode,ScheduledDate, * ScheduledTime}`-Hooks; hier bleibt nur die generische Re-Validierung. */ public function updated(string $property): void { if (! $this->getErrorBag()->has($property)) { return; } try { $this->validateOnly($property, $this->formRules()); } catch (ValidationException) { // Feld bleibt invalid — Error-Bag wird automatisch befüllt. } } protected function syncScheduledAt(): void { if ($this->publishMode !== 'scheduled') { $this->scheduledAt = null; return; } if (blank($this->scheduledDate) && blank($this->scheduledTime) && filled($this->scheduledAt)) { $scheduledAt = Carbon::parse($this->scheduledAt); $this->scheduledDate = $scheduledAt->format('Y-m-d'); $this->scheduledTime = $scheduledAt->format('H:i'); return; } if (blank($this->scheduledDate) || blank($this->scheduledTime)) { $this->scheduledAt = null; return; } $this->scheduledAt = "{$this->scheduledDate}T{$this->scheduledTime}"; } /** * Parst den erfassten Termin in der Anwendungs-Zeitzone (Europe/Berlin). * Null, wenn kein Termin gesetzt ist. */ protected function resolveScheduledAt(): ?Carbon { if (blank($this->scheduledAt)) { return null; } return Carbon::parse($this->scheduledAt); } protected function validateScheduledAtWhenReady(): void { if (blank($this->scheduledAt)) { return; } $this->resetErrorBag('scheduledAt'); $scheduledAt = $this->resolveScheduledAt(); if ($scheduledAt === null || $scheduledAt->lessThanOrEqualTo(now()->addMinutes(5))) { $this->addError('scheduledAt', __('Der Veröffentlichungstermin muss mindestens 5 Minuten in der Zukunft liegen.')); return; } try { $this->validateOnly('scheduledAt', $this->formRules()); } catch (ValidationException) { // Termin bleibt invalid — Error-Bag wird automatisch befüllt. } } /** * Toast mit Sammelhinweis nach fehlgeschlagener Validierung. Nennt die * betroffenen Felder beim Namen (aus validation.attributes), damit der * User nicht raten muss, wo es hakt. Die einzelnen Feld-Errors werden * weiterhin direkt am Input angezeigt, zusätzlich rendert * [[x-portal.pr-error-summary]] eine persistente Übersicht im Formular. */ protected function notifyValidationError(?ValidationException $exception = null): void { $fieldKeys = $exception ? array_keys($exception->errors()) : $this->getErrorBag()->keys(); $fieldLabels = collect($fieldKeys) ->map(fn (string $key): string => trans()->has('validation.attributes.'.$key) ? __('validation.attributes.'.$key) : $key) ->unique() ->values(); Flux::toast( heading: __('Bitte Eingaben prüfen'), text: $fieldLabels->isNotEmpty() ? __('Bitte prüfe: :fields', ['fields' => $fieldLabels->join(', ')]) : __('Ein Feld benötigt deine Aufmerksamkeit.'), variant: 'danger', duration: 8000, ); } }