KI-AGENT: Ergänze Kalender-Abo für Mitarbeiterprofile
This commit is contained in:
@@ -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" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user