Skip to content

Commit

Permalink
feat: add Solo Endorsement overview on admin panel
Browse files Browse the repository at this point in the history
  • Loading branch information
AxonC committed Dec 28, 2024
1 parent d1e3049 commit 6ce2301
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 0 deletions.
90 changes: 90 additions & 0 deletions app/Filament/Resources/SoloEndorsementResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

namespace App\Filament\Resources;

use App\Filament\Resources\SoloEndorsementResource\Pages;
use App\Models\Atc\Position;
use App\Models\Mship\Account\Endorsement;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;

class SoloEndorsementResource extends Resource
{
protected static ?string $model = Endorsement::class;

protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';

protected static ?string $modelLabel = 'Solo Endorsements';

protected static ?string $navigationGroup = 'Mentoring';

public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->where('endorsable_type', Position::class)->whereNotNull('expires_at');
}

/**
* Overriding here as this is a specialisation of the Endorsement model
* with a filtered eloquent query
* and thus using the model policy might have unintended consequences.
*/
public static function canAccess(): bool
{
return auth()->user()->hasAnyPermission('endorsement.view.*');
}

public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('account.id')->label('CID'),
Tables\Columns\TextColumn::make('account.name')->label('Account'),
Tables\Columns\TextColumn::make('endorsable.description')->label('Position'),
Tables\Columns\TextColumn::make('duration')->getStateUsing(fn ($record) => $record->expires_at->diffInDays($record->created_at).' days')->label('Duration'),
Tables\Columns\TextColumn::make('created_at')->label('Started At')->isoDateTimeFormat('lll'),
Tables\Columns\TextColumn::make('expires_at')->label('Expires At')->isoDateTimeFormat('lll'),
Tables\Columns\TextColumn::make('status')->label('Status')->badge()
->getStateUsing(fn ($record) => $record->expires_at->isPast() ? 'Expired' : 'Active')
->color(
fn (string $state): string => match ($state) {
'Expired' => 'danger',
'Active' => 'success',
default => 'primary',
}
),
])
->filters([
Tables\Filters\TernaryFilter::make('expires_at')
->label('Endorsement Expiry Status')
->trueLabel('Active')
->default(true)
->falseLabel('Expired')
->nullable()
->placeholder('All endorsements')
->queries(
true: fn (Builder $query) => $query->where('expires_at', '>', now()),
false: fn (Builder $query) => $query->where('expires_at', '<=', now()),
blank: fn (Builder $query) => $query
),

Tables\Filters\QueryBuilder::make()
->constraints([
Tables\Filters\QueryBuilder\Constraints\TextConstraint::make('account.id')->operators(
[
Tables\Filters\QueryBuilder\Constraints\TextConstraint\Operators\EqualsOperator::class,
]
),
]),
], layout: FiltersLayout::AboveContent);
}

public static function getPages(): array
{
return [
'index' => Pages\ListSoloEndorsements::route('/'),
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Filament\Resources\SoloEndorsementResource\Pages;

use App\Filament\Resources\SoloEndorsementResource;
use Filament\Resources\Pages\ListRecords;

class ListSoloEndorsements extends ListRecords
{
protected static string $resource = SoloEndorsementResource::class;
}
2 changes: 2 additions & 0 deletions database/seeders/RolesAndPermissionsSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ public function run()
'endorsement.create.*',
'endorsement.create.permanent',
'endorsement.create.temporary',
'endorsement.view.*',
'endorsement.view.solo',

'endorsement-request.access',
'endorsement-request.create.*',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

namespace Tests\Feature\Admin\SoloEndorsement\Pages;

use App\Filament\Resources\SoloEndorsementResource\Pages\ListSoloEndorsements;
use App\Models\Atc\Position;
use App\Models\Mship\Account\Endorsement;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Livewire\Livewire;
use Tests\Feature\Admin\BaseAdminTestCase;

class ListSoloEndorsementPageTest extends BaseAdminTestCase
{
use DatabaseTransactions;

protected function setUp(): void
{
parent::setUp();

Livewire::actingAs($this->adminUser);
}

public function test_can_access_list_page_with_permission()
{
$this->adminUser->givePermissionTo('endorsement.view.*');

Livewire::test(ListSoloEndorsements::class)
->assertSee('Solo Endorsements');
}

public function test_cannot_access_list_page_without_permission()
{
Livewire::test(ListSoloEndorsements::class)
->assertForbidden();
}

public function test_only_displays_solo_endorsements_with_expiry()
{
$this->adminUser->givePermissionTo('endorsement.view.*');

$soloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->addDays(1),
]);

$soloEndorsementWithoutExpiry = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => null,
]);

Livewire::test(ListSoloEndorsements::class)
->assertSee($soloEndorsement->account->name)
->assertDontSee($soloEndorsementWithoutExpiry->account->name);
}

public function test_only_displays_active_solo_endorsements_by_default()
{
$this->adminUser->givePermissionTo('endorsement.view.*');

$soloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->addDays(1),
]);

$expiredSoloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->subDays(1),
]);

Livewire::test(ListSoloEndorsements::class)
->assertSee($soloEndorsement->account->name)
->assertDontSee($expiredSoloEndorsement->account->name);
}

public function test_filter_can_be_changed_to_expired_endorsements()
{
$this->adminUser->givePermissionTo('endorsement.view.*');

$soloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->addDays(1),
]);

$expiredSoloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->subDays(1),
]);

Livewire::test(ListSoloEndorsements::class)
->filterTable('expires_at', false)
->assertSee($expiredSoloEndorsement->account->name)
->assertDontSee($soloEndorsement->account->name);
}

public function test_filter_can_be_changed_to_all_endorsements()
{
$this->adminUser->givePermissionTo('endorsement.view.*');

$soloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->addDays(1),
]);

$expiredSoloEndorsement = Endorsement::factory()->create([
'endorsable_type' => Position::class,
'endorsable_id' => Position::factory(),
'expires_at' => now()->subDays(1),
]);

Livewire::test(ListSoloEndorsements::class)
->filterTable('expires_at', null)
->assertSee($soloEndorsement->account->name)
->assertSee($expiredSoloEndorsement->account->name);
}
}

0 comments on commit 6ce2301

Please sign in to comment.