diff --git a/public/js/components/Tempus/ResourcesAssignmentModal.js b/public/js/components/Tempus/ResourcesAssignmentModal.js new file mode 100644 index 000000000..fb366f4ba --- /dev/null +++ b/public/js/components/Tempus/ResourcesAssignmentModal.js @@ -0,0 +1,282 @@ +/** + * 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 . + */ +import BsModal from "../Bootstrap/Modal.js"; +import FormInput from "../Form/Input.js"; +import ApiOperationalResourceToCalender from "../../api/factory/operationalResourceToCalender.js"; + +export default { + name: "ResourcesAssignmentModal", + components: { + BsModal, + FormInput, + }, + emits: ["saveFinished"], + data() { + return { + calendar: null, + availableResources: [], + filteredAvailableResources: [], + selectedAvailableResource: null, + assignedResources: [], + areFormButtonsDisplayed: false, + }; + }, + computed: { + dropdownParsedAvailableResources() { + return this.availableResources + .map((unit) => ({ + label: unit.beschreibung, + value: unit.betriebsmittel_id, + data: unit, + })) + .sort((a, b) => a.label?.localeCompare(b.label)); + }, + }, + watch: { + selectedAvailableResource(newValue) { + if (!newValue) return; + + this.assignedResources.push({ + betriebsmittel_kalender_id: null, + betriebsmittel_id: newValue.data.betriebsmittel_id, + beschreibung: newValue.data.beschreibung, + anmerkung: "", + isNoteTextareaShown: false, + }); + + this.areFormButtonsDisplayed = true; + }, + }, + methods: { + async open(calendar) { + if (!calendar?.kalender_id) return; + + this.calendar = calendar; + this.availableResources = + await this.fetchSchedulableResourcesByCalender(calendar.kalender_id); + this.filteredAvailableResources = [ + ...this.dropdownParsedAvailableResources, + ]; + this.assignedResources = + await this.fetchAssignedResourcesByCalender(calendar.kalender_id); + + this.show(); + }, + show() { + this.$refs.modal.show(); + }, + hide() { + this.$refs.modal.hide(); + }, + reset() { + this.calendar = null; + this.availableResources = []; + this.filteredAvailableResources = []; + this.selectedAvailableResource = null; + this.assignedResources = []; + this.areFormButtonsDisplayed = false; + }, + async fetchAssignedResourcesByCalender(calenderId) { + const result = await this.$api.call( + ApiOperationalResourceToCalender.getAssignedResourcesByCalender( + calenderId, + ), + ); + + if (result.meta.status === "success") { + return result.data + .filter((unit) => !!unit) + .map((unit) => ({ + isNoteTextareaShown: + unit.anmerkung && unit.anmerkung.trim() !== "", + ...unit, + })); + } + + this.$fhcAlert.alertError( + this.$p.t("ui", "failed_assigned_resources_fetch_error_message"), + ); + return []; + }, + async fetchSchedulableResourcesByCalender(calendarId) { + const result = await this.$api.call( + ApiOperationalResourceToCalender.getSchedulableResourcesByCalendar( + calendarId, + ), + ); + + if (result.meta.status === "success") return result.data; + + this.$fhcAlert.alertError( + this.$p.t("ui", "failed_schedulable_resources_fetch_error_message"), + ); + return []; + }, + filterAvailableResources(event) { + const query = event.query.toLowerCase(); + const unassignedResources = this.dropdownParsedAvailableResources.filter( + (unit) => + !this.assignedResources.some( + (assigned) => assigned.betriebsmittel_id === unit.value, + ), + ); + + this.filteredAvailableResources = query + ? unassignedResources.filter((unit) => + unit.label.toLowerCase().includes(query), + ) + : unassignedResources; + }, + toggleAssignedResourceNoteInput(resource) { + const assignedResource = this.assignedResources.find( + (assigned) => assigned.betriebsmittel_id === resource.betriebsmittel_id, + ); + + if (assignedResource) { + assignedResource.isNoteTextareaShown = + !assignedResource.isNoteTextareaShown; + } + + this.areFormButtonsDisplayed = true; + }, + removeAssignedResource(resource) { + this.assignedResources = this.assignedResources.filter( + (assigned) => + assigned.betriebsmittel_id !== resource.betriebsmittel_id, + ); + this.areFormButtonsDisplayed = true; + }, + async refreshResourcesAssignmentModalData() { + if (!this.calendar?.kalender_id) return; + + this.availableResources = + await this.fetchSchedulableResourcesByCalender( + this.calendar.kalender_id, + ); + this.filteredAvailableResources = [ + ...this.dropdownParsedAvailableResources, + ]; + this.assignedResources = await this.fetchAssignedResourcesByCalender( + this.calendar.kalender_id, + ); + this.selectedAvailableResource = null; + this.areFormButtonsDisplayed = false; + }, + async saveAssignedResourcesToCalendarItem() { + if (!this.calendar?.kalender_id) return; + + const result = await this.$api.call( + ApiOperationalResourceToCalender.storeResourcesToCalendarRelationship( + this.calendar.kalender_id, + this.assignedResources, + ), + ); + + if (result.meta.status === "success") { + this.$fhcAlert.alertSuccess( + this.$p.t("ui", "assigned_resources_save_success_message"), + ); + await this.refreshResourcesAssignmentModalData(); + } else { + this.$fhcAlert.alertError( + this.$p.t("ui", "failed_assigned_resources_save_error_message"), + ); + } + + this.$emit("saveFinished"); + this.hide(); + }, + }, + template: ` + + + + + `, +}; diff --git a/public/js/components/Tempus/Tempus.js b/public/js/components/Tempus/Tempus.js index af762c554..3774d98f9 100644 --- a/public/js/components/Tempus/Tempus.js +++ b/public/js/components/Tempus/Tempus.js @@ -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 ApiOperationalResourceToCalender from "../../api/factory/operationalResourceToCalender.js"; import ApiTempusTag from "../../api/factory/tempus/tag.js"; import AppMenu from "../AppMenu.js"; import drop from "../../directives/drop.js"; @@ -47,6 +46,7 @@ import KeyboardShortcuts from "./KeyboardShortcuts.js"; import { useContextMenuActions } from "../../composables/Tempus/ContextMenuActions.js"; import MultiWeekPlanModal from "./MultiWeekPlanModal.js"; import HistoryModal from "./HistoryModal.js"; +import ResourcesAssignmentModal from "./ResourcesAssignmentModal.js"; import { getTempusSearchbarOptions } from "./Filters/searchbarOptions.js"; import CoreTag from '../Tag/Tag.js'; @@ -73,6 +73,7 @@ export default { KeyboardShortcuts, MultiWeekPlanModal, HistoryModal, + ResourcesAssignmentModal, CoreTag, }, props: { @@ -99,7 +100,7 @@ export default { contextMenuActions: useContextMenuActions({ openRaumauswahl: (orig) => this.openRaumauswahl(orig), openResourcesAssignmentModal: (orig) => - this.openResourcesAssignmentModal(orig), + this.$refs.resourcesAssignmentModal?.open(orig), openTagsModal: (orig) => this.openTagsAssignmentModal(orig), openHistory: (orig) => this.openHistory(orig), deleteEntry: (orig) => this.deleteEntry(orig), @@ -169,14 +170,6 @@ export default { endTime: null, }, studiengaenge_all: [], - resourcesAssignmentModal: { - calendar: null, - availableResources: [], - filteredAvailableResources: [], - selectedAvailableResource: null, - assignedResources: [], - areFormButtonsDisplayed: false, - }, tagsAssignmentModal: { calendar: null, availableTags: [], @@ -220,17 +213,6 @@ export default { searchbaroptions() { return getTempusSearchbarOptions(this); }, - dropdownParsedAvailableResources() { - return this.resourcesAssignmentModal.availableResources - .map((unit) => { - return { - label: unit.beschreibung, - value: unit.betriebsmittel_id, - data: unit, - }; - }) - .sort((a, b) => a.label?.localeCompare(b.label)); - }, dropdownParsedAvailableTags() { return this.tagsAssignmentModal.availableTags .map((tag) => { @@ -254,21 +236,6 @@ export default { this.$refs.raumModal.show(); }); }, - async openResourcesAssignmentModal(orig) { - if (!orig?.kalender_id) return; - - this.resourcesAssignmentModal.calendar = orig; - this.resourcesAssignmentModal.availableResources = - await this.fetchSchedulableResourcesByCalender(orig.kalender_id); - this.resourcesAssignmentModal.filteredAvailableResources = [ - ...this.dropdownParsedAvailableResources, - ]; - - this.resourcesAssignmentModal.assignedResources = - await this.fetchAssignedResourcesByCalender(orig.kalender_id); - - this.$refs.resourcesAssignmentModal.show(); - }, async openTagsAssignmentModal(orig) { console.log("openTagsAssignmentModal called with orig:", orig); if (!orig?.kalender_id) return; @@ -827,138 +794,6 @@ export default { this.extraBackgrounds = res; }, - async fetchAssignedResourcesByCalender(calenderId) { - let getAssignedResources = await this.$api.call( - ApiOperationalResourceToCalender.getAssignedResourcesByCalender( - calenderId, - ), - ); - if (getAssignedResources.meta.status === "success") { - return getAssignedResources.data - .filter((unit) => !!unit) - .map((unit) => { - return { - isNoteTextareaShown: - unit.anmerkung && unit.anmerkung.trim() !== "", - ...unit, - }; - }) - .filter((unit) => !!unit); - } else { - this.$fhcAlert.alertError( - this.$p.t("ui", "failed_assigned_resources_fetch_error_message"), - ); - } - - return []; - }, - async fetchSchedulableResourcesByCalender(calendarID) { - let getSchedulableResourcesByCalendar = await this.$api.call( - ApiOperationalResourceToCalender.getSchedulableResourcesByCalendar( - calendarID, - ), - ); - if (getSchedulableResourcesByCalendar.meta.status === "success") { - return getSchedulableResourcesByCalendar.data; - } else { - this.$fhcAlert.alertError( - this.$p.t("ui", "failed_schedulable_resources_fetch_error_message"), - ); - } - - return []; - }, - filterAvailableResources(event) { - this.resourcesAssignmentModal.filteredAvailableResources; - const query = event.query.toLowerCase(); - if (!query) { - return (this.resourcesAssignmentModal.filteredAvailableResources = [ - ...this.dropdownParsedAvailableResources.filter((unit) => { - return !this.resourcesAssignmentModal.assignedResources.some( - (assigned) => assigned.betriebsmittel_id === unit.value, - ); - }), - ]); - } - - return (this.resourcesAssignmentModal.filteredAvailableResources = - this.dropdownParsedAvailableResources - .filter((unit) => { - return !this.resourcesAssignmentModal.assignedResources.some( - (assigned) => assigned.betriebsmittel_id === unit.value, - ); - }) - .filter((unit) => { - return unit.label.toLowerCase().includes(query); - })); - }, - toggleAssignedResourceNoteInput(resource) { - const index = this.resourcesAssignmentModal.assignedResources.findIndex( - (assigned) => assigned.betriebsmittel_id === resource.betriebsmittel_id, - ); - if (index !== -1) { - this.resourcesAssignmentModal.assignedResources[ - index - ].isNoteTextareaShown = - !this.resourcesAssignmentModal.assignedResources[index] - .isNoteTextareaShown; - } - - this.resourcesAssignmentModal.areFormButtonsDisplayed = true; - }, - removeAssignedResource(resource) { - this.resourcesAssignmentModal.assignedResources = - this.resourcesAssignmentModal.assignedResources.filter( - (assigned) => - assigned.betriebsmittel_id !== resource.betriebsmittel_id, - ); - - this.resourcesAssignmentModal.areFormButtonsDisplayed = true; - }, - async refreshResourcesAssignmentModalData(calenderItem) { - this.resourcesAssignmentModal.availableResources = - await this.fetchSchedulableResourcesByCalender( - calenderItem.kalender_id, - ); - this.resourcesAssignmentModal.filteredAvailableResources = [ - ...this.dropdownParsedAvailableResources, - ]; - - this.resourcesAssignmentModal.assignedResources = - await this.fetchAssignedResourcesByCalender(calenderItem.kalender_id); - this.resourcesAssignmentModal.selectedAvailableResource = null; - this.resourcesAssignmentModal.areFormButtonsDisplayed = false; - }, - async saveAssignedResourcesToCalendarItem(calenderItem, assignedResources) { - let getSchedulableResourcesByCalendar = await this.$api.call( - ApiOperationalResourceToCalender.storeResourcesToCalendarRelationship( - calenderItem.kalender_id, - assignedResources, - ), - ); - if (getSchedulableResourcesByCalendar.meta.status === "success") { - this.$fhcAlert.alertSuccess( - this.$p.t("ui", "assigned_resources_save_success_message"), - ); - await this.refreshResourcesAssignmentModalData(calenderItem); - } else { - this.$fhcAlert.alertError( - this.$p.t("ui", "failed_assigned_resources_save_error_message"), - ); - } - - this.$refs.calendar.resetEventLoader(); - this.$refs.resourcesAssignmentModal.hide(); - }, - closeResourcesAssignmentModal() { - this.resourcesAssignmentModal = { - availableResources: [], - filteredAvailableResources: [], - selectedAvailableResource: null, - assignedResources: [], - areFormButtonsDisplayed: false, - }; - }, async fetchAvailableTags() { let getAvailableTags = await this.$api.call( ApiTempusTag.getTags(), @@ -1136,19 +971,6 @@ export default { handler() { this.$refs.calendar.resetEventLoader(); }, - }, - "resourcesAssignmentModal.selectedAvailableResource": function (newVal) { - if (!newVal) return; - - this.resourcesAssignmentModal.assignedResources.push({ - betriebsmittel_kalender_id: null, - betriebsmittel_id: newVal.data.betriebsmittel_id, - beschreibung: newVal.data.beschreibung, - anmerkung: "", - isNoteTextareaShown: false, - }); - - this.resourcesAssignmentModal.areFormButtonsDisplayed = true; }, }, mounted() { @@ -1439,7 +1261,6 @@ export default { - - - - - + @save-finished="$refs.calendar.resetEventLoader()" + />