Skip to content

Commit b116520

Browse files
simonhampclaude
andcommitted
Add license holder promo, Plugin Dev Kit benefit, and monthly billing option
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 176b0f6 commit b116520

7 files changed

Lines changed: 393 additions & 1 deletion
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Enums\Subscription;
6+
use App\Models\License;
7+
use App\Notifications\UltraLicenseHolderPromotion;
8+
use Illuminate\Console\Command;
9+
10+
class SendUltraLicenseHolderPromotion extends Command
11+
{
12+
protected $signature = 'ultra:send-license-holder-promo
13+
{--dry-run : Show what would be sent without actually sending}';
14+
15+
protected $description = 'Send a promotional email to license holders without an active subscription encouraging them to subscribe to Ultra';
16+
17+
public function handle(): int
18+
{
19+
$dryRun = $this->option('dry-run');
20+
21+
if ($dryRun) {
22+
$this->info('DRY RUN - No emails will be sent');
23+
}
24+
25+
$legacyLicenses = License::query()
26+
->whereNull('subscription_item_id')
27+
->whereHas('user')
28+
->with('user')
29+
->get();
30+
31+
// Group by user to avoid sending multiple emails to the same person
32+
$userLicenses = $legacyLicenses->groupBy('user_id');
33+
34+
$eligible = 0;
35+
$skipped = 0;
36+
37+
foreach ($userLicenses as $userId => $licenses) {
38+
$user = $licenses->first()->user;
39+
40+
if (! $user) {
41+
$skipped++;
42+
43+
continue;
44+
}
45+
46+
// Skip users who already have an active subscription
47+
$hasActiveSubscription = $user->subscriptions()
48+
->where('stripe_status', 'active')
49+
->exists();
50+
51+
if ($hasActiveSubscription) {
52+
$this->line("Skipping {$user->email} - already has active subscription");
53+
$skipped++;
54+
55+
continue;
56+
}
57+
58+
$license = $licenses->sortBy('created_at')->first();
59+
$planName = Subscription::from($license->policy_name)->name();
60+
61+
if ($dryRun) {
62+
$this->line("Would send to: {$user->email} ({$planName})");
63+
} else {
64+
$user->notify(new UltraLicenseHolderPromotion($planName));
65+
$this->line("Sent to: {$user->email} ({$planName})");
66+
}
67+
68+
$eligible++;
69+
}
70+
71+
$this->newLine();
72+
$this->info("Found {$eligible} eligible license holder(s)");
73+
$this->info($dryRun ? "Would send: {$eligible} email(s)" : "Sent: {$eligible} email(s)");
74+
$this->info("Skipped: {$skipped} user(s)");
75+
76+
return Command::SUCCESS;
77+
}
78+
}

app/Notifications/MaxToUltraAnnouncement.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public function toMail($notifiable): MailMessage
2828
->line('Here\'s what you now get as an Ultra subscriber:')
2929
->line('- **Teams** - invite up to 10 collaborators to share your plugin access')
3030
->line('- **Free official plugins** - every NativePHP-published plugin, included with your subscription')
31+
->line('- **Plugin Dev Kit** - tools and resources to build and publish your own plugins')
3132
->line('- **Priority support** - get help faster when you need it')
3233
->line('- **Early access** - be first to try new features and plugins')
3334
->line('- **Exclusive content** - tutorials, guides, and deep dives just for Ultra members')
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace App\Notifications;
4+
5+
use Illuminate\Bus\Queueable;
6+
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Notifications\Messages\MailMessage;
8+
use Illuminate\Notifications\Notification;
9+
10+
class UltraLicenseHolderPromotion extends Notification implements ShouldQueue
11+
{
12+
use Queueable;
13+
14+
public function __construct(public string $planName) {}
15+
16+
public function via($notifiable): array
17+
{
18+
return ['mail'];
19+
}
20+
21+
public function toMail($notifiable): MailMessage
22+
{
23+
$firstName = $notifiable->name ? explode(' ', $notifiable->name)[0] : null;
24+
$greeting = $firstName ? "Hi {$firstName}," : 'Hi there,';
25+
26+
return (new MailMessage)
27+
->subject('Unlock More with NativePHP Ultra')
28+
->greeting($greeting)
29+
->line("You previously purchased a **{$this->planName}** license - thank you for supporting NativePHP early on!")
30+
->line('Although NativePHP for Mobile is now free and open source and doesn\'t require licenses any more, we\'ve created a subscription plan that gives you some incredible benefits:')
31+
->line('- **Teams** - invite up to 10 collaborators to share your plugin access')
32+
->line('- **Free official plugins** - every NativePHP-published plugin, included with your subscription')
33+
->line('- **Plugin Dev Kit** - tools and resources to build and publish your own plugins')
34+
->line('- **Priority support** - get help faster when you need it')
35+
->line('- **Early access** - be first to try new features and plugins')
36+
->line('- **Exclusive content** - tutorials, guides, and deep dives just for Ultra members')
37+
->line('- **Shape the roadmap** - your feedback directly influences what we build next')
38+
->line('---')
39+
->line('Ultra is available with **annual or monthly billing** - choose what works best for you.')
40+
->action('See Ultra Plans', route('pricing'))
41+
->salutation("Cheers,\n\nThe NativePHP Team");
42+
}
43+
}

app/Notifications/UltraUpgradePromotion.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ public function toMail($notifiable): MailMessage
3030
->line('**NativePHP Ultra** gives you everything you need to build and ship faster:')
3131
->line('- **Teams** - invite up to 10 collaborators to share your plugin access')
3232
->line('- **Free official plugins** - every NativePHP-published plugin, included with your subscription')
33+
->line('- **Plugin Dev Kit** - tools and resources to build and publish your own plugins')
3334
->line('- **Priority support** - get help faster when you need it')
3435
->line('- **Early access** - be first to try new features and plugins')
3536
->line('- **Exclusive content** - tutorials, guides, and deep dives just for Ultra members')
3637
->line('- **Shape the roadmap** - your feedback directly influences what we build next')
3738
->line('---')
38-
->line('**Upgrading is seamless.** You\'ll only pay the prorated difference for the rest of your billing cycle - no double charges.')
39+
->line('**Upgrading is seamless.** You\'ll only pay the prorated difference for the rest of your billing cycle - no double charges. Ultra is available with **annual or monthly billing**.')
3940
->action('Upgrade to Ultra', route('pricing'))
4041
->salutation("Cheers,\n\nThe NativePHP Team");
4142
}

tests/Feature/SendMaxToUltraAnnouncementTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ public function test_notification_contains_ultra_benefits(): void
245245

246246
$this->assertStringContainsString('Teams', $rendered);
247247
$this->assertStringContainsString('Free official plugins', $rendered);
248+
$this->assertStringContainsString('Plugin Dev Kit', $rendered);
248249
$this->assertStringContainsString('Priority support', $rendered);
249250
$this->assertStringContainsString('Early access', $rendered);
250251
$this->assertStringContainsString('Exclusive content', $rendered);

0 commit comments

Comments
 (0)