Skip to content

Commit 3db7116

Browse files
simonhampclaude
andcommitted
Add notification email opt-in with branded email templates
- Add receives_notification_emails column to users table - Add SuppressMailNotificationListener to respect user email preferences - Publish and customize mail templates with NativePHP branding (PNG logo) - Update all notifications to support database channel - Add settings UI for toggling notification emails - Remove TestNotification and SendTestEmail command - Add tests for suppression listener and settings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e77aa06 commit 3db7116

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+967
-151
lines changed

app/Console/Commands/SendTestEmail.php

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace App\Listeners;
4+
5+
use App\Models\User;
6+
use Illuminate\Notifications\Events\NotificationSending;
7+
8+
class SuppressMailNotificationListener
9+
{
10+
public function handle(NotificationSending $event): bool
11+
{
12+
if ($event->channel !== 'mail') {
13+
return true;
14+
}
15+
16+
if (! $event->notifiable instanceof User) {
17+
return true;
18+
}
19+
20+
return $event->notifiable->receives_notification_emails;
21+
}
22+
}

app/Livewire/Customer/Settings.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
use Illuminate\Support\Facades\Hash;
77
use Livewire\Attributes\Layout;
88
use Livewire\Attributes\Title;
9+
use Livewire\Attributes\Url;
910
use Livewire\Component;
1011

1112
#[Layout('components.layouts.dashboard')]
1213
#[Title('Settings')]
1314
class Settings extends Component
1415
{
16+
#[Url]
17+
public string $tab = 'account';
18+
1519
public string $name = '';
1620

1721
public string $currentPassword = '';
@@ -22,9 +26,17 @@ class Settings extends Component
2226

2327
public string $deleteConfirmPassword = '';
2428

29+
public bool $receivesNotificationEmails = true;
30+
2531
public function mount(): void
2632
{
2733
$this->name = auth()->user()->name ?? '';
34+
$this->receivesNotificationEmails = auth()->user()->receives_notification_emails;
35+
}
36+
37+
public function updatedReceivesNotificationEmails(bool $value): void
38+
{
39+
auth()->user()->update(['receives_notification_emails' => $value]);
2840
}
2941

3042
public function updateName(): void

app/Models/User.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ protected function casts(): array
358358
return [
359359
'email_verified_at' => 'datetime',
360360
'password' => 'hashed',
361+
'receives_notification_emails' => 'boolean',
361362
'mobile_repo_access_granted_at' => 'datetime',
362363
'claude_plugins_repo_access_granted_at' => 'datetime',
363364
'discord_role_granted_at' => 'datetime',

app/Notifications/BundleGranted.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function __construct(
2727
*/
2828
public function via(object $notifiable): array
2929
{
30-
return ['mail'];
30+
return ['mail', 'database'];
3131
}
3232

3333
public function toMail(object $notifiable): MailMessage
@@ -53,6 +53,8 @@ public function toMail(object $notifiable): MailMessage
5353
public function toArray(object $notifiable): array
5454
{
5555
return [
56+
'title' => "You've been granted the {$this->bundle->name} bundle!",
57+
'body' => "You now have access to {$this->grantedPlugins->count()} plugins in the {$this->bundle->name} bundle.",
5658
'bundle_id' => $this->bundle->id,
5759
'bundle_name' => $this->bundle->name,
5860
'granted_plugin_ids' => $this->grantedPlugins->pluck('id')->toArray(),

app/Notifications/BundlePluginAdded.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function __construct(
2323
*/
2424
public function via(object $notifiable): array
2525
{
26-
return ['mail'];
26+
return ['mail', 'database'];
2727
}
2828

2929
public function toMail(object $notifiable): MailMessage
@@ -48,6 +48,8 @@ public function toMail(object $notifiable): MailMessage
4848
public function toArray(object $notifiable): array
4949
{
5050
return [
51+
'title' => "New plugin added to your {$this->bundle->name} bundle!",
52+
'body' => "{$this->plugin->name} has been added to your bundle — it's yours for free.",
5153
'plugin_id' => $this->plugin->id,
5254
'plugin_name' => $this->plugin->name,
5355
'bundle_id' => $this->bundle->id,

app/Notifications/LegacyLicenseThankYou.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,20 @@ public function __construct(
1818

1919
public function via($notifiable): array
2020
{
21-
return ['mail'];
21+
return ['mail', 'database'];
22+
}
23+
24+
/**
25+
* @return array<string, mixed>
26+
*/
27+
public function toArray($notifiable): array
28+
{
29+
return [
30+
'title' => 'Thank You for Making NativePHP Mobile Free',
31+
'body' => 'NativePHP for Mobile is now free for everyone — thanks to early supporters like you.',
32+
'license_id' => $this->license->id,
33+
'license_key' => $this->license->key,
34+
];
2235
}
2336

2437
public function toMail($notifiable): MailMessage

app/Notifications/LicenseExpiryWarning.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function __construct(
1919

2020
public function via($notifiable): array
2121
{
22-
return ['mail'];
22+
return ['mail', 'database'];
2323
}
2424

2525
public function toMail($notifiable): MailMessage
@@ -43,6 +43,20 @@ public function toMail($notifiable): MailMessage
4343
->salutation("Best regards,\nThe NativePHP Team");
4444
}
4545

46+
/**
47+
* @return array<string, mixed>
48+
*/
49+
public function toArray($notifiable): array
50+
{
51+
return [
52+
'title' => $this->getSubject(),
53+
'body' => $this->getMainMessage(),
54+
'license_id' => $this->license->id,
55+
'license_key' => $this->license->key,
56+
'days_until_expiry' => $this->daysUntilExpiry,
57+
];
58+
}
59+
4660
private function getSubject(): string
4761
{
4862
return match ($this->daysUntilExpiry) {

app/Notifications/LicenseKeyGenerated.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function __construct(
2525
*/
2626
public function via(object $notifiable): array
2727
{
28-
return ['mail'];
28+
return ['mail', 'database'];
2929
}
3030

3131
public function toMail(object $notifiable): MailMessage
@@ -58,6 +58,8 @@ public function toMail(object $notifiable): MailMessage
5858
public function toArray(object $notifiable): array
5959
{
6060
return [
61+
'title' => 'Your NativePHP License Key',
62+
'body' => 'Your license key has been generated and is ready to use.',
6163
'license_key' => $this->licenseKey,
6264
'firstName' => $this->firstName,
6365
];

app/Notifications/PluginApproved.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function __construct(
2323
*/
2424
public function via(object $notifiable): array
2525
{
26-
return ['mail'];
26+
return ['mail', 'database'];
2727
}
2828

2929
/**
@@ -47,6 +47,8 @@ public function toMail(object $notifiable): MailMessage
4747
public function toArray(object $notifiable): array
4848
{
4949
return [
50+
'title' => 'Your Plugin Has Been Approved!',
51+
'body' => "{$this->plugin->name} is now listed in the NativePHP Plugin Directory.",
5052
'plugin_id' => $this->plugin->id,
5153
'plugin_name' => $this->plugin->name,
5254
];

0 commit comments

Comments
 (0)