Skip to content

Commit 9a9394f

Browse files
committed
Improve license manager
1 parent d1402f8 commit 9a9394f

File tree

9 files changed

+368
-219
lines changed

9 files changed

+368
-219
lines changed

app/Livewire/SubLicenseManager.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace App\Livewire;
4+
5+
use App\Models\License;
6+
use Livewire\Component;
7+
8+
class SubLicenseManager extends Component
9+
{
10+
public License $license;
11+
12+
public bool $isPolling = false;
13+
14+
public int $initialSubLicenseCount;
15+
16+
public function mount(License $license): void
17+
{
18+
$this->license = $license;
19+
$this->initialSubLicenseCount = $license->subLicenses->count();
20+
}
21+
22+
public function startPolling(): void
23+
{
24+
$this->isPolling = true;
25+
}
26+
27+
public function render()
28+
{
29+
// Refresh the license and sublicenses from the database
30+
$this->license->refresh();
31+
$this->license->load('subLicenses');
32+
33+
// Check if a new sublicense has been added
34+
if ($this->isPolling && $this->license->subLicenses->count() > $this->initialSubLicenseCount) {
35+
$this->isPolling = false;
36+
$this->initialSubLicenseCount = $this->license->subLicenses->count();
37+
}
38+
39+
$activeSubLicenses = $this->license->subLicenses->where('is_suspended', false);
40+
$suspendedSubLicenses = $this->license->subLicenses->where('is_suspended', true);
41+
42+
return view('livewire.sub-license-manager', [
43+
'activeSubLicenses' => $activeSubLicenses,
44+
'suspendedSubLicenses' => $suspendedSubLicenses,
45+
]);
46+
}
47+
}

app/Models/License.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Illuminate\Database\Eloquent\Model;
1010
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1111
use Illuminate\Database\Eloquent\Relations\HasMany;
12+
use Illuminate\Support\Carbon;
1213
use Laravel\Cashier\SubscriptionItem;
1314

1415
class License extends Model
@@ -115,6 +116,12 @@ public function canCreateSubLicense(): bool
115116
return $remaining === null || $remaining > 0;
116117
}
117118

119+
public function isLegacy(): bool
120+
{
121+
return !$this->subscription_item_id
122+
&& $this->created_at->lt(Carbon::create(2025, 5, 8));
123+
}
124+
118125
public function suspendAllSubLicenses(): int
119126
{
120127
return $this->subLicenses()->update(['is_suspended' => true]);

app/Notifications/LicenseExpiryWarning.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private function getMainMessage(): string
5959
return match ($this->daysUntilExpiry) {
6060
30 => 'This is a friendly reminder that your NativePHP license will expire in 30 days.',
6161
7 => 'Your NativePHP license will expire in just 7 days. This is an important reminder to set up your renewal.',
62-
1 => 'Your NativePHP license expires tomorrow! Please take immediate action to avoid service interruption.',
62+
1 => 'Your NativePHP license expires tomorrow! Please take immediate action to avoid interruption.',
6363
0 => 'Your NativePHP license expires today. Renew now to maintain access.',
6464
default => "Your NativePHP license will expire in {$this->daysUntilExpiry} days.",
6565
};

resources/views/components/navigation-bar.blade.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ class="opacity-60 transition duration-200 hover:opacity-100"
146146

147147
{{-- Login/Logout --}}
148148
@feature(App\Features\ShowAuthButtons::class)
149+
{{-- Decorative circle --}}
150+
<div
151+
class="size-[3px] rotate-45 rounded-xs bg-gray-400 transition duration-200 dark:opacity-60"
152+
aria-hidden="true"
153+
></div>
154+
149155
@auth
150156
<form
151157
method="POST"

resources/views/customer/licenses/index.blade.php

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@
2828
<div class="bg-white dark:bg-gray-800 shadow overflow-hidden sm:rounded-md">
2929
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
3030
@foreach($licenses as $license)
31-
<li>
32-
<a href="{{ route('customer.licenses.show', $license->key) }}" class="block hover:bg-gray-50 dark:hover:bg-gray-700">
31+
@php
32+
$isLegacyLicense = $license->isLegacy();
33+
$daysUntilExpiry = $license->expires_at ? $license->expires_at->diffInDays(now()) : null;
34+
$needsRenewal = $isLegacyLicense && $daysUntilExpiry !== null && $daysUntilExpiry <= 30 && !$license->expires_at->isPast();
35+
@endphp
36+
<li class="{{ $needsRenewal ? 'bg-blue-50 dark:bg-blue-900/20' : '' }}">
37+
<a href="{{ route('customer.licenses.show', $license->key) }}" class="block hover:bg-gray-50 dark:hover:bg-gray-700 {{ $needsRenewal ? 'hover:bg-blue-100 dark:hover:bg-blue-900/30' : '' }}">
3338
<div class="px-4 py-4 sm:px-6">
3439
<div class="flex items-center justify-between">
3540
<div class="flex items-center">
@@ -38,12 +43,14 @@
3843
<div class="w-3 h-3 bg-red-400 rounded-full"></div>
3944
@elseif($license->expires_at && $license->expires_at->isPast())
4045
<div class="w-3 h-3 bg-yellow-400 rounded-full"></div>
46+
@elseif($needsRenewal)
47+
<div class="w-3 h-3 bg-blue-400 rounded-full animate-pulse"></div>
4148
@else
4249
<div class="w-3 h-3 bg-green-400 rounded-full"></div>
4350
@endif
4451
</div>
4552
<div class="ml-4">
46-
<div class="flex items-center">
53+
<div class="flex items-start">
4754
<div class="flex flex-col">
4855
@if($license->name)
4956
<p class="text-sm font-medium text-blue-600 dark:text-blue-400 truncate">
@@ -66,6 +73,10 @@
6673
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200">
6774
Expired
6875
</span>
76+
@elseif($needsRenewal)
77+
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
78+
Needs Renewal
79+
</span>
6980
@else
7081
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
7182
Active
@@ -78,16 +89,28 @@
7889
</div>
7990
</div>
8091
<div class="flex flex-col items-end">
81-
<p class="text-sm text-gray-900 dark:text-white">
82-
@if($license->expires_at)
83-
Expires {{ $license->expires_at->format('M j, Y') }}
84-
@else
85-
No expiration
92+
@if($needsRenewal)
93+
<p class="text-sm font-medium text-blue-600 dark:text-blue-400">
94+
Expires in {{ $daysUntilExpiry }} day{{ $daysUntilExpiry === 1 ? '' : 's' }}
95+
</p>
96+
97+
@if($isLegacyLicense)
98+
<p class="text-xs text-blue-500 dark:text-blue-300">
99+
Lock in Early Access Pricing
100+
</p>
86101
@endif
87-
</p>
88-
<p class="text-xs text-gray-500 dark:text-gray-400">
89-
Created {{ $license->created_at->format('M j, Y') }}
90-
</p>
102+
@else
103+
<p class="text-sm text-gray-900 dark:text-white">
104+
@if($license->expires_at)
105+
Expires {{ $license->expires_at->format('M j, Y') }}
106+
@else
107+
No expiration
108+
@endif
109+
</p>
110+
<p class="text-xs text-gray-500 dark:text-gray-400">
111+
Created {{ $license->created_at->format('M j, Y') }}
112+
</p>
113+
@endif
91114
</div>
92115
</div>
93116
</div>

0 commit comments

Comments
 (0)