Skip to content

Commit 488bf59

Browse files
[ADVAPP-2667]: Introduce the ability to archive completed campaigns (#2590)
* Implement ArchiveCampaignAction for campaign archiving functionality * Update code formatting and copyright headers * create tests * Add tests for archive action and edit visibility on completed campaigns --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent ea15a13 commit 488bf59

4 files changed

Lines changed: 239 additions & 32 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
/*
4+
<COPYRIGHT>
5+
6+
Copyright © 2016-2026, Canyon GBS Inc. All rights reserved.
7+
8+
Advising App® is licensed under the Elastic License 2.0. For more details,
9+
see https://github.com/canyongbs/advisingapp/blob/main/LICENSE.
10+
11+
Notice:
12+
13+
- You may not provide the software to third parties as a hosted or managed
14+
service, where the service provides users with access to any substantial set of
15+
the features or functionality of the software.
16+
- You may not move, change, disable, or circumvent the license key functionality
17+
in the software, and you may not remove or obscure any functionality in the
18+
software that is protected by the license key.
19+
- You may not alter, remove, or obscure any licensing, copyright, or other notices
20+
of the licensor in the software. Any use of the licensor’s trademarks is subject
21+
to applicable law.
22+
- Canyon GBS Inc. respects the intellectual property rights of others and expects the
23+
same in return. Canyon GBS® and Advising App® are registered trademarks of
24+
Canyon GBS Inc., and we are committed to enforcing and protecting our trademarks
25+
vigorously.
26+
- The software solution, including services, infrastructure, and code, is offered as a
27+
Software as a Service (SaaS) by Canyon GBS Inc.
28+
- Use of this software implies agreement to the license terms and conditions as stated
29+
in the Elastic License 2.0.
30+
31+
For more information or inquiries please visit our website at
32+
https://www.canyongbs.com or contact us via email at legal@canyongbs.com.
33+
34+
</COPYRIGHT>
35+
*/
36+
37+
namespace AdvisingApp\Campaign\Filament\Actions;
38+
39+
use AdvisingApp\Campaign\Models\Campaign;
40+
use CanyonGBS\Common\Filament\Actions\ArchiveAction;
41+
use Filament\Actions\Action;
42+
use Filament\Notifications\Notification;
43+
use Illuminate\Support\Facades\DB;
44+
use Throwable;
45+
46+
class ArchiveCampaignAction
47+
{
48+
public static function make(): Action
49+
{
50+
return ArchiveAction::make()
51+
->label(fn (Campaign $record): string => $record->enabled ? 'Disable and Archive' : 'Archive')
52+
->modalHeading(fn (Campaign $record): string => $record->enabled ? 'Disable and Archive Campaign' : 'Archive Campaign')
53+
->modalSubmitActionLabel(fn (Campaign $record): string => $record->enabled ? 'Disable and Archive' : 'Archive')
54+
->action(function (Campaign $record): void {
55+
try {
56+
DB::transaction(function () use ($record) {
57+
if ($record->enabled) {
58+
$record->update(['enabled' => false]);
59+
}
60+
$record->archive();
61+
});
62+
63+
Notification::make()
64+
->success()
65+
->title('Campaign archived successfully')
66+
->send();
67+
} catch (Throwable $exception) {
68+
report($exception);
69+
70+
Notification::make()
71+
->danger()
72+
->title('Failed to archive campaign')
73+
->body($exception->getMessage())
74+
->send();
75+
}
76+
});
77+
}
78+
}

app-modules/campaign/src/Filament/Resources/Campaigns/Pages/EditCampaign.php

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,16 @@
3636

3737
namespace AdvisingApp\Campaign\Filament\Resources\Campaigns\Pages;
3838

39+
use AdvisingApp\Campaign\Filament\Actions\ArchiveCampaignAction;
3940
use AdvisingApp\Campaign\Filament\Resources\Campaigns\CampaignResource;
40-
use AdvisingApp\Campaign\Models\Campaign;
4141
use AdvisingApp\Group\Models\Group;
4242
use App\Filament\Resources\Pages\EditRecord\Concerns\EditPageRedirection;
43-
use CanyonGBS\Common\Filament\Actions\ArchiveAction;
4443
use Filament\Actions\DeleteAction;
4544
use Filament\Forms\Components\Select;
4645
use Filament\Forms\Components\TextInput;
4746
use Filament\Forms\Components\Toggle;
48-
use Filament\Notifications\Notification;
4947
use Filament\Resources\Pages\EditRecord;
5048
use Filament\Schemas\Schema;
51-
use Illuminate\Support\Facades\DB;
52-
use Throwable;
5349

5450
class EditCampaign extends EditRecord
5551
{
@@ -81,33 +77,7 @@ public function form(Schema $schema): Schema
8177
protected function getHeaderActions(): array
8278
{
8379
return [
84-
ArchiveAction::make()
85-
->label(fn (Campaign $record): string => $record->enabled ? 'Disable and Archive' : 'Archive')
86-
->modalHeading(fn (Campaign $record): string => $record->enabled ? 'Disable and Archive Campaign' : 'Archive Campaign')
87-
->modalSubmitActionLabel(fn (Campaign $record): string => $record->enabled ? 'Disable and Archive' : 'Archive')
88-
->action(function (Campaign $record): void {
89-
try {
90-
DB::transaction(function () use ($record) {
91-
if ($record->enabled) {
92-
$record->update(['enabled' => false]);
93-
}
94-
$record->archive();
95-
});
96-
97-
Notification::make()
98-
->success()
99-
->title('Campaign archived successfully')
100-
->send();
101-
} catch (Throwable $exception) {
102-
report($exception);
103-
104-
Notification::make()
105-
->danger()
106-
->title('Failed to archive campaign')
107-
->body($exception->getMessage())
108-
->send();
109-
}
110-
}),
80+
ArchiveCampaignAction::make(),
11181
DeleteAction::make(),
11282
];
11383
}

app-modules/campaign/src/Filament/Resources/Campaigns/Pages/ViewCampaign.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
namespace AdvisingApp\Campaign\Filament\Resources\Campaigns\Pages;
3838

39+
use AdvisingApp\Campaign\Filament\Actions\ArchiveCampaignAction;
3940
use AdvisingApp\Campaign\Filament\Resources\Campaigns\CampaignResource;
4041
use AdvisingApp\Campaign\Models\Campaign;
4142
use Filament\Actions\EditAction;
@@ -73,6 +74,7 @@ public function infolist(Schema $schema): Schema
7374
protected function getHeaderActions(): array
7475
{
7576
return [
77+
ArchiveCampaignAction::make(),
7678
EditAction::make()
7779
->hidden(fn (Campaign $record) => $record->hasBeenExecuted() === true),
7880
];
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
3+
/*
4+
<COPYRIGHT>
5+
6+
Copyright © 2016-2026, Canyon GBS Inc. All rights reserved.
7+
8+
Advising App® is licensed under the Elastic License 2.0. For more details,
9+
see https://github.com/canyongbs/advisingapp/blob/main/LICENSE.
10+
11+
Notice:
12+
13+
- You may not provide the software to third parties as a hosted or managed
14+
service, where the service provides users with access to any substantial set of
15+
the features or functionality of the software.
16+
- You may not move, change, disable, or circumvent the license key functionality
17+
in the software, and you may not remove or obscure any functionality in the
18+
software that is protected by the license key.
19+
- You may not alter, remove, or obscure any licensing, copyright, or other notices
20+
of the licensor in the software. Any use of the licensor’s trademarks is subject
21+
to applicable law.
22+
- Canyon GBS Inc. respects the intellectual property rights of others and expects the
23+
same in return. Canyon GBS® and Advising App® are registered trademarks of
24+
Canyon GBS Inc., and we are committed to enforcing and protecting our trademarks
25+
vigorously.
26+
- The software solution, including services, infrastructure, and code, is offered as a
27+
Software as a Service (SaaS) by Canyon GBS Inc.
28+
- Use of this software implies agreement to the license terms and conditions as stated
29+
in the Elastic License 2.0.
30+
31+
For more information or inquiries please visit our website at
32+
https://www.canyongbs.com or contact us via email at legal@canyongbs.com.
33+
34+
</COPYRIGHT>
35+
*/
36+
37+
namespace AdvisingApp\Campaign\Tests\Tenant\Filament\Resources\Campaigns\Pages;
38+
39+
use AdvisingApp\Authorization\Enums\LicenseType;
40+
use AdvisingApp\Campaign\Filament\Resources\Campaigns\Pages\ListCampaigns;
41+
use AdvisingApp\Campaign\Filament\Resources\Campaigns\Pages\ViewCampaign;
42+
use AdvisingApp\Campaign\Models\Campaign;
43+
use AdvisingApp\Campaign\Models\CampaignAction;
44+
use App\Models\User;
45+
46+
use function Pest\Laravel\actingAs;
47+
use function Pest\Livewire\livewire;
48+
use function Tests\asSuperAdmin;
49+
50+
test('archive action is visible on view page', function () {
51+
$user = User::factory()->licensed(LicenseType::cases())->create();
52+
$campaign = Campaign::factory()->enabled()->create();
53+
54+
$user->givePermissionTo('campaign.view-any');
55+
$user->givePermissionTo('campaign.*.view');
56+
$user->givePermissionTo('group.*.view');
57+
58+
actingAs($user);
59+
60+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
61+
->assertActionHidden('archive');
62+
63+
$user->givePermissionTo('campaign.*.delete');
64+
65+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
66+
->assertActionVisible('archive');
67+
});
68+
69+
test('archive action shows disable and archive label for enabled campaigns', function () {
70+
asSuperAdmin();
71+
72+
$campaign = Campaign::factory()->enabled()->create();
73+
74+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
75+
->assertActionHasLabel('archive', 'Disable and Archive');
76+
});
77+
78+
test('archive action shows archive label for disabled campaigns', function () {
79+
asSuperAdmin();
80+
81+
$campaign = Campaign::factory()->disabled()->create();
82+
83+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
84+
->assertActionHasLabel('archive', 'Archive');
85+
});
86+
87+
test('archive action disables and archives enabled campaigns', function () {
88+
asSuperAdmin();
89+
90+
$campaign = Campaign::factory()->enabled()->create();
91+
92+
expect($campaign->enabled)->toBeTrue()
93+
->and($campaign->isArchived())->toBeFalse();
94+
95+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
96+
->callAction('archive');
97+
98+
$campaign = $campaign->fresh();
99+
100+
expect($campaign->enabled)->toBeFalse()
101+
->and($campaign->isArchived())->toBeTrue();
102+
});
103+
104+
test('archive action archives disabled campaigns', function () {
105+
asSuperAdmin();
106+
107+
$campaign = Campaign::factory()->disabled()->create();
108+
109+
expect($campaign->enabled)->toBeFalse()
110+
->and($campaign->isArchived())->toBeFalse();
111+
112+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
113+
->callAction('archive');
114+
115+
$campaign = $campaign->fresh();
116+
117+
expect($campaign->enabled)->toBeFalse()
118+
->and($campaign->isArchived())->toBeTrue();
119+
});
120+
121+
test('archive action redirects to index after archiving', function () {
122+
asSuperAdmin();
123+
124+
$campaign = Campaign::factory()->enabled()->create();
125+
126+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
127+
->callAction('archive')
128+
->assertRedirect(ListCampaigns::getUrl());
129+
});
130+
131+
test('edit action is hidden for completed campaigns', function () {
132+
asSuperAdmin();
133+
134+
$campaign = Campaign::factory()->has(CampaignAction::factory()->finishedAt(), 'actions')->create();
135+
136+
expect($campaign->hasBeenExecuted())->toBeTrue();
137+
138+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
139+
->assertActionHidden('edit')
140+
->assertActionVisible('archive');
141+
});
142+
143+
test('archive action successfully archives completed campaigns', function () {
144+
asSuperAdmin();
145+
146+
$campaign = Campaign::factory()->has(CampaignAction::factory()->finishedAt(), 'actions')->create();
147+
148+
expect($campaign->hasBeenExecuted())->toBeTrue()
149+
->and($campaign->isArchived())->toBeFalse();
150+
151+
livewire(ViewCampaign::class, ['record' => $campaign->getRouteKey()])
152+
->callAction('archive');
153+
154+
$campaign = $campaign->fresh();
155+
156+
expect($campaign->isArchived())->toBeTrue();
157+
});

0 commit comments

Comments
 (0)