Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/Models/License.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ protected function remainingSubLicenses(): Attribute
});
}

public function isExpired(): bool
{
return $this->expires_at && $this->expires_at->isPast();
}

public function canCreateSubLicense(): bool
{
if (! $this->supportsSubLicenses()) {
Expand Down
66 changes: 0 additions & 66 deletions resources/views/livewire/customer/licenses.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,10 @@
<flux:table.columns>
<flux:table.column>License</flux:table.column>
<flux:table.column>Key</flux:table.column>
<flux:table.column>Status</flux:table.column>
<flux:table.column>Expires</flux:table.column>
</flux:table.columns>

<flux:table.rows>
@foreach($this->licenses as $license)
@php
$isLegacyLicense = $license->isLegacy();
$daysUntilExpiry = $license->expires_at ? (int) now()->diffInDays($license->expires_at, false) : null;
$needsRenewal = $isLegacyLicense && $daysUntilExpiry !== null && !$license->expires_at->isPast();

$status = match(true) {
$license->is_suspended => 'Suspended',
$license->expires_at && $license->expires_at->isPast() => 'Expired',
$needsRenewal => 'Needs Renewal',
default => 'Active',
};
@endphp
<flux:table.row :key="$license->id">
<flux:table.cell>
<div>
Expand All @@ -42,32 +28,6 @@
<flux:table.cell>
<x-customer.masked-key :key-value="$license->key" />
</flux:table.cell>

<flux:table.cell>
<x-customer.status-badge :status="$status" />
</flux:table.cell>

<flux:table.cell>
@if($needsRenewal)
<div>
<span class="font-medium text-blue-600 dark:text-blue-400">
{{ $daysUntilExpiry }} day{{ $daysUntilExpiry === 1 ? '' : 's' }}
</span>
@if($isLegacyLicense)
<flux:text class="text-xs text-blue-500 dark:text-blue-300">Lock in Early Access Pricing</flux:text>
@endif
</div>
@elseif($license->expires_at)
<div>
{{ $license->expires_at->format('M j, Y') }}
@if($license->expires_at->isPast())
<flux:text class="text-xs">Expired {{ $license->expires_at->diffForHumans() }}</flux:text>
@endif
</div>
@else
No expiration
@endif
</flux:table.cell>
</flux:table.row>
@endforeach
</flux:table.rows>
Expand All @@ -82,19 +42,10 @@
<flux:table.columns>
<flux:table.column>License</flux:table.column>
<flux:table.column>Key</flux:table.column>
<flux:table.column>Status</flux:table.column>
<flux:table.column>Expires</flux:table.column>
</flux:table.columns>

<flux:table.rows>
@foreach($this->assignedSubLicenses as $subLicense)
@php
$subStatus = match(true) {
$subLicense->is_suspended => 'Suspended',
$subLicense->expires_at && $subLicense->expires_at->isPast() => 'Expired',
default => 'Active',
};
@endphp
<flux:table.row :key="$subLicense->id">
<flux:table.cell>
<div>
Expand All @@ -106,23 +57,6 @@
<flux:table.cell>
<x-customer.masked-key :key-value="$subLicense->key" />
</flux:table.cell>

<flux:table.cell>
<x-customer.status-badge :status="$subStatus" />
</flux:table.cell>

<flux:table.cell>
@if($subLicense->expires_at)
<div>
{{ $subLicense->expires_at->format('M j, Y') }}
@if($subLicense->expires_at->isPast())
<flux:text class="text-xs">Expired {{ $subLicense->expires_at->diffForHumans() }}</flux:text>
@endif
</div>
@else
No expiration
@endif
</flux:table.cell>
</flux:table.row>
@endforeach
</flux:table.rows>
Expand Down
41 changes: 6 additions & 35 deletions resources/views/livewire/customer/licenses/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,9 @@

{{-- License Information Card --}}
<flux:card class="mb-6">
<div class="flex items-center justify-between mb-4">
<div>
<flux:heading size="lg">License Information</flux:heading>
<flux:text>Details about your NativePHP license.</flux:text>
</div>
<x-customer.status-badge :status="$license->is_suspended ? 'Suspended' : ($license->expires_at && $license->expires_at->isPast() ? 'Expired' : 'Active')" />
<div class="mb-4">
<flux:heading size="lg">License Information</flux:heading>
<flux:text>Details about your NativePHP license.</flux:text>
</div>

<flux:separator />
Expand Down Expand Up @@ -80,23 +77,6 @@
<flux:text class="inline text-xs">({{ $license->created_at->diffForHumans() }})</flux:text>
</flux:table.cell>
</flux:table.row>

{{-- Expires --}}
<flux:table.row>
<flux:table.cell class="font-medium text-zinc-500 dark:text-zinc-400">Expires</flux:table.cell>
<flux:table.cell>
@if($license->expires_at)
{{ $license->expires_at->format('F j, Y \a\t g:i A') }}
@if($license->expires_at->isPast())
<flux:text class="inline text-xs">(Expired {{ $license->expires_at->diffForHumans() }})</flux:text>
@else
<flux:text class="inline text-xs">({{ $license->expires_at->diffForHumans() }})</flux:text>
@endif
@else
Never
@endif
</flux:table.cell>
</flux:table.row>
</flux:table.rows>
</flux:table>
</flux:card>
Expand Down Expand Up @@ -126,20 +106,11 @@
</flux:callout>
@endif

@if($license->is_suspended || ($license->expires_at && $license->expires_at->isPast()))
@if($license->is_suspended)
<flux:callout variant="warning" icon="exclamation-triangle" class="mt-6">
<flux:callout.heading>
{{ $license->is_suspended ? 'License Suspended' : 'License Expired' }}
</flux:callout.heading>
<flux:callout.heading>License Suspended</flux:callout.heading>
<flux:callout.text>
@if($license->is_suspended)
This license has been suspended. Please contact support for assistance.
@elseif($isLegacyLicense)
This license has expired. You can still renew it to restore access.
<a href="{{ route('license.renewal', $license->key) }}" class="font-medium underline hover:no-underline">Renew now</a>
@else
This license has expired. Please renew your subscription to continue using NativePHP.
@endif
This license has been suspended. Please contact support for assistance.
</flux:callout.text>
</flux:callout>
@endif
Expand Down
11 changes: 2 additions & 9 deletions resources/views/livewire/sub-license-manager.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@
<flux:heading size="lg">
Keys
<span class="ml-2 text-sm text-zinc-500 dark:text-zinc-400">
({{ $activeSubLicenses->count() }}{{ $license->subLicenseLimit ? '/' . $license->subLicenseLimit : '' }})
({{ $activeSubLicenses->count() }}{{ $license->subLicenseLimit && ! $license->isExpired() ? '/' . $license->subLicenseLimit : '' }})
</span>
</flux:heading>
<flux:text>Manage license keys for team members or additional devices.</flux:text>
</div>
@if($license->canCreateSubLicense())
<flux:button variant="primary" wire:click="openCreateModal">
Create Key
</flux:button>
@endif
</div>

@if($license->subLicenses->isEmpty())
Expand Down Expand Up @@ -120,15 +115,13 @@
@endif
@endif

@if(!$license->canCreateSubLicense())
@if(!$license->canCreateSubLicense() && ! $license->isExpired())
<flux:callout variant="warning" icon="exclamation-triangle" class="mt-4">
<flux:callout.text>
@if($license->remainingSubLicenses === 0)
You have reached the maximum number of keys for this plan.
@elseif($license->is_suspended)
Keys cannot be created for suspended licenses.
@elseif($license->expires_at && $license->expires_at->isPast())
Keys cannot be created for expired licenses.
@else
Keys cannot be created at this time.
@endif
Expand Down
18 changes: 13 additions & 5 deletions tests/Feature/CustomerLicenseManagementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ public function test_customer_can_view_individual_license_details(): void
$response->assertSee('pro');
$response->assertSee('test-license-key-123');
$response->assertSee('License Information');
$response->assertSee('Active');
$response->assertDontSee('Active');
$response->assertDontSee('Expires');
}

public function test_customer_cannot_view_other_customers_license_details(): void
Expand All @@ -124,36 +125,43 @@ public function test_customer_cannot_view_other_customers_license_details(): voi
$response->assertStatus(404);
}

