Notification Resources
Drei Resources für das Benachrichtigungssystem:
- NotificationResource: Gesendete Benachrichtigungen anzeigen
- NotificationTemplateResource: Templates verwalten
- EmailTemplateResource: E-Mail-Templates verwalten
NotificationResource
File: NotificationResource.php
Zeigt alle gesendeten Datenbank-Benachrichtigungen (Read-Only mit Statusänderung).
Konfiguration
| Eigenschaft | Wert |
|---|---|
| Model | Illuminate\Notifications\DatabaseNotification |
| Navigation Group | Kommunikation |
| Navigation Label | Benachrichtigungen |
| Navigation Icon | heroicon-o-bell |
| Navigation Sort | 10 |
| Polling Interval | 30 Sekunden |
Navigation Badge
public static function getNavigationBadge(): ?string
{
return static::getModel()::query()
->whereNull('read_at')
->count();
}
Berechtigungen
public static function canCreate(): bool
{
return false; // Benachrichtigungen werden programmatisch erstellt
}
Table-Spalten
| Spalte | Typ | Beschreibung |
|---|---|---|
| notifiable_name | TextColumn | Empfänger-Name |
| type | BadgeColumn | Benachrichtigungstyp mit Farben |
| data | TextColumn | Titel/Betreff aus JSON |
| read_at | BadgeColumn | "Gelesen" oder "Ungelesen" |
| created_at | TextColumn | Erstellungsdatum |
Notification-Typen
| Typ | Label | Farbe |
|---|---|---|
| OrderAcceptedOrRejected | Auftrag angenommen/abgelehnt | success |
| NewOrderAvailable | Neuer Auftrag | info |
| OrderCompleted | Auftrag abgeschlossen | success |
| InvoiceGenerated | Rechnung erstellt | primary |
| UpcomingAppointment | Terminerinnerung | warning |
| PaymentReminder | Zahlungserinnerung | warning |
| InvoiceRejected | Rechnung abgelehnt | danger |
| OrderCancelled | Auftrag storniert | danger |
| BillingStatusChanged | Abrechnungsstatus geändert | info |
Actions
Action::make('mark_as_read')
->label('Als gelesen markieren')
->icon('heroicon-o-check')
->action(fn ($record) => $record->update(['read_at' => now()]))
->visible(fn ($record) => $record->read_at === null)
Action::make('mark_as_unread')
->label('Als ungelesen markieren')
->icon('heroicon-o-eye-slash')
->action(fn ($record) => $record->update(['read_at' => null]))
->visible(fn ($record) => $record->read_at !== null)
Bulk Actions
- mark_as_read: Mehrere als gelesen markieren
- mark_as_unread: Mehrere als ungelesen markieren
- delete: Löschen
NotificationTemplateResource
File: NotificationTemplateResource.php
Verwaltet Benachrichtigungs-Templates für alle Kanäle.
Konfiguration
| Eigenschaft | Wert |
|---|---|
| Model | App\Models\NotificationTemplate |
| Navigation Group | Kommunikation |
| Navigation Label | Benachrichtigungs-Templates |
| Navigation Icon | heroicon-o-envelope |
| Navigation Sort | 11 |
Navigation Badge
public static function getNavigationBadge(): ?string
{
return static::getModel()::query()
->where('is_active', false)
->count();
}
public static function getNavigationBadgeColor(): ?string
{
return 'warning';
}
Form-Struktur
Basis-Daten
| Feld | Typ | Beschreibung |
|---|---|---|
| notification_type | Select | Aus verfügbaren Typen |
| target_role_id | Select | Ziel-Rolle (admin/requester/interpreter) |
| channel | Select | mail/database/push |
| locale | Select | de/en |
| name | TextInput | Template-Name |
| description | Textarea | Beschreibung |
| is_active | Toggle | Aktiv/Inaktiv |
Kanal-spezifische Felder
| Kanal | Felder |
|---|---|
| subject, content_template (MarkdownEditor) | |
| database | title, content_template (Textarea) |
| push | title, content_template (Textarea, max 200 chars) |
Dynamische Variablen
Das Formular zeigt verfügbare Variablen basierend auf dem gewählten Notification-Typ:
Forms\Components\Placeholder::make('available_variables')
->label('Verfügbare Variablen')
->content(function (Get $get) {
$type = $get('notification_type');
if (!$type) return 'Wählen Sie zuerst einen Benachrichtigungstyp';
$notification = $this->createDummyNotificationInstance($type);
if (!$notification) return 'Keine Variablen verfügbar';
$variables = $notification->getAvailableVariables();
return implode(', ', array_map(fn ($v) => "{{ $v }}", $variables));
})
Verfügbare Notification-Typen
NotificationTemplate::getAvailableNotificationTypes()
// Beispiel-Output:
[
'App\Notifications\OrderAcceptedOrRejected' => 'Auftrag angenommen/abgelehnt',
'App\Notifications\NewOrderAvailable' => 'Neuer Auftrag verfügbar',
'App\Notifications\UrgentOrderAvailable' => 'Dringender Auftrag verfügbar',
'App\Notifications\OrderCompleted' => 'Auftrag abgeschlossen',
'App\Notifications\InvoiceGenerated' => 'Rechnung erstellt',
// ...
]
Test-Actions
test_template
Rendert das Template mit Testdaten und sendet (bei Mail) oder zeigt Vorschau:
Action::make('test_template')
->label('Template testen')
->icon('heroicon-o-play')
->form([
Forms\Components\Select::make('test_user_id')
->label('Test-Empfänger')
->options(User::pluck('email', 'id'))
->required(),
])
->action(function (NotificationTemplate $record, array $data) {
$testVariables = $this->getTestVariables($record->notification_type);
$renderedContent = $this->renderTemplate($record->content_template, $testVariables);
if ($record->channel === 'mail') {
// Echte E-Mail senden
Mail::to(User::find($data['test_user_id']))
->send(new TemplateTestMail($record, $renderedContent));
Notification::make()
->success()
->title('Test-E-Mail gesendet')
->send();
} else {
// Vorschau anzeigen
Notification::make()
->title('Template-Vorschau')
->body($renderedContent)
->persistent()
->send();
}
})
test_push_notification
Sendet eine echte Push-Notification an einen Sprachmittler:
Action::make('test_push_notification')
->label('Push-Notification testen')
->icon('heroicon-o-device-phone-mobile')
->visible(fn ($record) => $record->channel === 'push')
->form([
Forms\Components\Select::make('interpreter_id')
->label('Sprachmittler')
->options(
User::interpreters()
->whereHas('devices')
->pluck('full_name', 'id')
)
->required(),
])
->action(function (NotificationTemplate $record, array $data) {
$interpreter = User::find($data['interpreter_id']);
$testVariables = $this->getTestVariables($record->notification_type);
OneSignal::sendNotificationToUser(
$interpreter->player_id,
$this->renderTemplate($record->title, $testVariables),
$this->renderTemplate($record->content_template, $testVariables)
);
Notification::make()
->success()
->title('Push-Notification gesendet')
->body("An: {$interpreter->full_name}")
->send();
})
Bulk Actions
- activate: Templates aktivieren
- deactivate: Templates deaktivieren
- delete: Templates löschen
EmailTemplateResource
File: EmailTemplateResource.php
Verwaltet allgemeine E-Mail-Templates (nicht Notification-spezifisch).
Konfiguration
| Eigenschaft | Wert |
|---|---|
| Model | App\Models\EmailTemplate |
| Navigation Group | Kommunikation |
| Navigation Label | E-Mail-Templates |
| Navigation Icon | heroicon-o-envelope |
| Navigation Sort | 12 |
Form-Struktur
Basis-Informationen
| Feld | Typ | Beschreibung |
|---|---|---|
| name | TextInput | Template-Name |
| type | Select | Typ (siehe unten) |
| language | Select | de/en/fr/es |
| subject | TextInput | E-Mail-Betreff |
| to | TextInput | Optional: Feste Empfängeradresse |
| version | TextInput | Versionsnummer |
Template-Typen
| Typ | Beschreibung |
|---|---|
| password_reset | Passwort-Zurücksetzung |
| profile_deletion | Profil-Löschung |
| welcome | Willkommens-E-Mail |
| notification | Allgemeine Benachrichtigung |
| invoice | Rechnungs-E-Mail |
| reminder | Erinnerung |
| other | Sonstiges |
Template-Inhalte
| Feld | Typ | Beschreibung |
|---|---|---|
| body_text | Textarea | Plain-Text Version |
| body_html | RichEditor | HTML Version (WYSIWYG) |
| body_html_raw | Textarea | Raw HTML (monospace) |
| show_html_editor | Toggle | Editor-Auswahl |
Forms\Components\Toggle::make('show_html_editor')
->label('WYSIWYG-Editor verwenden')
->default(true)
->live()
Forms\Components\RichEditor::make('body_html')
->visible(fn (Get $get) => $get('show_html_editor'))
Forms\Components\Textarea::make('body_html_raw')
->visible(fn (Get $get) => !$get('show_html_editor'))
->extraAttributes(['class' => 'font-mono'])
Variablen & Einstellungen
| Feld | Typ | Beschreibung |
|---|---|---|
| variables | KeyValue | Template-Variablen |
| metadata | KeyValue | Metadaten (description, category, tags) |
| is_active | Toggle | Aktiv |
| is_default | Toggle | Standard-Template für diesen Typ |
Table-Spalten
| Spalte | Typ | Formatierung |
|---|---|---|
| name | TextColumn | - |
| type | BadgeColumn | Farbcodiert |
| language | BadgeColumn | de=info, en=success, etc. |
| subject | TextColumn | - |
| to | TextColumn | Oder "Standard" |
| is_active | IconColumn | ✓/✗ |
| is_default | IconColumn | ⭐ |
| version | BadgeColumn | - |
Type-Farben
Tables\Columns\TextColumn::make('type')
->badge()
->color(fn (string $state) => match ($state) {
'password_reset' => 'danger',
'welcome' => 'success',
'invoice' => 'primary',
'reminder' => 'warning',
'notification' => 'info',
default => 'gray',
})
Test-Action
Action::make('test_template')
->label('Test-E-Mail senden')
->icon('heroicon-o-paper-airplane')
->form([
Forms\Components\TextInput::make('test_email')
->label('Empfänger')
->email()
->required()
->default(fn () => auth()->user()->email),
])
->action(function (EmailTemplate $record, array $data) {
$testVariables = $this->getTestVariables();
Mail::to($data['test_email'])->send(
new TemplateMail($record, $testVariables)
);
Notification::make()
->success()
->title('Test-E-Mail gesendet')
->body("An: {$data['test_email']}")
->send();
})
NotificationPreferenceResource
File: NotificationPreferenceResource.php
Diese Resource ist in der Navigation versteckt (shouldRegisterNavigation = false) und wird primär über den UserResource RelationManager verwendet.
Konfiguration
| Eigenschaft | Wert |
|---|---|
| Model | App\Models\NotificationPreference |
| Navigation | Hidden |
Table mit Toggle-Columns
Tables\Columns\ToggleColumn::make('email_enabled')
->label('E-Mail')
->onColor('success')
->offColor('danger')
Tables\Columns\ToggleColumn::make('push_enabled')
->label('Push')
->onColor('success')
->offColor('danger')
Tables\Columns\TextColumn::make('database_enabled')
->label('In-App')
->badge()
->state('Immer aktiv')
->color('gray')
Reset-Action
Action::make('reset_to_defaults')
->label('Auf Standard zurücksetzen')
->icon('heroicon-o-arrow-path')
->requiresConfirmation()
->action(function (NotificationPreference $record) {
$defaults = NotificationPreference::getDefaultPreferences($record->user->role);
$record->update($defaults[$record->notification_type] ?? []);
})