<template> <div class="relative w-full md:max-w-md"> <div class="flex flex-col items-center"> <p class="text-xl font-medium">Kalenderlink</p> </div> <br /> <div class="flex flex-col gap-2"> <div> <Listbox v-model="selectedTypes" name="type" multiple> <ListboxLabel>Typen zur Anzeige auswählen</ListboxLabel> <div class="relative mt-1"> <ListboxButton class="rounded-md shadow-sm relative block w-full px-3 py-2 border border-gray-300 focus:border-primary placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-0 focus:z-10 sm:text-sm resize-none" > <span class="block truncate w-full text-start"> {{ selectedTypes.length != 0 ? selectedTypes?.map((t) => t.type).join(", ") : "Standard-Typen werden ausgeliefert" }} </span> <span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"> <ChevronUpDownIcon class="h-5 w-5 text-gray-400" aria-hidden="true" /> </span> </ListboxButton> <transition leave-active-class="transition duration-100 ease-in" leave-from-class="opacity-100" leave-to-class="opacity-0" > <ListboxOptions class="absolute mt-1 max-h-60 z-20 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm h-32 overflow-y-auto" > <ListboxOption v-if="calendarTypes.length == 0" disabled as="template"> <li :class="['relative cursor-default select-none py-2 pl-10 pr-4']"> <span :class="['font-normal', 'block truncate']">keine Auswahl vorhanden</span> </li> </ListboxOption> <ListboxOption v-slot="{ active, selected }" v-for="type in calendarTypes" :key="type.id" :value="type" as="template" > <li :class="[ active ? 'bg-red-200 text-amber-900' : 'text-gray-900', 'relative cursor-default select-none py-2 pl-10 pr-4', ]" > <span :class="[selected ? 'font-medium' : 'font-normal', 'block truncate']"> {{ type.type }} <small v-if="type.passphrase">(passwortgeschützt)</small> <small v-if="type.nscdr">(standard-Auslieferung)</small> </span> <span v-if="selected" class="absolute inset-y-0 left-0 flex items-center pl-3 text-primary"> <CheckIcon class="h-5 w-5" aria-hidden="true" /> </span> </li> </ListboxOption> </ListboxOptions> </transition> </div> </Listbox> </div> <p class="flex flex-row text-sm"> <InformationCircleIcon class="text-gray-500 h-5 w-5" /> Wenn kein Typ ausgewählt ist, werden die Standard-Typen zur Verfügung gestellt: <br /> -> {{ defaultTypes }} </p> <br /> <TextCopy :copyText="generatedLink" /> <div v-if="selectedTypes.length != 0" class="flex flex-row gap-2 items-center"> <input type="checkbox" id="nscdr" v-model="provideNSCDR" /> <label for="nscdr">Standard-Typen trotz Auswahl ausliefern</label> </div> <br /> </div> <RouterLink :to="{ name: 'public-calendar' }" title="Zur öffentlichen Kalender Anzeige" class="absolute top-3 right-3" target="_blank" > <CalendarDaysIcon class="text-gray-500 h-5 w-5" /> </RouterLink> <div class="flex flex-row justify-end"> <div class="flex flex-row gap-4 py-2"> <button primary-outline @click="closeModal">schließen</button> </div> </div> </div> </template> <script setup lang="ts"> import { defineComponent } from "vue"; import { mapState, mapActions } from "pinia"; import { RouterLink } from "vue-router"; import { useModalStore } from "@/stores/modal"; import { useCalendarTypeStore } from "@/stores/admin/configuration/calendarType"; import type { CalendarTypeViewModel } from "@/viewmodels/admin/configuration/calendarType.models"; import { Listbox, ListboxButton, ListboxOptions, ListboxOption, ListboxLabel } from "@headlessui/vue"; import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid"; import TextCopy from "@/components/TextCopy.vue"; import { CalendarDaysIcon, InformationCircleIcon } from "@heroicons/vue/24/outline"; import { host } from "@/serverCom"; </script> <script lang="ts"> export default defineComponent({ data() { return { selectedTypes: [] as Array<CalendarTypeViewModel>, provideNSCDR: false as boolean, }; }, computed: { ...mapState(useModalStore, ["data"]), ...mapState(useCalendarTypeStore, ["calendarTypes"]), defaultTypes() { return this.calendarTypes .filter((t) => t.nscdr) .map((t) => t.type) .join(", "); }, generatedLink() { let extend = this.selectedTypes.map((t) => [t.type, t.passphrase].filter((at) => at).join(":")); return `webcal://${host || window.location.host}/api/public/calendar${extend.length == 0 ? "" : "?types=" + extend.join("&types=")}${this.provideNSCDR && extend.length != 0 ? "&nscdr=true" : ""}`; }, }, mounted() { this.fetchCalendarTypes(); }, methods: { ...mapActions(useModalStore, ["closeModal"]), ...mapActions(useCalendarTypeStore, ["fetchCalendarTypes"]), }, }); </script>