E-Mail-Praeferenzen: Opt-out je Mail-Typ + One-Click-Unsubscribe ohne Login
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
484e062264
commit
d5b806443e
21 changed files with 746 additions and 9 deletions
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\EmailNotificationType;
|
||||
use App\Enums\VatIdCheckStatus;
|
||||
use App\Models\User;
|
||||
use App\Services\Billing\VatIdValidationService;
|
||||
|
|
@ -60,6 +61,15 @@ new #[Layout('components.layouts.app'), Title('Mein Profil')] class extends Comp
|
|||
|
||||
public ?string $vatCheckMessage = null;
|
||||
|
||||
/**
|
||||
* E-Mail-Benachrichtigungs-Präferenzen: Enum-Value => aktiviert?
|
||||
* Spiegel der Opt-out-Tabelle (email_notification_opt_outs) — vor jedem
|
||||
* Versand prüft das System, ob der Typ abbestellt wurde.
|
||||
*
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
public array $emailNotifications = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
|
@ -103,6 +113,12 @@ new #[Layout('components.layouts.app'), Title('Mein Profil')] class extends Comp
|
|||
if (filled($this->taxIdNumber)) {
|
||||
$this->refreshVatCheck();
|
||||
}
|
||||
|
||||
$optedOutTypes = $user->emailNotificationOptOuts()->pluck('type')->all();
|
||||
|
||||
foreach (EmailNotificationType::cases() as $notificationType) {
|
||||
$this->emailNotifications[$notificationType->value] = ! in_array($notificationType->value, $optedOutTypes, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -254,6 +270,14 @@ new #[Layout('components.layouts.app'), Title('Mein Profil')] class extends Comp
|
|||
);
|
||||
}
|
||||
|
||||
foreach (EmailNotificationType::cases() as $notificationType) {
|
||||
if ($this->emailNotifications[$notificationType->value] ?? true) {
|
||||
$user->optIntoEmailNotification($notificationType);
|
||||
} else {
|
||||
$user->optOutOfEmailNotification($notificationType);
|
||||
}
|
||||
}
|
||||
|
||||
// Fokus-Fix: Nach dem Speichern soll kein Eingabefeld den Fokus
|
||||
// erhalten (Browser/Autofill springen sonst auf das erste Feld).
|
||||
$this->dispatch('profile-saved');
|
||||
|
|
@ -522,7 +546,34 @@ new #[Layout('components.layouts.app'), Title('Mein Profil')] class extends Comp
|
|||
</div>
|
||||
</article>
|
||||
|
||||
{{-- ============== 4) EINSTELLUNGEN ============== --}}
|
||||
{{-- ============== 4) E-MAIL-BENACHRICHTIGUNGEN ============== --}}
|
||||
<article class="panel" id="e-mail-benachrichtigungen">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('E-Mail-Benachrichtigungen') }}</span>
|
||||
</div>
|
||||
<div class="p-5 space-y-4">
|
||||
<p class="text-[12.5px] leading-[1.55] text-[color:var(--color-ink-3)] m-0 max-w-[680px]">
|
||||
{{ __('Welche Benachrichtigungs-E-Mails möchten Sie erhalten? System-E-Mails wie Passwort-Zurücksetzen oder rechtlich erforderliche Bestätigungen sind hiervon ausgenommen und werden immer zugestellt.') }}
|
||||
</p>
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
@foreach (\App\Enums\EmailNotificationType::cases() as $notificationType)
|
||||
<flux:switch
|
||||
wire:model="emailNotifications.{{ $notificationType->value }}"
|
||||
align="right"
|
||||
:label="$notificationType->label()"
|
||||
:description="$notificationType->settingsDescription()"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-5 py-4 border-t border-[color:var(--color-bg-rule)] flex justify-end">
|
||||
<flux:button type="submit" variant="primary">
|
||||
{{ __('Speichern') }}
|
||||
</flux:button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{{-- ============== 5) EINSTELLUNGEN ============== --}}
|
||||
<article class="panel">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('Einstellungen') }}</span>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue