Compare commits
No commits in common. "1630bce7950be3d3579e20186f4a989610f6aa49" and "1a5675634f7cef734f1b4fa5e94551b302115a3e" have entirely different histories.
1630bce795
...
1a5675634f
|
@ -37,7 +37,7 @@ class ParticipantIndexAction
|
|||
|
||||
$data = match ($parent) {
|
||||
null => $this->handle($form, $filter),
|
||||
-1 => $this->getQuery($form, $filter)->where('parent_id', null)->paginate(15),
|
||||
-1 => $this->getQuery($form, $filter)->where('parent_id', null)->get(),
|
||||
default => $this->getQuery($form, $filter)->where('parent_id', $parent)->get(),
|
||||
};
|
||||
|
||||
|
|
|
@ -35,11 +35,6 @@ class FieldCollection extends Collection
|
|||
return $this->filter(fn ($field) => !is_a($field, NamiField::class));
|
||||
}
|
||||
|
||||
public function hasNamiField(): bool
|
||||
{
|
||||
return $this->first(fn ($field) => is_a($field, NamiField::class)) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return stdClass
|
||||
*/
|
||||
|
|
|
@ -46,10 +46,8 @@ class FormResource extends JsonResource
|
|||
'participants_count' => $this->participants_count,
|
||||
'is_active' => $this->is_active,
|
||||
'is_private' => $this->is_private,
|
||||
'has_nami_field' => $this->getFields()->hasNamiField(),
|
||||
'links' => [
|
||||
'participant_index' => route('form.participant.index', ['form' => $this->getModel(), 'parent' => null]),
|
||||
'participant_root_index' => route('form.participant.index', ['form' => $this->getModel(), 'parent' => -1]),
|
||||
'participant_index' => route('form.participant.index', ['form' => $this->getModel()]),
|
||||
'update' => route('form.update', ['form' => $this->getModel()]),
|
||||
'destroy' => route('form.destroy', ['form' => $this->getModel()]),
|
||||
'is_dirty' => route('form.is-dirty', ['form' => $this->getModel()]),
|
||||
|
|
|
@ -23,13 +23,11 @@ class ParticipantResource extends JsonResource
|
|||
{
|
||||
return [
|
||||
...$this->getModel()->getFields()->present(),
|
||||
'id' => $this->id,
|
||||
'created_at' => $this->created_at->format('Y-m-d H:i:s'),
|
||||
'created_at_display' => $this->created_at->format('d.m.Y'),
|
||||
'children_count' => $this->children_count,
|
||||
'links' => [
|
||||
'destroy' => route('participant.destroy', ['participant' => $this->getModel()]),
|
||||
'children' => route('form.participant.index', ['form' => $this->form, 'parent' => $this->id])
|
||||
]
|
||||
];
|
||||
}
|
||||
|
@ -59,7 +57,6 @@ class ParticipantResource extends JsonResource
|
|||
'default_filter_value' => ParticipantFilterScope::$nan,
|
||||
'filters' => $filterData,
|
||||
'form_meta' => $form->meta,
|
||||
'has_nami_field' => $form->getFields()->hasNamiField(),
|
||||
'links' => [
|
||||
'update_form_meta' => route('form.update-meta', ['form' => $form]),
|
||||
],
|
||||
|
|
|
@ -2,12 +2,10 @@ import {ref, inject, onBeforeUnmount} from 'vue';
|
|||
import {router} from '@inertiajs/vue3';
|
||||
import useQueueEvents from './useQueueEvents.js';
|
||||
|
||||
export function useApiIndex(firstUrl, siteName) {
|
||||
export function useApiIndex(url, siteName) {
|
||||
const axios = inject('axios');
|
||||
const {startListener, stopListener} = useQueueEvents(siteName, () => reload());
|
||||
const single = ref(null);
|
||||
|
||||
const url = ref(firstUrl);
|
||||
const inner = {
|
||||
data: ref([]),
|
||||
meta: ref({}),
|
||||
|
@ -19,7 +17,7 @@ export function useApiIndex(firstUrl, siteName) {
|
|||
...p,
|
||||
};
|
||||
|
||||
var response = (await axios.get(url.value, {params})).data;
|
||||
var response = (await axios.get(url, {params})).data;
|
||||
inner.data.value = response.data;
|
||||
inner.meta.value = response.meta;
|
||||
}
|
||||
|
@ -74,10 +72,6 @@ export function useApiIndex(firstUrl, siteName) {
|
|||
single.value = null;
|
||||
}
|
||||
|
||||
function updateUrl(newUrl) {
|
||||
url.value = newUrl;
|
||||
}
|
||||
|
||||
startListener();
|
||||
onBeforeUnmount(() => stopListener());
|
||||
|
||||
|
@ -97,7 +91,5 @@ export function useApiIndex(firstUrl, siteName) {
|
|||
cancel,
|
||||
axios,
|
||||
toFilterString,
|
||||
updateUrl,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import {computed, ref, inject} from 'vue';
|
||||
|
||||
export default function (init) {
|
||||
const axios = inject('axios');
|
||||
|
||||
const children = ref(init);
|
||||
|
||||
function isOpen(child) {
|
||||
return child in children.value;
|
||||
}
|
||||
|
||||
async function toggle(parent) {
|
||||
if (isOpen(parent.id)) {
|
||||
delete children.value[parent.id];
|
||||
} else {
|
||||
children.value[parent.id] = (await axios.get(parent.links.children)).data.data;
|
||||
}
|
||||
}
|
||||
|
||||
function childrenOf(parentId) {
|
||||
return children.value[parentId] ? children.value[parentId] : [];
|
||||
}
|
||||
|
||||
function clearToggle() {
|
||||
children.value = {};
|
||||
}
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
toggle,
|
||||
childrenOf,
|
||||
clearToggle,
|
||||
};
|
||||
}
|
|
@ -32,7 +32,7 @@
|
|||
</ui-popup>
|
||||
|
||||
<ui-popup v-if="showing !== null" :heading="`Teilnehmende für ${showing.name}`" full @close="showing = null">
|
||||
<participants :has-nami-field="showing.has_nami_field" :root-url="showing.links.participant_root_index" :url="showing.links.participant_index"> </participants>
|
||||
<participants :url="showing.links.participant_index"></participants>
|
||||
</ui-popup>
|
||||
|
||||
<ui-popup v-if="single !== null && single.config !== null" :heading="`Veranstaltung ${single.id ? 'bearbeiten' : 'erstellen'}`" full @close="cancel">
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
</div>
|
||||
</ui-popup>
|
||||
<page-filter breakpoint="lg">
|
||||
<f-switch v-if="meta.has_nami_field" id="group_participants" v-model="groupParticipants" label="Gruppieren" size="sm" name="group_participants"></f-switch>
|
||||
<f-multipleselect id="active_columns" v-model="activeColumnsConfig" :options="meta.columns" label="Aktive Spalten" size="sm" name="active_columns"></f-multipleselect>
|
||||
|
||||
<template v-for="(filter, index) in meta.filters">
|
||||
|
@ -55,44 +54,15 @@
|
|||
<th></th>
|
||||
</thead>
|
||||
|
||||
<template v-for="(participant, index) in data" :key="index">
|
||||
<tr>
|
||||
<td v-for="(column, columnindex) in activeColumns" :key="column.id">
|
||||
<ui-table-toggle-button
|
||||
v-if="columnindex === 0 && groupParticipants"
|
||||
:value="participant"
|
||||
:text="participant[column.display_attribute]"
|
||||
:level="0"
|
||||
:active="isOpen(participant.id)"
|
||||
@toggle="toggle(participant)"
|
||||
></ui-table-toggle-button>
|
||||
<div v-else v-text="participant[column.display_attribute]"></div>
|
||||
<tr v-for="(participant, index) in data" :key="index">
|
||||
<td v-for="column in activeColumns" :key="column.id">
|
||||
<div v-text="participant[column.display_attribute]"></div>
|
||||
</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="`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>
|
||||
</tr>
|
||||
<template v-for="child in childrenOf(participant.id)" :key="child.id">
|
||||
<tr>
|
||||
<td v-for="(column, columnindex) in activeColumns" :key="column.id">
|
||||
<ui-table-toggle-button
|
||||
v-if="columnindex === 0 && groupParticipants"
|
||||
:value="child"
|
||||
:text="child[column.display_attribute]"
|
||||
:level="1"
|
||||
:active="isOpen(child.id)"
|
||||
@toggle="toggle(child)"
|
||||
></ui-table-toggle-button>
|
||||
<div v-else v-text="child[column.display_attribute]"></div>
|
||||
</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="`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>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</table>
|
||||
<div class="px-6">
|
||||
<ui-pagination class="mt-4" :value="meta" @reload="reloadPage"></ui-pagination>
|
||||
|
@ -103,10 +73,8 @@
|
|||
<script setup>
|
||||
import {watch, ref, computed} from 'vue';
|
||||
import {useApiIndex} from '../../composables/useApiIndex.js';
|
||||
import useTableToggle from '../../composables/useTableToggle.js';
|
||||
|
||||
const deleting = ref(null);
|
||||
const {isOpen, toggle, childrenOf, clearToggle} = useTableToggle({});
|
||||
|
||||
const props = defineProps({
|
||||
url: {
|
||||
|
@ -114,30 +82,9 @@ const props = defineProps({
|
|||
required: true,
|
||||
validator: (value) => value.startsWith('http'),
|
||||
},
|
||||
rootUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => value.startsWith('http'),
|
||||
},
|
||||
hasNamiField: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
const groupParticipants = computed({
|
||||
get() {
|
||||
return url.value === props.rootUrl;
|
||||
},
|
||||
async set(v) {
|
||||
updateUrl(v ? props.rootUrl : props.url);
|
||||
if (!v) {
|
||||
clearToggle();
|
||||
}
|
||||
await reload();
|
||||
},
|
||||
});
|
||||
|
||||
var {meta, data, reload, reloadPage, axios, remove, toFilterString, url, updateUrl} = useApiIndex(props.hasNamiField ? props.rootUrl : props.url, 'participant');
|
||||
var {meta, data, reload, reloadPage, axios, remove, toFilterString} = useApiIndex(props.url, 'participant');
|
||||
|
||||
const activeColumns = computed(() => meta.value.columns.filter((c) => meta.value.form_meta.active_columns.includes(c.id)));
|
||||
|
||||
|
|
|
@ -89,16 +89,25 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import {ref, reactive} from 'vue';
|
||||
import {indexProps, useIndex} from '../../composables/useInertiaApiIndex.js';
|
||||
import useTableToggle from '../../composables/useTableToggle.js';
|
||||
|
||||
const props = defineProps(indexProps);
|
||||
var {axios, meta, data} = useIndex(props.data, 'invoice');
|
||||
const {isOpen, toggle, childrenOf} = useTableToggle({null: data.value});
|
||||
|
||||
const children = reactive({
|
||||
null: data.value,
|
||||
});
|
||||
|
||||
var editing = ref(null);
|
||||
|
||||
async function toggle(parent) {
|
||||
if (isOpen(parent.id)) {
|
||||
delete children[parent.id];
|
||||
} else {
|
||||
children[parent.id] = (await axios.get(parent.links.children)).data.data;
|
||||
}
|
||||
}
|
||||
|
||||
async function edit(parent) {
|
||||
editing.value = {
|
||||
parent: parent,
|
||||
|
@ -106,6 +115,14 @@ async function edit(parent) {
|
|||
};
|
||||
}
|
||||
|
||||
function isOpen(child) {
|
||||
return child in children;
|
||||
}
|
||||
|
||||
function childrenOf(parent) {
|
||||
return children[parent] ? children[parent] : [];
|
||||
}
|
||||
|
||||
async function store() {
|
||||
await axios.post(meta.value.links.bulkstore, [editing.value.parent, ...editing.value.children]);
|
||||
children[editing.value.parent.id] = (await axios.get(editing.value.parent.links.children)).data.data;
|
||||
|
|
|
@ -83,18 +83,6 @@ class FormIndexActionTest extends FormTestCase
|
|||
->assertInertiaCount('data.data', 2);
|
||||
}
|
||||
|
||||
public function testItDisplaysParentLinkForFormWithNamiFields(): void
|
||||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$form = Form::factory()->fields([$this->namiField('mitglieder')])->create();
|
||||
|
||||
sleep(1);
|
||||
$this->callFilter('form.index', [])
|
||||
->assertInertiaPath('data.data.0.has_nami_field', true)
|
||||
->assertInertiaPath('data.data.0.links.participant_root_index', route('form.participant.index', ['form' => $form, 'parent' => -1]))
|
||||
->assertInertiaPath('data.data.0.links.participant_index', route('form.participant.index', ['form' => $form, 'parent' => null]));
|
||||
}
|
||||
|
||||
public function testItDisplaysRegisterUrl(): void
|
||||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
|
|
|
@ -21,7 +21,8 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
$group = Group::factory()->innerName('Stamm')->create();
|
||||
$form = Form::factory()
|
||||
->has(Participant::factory()->data(['vorname' => 'Max', 'select' => ['A', 'B'], 'stufe' => 'Pfadfinder', 'test1' => '', 'test2' => '', 'test3' => '', 'birthday' => '1991-04-20', 'bezirk' => $group->id]))
|
||||
->fields([
|
||||
->sections([
|
||||
FormtemplateSectionRequest::new()->fields([
|
||||
$this->textField('vorname')->name('Vorname'),
|
||||
$this->checkboxesField('select')->options(['A', 'B', 'C']),
|
||||
$this->dropdownField('stufe')->options(['Wölfling', 'Jungpfadfinder', 'Pfadfinder']),
|
||||
|
@ -30,12 +31,12 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
$this->textField('test3')->name('Test 3'),
|
||||
$this->dateField('birthday')->name('Geburtsdatum'),
|
||||
$this->groupField('bezirk')->name('bezirk'),
|
||||
]),
|
||||
])
|
||||
->create();
|
||||
|
||||
$this->callFilter('form.participant.index', [], ['form' => $form])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.0.id', $form->participants->first()->id)
|
||||
->assertJsonPath('data.0.vorname', 'Max')
|
||||
->assertJsonPath('data.0.vorname_display', 'Max')
|
||||
->assertJsonPath('data.0.stufe', 'Pfadfinder')
|
||||
|
@ -52,7 +53,6 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
->assertJsonPath('meta.columns.6.display_attribute', 'birthday_display')
|
||||
->assertJsonPath('meta.columns.0.display_attribute', 'vorname_display')
|
||||
->assertJsonPath('meta.form_meta.active_columns', ['vorname', 'select', 'stufe', 'test1'])
|
||||
->assertJsonPath('meta.has_nami_field', false)
|
||||
->assertJsonPath('meta.links.update_form_meta', route('form.update-meta', ['form' => $form]))
|
||||
->assertJsonPath('meta.form_meta.sorting', ['vorname', 'asc']);
|
||||
}
|
||||
|
@ -74,13 +74,6 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
$this->callFilter('form.participant.index', ['data' => []], ['form' => $form])->assertJsonPath('meta.filter.data.check', ParticipantFilterScope::$nan);
|
||||
}
|
||||
|
||||
public function testItDisplaysHasNamiField(): void
|
||||
{
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
$form = Form::factory()->fields([$this->namiField('mitglieder')])->create();
|
||||
$this->callFilter('form.participant.index', [], ['form' => $form])->assertJsonPath('meta.has_nami_field', true);
|
||||
}
|
||||
|
||||
public function testItFiltersParticipantsByCheckboxValue(): void
|
||||
{
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
|
@ -140,8 +133,10 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
->has(Participant::factory()->data(['mitglieder' => [['id' => 393], ['id' => 394]]]))
|
||||
->has(Participant::factory()->nr(393)->data(['mitglieder' => []]))
|
||||
->has(Participant::factory()->nr(394)->data(['mitglieder' => []]))
|
||||
->fields([
|
||||
->sections([
|
||||
FormtemplateSectionRequest::new()->fields([
|
||||
$this->namiField('mitglieder'),
|
||||
]),
|
||||
])
|
||||
->create();
|
||||
|
||||
|
@ -155,8 +150,10 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
$form = Form::factory()
|
||||
->has(Participant::factory()->data(['vorname' => 'Max']))
|
||||
->fields([
|
||||
->sections([
|
||||
FormtemplateSectionRequest::new()->fields([
|
||||
$this->textField('vorname')->name('Vorname'),
|
||||
]),
|
||||
])
|
||||
->create();
|
||||
|
||||
|
@ -196,9 +193,7 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
|
||||
$this->callFilter('form.participant.index', [], ['form' => $form, 'parent' => -1])
|
||||
->assertJsonPath('data.0.children_count', 2)
|
||||
->assertJsonPath('data.1.children_count', 0)
|
||||
->assertJsonPath('data.0.links.children', route('form.participant.index', ['form' => $form, 'parent' => $participant->id]))
|
||||
->assertJsonPath('meta.current_page', 1);
|
||||
->assertJsonPath('data.1.children_count', 0);
|
||||
$this->callFilter('form.participant.index', [], ['form' => $form, 'parent' => $participant->id])->assertJsonPath('data.0.children_count', 0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue