KI-AGENT: Ergänze Kalender-Abo für Mitarbeiterprofile

This commit is contained in:
2026-05-19 16:26:49 +02:00
parent f9d3f10eae
commit 167e9a40c3
7 changed files with 392 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ const toast = useToast()
const auth = useAuthStore()
const admin = useAdmin()
const { $api } = useNuxtApp()
const runtimeConfig = useRuntimeConfig()
const id = route.params.id as string
const profile = ref<any>(null)
@@ -15,6 +16,7 @@ const saving = ref(false)
const creatingLinkedUser = ref(false)
const createLinkedUserModalOpen = ref(false)
const createdLinkedUserPassword = ref("")
const generatingCalendarSubscription = ref(false)
const createLinkedUserForm = reactive({
email: "",
})
@@ -26,6 +28,30 @@ const selectMenuUi = {
const canCreateLinkedUser = computed(() => Boolean(auth.user?.is_admin && profile.value && !profile.value.user_id))
const linkedUserStatusLabel = computed(() => profile.value?.user_id ? "Benutzer verknüpft" : "Kein Benutzer verknüpft")
const linkedUserStatusColor = computed(() => profile.value?.user_id ? "green" : "orange")
const calendarSubscriptionHttpUrl = computed(() => {
const token = profile.value?.calendar_subscription_token
if (!token) return ""
const path = profile.value?.calendar_subscription_path || `/api/public/calendar/subscriptions/${token}.ics`
const apiBase = String(runtimeConfig.public.apiBase || "")
if (/^https?:\/\//i.test(apiBase)) {
const apiUrl = new URL(apiBase)
return new URL(path, `${apiUrl.protocol}//${apiUrl.host}`).toString()
}
if (process.client) {
return `${window.location.origin}${path}`
}
return path
})
const calendarSubscriptionWebcalUrl = computed(() =>
calendarSubscriptionHttpUrl.value
? calendarSubscriptionHttpUrl.value.replace(/^https?/i, "webcal")
: ""
)
async function fetchBranches() {
try {
@@ -195,6 +221,55 @@ async function createLinkedUser() {
}
}
async function generateCalendarSubscription() {
if (!profile.value || generatingCalendarSubscription.value) return
generatingCalendarSubscription.value = true
try {
profile.value = await $api(`/api/profiles/${id}/calendar-subscription-token`, {
method: "POST"
})
ensureWorkingHoursStructure()
ensureBranchStructure()
ensureTeamStructure()
toast.add({
title: "Kalender-Abo erstellt",
description: "Der abonnierbare Kalender-Link wurde generiert.",
color: "green"
})
} catch (err: any) {
console.error("[generateCalendarSubscription]", err)
toast.add({
title: "Kalender-Abo konnte nicht erstellt werden",
description: err?.data?.error || err?.message || "Unbekannter Fehler",
color: "red"
})
} finally {
generatingCalendarSubscription.value = false
}
}
async function copyCalendarSubscriptionUrl(value: string, successTitle: string) {
if (!value) return
try {
await navigator.clipboard.writeText(value)
toast.add({
title: successTitle,
color: "green"
})
} catch (err) {
console.error("[copyCalendarSubscriptionUrl]", err)
toast.add({
title: "Link konnte nicht kopiert werden",
color: "red"
})
}
}
const weekdays = [
{ key: '1', label: 'Montag' },
{ key: '2', label: 'Dienstag' },
@@ -471,6 +546,57 @@ onMounted(async () => {
</UForm>
</UCard>
<UCard v-if="!pending && profile" class="mt-3">
<USeparator label="Kalender-Abo" />
<div class="mt-4 space-y-4">
<p class="text-sm text-gray-500">
Hier kann ein abonnierbarer Kalender-Link für Handy-Kalender erzeugt werden. Das Abo nutzt einen persönlichen Backend-Link und kann in vielen Kalender-Apps direkt als `webcal` oder `ics` eingebunden werden.
</p>
<div class="flex flex-wrap gap-2">
<UButton
icon="i-heroicons-link"
color="primary"
:loading="generatingCalendarSubscription"
@click="generateCalendarSubscription"
>
{{ profile.calendar_subscription_token ? 'Link neu generieren' : 'Link generieren' }}
</UButton>
<UButton
v-if="calendarSubscriptionHttpUrl"
icon="i-heroicons-clipboard-document"
color="neutral"
variant="outline"
@click="copyCalendarSubscriptionUrl(calendarSubscriptionHttpUrl, 'ICS-Link kopiert')"
>
ICS kopieren
</UButton>
<UButton
v-if="calendarSubscriptionWebcalUrl"
icon="i-heroicons-device-phone-mobile"
color="neutral"
variant="outline"
@click="copyCalendarSubscriptionUrl(calendarSubscriptionWebcalUrl, 'Webcal-Link kopiert')"
>
Webcal kopieren
</UButton>
</div>
<UForm :state="profile" class="grid grid-cols-1 md:grid-cols-2 gap-6">
<UFormField label="ICS-Link" class="w-full">
<UInput :model-value="calendarSubscriptionHttpUrl" readonly class="w-full" />
</UFormField>
<UFormField label="Webcal-Link" class="w-full">
<UInput :model-value="calendarSubscriptionWebcalUrl" readonly class="w-full" />
</UFormField>
</UForm>
</div>
</UCard>
<UCard v-if="!pending && profile" class="mt-3">
<USeparator label="Adresse & Standort" />