diff --git a/app/Filament/Resources/ArticleResource.php b/app/Filament/Resources/ArticleResource.php new file mode 100644 index 00000000..86027d11 --- /dev/null +++ b/app/Filament/Resources/ArticleResource.php @@ -0,0 +1,133 @@ +columns([ + TextColumn::make('title') + ->label('Titre') + ->sortable(), + TextColumn::make('status') + ->getStateUsing(function ($record) { + if ($record->approved_at) { + return 'Approuver'; + } elseif ($record->declined_at) { + return 'Décliner'; + } elseif ($record->submitted_at) { + return 'Soumis'; + } else { + return 'Brouillon'; + } + }) + ->colors([ + 'success' => 'Approuver', + 'danger' => 'Décliner', + 'warning' => 'Soumis', + 'default' => 'Brouillon', + ]) + ->badge(), + TextColumn::make('submitted_at') + ->label('Date de soumission') + ->dateTime(), + TextColumn::make('user.name') + ->label('Auteur') + ->sortable(), + ]) + ->filters([ + Filter::make('submitted_at')->query(fn (Builder $query) => $query->whereNotNull('submitted_at'))->label('Soumis'), + Filter::make('declined_at')->query(fn (Builder $query) => $query->whereNotNull('declined_at'))->label('Décliner'), + Filter::make('approved_at')->query(fn (Builder $query) => $query->whereNotNull('approved_at'))->label('Approuver'), + ]) + + ->actions([ + ActionGroup::make([ + Action::make('approved') + ->visible(fn (Article $record) => $record->isAwaitingApproval()) + ->label('Approuver') + ->icon('heroicon-s-check') + ->color('success') + ->modalHeading(__('Voulez vous approuver cet article')) + ->successNotificationTitle(__('Opération effectuée avec succès')) + ->requiresConfirmation() + ->modalIcon('heroicon-s-check') + ->action(function ($record): void { + $record->approved_at = now(); + $record->save(); + }), + Action::make('declined') + ->visible(fn (Article $record) => $record->isAwaitingApproval()) + ->label('Décliner') + ->icon('heroicon-s-x-mark') + ->color('warning') + ->modalHeading(__('Voulez vous décliner cet article')) + ->successNotificationTitle(__('Opération effectuée avec succès')) + ->requiresConfirmation() + ->modalIcon('heroicon-s-x-mark') + ->action(function ($record): void { + $record->declined_at = now(); + $record->save(); + }), + Tables\Actions\DeleteAction::make('delete'), + ]), + + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + BulkAction::make('approved') + ->label('Approuver la sélection') + ->icon('heroicon-s-check') + ->color('success') + ->action(fn (Collection $records) => $records->each->update(['approved_at' => now()])) + ->deselectRecordsAfterCompletion() + ->requiresConfirmation() + ->modalIcon('heroicon-s-check') + ->modalHeading('Approuver') + ->modalSubheading('Voulez-vous vraiment approuver ces articles ?') + ->modalButton('Confirmer'), + BulkAction::make('declined') + ->label('Décliner la sélection') + ->icon('heroicon-s-x-mark') + ->color('warning') + ->action(fn (Collection $records) => $records->each->update(['declined_at' => now()])) + ->deselectRecordsAfterCompletion() + ->requiresConfirmation() + ->modalIcon('heroicon-s-x-mark') + ->modalHeading('Décliner') + ->modalSubheading('Voulez-vous vraiment décliner ces articles ?') + ->modalButton('Confirmer'), + + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListArticles::route('/'), + ]; + } +} diff --git a/app/Filament/Resources/ArticleResource/Pages/ListArticles.php b/app/Filament/Resources/ArticleResource/Pages/ListArticles.php new file mode 100644 index 00000000..0d007448 --- /dev/null +++ b/app/Filament/Resources/ArticleResource/Pages/ListArticles.php @@ -0,0 +1,13 @@ +user = $this->login(); + $this->articles = Article::factory()->count(10)->create([ + 'submitted_at' => now(), + ]); +}); + +describe(ArticleResource::class, function (): void { + + it('page can display table with records', function (): void { + Livewire::test(ArticleResource\Pages\ListArticles::class) + ->assertCanSeeTableRecords($this->articles); + }); + + it('admin user can approved article', function (): void { + $article = $this->articles->first(); + + Livewire::test(ArticleResource\Pages\ListArticles::class) + ->callTableAction('approved', $article); + + $article->refresh(); + + expect($article->approved_at) + ->not + ->toBe(null) + ->and($article->declined_at) + ->toBe(null); + + Livewire::test(ArticleResource\Pages\ListArticles::class) + ->assertTableActionHidden('approved', $article) + ->assertTableActionHidden('declined', $article); + }); + + it('admin user can declined article', function (): void { + $article = $this->articles->first(); + + Livewire::test(ArticleResource\Pages\ListArticles::class) + ->callTableAction('declined', $article); + + $article->refresh(); + + expect($article->declined_at) + ->not + ->toBe(null) + ->and($article->approved_at) + ->toBe(null); + + Livewire::test(ArticleResource\Pages\ListArticles::class) + ->assertTableActionHidden('approved', $article) + ->assertTableActionHidden('declined', $article); + + }); +})->group('articles');