Compare commits

...

3 Commits

Author SHA1 Message Date
philipp lang 56c28ae00e Add form to edit
continuous-integration/drone/push Build is failing Details
2024-07-12 20:18:41 +02:00
philipp lang a603aca80c Add backend for update 2024-07-12 20:15:24 +02:00
philipp lang c05434a7fb Add participant fields link 2024-07-12 19:49:47 +02:00
9 changed files with 158 additions and 4 deletions

View File

@ -0,0 +1,22 @@
<?php
namespace App\Form\Actions;
use App\Form\Models\Participant;
use Illuminate\Http\JsonResponse;
use Lorisleiva\Actions\Concerns\AsAction;
class ParticipantFieldsAction
{
use AsAction;
public function handle(Participant $participant): JsonResponse
{
return response()->json([
'data' => [
'id' => $participant->id,
'config' => $participant->getConfig(),
]
]);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Form\Actions;
use App\Form\Models\Participant;
use App\Lib\Events\Succeeded;
use Illuminate\Http\JsonResponse;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
class ParticipantUpdateAction
{
use AsAction;
public function rules(): array
{
return [
'data' => 'required',
];
}
public function handle(Participant $participant, ActionRequest $request): JsonResponse
{
$participant->update(['data' => [...$participant->data, ...$request->validated('data')]]);
Succeeded::message('Teilnehmer*in bearbeitet.')->dispatch();
return response()->json([]);
}
}

View File

@ -31,7 +31,9 @@ class ParticipantResource extends JsonResource
'links' => [ 'links' => [
'assign' => route('participant.assign', ['participant' => $this->getModel()]), 'assign' => route('participant.assign', ['participant' => $this->getModel()]),
'destroy' => route('participant.destroy', ['participant' => $this->getModel()]), 'destroy' => route('participant.destroy', ['participant' => $this->getModel()]),
'children' => route('form.participant.index', ['form' => $this->form, 'parent' => $this->id]) 'children' => route('form.participant.index', ['form' => $this->form, 'parent' => $this->id]),
'fields' => route('participant.fields', ['participant' => $this->getModel()]),
'update' => route('participant.update', ['participant' => $this->getModel()]),
] ]
]; ];
} }

@ -1 +1 @@
Subproject commit 25d36a53ce5bc10637773513185935503503d41c Subproject commit 768cf47bd3f5a6199d178b12ff6fd68e94dd1949

View File

@ -1,5 +1,14 @@
<template> <template>
<div class="mt-5"> <div class="mt-5">
<ui-popup v-if="editing !== null" heading="Mitglied bearbeiten" closeable full @close="editing = null">
<event-form
:value="editingPreviewString"
:base-url="meta.base_url"
style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)"
as-form
@save="updateParticipant($event.detail[0])"
></event-form>
</ui-popup>
<ui-popup v-if="assigning !== null" heading="Mitglied zuweisen" closeable @close="assigning = null"> <ui-popup v-if="assigning !== null" heading="Mitglied zuweisen" closeable @close="assigning = null">
<member-assign @assign="assign"></member-assign> <member-assign @assign="assign"></member-assign>
</ui-popup> </ui-popup>
@ -77,7 +86,7 @@
</div> </div>
</td> </td>
<td> <td>
<a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="edit(participant)"><ui-sprite src="pencil"></ui-sprite></a> <a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="editReal(participant)"><ui-sprite src="pencil"></ui-sprite></a>
<a v-tooltip="`Löschen`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = participant"><ui-sprite src="trash"></ui-sprite></a> <a v-tooltip="`Löschen`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = participant"><ui-sprite src="trash"></ui-sprite></a>
</td> </td>
</tr> </tr>
@ -95,7 +104,7 @@
<div v-else v-text="child[column.display_attribute]"></div> <div v-else v-text="child[column.display_attribute]"></div>
</td> </td>
<td> <td>
<a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="edit(child)"><ui-sprite src="pencil"></ui-sprite></a> <a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="editReal(child)"><ui-sprite src="pencil"></ui-sprite></a>
<a v-tooltip="`Löschen`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = child"><ui-sprite src="trash"></ui-sprite></a> <a v-tooltip="`Löschen`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = child"><ui-sprite src="trash"></ui-sprite></a>
</td> </td>
</tr> </tr>
@ -202,4 +211,23 @@ function dropdownFilterOptions(filter) {
}), }),
]; ];
} }
async function editReal(participant) {
const response = await axios.get(participant.links.fields);
editing.value = {
participant: participant,
config: response.data.data.config,
};
}
async function updateParticipant(payload) {
await axios.patch(editing.value.participant.links.update, {data: payload});
await reload();
editing.value = null;
}
const editing = ref(null);
const editingPreviewString = computed(() => editing.value === null ? '' : JSON.stringify(editing.value.config));
</script> </script>

View File

