Skip to content

Commit e6de85e

Browse files
authored
Filament updates (#154)
* filament updates * remove test exception
1 parent 4602a71 commit e6de85e

File tree

13 files changed

+339
-203
lines changed

13 files changed

+339
-203
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace App\Actions\Licenses;
4+
5+
use App\Models\License;
6+
use App\Services\Anystack\Anystack;
7+
8+
class DeleteLicense
9+
{
10+
public function __construct(
11+
protected Anystack $anystack
12+
) {}
13+
14+
/**
15+
* Handle the deletion of a license.
16+
*/
17+
public function handle(License $license, bool $deleteFromAnystack = true): bool
18+
{
19+
if ($deleteFromAnystack) {
20+
$this->anystack->deleteLicense($license->anystack_product_id, $license->anystack_id);
21+
}
22+
23+
return $license->delete();
24+
}
25+
}

app/Filament/Resources/LicenseResource.php

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
use App\Models\License;
88
use Filament\Forms;
99
use Filament\Forms\Form;
10-
use Filament\Infolists;
11-
use Filament\Infolists\Infolist;
1210
use Filament\Resources\Resource;
1311
use Filament\Tables;
1412
use Filament\Tables\Table;
@@ -25,27 +23,39 @@ public static function form(Form $form): Form
2523
->schema([
2624
Forms\Components\Section::make('License Information')
2725
->schema([
28-
Forms\Components\TextInput::make('id'),
26+
Forms\Components\TextInput::make('id')
27+
->disabled(),
2928
Forms\Components\TextInput::make('anystack_id')
30-
->maxLength(36),
29+
->maxLength(36)
30+
->disabled(),
3131
Forms\Components\Select::make('user_id')
32-
->relationship('user', 'email'),
32+
->relationship('user', 'email')
33+
->searchable(['id', 'email']),
34+
Forms\Components\Select::make('subscription_item_id')
35+
->relationship('subscriptionItem', 'id')
36+
->nullable()
37+
->searchable(),
3338
Forms\Components\TextInput::make('policy_name')
34-
->label('Plan'),
35-
Forms\Components\TextInput::make('key'),
36-
Forms\Components\DateTimePicker::make('expires_at'),
37-
Forms\Components\DateTimePicker::make('created_at'),
39+
->label('Plan')
40+
->disabled(),
41+
Forms\Components\TextInput::make('key')
42+
->disabled(),
43+
Forms\Components\DateTimePicker::make('expires_at')
44+
->disabled(),
45+
Forms\Components\DateTimePicker::make('created_at')
46+
->disabled(),
3847
Forms\Components\Toggle::make('is_suspended')
39-
->label('Suspended'),
48+
->label('Suspended')
49+
->disabled(),
4050
])
41-
->columns(2)
42-
->disabled(),
51+
->columns(2),
4352
]);
4453
}
4554

4655
public static function table(Table $table): Table
4756
{
4857
return $table
58+
->defaultSort('id', 'desc')
4959
->columns([
5060
Tables\Columns\TextColumn::make('id')
5161
->sortable()
@@ -75,7 +85,8 @@ public static function table(Table $table): Table
7585
->sortable(),
7686
])
7787
->filters([
78-
//
88+
Tables\Filters\TernaryFilter::make('is_suspended')
89+
->label('Suspended'),
7990
])
8091
->actions([
8192
Tables\Actions\ActionGroup::make([
@@ -92,39 +103,10 @@ public static function table(Table $table): Table
92103
->icon('heroicon-m-ellipsis-vertical'),
93104
])
94105
->defaultPaginationPageOption(25)
95-
->bulkActions([]);
96-
}
97-
98-
public static function infolist(Infolist $infolist): Infolist
99-
{
100-
return $infolist
101-
->schema([
102-
Infolists\Components\Section::make('License Information')
103-
->schema([
104-
Infolists\Components\TextEntry::make('id')
105-
->copyable(),
106-
Infolists\Components\TextEntry::make('anystack_id')
107-
->copyable(),
108-
Infolists\Components\TextEntry::make('user.email')
109-
->label('User')
110-
->copyable(),
111-
Infolists\Components\TextEntry::make('policy_name')
112-
->label('Plan')
113-
->copyable(),
114-
Infolists\Components\TextEntry::make('key')
115-
->copyable(),
116-
Infolists\Components\TextEntry::make('expires_at')
117-
->dateTime()
118-
->copyable(),
119-
Infolists\Components\TextEntry::make('created_at')
120-
->dateTime()
121-
->copyable(),
122-
Infolists\Components\IconEntry::make('is_suspended')
123-
->label('Suspended')
124-
->boolean(),
125-
])
126-
->columns(2),
127-
]);
106+
->bulkActions([])
107+
->recordUrl(
108+
fn ($record) => static::getUrl('edit', ['record' => $record])
109+
);
128110
}
129111

130112
public static function getRelations(): array
@@ -139,7 +121,7 @@ public static function getPages(): array
139121
{
140122
return [
141123
'index' => Pages\ListLicenses::route('/'),
142-
'view' => Pages\ViewLicense::route('/{record}'),
124+
'edit' => Pages\EditLicense::route('/{record}/edit'),
143125
];
144126
}
145127
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
namespace App\Filament\Resources\LicenseResource\Pages;
4+
5+
use App\Actions\Licenses\DeleteLicense;
6+
use App\Actions\Licenses\SuspendLicense;
7+
use App\Filament\Resources\LicenseResource;
8+
use App\Jobs\UpsertLicenseFromAnystackLicense;
9+
use App\Models\License;
10+
use App\Services\Anystack\Anystack;
11+
use Filament\Actions;
12+
use Filament\Forms\Components\Checkbox;
13+
use Filament\Notifications\Notification;
14+
use Filament\Resources\Pages\EditRecord;
15+
16+
/**
17+
* @property ?License $record
18+
*/
19+
class EditLicense extends EditRecord
20+
{
21+
protected static string $resource = LicenseResource::class;
22+
23+
protected function getHeaderActions(): array
24+
{
25+
return [
26+
Actions\ActionGroup::make([
27+
Actions\Action::make('upsert_from_anystack')
28+
->label('Sync from Anystack')
29+
->icon('heroicon-o-arrow-path')
30+
->color('gray')
31+
->requiresConfirmation()
32+
->modalHeading('Sync License from Anystack')
33+
->modalDescription('This will retrieve the latest license data from Anystack and update the local record.')
34+
->modalSubmitActionLabel('Sync License')
35+
->visible(fn () => filled($this->record->anystack_id))
36+
->action(function () {
37+
try {
38+
$response = app(Anystack::class)->getLicense($this->record->anystack_product_id, $this->record->anystack_id);
39+
dispatch_sync(new UpsertLicenseFromAnystackLicense($response->json('data')));
40+
41+
Notification::make()
42+
->title('License synced')
43+
->body('The license data has been synced.')
44+
->success()
45+
->send();
46+
} catch (\Exception $e) {
47+
Notification::make()
48+
->title('Error syncing license')
49+
->body('Failed to sync license from Anystack: '.$e->getMessage())
50+
->danger()
51+
->send();
52+
}
53+
}),
54+
Actions\Action::make('suspend')
55+
->label('Suspend')
56+
->icon('heroicon-o-archive-box-x-mark')
57+
->color('danger')
58+
->requiresConfirmation()
59+
->modalHeading('Suspend')
60+
->modalDescription('Are you sure you want to suspend this license?')
61+
->modalSubmitActionLabel('Suspend license')
62+
->visible(fn () => ! $this->record->is_suspended)
63+
->action(function () {
64+
app(SuspendLicense::class)->handle($this->record);
65+
66+
Notification::make()
67+
->title('License suspended successfully')
68+
->success()
69+
->send();
70+
}),
71+
Actions\Action::make('delete')
72+
->label('Delete')
73+
->icon('heroicon-o-trash')
74+
->color('danger')
75+
->requiresConfirmation()
76+
->modalHeading('Delete License')
77+
->modalDescription('Are you sure you want to delete this license?')
78+
->modalSubmitActionLabel('Delete')
79+
->form([
80+
Checkbox::make('delete_from_anystack')
81+
->label('Also delete from Anystack')
82+
->default(true),
83+
])
84+
->action(function (array $data) {
85+
try {
86+
app(DeleteLicense::class)->handle($this->record, $data['delete_from_anystack']);
87+
88+
Notification::make()
89+
->title('License deleted successfully')
90+
->success()
91+
->send();
92+
93+
$this->redirect(LicenseResource::getUrl('index'));
94+
} catch (\Exception $e) {
95+
Notification::make()
96+
->title('Error deleting license')
97+
->body('Failed to delete license: '.$e->getMessage())
98+
->danger()
99+
->send();
100+
}
101+
}),
102+
])
103+
->label('Actions')
104+
->icon('heroicon-m-ellipsis-vertical'),
105+
];
106+
}
107+
}

app/Filament/Resources/LicenseResource/Pages/ListLicenses.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,69 @@
22

33
namespace App\Filament\Resources\LicenseResource\Pages;
44

5+
use App\Enums\Subscription;
56
use App\Filament\Resources\LicenseResource;
7+
use App\Jobs\UpsertLicenseFromAnystackLicense;
8+
use App\Models\License;
9+
use App\Services\Anystack\Anystack;
10+
use Filament\Actions;
11+
use Filament\Forms\Components\Select;
12+
use Filament\Forms\Components\TextInput;
13+
use Filament\Notifications\Notification;
614
use Filament\Resources\Pages\ListRecords;
715

816
class ListLicenses extends ListRecords
917
{
1018
protected static string $resource = LicenseResource::class;
19+
20+
protected function getHeaderActions(): array
21+
{
22+
return [
23+
Actions\Action::make('import_from_anystack')
24+
->label('Import from Anystack')
25+
->icon('heroicon-o-arrow-down-tray')
26+
->color('primary')
27+
->form([
28+
TextInput::make('anystack_id')
29+
->label('Anystack License UUID')
30+
->placeholder('Enter the Anystack license UUID')
31+
->required()
32+
->uuid()
33+
->helperText('Paste the license UUID from Anystack to import it into the system.'),
34+
Select::make('subscription_item_id')
35+
->label('Subscription Item ID')
36+
->placeholder('Enter the subscription item ID')
37+
->nullable()
38+
->helperText('Provide the subscription item ID if this license relates to a subscription.')
39+
->relationship('subscriptionItem', 'id')
40+
->searchable(),
41+
])
42+
->action(function (array $data) {
43+
try {
44+
$productId = Subscription::Mini->anystackProductId();
45+
$response = app(Anystack::class)->getLicense($productId, $data['anystack_id']);
46+
$licenseData = $response->json('data');
47+
48+
dispatch_sync(new UpsertLicenseFromAnystackLicense($licenseData));
49+
50+
if (filled($data['subscription_item_id'] ?? null)) {
51+
$license = License::where('anystack_id', $data['anystack_id'])->firstOrFail();
52+
$license->update(['subscription_item_id' => $data['subscription_item_id']]);
53+
}
54+
55+
Notification::make()
56+
->title('License Imported')
57+
->body('The license was imported.')
58+
->success()
59+
->send();
60+
} catch (\Exception $e) {
61+
Notification::make()
62+
->title('Error importing license')
63+
->body('Failed to import license from Anystack: '.$e->getMessage())
64+
->danger()
65+
->send();
66+
}
67+
}),
68+
];
69+
}
1170
}

app/Filament/Resources/LicenseResource/Pages/ViewLicense.php

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)