mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-22 17:32:18 +00:00
add tagsAssignmentModal extraction from tempus component
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Copyright (C) 2024 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import BsModal from "../Bootstrap/Modal.js";
|
||||
import FormInput from "../Form/Input.js";
|
||||
import CoreTag from "../Tag/Tag.js";
|
||||
import ApiTempusTag from "../../api/factory/tempus/tag.js";
|
||||
|
||||
export default {
|
||||
name: "TagsAssignmentModal",
|
||||
components: {
|
||||
BsModal,
|
||||
FormInput,
|
||||
CoreTag,
|
||||
},
|
||||
emits: ["tagsChanged"],
|
||||
data() {
|
||||
return {
|
||||
calendar: null,
|
||||
availableTags: [],
|
||||
filteredAvailableTags: [],
|
||||
selectedAvailableTag: null,
|
||||
assignedTags: [],
|
||||
tagEndpoint: ApiTempusTag,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dropdownParsedAvailableTags() {
|
||||
return this.availableTags.map((tag) => ({
|
||||
label: tag.bezeichnung,
|
||||
value: tag.tag_typ_kurzbz,
|
||||
data: tag,
|
||||
}));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async open(calendar) {
|
||||
if (!calendar?.kalender_id) return;
|
||||
|
||||
this.calendar = calendar;
|
||||
this.availableTags = await this.fetchAvailableTags();
|
||||
this.filteredAvailableTags = [...this.dropdownParsedAvailableTags];
|
||||
this.assignedTags = await this.fetchAssignedTagsByCalender(
|
||||
calendar.eindeutige_gruppen_id,
|
||||
);
|
||||
|
||||
this.show();
|
||||
},
|
||||
show() {
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
reset() {
|
||||
this.calendar = null;
|
||||
this.availableTags = [];
|
||||
this.filteredAvailableTags = [];
|
||||
this.selectedAvailableTag = null;
|
||||
this.assignedTags = [];
|
||||
},
|
||||
async fetchAvailableTags() {
|
||||
const result = await this.$api.call(ApiTempusTag.getTags());
|
||||
|
||||
if (result.meta.status === "success") return result.data;
|
||||
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_available_tags_fetch_error_message"),
|
||||
);
|
||||
return [];
|
||||
},
|
||||
async fetchAssignedTagsByCalender(calendarGroupId) {
|
||||
const result = await this.$api.call(
|
||||
ApiTempusTag.getTagsByCalendar(calendarGroupId),
|
||||
);
|
||||
|
||||
if (result.meta.status === "success") {
|
||||
return result.data.filter((tag) => !!tag);
|
||||
}
|
||||
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
|
||||
);
|
||||
return [];
|
||||
},
|
||||
filterAvailableTags(event) {
|
||||
const query = event.query.toLowerCase();
|
||||
const unassignedTags = this.dropdownParsedAvailableTags.filter(
|
||||
(tag) =>
|
||||
!this.assignedTags.some(
|
||||
(assigned) => assigned.tag_id === tag.value,
|
||||
),
|
||||
);
|
||||
|
||||
this.filteredAvailableTags = query
|
||||
? unassignedTags.filter((tag) =>
|
||||
tag.label.toLowerCase().includes(query),
|
||||
)
|
||||
: unassignedTags;
|
||||
},
|
||||
selectTag(event) {
|
||||
this.selectedAvailableTag = event.value;
|
||||
this.$refs.tagComponent?.openModal(event.value.data);
|
||||
},
|
||||
editTag(tag) {
|
||||
this.$refs.tagComponent?.editTag(tag.notiz_id);
|
||||
},
|
||||
async handleCalendarTagChange() {
|
||||
const calendarGroupId = this.calendar?.eindeutige_gruppen_id;
|
||||
if (!calendarGroupId) return;
|
||||
|
||||
this.assignedTags =
|
||||
await this.fetchAssignedTagsByCalender(calendarGroupId);
|
||||
this.$emit("tagsChanged");
|
||||
},
|
||||
},
|
||||
template: /* html */`
|
||||
<bs-modal
|
||||
ref="modal"
|
||||
@hide-bs-modal="reset"
|
||||
body-class="p-4"
|
||||
class="bootstrap-prompt"
|
||||
data-cy="tagsAssignmentModal"
|
||||
>
|
||||
<template #title>{{ $p.t('ui', 'tags_assignment_modal_title') }}</template>
|
||||
<template #default>
|
||||
<div class="mb-5">
|
||||
<form-input
|
||||
v-if="availableTags.length"
|
||||
@item-select="selectTag"
|
||||
:label="$capitalize($p.t('ui', 'tags'))"
|
||||
:suggestions="filteredAvailableTags"
|
||||
:option-value="option => option.value"
|
||||
:option-label="option => option.label"
|
||||
@complete="filterAvailableTags"
|
||||
dropdown
|
||||
force-selection
|
||||
type="autocomplete"
|
||||
name="availableTags"
|
||||
:close-on-select="false"
|
||||
>
|
||||
<template #option="{ option }">
|
||||
<span :class="['tag', option.data.style]">{{ option.label }}</span>
|
||||
</template>
|
||||
</form-input>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<h6 class="mb-1 mx-auto text-bold fw-1">
|
||||
{{ $p.t('ui', 'assigned_tags_subtitle') }}
|
||||
</h6>
|
||||
</div>
|
||||
<div v-if="assignedTags.length">
|
||||
<span
|
||||
v-for="tag in assignedTags"
|
||||
:key="tag.tag_typ_kurzbz"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
@click="editTag(tag)"
|
||||
class="tag"
|
||||
>{{ tag.bezeichnung }}</span>
|
||||
</div>
|
||||
<div v-else class="d-flex align-items-center justify-content-center mb-2">
|
||||
<p class="text-muted mb-0">{{ $p.t('ui', 'no_assigned_tags') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</bs-modal>
|
||||
<core-tag
|
||||
v-if="calendar?.eindeutige_gruppen_id"
|
||||
ref="tagComponent"
|
||||
:is-list-item-shown="false"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="[calendar.eindeutige_gruppen_id]"
|
||||
zuordnung_typ="eindeutige_kalender_gruppen_id"
|
||||
@added="handleCalendarTagChange"
|
||||
@deleted="handleCalendarTagChange"
|
||||
@updated="handleCalendarTagChange"
|
||||
/>
|
||||
`,
|
||||
};
|
||||
@@ -28,7 +28,6 @@ import ApiSearchbar from "../../api/factory/searchbar.js";
|
||||
import ApiRenderers from "../../api/factory/renderers.js";
|
||||
import ApiTempusConfig from "../../api/factory/tempus/config.js";
|
||||
import ApiBetriebsmittel from "../../api/factory/betriebsmittel.js";
|
||||
import ApiTempusTag from "../../api/factory/tempus/tag.js";
|
||||
import AppMenu from "../AppMenu.js";
|
||||
import drop from "../../directives/drop.js";
|
||||
import AppConfig from "../AppConfig.js";
|
||||
@@ -39,7 +38,6 @@ import StvVerband from "../Stv/Studentenverwaltung/Verband.js";
|
||||
import ApiStudiengangTree from "../../api/factory/tempus/studiengangtree.js";
|
||||
import ApiInfo from "../../api/factory/tempus/info.js";
|
||||
import StvStudiensemester from "../Stv/Studentenverwaltung/Studiensemester.js";
|
||||
import FormInput from "../../../js/components/Form/Input.js";
|
||||
import Reservierung from "./Reservierung.js";
|
||||
import { getTempusShortcuts } from "./shortcuts.js";
|
||||
import KeyboardShortcuts from "./KeyboardShortcuts.js";
|
||||
@@ -47,8 +45,8 @@ import { useContextMenuActions } from "../../composables/Tempus/ContextMenuActio
|
||||
import MultiWeekPlanModal from "./MultiWeekPlanModal.js";
|
||||
import HistoryModal from "./HistoryModal.js";
|
||||
import ResourcesAssignmentModal from "./ResourcesAssignmentModal.js";
|
||||
import TagsAssignmentModal from "./TagsAssignmentModal.js";
|
||||
import { getTempusSearchbarOptions } from "./Filters/searchbarOptions.js";
|
||||
import CoreTag from '../Tag/Tag.js';
|
||||
|
||||
export default {
|
||||
name: "Tempus",
|
||||
@@ -68,13 +66,12 @@ export default {
|
||||
StvVerband,
|
||||
StvStudiensemester,
|
||||
Multiselect: primevue.multiselect,
|
||||
FormInput,
|
||||
Reservierung,
|
||||
KeyboardShortcuts,
|
||||
MultiWeekPlanModal,
|
||||
HistoryModal,
|
||||
ResourcesAssignmentModal,
|
||||
CoreTag,
|
||||
TagsAssignmentModal,
|
||||
},
|
||||
props: {
|
||||
defaultSemester: String,
|
||||
@@ -101,7 +98,7 @@ export default {
|
||||
openRaumauswahl: (orig) => this.openRaumauswahl(orig),
|
||||
openResourcesAssignmentModal: (orig) =>
|
||||
this.$refs.resourcesAssignmentModal?.open(orig),
|
||||
openTagsModal: (orig) => this.openTagsAssignmentModal(orig),
|
||||
openTagsModal: (orig) => this.$refs.tagsAssignmentModal?.open(orig),
|
||||
openHistory: (orig) => this.openHistory(orig),
|
||||
deleteEntry: (orig) => this.deleteEntry(orig),
|
||||
syncToLecturer: (orig) => this.syncToLecturer(orig),
|
||||
@@ -170,15 +167,6 @@ export default {
|
||||
endTime: null,
|
||||
},
|
||||
studiengaenge_all: [],
|
||||
tagsAssignmentModal: {
|
||||
calendar: null,
|
||||
availableTags: [],
|
||||
filteredAvailableTags: [],
|
||||
selectedAvailableTag: null,
|
||||
assignedTags: [],
|
||||
areFormButtonsDisplayed: false,
|
||||
},
|
||||
tagEndpoint: ApiTempusTag,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -213,16 +201,6 @@ export default {
|
||||
searchbaroptions() {
|
||||
return getTempusSearchbarOptions(this);
|
||||
},
|
||||
dropdownParsedAvailableTags() {
|
||||
return this.tagsAssignmentModal.availableTags
|
||||
.map((tag) => {
|
||||
return {
|
||||
label: tag.bezeichnung,
|
||||
value: tag.tag_typ_kurzbz,
|
||||
data: tag,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async openRaumauswahl(orig) {
|
||||
@@ -236,19 +214,6 @@ export default {
|
||||
this.$refs.raumModal.show();
|
||||
});
|
||||
},
|
||||
async openTagsAssignmentModal(orig) {
|
||||
console.log("openTagsAssignmentModal called with orig:", orig);
|
||||
if (!orig?.kalender_id) return;
|
||||
|
||||
this.tagsAssignmentModal.calendar = orig;
|
||||
this.tagsAssignmentModal.availableTags = await this.fetchAvailableTags();
|
||||
this.tagsAssignmentModal.filteredAvailableTags = [
|
||||
...this.dropdownParsedAvailableTags,
|
||||
];
|
||||
|
||||
this.tagsAssignmentModal.assignedTags = await this.fetchAssignedTagsByCalender(orig.eindeutige_gruppen_id);
|
||||
this.$refs.tagsAssignmentModal.show();
|
||||
},
|
||||
async deleteEntry(orig) {
|
||||
if (!orig?.kalender_id) return;
|
||||
|
||||
@@ -794,114 +759,6 @@ export default {
|
||||
this.extraBackgrounds = res;
|
||||
},
|
||||
|
||||
async fetchAvailableTags() {
|
||||
let getAvailableTags = await this.$api.call(
|
||||
ApiTempusTag.getTags(),
|
||||
);
|
||||
if (getAvailableTags.meta.status === "success") {
|
||||
return getAvailableTags.data;
|
||||
} else {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_available_tags_fetch_error_message"),
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
async fetchAssignedTagsByCalender(calenderId) {
|
||||
let getAssignedTags = await this.$api.call(
|
||||
ApiTempusTag.getTagsByCalendar(calenderId),
|
||||
);
|
||||
if (getAssignedTags.meta.status === "success") {
|
||||
return getAssignedTags.data.filter((unit) => !!unit);
|
||||
} else {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_fetch_error_message"),
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
filterAvailableTags(event) {
|
||||
this.tagsAssignmentModal.filteredAvailableTags;
|
||||
const query = event.query.toLowerCase();
|
||||
if (!query) {
|
||||
return (this.tagsAssignmentModal.filteredAvailableTags = [
|
||||
...this.dropdownParsedAvailableTags.filter((tag) => {
|
||||
return !this.tagsAssignmentModal.assignedTags.some(
|
||||
(assigned) => assigned.tag_id === tag.value,
|
||||
);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
return (this.tagsAssignmentModal.filteredAvailableTags =
|
||||
this.dropdownParsedAvailableTags
|
||||
.filter((tag) => {
|
||||
return !this.tagsAssignmentModal.assignedTags.some(
|
||||
(assigned) => assigned.tag_id === tag.value,
|
||||
);
|
||||
})
|
||||
.filter((tag) => {
|
||||
return tag.label.toLowerCase().includes(query);
|
||||
}));
|
||||
},
|
||||
removeAssignedTag(tag) {
|
||||
this.tagsAssignmentModal.assignedTags =
|
||||
this.tagsAssignmentModal.assignedTags.filter(
|
||||
(assigned) => assigned.tag_id !== tag.tag_id,
|
||||
);
|
||||
|
||||
this.tagsAssignmentModal.areFormButtonsDisplayed = true;
|
||||
},
|
||||
async refreshTagsAssignmentModalData(calenderItem) {
|
||||
this.tagsAssignmentModal.availableTags =
|
||||
await this.fetchAvailableTags();
|
||||
this.tagsAssignmentModal.filteredAvailableTags = [
|
||||
...this.dropdownParsedAvailableTags,
|
||||
];
|
||||
|
||||
this.tagsAssignmentModal.assignedTags =
|
||||
await this.fetchAssignedTagsByCalender(calenderItem.eindeutige_gruppen_id);
|
||||
this.tagsAssignmentModal.selectedAvailableTag = null;
|
||||
this.tagsAssignmentModal.areFormButtonsDisplayed = false;
|
||||
},
|
||||
async saveAssignedTagsToCalendarItem(calenderItem, assignedTags) {
|
||||
let saveAssignedTagsByCalender = await this.$api.call(
|
||||
ApiTempusTag.getTags(
|
||||
calenderItem.eindeutige_gruppen_id,
|
||||
assignedTags,
|
||||
),
|
||||
);
|
||||
if (saveAssignedTagsByCalender.meta.status === "success") {
|
||||
this.$fhcAlert.alertSuccess(
|
||||
this.$p.t("ui", "assigned_tags_save_success_message"),
|
||||
);
|
||||
await this.refreshTagsAssignmentModalData(calenderItem);
|
||||
} else {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("ui", "failed_assigned_tags_save_error_message"),
|
||||
);
|
||||
}
|
||||
|
||||
this.$refs.calendar.resetEventLoader();
|
||||
this.$refs.tagsAssignmentModal.hide();
|
||||
},
|
||||
closeTagsAssignmentModal() {
|
||||
this.tagsAssignmentModal = {
|
||||
availableTags: [],
|
||||
filteredAvailableTags: [],
|
||||
selectedAvailableTag: null,
|
||||
assignedTags: [],
|
||||
areFormButtonsDisplayed: false,
|
||||
};
|
||||
},
|
||||
async handleCalenderTagChange(calenderID) {
|
||||
this.tagsAssignmentModal.assignedTags =
|
||||
await this.fetchAssignedTagsByCalender(calenderID);
|
||||
|
||||
this.$refs.calendar.resetEventLoader();
|
||||
},
|
||||
removeLecturer(uid) {
|
||||
if (uid == null) {
|
||||
for (const lect of this.lecturers) delete this.overlayCache[lect.uid];
|
||||
@@ -1283,66 +1140,11 @@ export default {
|
||||
ref="resourcesAssignmentModal"
|
||||
@save-finished="$refs.calendar.resetEventLoader()"
|
||||
/>
|
||||
<bs-modal
|
||||
<tags-assignment-modal
|
||||
ref="tagsAssignmentModal"
|
||||
@hideBsModal="closeTagsAssignmentModal"
|
||||
bodyClass="p-4"
|
||||
class="bootstrap-prompt"
|
||||
data-cy="tagsAssignmentModal"
|
||||
>
|
||||
<template #title>{{$p.t('ui', 'tags_assignment_modal_title')}}</template>
|
||||
<template #default>
|
||||
<div class="mb-5">
|
||||
<form-input
|
||||
v-if="tagsAssignmentModal.availableTags.length"
|
||||
@itemSelect="(option) => { tagsAssignmentModal.selectedAvailableTag = option.value; $refs.tagComponent.openModal(option.value.data); }"
|
||||
:label="$capitalize($p.t('ui', 'tags'))"
|
||||
:suggestions="tagsAssignmentModal.filteredAvailableTags"
|
||||
:optionValue="(option) => option.value"
|
||||
:optionLabel="(option) => option.label"
|
||||
@complete="filterAvailableTags"
|
||||
dropdown
|
||||
forceSelection
|
||||
type="autocomplete"
|
||||
name="availableTags"
|
||||
:closeOnSelect="false"
|
||||
>
|
||||
<template #option="{ option }">
|
||||
<span :class="['tag', option.data.style]">{{ option.label }}</span>
|
||||
</template>
|
||||
</form-input>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<h6 class="mb-1 mx-auto text-bold fw-1">{{$p.t('ui', 'assigned_tags_subtitle')}}</h6>
|
||||
</div>
|
||||
<div v-if="tagsAssignmentModal.assignedTags.length">
|
||||
<span
|
||||
v-for="tag in tagsAssignmentModal.assignedTags"
|
||||
:key="tag.tag_typ_kurzbz"
|
||||
:class="[tag.style, { tag_done: tag.done }]"
|
||||
@click="$refs.tagComponent.editTag(tag.notiz_id)"
|
||||
class="tag"
|
||||
>{{ tag.bezeichnung }}</span>
|
||||
</div>
|
||||
<div v-else class="d-flex align-items-center justify-content-center mb-2">
|
||||
<p class="text-muted mb-0">{{$p.t('ui', 'no_assigned_tags')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</bs-modal>
|
||||
@tags-changed="$refs.calendar.resetEventLoader()"
|
||||
/>
|
||||
<history-modal ref="historyModal" :entries="historyEntries" />
|
||||
<core-tag
|
||||
v-if="tagEndpoint && tagsAssignmentModal.calendar?.eindeutige_gruppen_id"
|
||||
ref="tagComponent"
|
||||
:isListItemShown="false"
|
||||
:endpoint="tagEndpoint"
|
||||
:values="[tagsAssignmentModal.calendar?.eindeutige_gruppen_id]"
|
||||
:zuordnung_typ="'eindeutige_kalender_gruppen_id'"
|
||||
@added="handleCalenderTagChange(tagsAssignmentModal.calendar?.eindeutige_gruppen_id)"
|
||||
@deleted="handleCalenderTagChange(tagsAssignmentModal.calendar?.eindeutige_gruppen_id)"
|
||||
@updated="handleCalenderTagChange(tagsAssignmentModal.calendar?.eindeutige_gruppen_id)"
|
||||
></core-tag>
|
||||
<reservierung
|
||||
ref="reservierung"
|
||||
:rooms="rooms"
|
||||
|
||||
Reference in New Issue
Block a user