@ -38,7 +38,9 @@ use App\Form\Actions\FormUpdateMetaAction;
use App\Form\Actions\IsDirtyAction; use App\Form\Actions\IsDirtyAction;
use App\Form\Actions\ParticipantAssignAction; use App\Form\Actions\ParticipantAssignAction;
use App\Form\Actions\ParticipantDestroyAction; use App\Form\Actions\ParticipantDestroyAction;
use App\Form\Actions\ParticipantFieldsAction;
use App\Form\Actions\ParticipantIndexAction; use App\Form\Actions\ParticipantIndexAction;
use App\Form\Actions\ParticipantUpdateAction;
use App\Initialize\Actions\InitializeAction; use App\Initialize\Actions\InitializeAction;
use App\Initialize\Actions\InitializeFormAction; use App\Initialize\Actions\InitializeFormAction;
use App\Initialize\Actions\NamiGetSearchLayerAction; use App\Initialize\Actions\NamiGetSearchLayerAction;
@ -172,6 +174,8 @@ Route::group(['middleware' => 'auth:web'], function (): void {
Route::post('/form/{form}/is-dirty', IsDirtyAction::class)->name('form.is-dirty'); Route::post('/form/{form}/is-dirty', IsDirtyAction::class)->name('form.is-dirty');
Route::delete('/participant/{participant}', ParticipantDestroyAction::class)->name('participant.destroy'); Route::delete('/participant/{participant}', ParticipantDestroyAction::class)->name('participant.destroy');
Route::post('/participant/{participant}/assign', ParticipantAssignAction::class)->name('participant.assign'); Route::post('/participant/{participant}/assign', ParticipantAssignAction::class)->name('participant.assign');
Route::get('/participant/{participant}/fields', ParticipantFieldsAction::class)->name('participant.fields');
Route::patch('/participant/{participant}', ParticipantUpdateAction::class)->name('participant.update');
// ------------------------------------ fileshare ----------------------------------- // ------------------------------------ fileshare -----------------------------------
Route::post('/fileshare', FileshareStoreAction::class)->name('fileshare.store'); Route::post('/fileshare', FileshareStoreAction::class)->name('fileshare.store');

View File

@ -0,0 +1,36 @@
<?php
namespace Tests\Feature\Form;
use App\Form\Models\Form;
use App\Form\Models\Participant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ParticipantFieldsActionTest extends FormTestCase
{
use DatabaseTransactions;
public function testItShowsParticipantsFields(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$participant = Participant::factory()->data(['vorname' => 'Max', 'select' => ['A', 'B']])
->for(Form::factory()->sections([
FormtemplateSectionRequest::new()->name('Sektion')->fields([
$this->textField('vorname')->name('Vorname'),
$this->checkboxesField('select')->options(['A', 'B', 'C']),
])
]))
->create();
$this->callFilter('participant.fields', [], ['participant' => $participant->id])
->assertOk()
->assertJsonPath('data.id', $participant->id)
->assertJsonPath('data.config.sections.0.name', 'Sektion')
->assertJsonPath('data.config.sections.0.fields.0.key', 'vorname')
->assertJsonPath('data.config.sections.0.fields.0.value', 'Max')
->assertJsonPath('data.config.sections.0.fields.1.key', 'select')
->assertJsonPath('data.config.sections.0.fields.1.value', ['A', 'B']);
}
}

View File

@ -48,6 +48,8 @@ class ParticipantIndexActionTest extends FormTestCase
->assertJsonPath('data.0.select_display', 'A, B') ->assertJsonPath('data.0.select_display', 'A, B')
->assertJsonPath('data.0.links.destroy', route('participant.destroy', ['participant' => $form->participants->first()])) ->assertJsonPath('data.0.links.destroy', route('participant.destroy', ['participant' => $form->participants->first()]))
->assertJsonPath('data.0.links.assign', route('participant.assign', ['participant' => $form->participants->first()])) ->assertJsonPath('data.0.links.assign', route('participant.assign', ['participant' => $form->participants->first()]))
->assertJsonPath('data.0.links.fields', route('participant.fields', ['participant' => $form->participants->first()]))
->assertJsonPath('data.0.links.update', route('participant.update', ['participant' => $form->participants->first()]))
->assertJsonPath('meta.columns.0.name', 'Vorname') ->assertJsonPath('meta.columns.0.name', 'Vorname')
->assertJsonPath('meta.columns.0.base_type', class_basename(TextField::class)) ->assertJsonPath('meta.columns.0.base_type', class_basename(TextField::class))
->assertJsonPath('meta.columns.0.id', 'vorname') ->assertJsonPath('meta.columns.0.id', 'vorname')

View File

@ -0,0 +1,31 @@
<?php
namespace Tests\Feature\Form;
use App\Form\Models\Form;
use App\Form\Models\Participant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ParticipantUpdateActionTest extends FormTestCase
{
use DatabaseTransactions;
public function testItUpdatesParticipant(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$participant = Participant::factory()->data(['vorname' => 'Max', 'select' => ['A', 'B']])
->for(Form::factory()->sections([
FormtemplateSectionRequest::new()->name('Sektion')->fields([
$this->textField('vorname')->name('Vorname'),
$this->checkboxesField('select')->options(['A', 'B', 'C']),
])
]))
->create();
$this->patchJson(route('participant.update', ['participant' => $participant->id]), ['data' => ['vorname' => 'Jane']])
->assertOk();
$this->assertEquals('Jane', $participant->fresh()->data['vorname']);
}
}