299 lines
14 KiB
Vue
299 lines
14 KiB
Vue
<template>
|
|
<div class="relative w-full flex flex-col">
|
|
<info :step="1" v-model="step">
|
|
<template #current>
|
|
<div class="space-y-1">
|
|
<p>Bitte melde dich mit deinen <span class="font-semibold">NaMi Zugangsdaten</span> an. Im Anschluss kannst du deine Grüpplinge aus deiner Gruppierung hier hinzufügen.</p>
|
|
<p>
|
|
Falls du noch keine NaMi Zugangsdaten hast, kannst du sie
|
|
<a href="https://nami.dpsg.de/ica/pages/requestLogin.jsp" target="_BLANK" class="font-semibold">hier</a>
|
|
beantragen.
|
|
</p>
|
|
<p>
|
|
Bitte achte außerdem darauf, dass du mindestens <span class="font-semibold">Leserechte</span> auf deine Gruppierung hast. Diese kann dir i.d.R. dein
|
|
<span class="font-semibold">StaVo</span> erteilen.
|
|
</p>
|
|
</div>
|
|
<div class="flex mt-4 space-x-3">
|
|
<v-text @keypress.enter="innerLogin" name="nami_mglnr" label="Mitgliedsnummer" id="nami_mglnr" v-model="loginData.mglnr" required></v-text>
|
|
<v-text @keypress.enter="innerLogin" name="nami_password" label="Passwort" id="nami_password" v-model="loginData.password" type="password" required></v-text>
|
|
<v-btn class="self-end" @click.prevent="innerLogin">Anmelden</v-btn>
|
|
</div>
|
|
</template>
|
|
<template #finished>
|
|
<div class="flex items-center justify-between">
|
|
<div>Erfolgreich eingeloggt als {{ user }}.</div>
|
|
<v-btn class="self-end" @click.prevent="innerLogout">Abmelden</v-btn>
|
|
</div>
|
|
</template>
|
|
</info>
|
|
|
|
<info class="mt-4" :step="2" v-model="step">
|
|
<template #due>
|
|
<div>Mitglieder auswählen</div>
|
|
</template>
|
|
<template #current>
|
|
<p>
|
|
Nun kannst du hier nach Mitgliedern suchen. Wähle die Mitglieder aus, die <span class="font-semibold">an der Veranstaltung teilnehmen</span>. Dich selbst musst du hier nicht
|
|
nochmal auswählen.
|
|
</p>
|
|
<div class="flex mt-4 space-x-3">
|
|
<v-text name="search_firstname" label="Vorname" id="search_firstname" v-model="searchData.vorname" @input="searchForMember(1)"></v-text>
|
|
<v-text name="search_lastname" label="Nachname" id="search_lastname" v-model="searchData.nachname" @input="searchForMember(1)"></v-text>
|
|
<v-dropdown
|
|
name="search_group"
|
|
:allowcustom="false"
|
|
label="Stufe"
|
|
id="search_group"
|
|
v-model="searchData.untergliederungId"
|
|
@input="searchForMember(1)"
|
|
:options="eventMeta.agegroups"
|
|
></v-dropdown>
|
|
</div>
|
|
<div class="relative min-h-48">
|
|
<div class="relative grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-2 mt-2">
|
|
<v-checkbox
|
|
:modelValue="memberSelected(member)"
|
|
@update:modelValue="toggleMember(member)"
|
|
:name="`${field.key}-memberselect-${member.id}`"
|
|
:id="`${field.key}-memberselect-${member.id}`"
|
|
:label="member.name"
|
|
intro=""
|
|
v-for="member in searchResults.data"
|
|
></v-checkbox>
|
|
</div>
|
|
<pagination class="mt-5" :model-value="searchResults" @reload="searchForMember($event)" v-if="searchResults.current_page"></pagination>
|
|
<div class="absolute flex h-full w-full top-0 left-0 justify-center items-center backdrop-blur-sm" v-if="searching">
|
|
<spinner class="w-20 h-20"></spinner>
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-center mt-5">
|
|
<v-btn @click.prevent="membersAccepted = true">Weiter</v-btn>
|
|
</div>
|
|
</template>
|
|
<template #finished>
|
|
<div class="flex items-center justify-between">
|
|
<div>{{ inner.length }} Mitglieder ausgewählt</div>
|
|
<v-btn class="self-end" @click.prevent="membersAccepted = false">Bearbeiten</v-btn>
|
|
</div>
|
|
</template>
|
|
</info>
|
|
|
|
<info class="mt-4" :step="3" v-model="step">
|
|
<template #due>
|
|
<div>Mitgliederdaten vervollständigen</div>
|
|
</template>
|
|
<template #current>
|
|
<p>
|
|
Hier siehst du noch einmal alle ausgewählten Mitglieder. Ggf sind hier pro Mitglied noch weitere Informationen erforderlich. Bitte gebe diese pro Mitglied an und klicke dann auf
|
|
"weiter".
|
|
</p>
|
|
<div class="grid gap-2 mt-6">
|
|
<accordion v-model="openValue" :index="index" :title="member.innerFormName" v-for="(member, index) in inner" :key="index" type="info">
|
|
<div class="mt-2" :class="containerClassesSm">
|
|
<template v-for="(memberField, memberIndex) in memberFields">
|
|
<v-checkbox
|
|
v-if="memberField.type === 'CheckboxField'"
|
|
v-model="member[memberField.key]"
|
|
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:label="memberField.description"
|
|
intro=""
|
|
:required="memberField.required"
|
|
:class="colClassesForField(memberField)"
|
|
></v-checkbox>
|
|
<v-dropdown
|
|
v-if="memberField.type === 'DropdownField'"
|
|
v-model="member[memberField.key]"
|
|
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:label="memberField.name"
|
|
:allowcustom="false"
|
|
:class="colClassesForField(memberField)"
|
|
:required="memberField.required"
|
|
:options="
|
|
memberField.options.map((o) => {
|
|
return {id: o, name: o};
|
|
})
|
|
"
|
|
></v-dropdown>
|
|
<v-text
|
|
v-if="memberField.type === 'TextField'"
|
|
v-model="member[memberField.key]"
|
|
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:label="memberField.name"
|
|
:required="memberField.required"
|
|
:class="colClassesForField(memberField)"
|
|
></v-text>
|
|
<v-text
|
|
v-if="memberField.type === 'DateField'"
|
|
v-model="member[memberField.key]"
|
|
:max-today="memberField.max_today"
|
|
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:label="memberField.name"
|
|
:required="memberField.required"
|
|
:class="colClassesForField(memberField)"
|
|
type="date"
|
|
></v-text>
|
|
<v-text
|
|
v-if="memberField.type === 'NumberField'"
|
|
v-model="member[memberField.key]"
|
|
:min="memberField.min"
|
|
:max="memberField.max"
|
|
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:label="memberField.name"
|
|
:required="memberField.required"
|
|
:class="colClassesForField(memberField)"
|
|
type="number"
|
|
></v-text>
|
|
<v-checkboxes
|
|
v-if="memberField.type === 'CheckboxesField'"
|
|
:intro="memberField.intro"
|
|
:options="memberField.options"
|
|
:label="memberField.name"
|
|
:name="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:hint="memberField.hint"
|
|
:class="colClassesForField(memberField)"
|
|
v-model="member[memberField.key]"
|
|
></v-checkboxes>
|
|
<v-radio
|
|
v-if="memberField.type === 'RadioField'"
|
|
:intro="memberField.intro"
|
|
:id="`${field.key}-memberattr-${member.id}-${memberField.key}`"
|
|
:required="memberField.required"
|
|
:allowcustom="memberField.allowcustom"
|
|
:options="memberField.options"
|
|
:label="memberField.name"
|
|
:hint="memberField.hint"
|
|
:class="colClassesForField(memberField)"
|
|
v-model="member[memberField.key]"
|
|
></v-radio>
|
|
</template>
|
|
</div>
|
|
</accordion>
|
|
</div>
|
|
<div class="flex justify-center mt-5">
|
|
<v-btn @click.prevent="membersCompleted = true">Mitgliederdaten speichern</v-btn>
|
|
</div>
|
|
</template>
|
|
<template #finished>
|
|
<div class="flex items-center justify-between">
|
|
<div>Daten vervollständigt</div>
|
|
<v-btn class="self-end" @click.prevent="membersCompleted = false">Bearbeiten</v-btn>
|
|
</div>
|
|
</template>
|
|
</info>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {computed, ref, warn} from 'vue';
|
|
import VDropdown from './VDropdown.vue';
|
|
import VCheckboxes from './VCheckboxes.vue';
|
|
import VText from './VText.vue';
|
|
import useFields from '../../composables/useFieldsWithoutNami.js';
|
|
import Info from '../Info.vue';
|
|
import VBtn from '../VBtn.vue';
|
|
import VCheckbox from './VCheckbox.vue';
|
|
import VRadio from './VRadio.vue';
|
|
import Spinner from '../Spinner.vue';
|
|
import useAdremaLogin from '../../composables/useAdremaLogin.js';
|
|
import useEventMeta from '../../composables/useEventMeta.js';
|
|
import Pagination from '../Pagination.vue';
|
|
import Accordion from '../Accordion.vue';
|
|
import useColumns from '../../composables/useColumns.js';
|
|
|
|
const eventMeta = useEventMeta();
|
|
const {colClassesForField, containerClassesSm} = useColumns();
|
|
const {login, logout, user, loginData, searchData, searchForMember, resetSearchData, searchResults, searching} = useAdremaLogin();
|
|
|
|
if (user.value !== null) {
|
|
resetSearchData();
|
|
searchForMember();
|
|
}
|
|
|
|
const {resolveComponentName} = useFields();
|
|
const step = computed(() => {
|
|
if (user.value === null) {
|
|
return 1;
|
|
}
|
|
|
|
if (!membersAccepted.value) {
|
|
return 2;
|
|
}
|
|
|
|
if (!membersCompleted.value) {
|
|
return 3;
|
|
}
|
|
|
|
return 4;
|
|
});
|
|
|
|
const openValue = ref(-1);
|
|
|
|
const membersAccepted = ref(false);
|
|
const membersCompleted = ref(false);
|
|
const emit = defineEmits(['update:modelValue']);
|
|
const props = defineProps({
|
|
modelValue: {
|
|
required: true,
|
|
validator: (value) => typeof value === 'object',
|
|
},
|
|
field: {
|
|
required: true,
|
|
validator: (value) => true,
|
|
},
|
|
fields: {
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
const defaultMember = computed(() => {
|
|
var fields = {};
|
|
memberFields.value.forEach((field) => (fields[field.key] = field.value));
|
|
|
|
return fields;
|
|
});
|
|
|
|
const memberFields = computed(() => props.fields.filter((field) => field.for_members === true && field.nami_type === null));
|
|
|
|
const inner = computed(
|
|
{
|
|
get: () => props.modelValue,
|
|
set: (v) => emit('update:modelValue', v),
|
|
},
|
|
{deep: true},
|
|
);
|
|
async function innerLogin() {
|
|
await login();
|
|
membersAccepted.value = false;
|
|
membersCompleted.value = false;
|
|
resetSearchData();
|
|
searchForMember();
|
|
}
|
|
|
|
function memberSelected(member) {
|
|
return inner.value.map((m) => m.id).includes(member.id);
|
|
}
|
|
|
|
function toggleMember(member) {
|
|
if (memberSelected(member)) {
|
|
inner.value = inner.value.filter((m) => m.id !== member.id);
|
|
} else {
|
|
inner.value.push(JSON.parse(JSON.stringify({id: member.id, innerFormName: member.name, ...defaultMember.value})));
|
|
}
|
|
}
|
|
|
|
async function innerLogout() {
|
|
logout();
|
|
resetSearchData();
|
|
membersAccepted.value = false;
|
|
membersCompleted.value = false;
|
|
inner.value = [];
|
|
}
|
|
</script>
|