Compare commits
5 Commits
39e5479947
...
afff7c123a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afff7c123a | ||
|
|
94dc125a1b | ||
|
|
f070a4b0df | ||
|
|
260767680b | ||
|
|
09299c65de |
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<DialogFrame ref="dialog" :header-title="localTitle">
|
<DialogFrame ref="dialog" :header-title="localTitle">
|
||||||
<div class="row justify-center">
|
<div class="row justify-center">
|
||||||
<q-select
|
<SearchableSelect
|
||||||
|
class="q-mx-xl"
|
||||||
|
dense
|
||||||
autofocus
|
autofocus
|
||||||
:label="$t('event')"
|
:label="$t('event')"
|
||||||
filled
|
filled
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
@keyup.enter="addAttendees"
|
@keyup.enter="addAttendees"
|
||||||
map-options
|
map-options
|
||||||
emit-value
|
emit-value
|
||||||
></q-select>
|
></SearchableSelect>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-center">
|
<div class="row justify-center">
|
||||||
<q-btn class="q-ma-md" color="primary" no-caps @click="addAttendees">{{ localTitle }}</q-btn>
|
<q-btn class="q-ma-md" color="primary" no-caps @click="addAttendees">{{ localTitle }}</q-btn>
|
||||||
@@ -40,6 +42,7 @@ import type { Members } from 'src/vueLib/models/member';
|
|||||||
import EditAllDialog from 'src/components/EventEditAllDialog.vue';
|
import EditAllDialog from 'src/components/EventEditAllDialog.vue';
|
||||||
import { useAttendeesTable } from 'src/vueLib/tables/attendees/AttendeesTable';
|
import { useAttendeesTable } from 'src/vueLib/tables/attendees/AttendeesTable';
|
||||||
import { useEventTable } from 'src/vueLib/tables/events/EventsTable';
|
import { useEventTable } from 'src/vueLib/tables/events/EventsTable';
|
||||||
|
import SearchableSelect from 'src/vueLib/general/SearchableSelect .vue';
|
||||||
|
|
||||||
const dialog = ref();
|
const dialog = ref();
|
||||||
const newEventRef = ref();
|
const newEventRef = ref();
|
||||||
@@ -105,7 +108,7 @@ async function addAttendees() {
|
|||||||
NotifyResponse(err, 'error');
|
NotifyResponse(err, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
await updateAttendees();
|
await updateAttendees(0);
|
||||||
updateEvents();
|
updateEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
115
src/vueLib/general/SearchableSelect .vue
Normal file
115
src/vueLib/general/SearchableSelect .vue
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<q-select
|
||||||
|
ref="selectRef"
|
||||||
|
v-model="modelValueLocal"
|
||||||
|
:options="filteredOptions"
|
||||||
|
:option-label="optionLabel"
|
||||||
|
:option-value="optionValue"
|
||||||
|
:use-input="search"
|
||||||
|
input-debounce="200"
|
||||||
|
@filter="filterFn"
|
||||||
|
@update:model-value="emitValue"
|
||||||
|
v-bind="$attrs"
|
||||||
|
><template v-slot:append
|
||||||
|
><q-btn
|
||||||
|
size="xs"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
round
|
||||||
|
icon="search"
|
||||||
|
:color="search ? 'primary' : 'grey'"
|
||||||
|
@click="searchBox"
|
||||||
|
>
|
||||||
|
</q-btn
|
||||||
|
></template>
|
||||||
|
</q-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" generic="T extends Record<string, string | number | object>">
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
|
const search = ref(false);
|
||||||
|
const selectRef = ref();
|
||||||
|
|
||||||
|
defineOptions({ inheritAttrs: false });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Object] as PropType<string | number | object | null>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array as PropType<T[]>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
optionLabel: {
|
||||||
|
type: [Function, String] as PropType<((option: T) => string) | string>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
optionValue: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: string | number | null): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const optionLabel = props.optionLabel;
|
||||||
|
const optionValue = props.optionValue;
|
||||||
|
|
||||||
|
const modelValueLocal = ref<string | number | object | null | undefined>(props.modelValue);
|
||||||
|
const filteredOptions = ref<T[]>([...props.options]);
|
||||||
|
|
||||||
|
function searchBox() {
|
||||||
|
if (search.value) {
|
||||||
|
selectRef.value.updateInputValue('');
|
||||||
|
}
|
||||||
|
search.value = !search.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(v) => (modelValueLocal.value = v),
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.options,
|
||||||
|
(o) => (filteredOptions.value = [...o]),
|
||||||
|
);
|
||||||
|
|
||||||
|
function filterFn(val: string, update: (fn: () => void) => void) {
|
||||||
|
update(() => {
|
||||||
|
if (!val) {
|
||||||
|
filteredOptions.value = [...props.options];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const needle = val.toLowerCase();
|
||||||
|
filteredOptions.value = props.options.filter((opt) => {
|
||||||
|
let field = null;
|
||||||
|
if (typeof optionLabel === 'function') {
|
||||||
|
field = optionLabel(opt);
|
||||||
|
} else {
|
||||||
|
field = opt[optionLabel];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof field !== 'string' && typeof field !== 'number') return false;
|
||||||
|
return String(field).toLowerCase().includes(needle);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove duplicates by optionValue
|
||||||
|
const seen = new Set();
|
||||||
|
filteredOptions.value = filteredOptions.value.filter((opt) => {
|
||||||
|
const value = opt[optionValue];
|
||||||
|
if (seen.has(value)) return false;
|
||||||
|
seen.add(value);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitValue(val: string | number | null) {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -38,7 +38,7 @@ export function useAttendeesTable() {
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
//updates Attendees list from database
|
//updates Attendees list from database
|
||||||
async function updateAttendees() {
|
async function updateAttendees(eventArray: number) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
let events: Events | undefined;
|
let events: Events | undefined;
|
||||||
@@ -60,11 +60,16 @@ export function useAttendeesTable() {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!events || events.length === 0 || !events[0]?.attendees || events[0].attendees === null) {
|
if (
|
||||||
|
!events ||
|
||||||
|
events.length === 0 ||
|
||||||
|
!events[eventArray]?.attendees ||
|
||||||
|
events[eventArray].attendees === null
|
||||||
|
) {
|
||||||
attendees.value = [];
|
attendees.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
attendees.value = events[0].attendees ?? [];
|
attendees.value = events[eventArray].attendees ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
dense
|
dense
|
||||||
class="bigger-table-text"
|
class="bigger-table-text"
|
||||||
>
|
>
|
||||||
|
<!--top left of event table-->
|
||||||
<template v-slot:top-left>
|
<template v-slot:top-left>
|
||||||
<q-btn-group push flat style="color: grey">
|
<q-btn-group push flat style="color: grey">
|
||||||
<q-btn
|
<q-btn
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
icon="person"
|
icon="person"
|
||||||
@click="openAllValueDialog"
|
@click="openAttendanceDialog"
|
||||||
><q-badge floating transparent color="primary" text-color="primary-text">+</q-badge>
|
><q-badge floating transparent color="primary" text-color="primary-text">+</q-badge>
|
||||||
<q-tooltip>{{ $t('addNewAttendees') }}</q-tooltip>
|
<q-tooltip>{{ $t('addNewAttendees') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
{{ $t('selected') }}: {{ selected.length }}
|
{{ $t('selected') }}: {{ selected.length }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<!--top right of event table-->
|
||||||
<template v-slot:top-right>
|
<template v-slot:top-right>
|
||||||
<q-input filled dense debounce="300" v-model="filter" :placeholder="$t('search')">
|
<q-input filled dense debounce="300" v-model="filter" :placeholder="$t('search')">
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
@@ -66,6 +68,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
</template>
|
</template>
|
||||||
|
<!--body of event table-->
|
||||||
<template v-slot:body-cell="props">
|
<template v-slot:body-cell="props">
|
||||||
<q-td v-if="props.col.field === 'attendees'" :props="props">
|
<q-td v-if="props.col.field === 'attendees'" :props="props">
|
||||||
<q-btn v-if="props.value !== null && props.value.length > 0" dense flat icon="people"
|
<q-btn v-if="props.value !== null && props.value.length > 0" dense flat icon="people"
|
||||||
@@ -91,11 +94,11 @@
|
|||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
</q-table>
|
</q-table>
|
||||||
<DialogFrame ref="memberTableDialog" :header-title="$t('members')" :width="700" :height="500">
|
<DialogFrame ref="attendanceDialog" :header-title="$t('members')" :width="700" :height="500">
|
||||||
<MembersTable
|
<MembersTable
|
||||||
add-attendees
|
add-attendees
|
||||||
:compare-members="attendees"
|
:compare-members="attendees"
|
||||||
v-on:update-event="updateTable"
|
v-on:update-event="(val) => updateTable(val)"
|
||||||
:event-id="localEvent?.id ?? 0"
|
:event-id="localEvent?.id ?? 0"
|
||||||
/>
|
/>
|
||||||
</DialogFrame>
|
</DialogFrame>
|
||||||
@@ -114,6 +117,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
//imports
|
||||||
import { appApi } from 'src/boot/axios';
|
import { appApi } from 'src/boot/axios';
|
||||||
import { onMounted, type PropType, ref } from 'vue';
|
import { onMounted, type PropType, ref } from 'vue';
|
||||||
import type { Members } from 'src/vueLib/models/member';
|
import type { Members } from 'src/vueLib/models/member';
|
||||||
@@ -126,21 +130,24 @@ import type { Event } from 'src/vueLib/models/event';
|
|||||||
import MembersTable from '../members/MembersTable.vue';
|
import MembersTable from '../members/MembersTable.vue';
|
||||||
import { i18n } from 'src/boot/lang';
|
import { i18n } from 'src/boot/lang';
|
||||||
|
|
||||||
export interface AttendeesDialog {
|
//use constants and function of imports
|
||||||
getSelected: () => Members;
|
const { attendees, pagination, loading, columns, updateAttendees } = useAttendeesTable();
|
||||||
}
|
|
||||||
|
|
||||||
|
//define given properties
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
event: {
|
event: {
|
||||||
type: Object as PropType<Event>,
|
type: Object as PropType<Event>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
eventArray: { type: Number, default: 0, required: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// define emits
|
||||||
const emit = defineEmits(['update']);
|
const emit = defineEmits(['update']);
|
||||||
|
|
||||||
|
// definitions
|
||||||
const { NotifyResponse } = useNotify();
|
const { NotifyResponse } = useNotify();
|
||||||
const memberTableDialog = ref();
|
const attendanceDialog = ref();
|
||||||
const okDialog = ref();
|
const okDialog = ref();
|
||||||
const deleteText = ref('');
|
const deleteText = ref('');
|
||||||
const selectOption = ref(false);
|
const selectOption = ref(false);
|
||||||
@@ -150,16 +157,15 @@ const openSubmenu = ref(false);
|
|||||||
const filter = ref('');
|
const filter = ref('');
|
||||||
const user = useUserStore();
|
const user = useUserStore();
|
||||||
|
|
||||||
const { attendees, pagination, loading, columns, updateAttendees } = useAttendeesTable();
|
// load at page mount
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
localEvent.value = props.event;
|
localEvent.value = props.event;
|
||||||
attendees.value = props.event.attendees ?? [];
|
attendees.value = props.event.attendees ?? [];
|
||||||
});
|
});
|
||||||
|
|
||||||
//opens dialog for one value
|
//opens attendance dialog
|
||||||
function openAllValueDialog() {
|
function openAttendanceDialog() {
|
||||||
memberTableDialog.value?.open();
|
attendanceDialog.value?.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
//opens remove dialog
|
//opens remove dialog
|
||||||
@@ -173,10 +179,11 @@ function openRemoveDialog(...attendees: Members) {
|
|||||||
} else {
|
} else {
|
||||||
deleteText.value = String(attendees.length) + ' ' + i18n.global.t('attendees');
|
deleteText.value = String(attendees.length) + ' ' + i18n.global.t('attendees');
|
||||||
}
|
}
|
||||||
|
|
||||||
okDialog.value?.open(attendees);
|
okDialog.value?.open(attendees);
|
||||||
}
|
}
|
||||||
|
|
||||||
//remove Attendees from database
|
//remove attendees from database
|
||||||
async function removeAttendees(...removeAttendees: Members) {
|
async function removeAttendees(...removeAttendees: Members) {
|
||||||
if (!localEvent.value) {
|
if (!localEvent.value) {
|
||||||
NotifyResponse('event is empty', 'error');
|
NotifyResponse('event is empty', 'error');
|
||||||
@@ -199,27 +206,17 @@ async function removeAttendees(...removeAttendees: Members) {
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
await updateAttendees();
|
await updateAttendees(props.eventArray);
|
||||||
emit('update');
|
emit('update', -removeAttendees.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateTable() {
|
async function updateTable(amount: number) {
|
||||||
await updateAttendees();
|
await updateAttendees(props.eventArray);
|
||||||
emit('update');
|
emit('update', amount);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes blink-yellow {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
background-color: yellow;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bigger-table-text .q-table__middle td {
|
.bigger-table-text .q-table__middle td {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
:inner-padding="0"
|
:inner-padding="0"
|
||||||
>
|
>
|
||||||
<q-card>
|
<q-card>
|
||||||
|
<!-- tabs declaration in header-->
|
||||||
<q-tabs
|
<q-tabs
|
||||||
v-model="tab"
|
v-model="tab"
|
||||||
dense
|
dense
|
||||||
@@ -16,21 +17,37 @@
|
|||||||
align="justify"
|
align="justify"
|
||||||
narrow-indicator
|
narrow-indicator
|
||||||
>
|
>
|
||||||
<q-tab no-caps name="attendance" :label="$t('attendees')" />
|
<q-tab no-caps name="attendance" :label="$t('attendees')"
|
||||||
<q-tab no-caps name="noneAttendees" :label="$t('noneAttendees')" />
|
><q-badge color="primary" text-color="primary-text" floating transparent>{{
|
||||||
|
attendees.length
|
||||||
|
}}</q-badge></q-tab
|
||||||
|
>
|
||||||
|
|
||||||
|
<q-tab no-caps name="noneAttendees" :label="$t('noneAttendees')"
|
||||||
|
><q-badge color="primary" text-color="primary-text" floating transparent>{{
|
||||||
|
missingAttendanceAmount
|
||||||
|
}}</q-badge></q-tab
|
||||||
|
>
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
|
|
||||||
<q-separator />
|
<q-separator />
|
||||||
|
|
||||||
|
<!--tab of attenting members-->
|
||||||
|
|
||||||
<q-tab-panels v-model="tab" animated>
|
<q-tab-panels v-model="tab" animated>
|
||||||
<q-tab-panel name="attendance" style="padding: 0px">
|
<q-tab-panel name="attendance" style="padding: 0px">
|
||||||
<AttendeesTable :event="localEvent!" v-on:update="updateTable" />
|
<AttendeesTable
|
||||||
|
:event="localEvent!"
|
||||||
|
:event-array="eA"
|
||||||
|
v-on:update="(val) => updateTable(val)"
|
||||||
|
/>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
<!--tab of missing attenting members-->
|
||||||
<q-tab-panel name="noneAttendees" style="padding: 0px">
|
<q-tab-panel name="noneAttendees" style="padding: 0px">
|
||||||
<MembersTable
|
<MembersTable
|
||||||
add-attendees
|
add-attendees
|
||||||
:compare-members="attendees"
|
:compare-members="attendees"
|
||||||
v-on:update-event="updateTable"
|
v-on:update-event="(val) => updateTable(val)"
|
||||||
:event-id="localEvent?.id ?? 0"
|
:event-id="localEvent?.id ?? 0"
|
||||||
/>
|
/>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
@@ -40,28 +57,68 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
// imports
|
||||||
import AttendeesTable from './AttendeesTable.vue';
|
import AttendeesTable from './AttendeesTable.vue';
|
||||||
import MembersTable from '../members/MembersTable.vue';
|
import MembersTable from '../members/MembersTable.vue';
|
||||||
import DialogFrame from 'src/vueLib/dialog/DialogFrame.vue';
|
import DialogFrame from 'src/vueLib/dialog/DialogFrame.vue';
|
||||||
import type { Event } from 'src/vueLib/models/event';
|
import type { Event } from 'src/vueLib/models/event';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useAttendeesTable } from './AttendeesTable';
|
import { useAttendeesTable } from './AttendeesTable';
|
||||||
|
import { useMemberTable } from '../members/MembersTable';
|
||||||
|
import { getLocalPageDefaults } from 'src/localstorage/localStorage';
|
||||||
|
|
||||||
|
//use constants and function of imports
|
||||||
|
const { attendees, updateAttendees } = useAttendeesTable();
|
||||||
|
const { setNewFilter, filteredMembers, updateMembers } = useMemberTable();
|
||||||
|
|
||||||
|
// declare emits
|
||||||
const emit = defineEmits(['update']);
|
const emit = defineEmits(['update']);
|
||||||
|
|
||||||
|
// declarations
|
||||||
const dialog = ref();
|
const dialog = ref();
|
||||||
const localEvent = ref<Event>();
|
const localEvent = ref<Event>();
|
||||||
|
const missingAttendanceAmount = ref(0);
|
||||||
|
const attendanceAmount = ref(0);
|
||||||
|
const eA = ref(0);
|
||||||
const tab = ref('attendance');
|
const tab = ref('attendance');
|
||||||
const { attendees, updateAttendees } = useAttendeesTable();
|
|
||||||
|
|
||||||
const open = (event: Event) => {
|
// opens attendace dialog of event
|
||||||
|
const open = async (eventArray: number, event: Event) => {
|
||||||
|
// local declarations
|
||||||
localEvent.value = event;
|
localEvent.value = event;
|
||||||
attendees.value = event.attendees ?? [];
|
attendanceAmount.value = event.attendees.length ?? [];
|
||||||
|
eA.value = eventArray;
|
||||||
|
|
||||||
|
// get attendance
|
||||||
|
await updateAttendees(eventArray);
|
||||||
|
//get missing attendance from memer updateTable
|
||||||
|
await updateMembers(event.attendees);
|
||||||
|
|
||||||
|
// set custom filter
|
||||||
|
const defaults = getLocalPageDefaults('attendance');
|
||||||
|
setNewFilter(defaults?.filteredColumn || '', ...(defaults?.filteredValue ?? []));
|
||||||
|
|
||||||
|
// set amount of missing attendace
|
||||||
|
missingAttendanceAmount.value = filteredMembers.value.length;
|
||||||
|
|
||||||
|
//open atttendance dialog
|
||||||
dialog.value.open();
|
dialog.value.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
async function updateTable() {
|
//updates amount of table display and both tables
|
||||||
await updateAttendees();
|
async function updateTable(amount?: number) {
|
||||||
|
// check wether amount is given and if it adds or substracts amount
|
||||||
|
if (amount && amount < 0) {
|
||||||
|
missingAttendanceAmount.value -= amount;
|
||||||
|
} else if (amount) {
|
||||||
|
missingAttendanceAmount.value = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update attendace table
|
||||||
|
await updateAttendees(eA.value);
|
||||||
|
// update for amoutn display in tab
|
||||||
|
if (localEvent.value) localEvent.value.attendees = attendees.value;
|
||||||
|
//emit to update event table
|
||||||
emit('update');
|
emit('update');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell="props">
|
<template v-slot:body-cell="props">
|
||||||
<q-td v-if="props.col.field === 'attendees'" :props="props">
|
<q-td v-if="props.col.field === 'attendees'" :props="props">
|
||||||
<q-btn dense flat icon="people" @click="openAttendees(props.row)"
|
<q-btn dense flat icon="people" @click="openAttendees(props.rowIndex, props.row)"
|
||||||
><q-badge color="primary" text-color="primary-text" floating transparent>{{
|
><q-badge color="primary" text-color="primary-text" floating transparent>{{
|
||||||
props.row.count
|
props.row.count
|
||||||
}}</q-badge></q-btn
|
}}</q-badge></q-btn
|
||||||
@@ -218,8 +218,8 @@ function openRemoveDialog(...Events: Events) {
|
|||||||
okDialog.value?.open(Events);
|
okDialog.value?.open(Events);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openAttendees(attendees: Members | null) {
|
function openAttendees(eventArray: number, attendees: Members | null) {
|
||||||
attendeesDialog.value.open(attendees);
|
attendeesDialog.value.open(eventArray, attendees);
|
||||||
}
|
}
|
||||||
|
|
||||||
//remove Event from database
|
//remove Event from database
|
||||||
@@ -244,20 +244,6 @@ function removeEvent(...removeEvents: Events) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes blink-yellow {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
background-color: yellow;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.blink-yellow {
|
|
||||||
animation: blink-yellow 1.5s step-start 6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bigger-table-text .q-table__middle td {
|
.bigger-table-text .q-table__middle td {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,16 +246,6 @@ async function save() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes blink-yellow {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
background-color: yellow;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bigger-table-text .q-table__middle td {
|
.bigger-table-text .q-table__middle td {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ export function useMemberTable() {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
filteredMembers.value = allMembers.value;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
@click="addMemberTo"
|
@click="addMemberTo"
|
||||||
>
|
>
|
||||||
<q-badge floating transparent color="primary" text-color="primary-text">+</q-badge>
|
<q-badge floating transparent color="primary" text-color="primary-text">+</q-badge>
|
||||||
|
<q-tooltip>{{ $t('addToEvent') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn v-else flat dense icon="more_vert" @click="openSubmenu = true" />
|
<q-btn v-else flat dense icon="more_vert" @click="openSubmenu = true" />
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell-group="props">
|
<template v-slot:body-cell-group="props">
|
||||||
<q-td :props="props">
|
<q-td :props="props">
|
||||||
<q-select
|
<SearchableSelect
|
||||||
v-if="groups.length > 0"
|
v-if="groups.length > 0"
|
||||||
dense
|
dense
|
||||||
:readonly="!user.isPermittedTo('members', 'write')"
|
:readonly="!user.isPermittedTo('members', 'write')"
|
||||||
@@ -175,20 +176,20 @@
|
|||||||
option-label="name"
|
option-label="name"
|
||||||
v-model="props.row.group"
|
v-model="props.row.group"
|
||||||
@update:model-value="updateMember(props.row)"
|
@update:model-value="updateMember(props.row)"
|
||||||
></q-select>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell-responsiblePerson="props">
|
<template v-slot:body-cell-responsiblePerson="props">
|
||||||
<q-td :props="props">
|
<q-td :props="props">
|
||||||
<q-select
|
<SearchableSelect
|
||||||
dense
|
|
||||||
v-if="responsibles.length > 0"
|
v-if="responsibles.length > 0"
|
||||||
:readonly="!user.isPermittedTo('members', 'write')"
|
:readonly="!user.isPermittedTo('members', 'write')"
|
||||||
:options="responsibles"
|
:options="responsibles"
|
||||||
:option-label="(opt) => opt.firstName + ' ' + opt.lastName"
|
:option-label="(opt) => opt.firstName + ' ' + opt.lastName"
|
||||||
|
option-value="firstName"
|
||||||
v-model="props.row.responsiblePerson"
|
v-model="props.row.responsiblePerson"
|
||||||
@update:model-value="updateMember(props.row)"
|
@update:model-value="updateMember(props.row)"
|
||||||
></q-select>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body-cell-option="props">
|
<template v-slot:body-cell-option="props">
|
||||||
@@ -274,6 +275,7 @@ import { databaseName } from 'src/vueLib/models/settings';
|
|||||||
import { useUserStore } from 'src/vueLib/login/userStore';
|
import { useUserStore } from 'src/vueLib/login/userStore';
|
||||||
import { i18n } from 'src/boot/lang';
|
import { i18n } from 'src/boot/lang';
|
||||||
import { getLocalPageDefaults, setLocalPageDefaults } from 'src/localstorage/localStorage';
|
import { getLocalPageDefaults, setLocalPageDefaults } from 'src/localstorage/localStorage';
|
||||||
|
import SearchableSelect from 'src/vueLib/general/SearchableSelect .vue';
|
||||||
|
|
||||||
const inProps = defineProps({
|
const inProps = defineProps({
|
||||||
addAttendees: { type: Boolean },
|
addAttendees: { type: Boolean },
|
||||||
@@ -348,13 +350,13 @@ onMounted(() => {
|
|||||||
selectedColumnFilter.value = defaults?.filteredColumn || '';
|
selectedColumnFilter.value = defaults?.filteredColumn || '';
|
||||||
selectedColumnOptions.value = defaults?.filteredValue ?? [];
|
selectedColumnOptions.value = defaults?.filteredValue ?? [];
|
||||||
|
|
||||||
|
// set custom filter
|
||||||
setNewFilter(selectedColumnFilter.value, ...selectedColumnOptions.value);
|
setNewFilter(selectedColumnFilter.value, ...selectedColumnOptions.value);
|
||||||
|
|
||||||
appApi
|
appApi
|
||||||
.post('database/open', { dbPath: databaseName.value, create: true })
|
.post('database/open', { dbPath: databaseName.value, create: true })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
updateMembers(inProps.compareMembers, inProps.addResponsible).catch((err) =>
|
updateTable().catch((err) => NotifyResponse(err, 'error'));
|
||||||
NotifyResponse(err, 'error'),
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(err, 'error'))
|
.catch((err) => NotifyResponse(err, 'error'))
|
||||||
|
|
||||||
@@ -363,6 +365,12 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function updateTable() {
|
||||||
|
await updateMembers(localCompareMembers.value, inProps.addResponsible).catch((err) =>
|
||||||
|
NotifyResponse(err, 'error'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// opens dialog for all member values
|
// opens dialog for all member values
|
||||||
function openSingleValueDialog(label: string, field: string, member: Member) {
|
function openSingleValueDialog(label: string, field: string, member: Member) {
|
||||||
editOneDialog.value?.open(label, field, member);
|
editOneDialog.value?.open(label, field, member);
|
||||||
@@ -414,7 +422,7 @@ function setColumnOptions(columnName: string) {
|
|||||||
async function filterMembers(field: string, ...keys: string[]) {
|
async function filterMembers(field: string, ...keys: string[]) {
|
||||||
setNewFilter(field, ...keys);
|
setNewFilter(field, ...keys);
|
||||||
setLocalPageDefaults(page.value, field, keys);
|
setLocalPageDefaults(page.value, field, keys);
|
||||||
await updateMembers();
|
await updateTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
//remove member from database
|
//remove member from database
|
||||||
@@ -428,7 +436,7 @@ function removeMember(...removeMembers: Members) {
|
|||||||
appApi
|
appApi
|
||||||
.post('members/delete', { ids: memberIds })
|
.post('members/delete', { ids: memberIds })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
updateMembers().catch((err) => NotifyResponse(err, 'error'));
|
updateTable().catch((err) => NotifyResponse(err, 'error'));
|
||||||
selected.value = [];
|
selected.value = [];
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(err, 'error'))
|
.catch((err) => NotifyResponse(err, 'error'))
|
||||||
@@ -443,7 +451,7 @@ function updateMember(member: Member | null) {
|
|||||||
.post('/members/edit', [member])
|
.post('/members/edit', [member])
|
||||||
.then(() => NotifyResponse(i18n.global.t('memberUpdated')))
|
.then(() => NotifyResponse(i18n.global.t('memberUpdated')))
|
||||||
.catch((err) => NotifyResponse(err, 'error'));
|
.catch((err) => NotifyResponse(err, 'error'));
|
||||||
updateMembers().catch((err) => NotifyResponse(err, 'error'));
|
updateTable().catch((err) => NotifyResponse(err, 'error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToEvent() {
|
function addToEvent() {
|
||||||
@@ -485,8 +493,10 @@ async function addMemberTo() {
|
|||||||
|
|
||||||
if (inProps.addAttendees) {
|
if (inProps.addAttendees) {
|
||||||
await updateMemberLastVisit(selected.value);
|
await updateMemberLastVisit(selected.value);
|
||||||
|
} else {
|
||||||
|
await updateTable();
|
||||||
|
emit('update-event', filteredMembers.value.length);
|
||||||
}
|
}
|
||||||
emit('update-event');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateMemberLastVisit(members: Members) {
|
async function updateMemberLastVisit(members: Members) {
|
||||||
@@ -514,11 +524,13 @@ async function updateMemberLastVisit(members: Members) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => NotifyResponse(err, 'error'));
|
.catch((err) => NotifyResponse(err, 'error'));
|
||||||
await updateMembers(localCompareMembers.value, inProps.addResponsible)
|
localCompareMembers.value?.push(...members);
|
||||||
.then(() => localCompareMembers.value?.push(...members))
|
await updateTable().catch((err) => NotifyResponse(err, 'error'));
|
||||||
.catch((err) => NotifyResponse(err, 'error'));
|
|
||||||
emit('update-event');
|
emit('update-event', filteredMembers.value.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({ allMembers, filteredMembers });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -221,16 +221,6 @@ function removeResponsible(...removeResponsibles: Members) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes blink-yellow {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
background-color: yellow;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bigger-table-text .q-table__middle td {
|
.bigger-table-text .q-table__middle td {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,16 +233,6 @@ function removeRole(...removeRoles: Roles) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes blink-yellow {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
background-color: yellow;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.blink-yellow {
|
.blink-yellow {
|
||||||
animation: blink-yellow 1.5s step-start 6 !important;
|
animation: blink-yellow 1.5s step-start 6 !important;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user