Add Backend for participant index

This commit is contained in:
philipp lang 2024-02-08 21:04:00 +01:00
parent 48383b25da
commit 590696750b
9 changed files with 126 additions and 3 deletions

View File

@ -0,0 +1,26 @@
<?php
namespace App\Form\Actions;
use App\Form\Models\Form;
use App\Form\Resources\ParticipantResource;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Pagination\LengthAwarePaginator;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
class ParticipantIndexAction
{
use AsAction;
public function handle(Form $form): LengthAwarePaginator
{
return $form->participants()->with('form')->paginate(15);
}
public function asController(ActionRequest $request, Form $form): AnonymousResourceCollection
{
return ParticipantResource::collection($this->handle($form))
->additional(['meta' => ParticipantResource::meta($form)]);
}
}

View File

@ -4,6 +4,7 @@ namespace App\Form\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Participant extends Model
{
@ -14,4 +15,12 @@ class Participant extends Model
public $casts = [
'data' => 'json',
];
/**
* @return BelongsTo<Form, self>
*/
public function form(): BelongsTo
{
return $this->belongsTo(Form::class);
}
}

View File

@ -42,6 +42,7 @@ class FormResource extends JsonResource
'config' => $this->config,
'participants_count' => $this->participants_count,
'links' => [
'participant_index' => route('form.participant.index', ['form' => $this->getModel()]),
'update' => route('form.update', ['form' => $this->getModel()]),
'destroy' => route('form.destroy', ['form' => $this->getModel()]),
]

View File

@ -0,0 +1,33 @@
<?php
namespace App\Form\Resources;
use App\Form\Models\Form;
use Illuminate\Http\Resources\Json\JsonResource;
class ParticipantResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return $this->form->getFields()->mapWithKeys(function ($field) {
return [$field['key'] => $this->data[$field['key']]];
})->toArray();
}
public static function meta(Form $form): array
{
return [
'columns' => $form->getFields()->map(fn ($field) => [
'name' => $field['name'],
'base_type' => class_basename($field['type']),
'id' => $field['key'],
])
];
}
}

View File

@ -38,4 +38,12 @@ class ParticipantFactory extends Factory
{
return $this->state(['config' => ['sections' => array_map(fn ($section) => $section->create(), $sections)]]);
}
/**
* @param array<string, mixed> $data
*/
public function data(array $data): self
{
return $this->state(['data' => $data]);
}
}

View File

@ -30,6 +30,7 @@ use App\Form\Actions\FormtemplateIndexAction;
use App\Form\Actions\FormtemplateStoreAction;
use App\Form\Actions\FormtemplateUpdateAction;
use App\Form\Actions\FormUpdateAction;
use App\Form\Actions\ParticipantIndexAction;
use App\Initialize\Actions\InitializeAction;
use App\Initialize\Actions\InitializeFormAction;
use App\Initialize\Actions\NamiGetSearchLayerAction;
@ -156,4 +157,5 @@ Route::group(['middleware' => 'auth:web'], function (): void {
Route::post('/formtemplate', FormtemplateStoreAction::class)->name('formtemplate.store');
Route::patch('/formtemplate/{formtemplate}', FormtemplateUpdateAction::class)->name('formtemplate.update');
Route::post('/form', FormStoreAction::class)->name('form.store');
Route::get('/form/{form}/participants', ParticipantIndexAction::class)->name('form.participant.index');
});

View File

@ -50,6 +50,7 @@ class FormIndexActionTest extends EndToEndTestCase
->assertInertiaPath('data.data.0.to', '2023-06-07')
->assertInertiaPath('data.data.0.registration_from', '2023-05-06 04:00:00')
->assertInertiaPath('data.data.0.registration_until', '2023-04-01 05:00:00')
->assertInertiaPath('data.data.0.links.participant_index', route('form.participant.index', ['form' => $form]))
->assertInertiaPath('data.meta.links.store', route('form.store'))
->assertInertiaPath('data.meta.links.formtemplate_index', route('formtemplate.index'))
->assertInertiaPath('data.meta.templates.0.name', 'tname')

View File

@ -0,0 +1,40 @@
<?php
namespace Tests\Feature\Form;
use App\Form\Fields\CheckboxesField;
use App\Form\Fields\DropdownField;
use App\Form\Fields\TextField;
use App\Form\Models\Form;
use App\Form\Models\Participant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class ParticipantIndexActionTest extends TestCase
{
use DatabaseTransactions;
public function testItShowsParticipantsAndColumns(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()
->has(Participant::factory()->data(['vorname' => 'Max', 'select' => 'A', 'stufe' => 'Pfadfinder']))
->sections([
FormtemplateSectionRequest::new()->fields([
FormtemplateFieldRequest::type(TextField::class)->name('Vorname')->key('vorname'),
FormtemplateFieldRequest::type(CheckboxesField::class)->key('select')->options(['A', 'B', 'C']),
FormtemplateFieldRequest::type(DropdownField::class)->key('stufe')->options(['Wölfling', 'Jungpfadfinder', 'Pfadfinder']),
]),
])
->create();
$this->callFilter('form.participant.index', [], ['form' => $form])
->assertOk()
->assertJsonPath('data.0.vorname', 'Max')
->assertJsonPath('data.0.stufe', 'Pfadfinder')
->assertJsonPath('meta.columns.0.name', 'Vorname')
->assertJsonPath('meta.columns.0.base_type', class_basename(TextField::class))
->assertJsonPath('meta.columns.0.id', 'vorname');
}
}

View File

@ -8,19 +8,22 @@ trait MakesHttpCalls
{
/**
* @param array<string, mixed> $filter
* @param array<string, mixed> $routeParams
*/
public function callFilter(string $routeName, array $filter): TestResponse
public function callFilter(string $routeName, array $filter, array $routeParams = []): TestResponse
{
return $this->call('GET', $this->filterUrl($routeName, $filter));
return $this->call('GET', $this->filterUrl($routeName, $filter, $routeParams));
}
/**
* @param array<string, mixed> $filter
* @param array<string, mixed> $routeParams
*/
public function filterUrl(string $routeName, array $filter): string
public function filterUrl(string $routeName, array $filter, array $routeParams = []): string
{
$params = [
'filter' => $this->filterString($filter),
...$routeParams
];
return route($routeName, $params);