public function test_license_status_displays_correctly(): void
public function test_license_index_does_not_display_status_or_expiry(): void
{
$user = User::factory()->create();

// Active license
$activeLicense = License::factory()->create([
'user_id' => $user->id,
'key' => 'license-key-one',
'expires_at' => now()->addDays(30),
'is_suspended' => false,
]);

// Expired license
$expiredLicense = License::factory()->create([
'user_id' => $user->id,
'key' => 'license-key-two',
'expires_at' => now()->subDays(1),
'is_suspended' => false,
]);

// Suspended license
$suspendedLicense = License::factory()->create([
'user_id' => $user->id,
'key' => 'license-key-three',
'is_suspended' => true,
]);

$response = $this->actingAs($user)->get('/dashboard/licenses');

$response->assertStatus(200);
$response->assertSee('Active');
$response->assertSee('Expired');
$response->assertSee('Suspended');
$response->assertSee('license-key-one');
$response->assertSee('license-key-two');
$response->assertSee('license-key-three');
$response->assertDontSee('Status');
$response->assertDontSee('Expires');
$response->assertDontSee('Expired');
$response->assertDontSee('Suspended');
}

public function test_customer_can_update_license_name(): void
Expand Down
18 changes: 17 additions & 1 deletion tests/Feature/CustomerSubLicenseManagementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,6 @@ public function test_license_show_page_displays_sub_licenses(): void
$response->assertSee('Testing Team');
$response->assertSee($subLicense1->key);
$response->assertSee($subLicense2->key);
$response->assertSee('Active');
$response->assertSee('Suspended');
}

Expand Down Expand Up @@ -520,4 +519,21 @@ public function test_livewire_component_displays_sublicenses(): void
->assertSee($activeSubLicense->key)
->assertSee($suspendedSubLicense->key);
}

public function test_expired_license_hides_key_limit_and_expired_banner(): void
{
$user = User::factory()->create();
$license = License::factory()->create([
'user_id' => $user->id,
'policy_name' => 'pro', // Pro has a sub-license limit of 9
'is_suspended' => false,
'expires_at' => now()->subDay(),
]);

$this->actingAs($user);

Livewire::test(SubLicenseManager::class, ['license' => $license])
->assertDontSee('/9')
->assertDontSee('Keys cannot be created for expired licenses.');
}
}
Loading