mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-07-16 17:48:51 +02:00
Merge branch '17-use-webshare-api' into 'main'
Resolve "use share api for room occupancies/calenders" Closes #17 See merge request htwk-software/htwkalender-pwa!22
This commit is contained in:
@ -84,7 +84,42 @@ const forwardToHTWKalendar = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions = computed(() => [
|
const shareLink = () => {
|
||||||
|
if (typeof navigator.share === 'function' && navigator.canShare()) {
|
||||||
|
navigator
|
||||||
|
.share({
|
||||||
|
title: t("calendarLink.shareTitle"),
|
||||||
|
text: t("calendarLink.shareText") + getLink(),
|
||||||
|
url: "https://" + domain + "/",
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
toast.add({
|
||||||
|
severity: "info",
|
||||||
|
summary: t("calendarLink.shareToastSummary"),
|
||||||
|
detail: t("calendarLink.shareToastNotification"),
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.add({
|
||||||
|
severity: "error",
|
||||||
|
summary: t("calendarLink.shareToastError"),
|
||||||
|
detail: t("calendarLink.shareToastErrorDetail"),
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast.add({
|
||||||
|
severity: "error",
|
||||||
|
summary: t("calendarLink.shareToastError"),
|
||||||
|
detail: t("calendarLink.shareToastErrorDetail"),
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const actions = computed(() => {
|
||||||
|
const actionList = [
|
||||||
{
|
{
|
||||||
label: t("calendarLink.copyToClipboard"),
|
label: t("calendarLink.copyToClipboard"),
|
||||||
icon: "pi pi-copy",
|
icon: "pi pi-copy",
|
||||||
@ -104,8 +139,21 @@ const actions = computed(() => [
|
|||||||
label: t("calendarLink.toHTWKalendar"),
|
label: t("calendarLink.toHTWKalendar"),
|
||||||
icon: "pi pi-home",
|
icon: "pi pi-home",
|
||||||
command: forwardToHTWKalendar,
|
command: forwardToHTWKalendar,
|
||||||
},
|
}
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if (typeof navigator.share === 'function' && navigator.canShare()) {
|
||||||
|
actionList.push({
|
||||||
|
label: t("calendarLink.share"),
|
||||||
|
icon: "pi pi-share-alt",
|
||||||
|
command: shareLink,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionList;
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -46,12 +46,21 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type CalendarEvent = {
|
||||||
|
title: string;
|
||||||
|
start: Date | null;
|
||||||
|
end: Date | null;
|
||||||
|
notes: string;
|
||||||
|
allDay: boolean;
|
||||||
|
location: string;
|
||||||
|
};
|
||||||
|
|
||||||
const op = ref();
|
const op = ref();
|
||||||
const clickedEvent = ref();
|
const clickedEvent : Ref<CalendarEvent | null> = ref(null);
|
||||||
|
|
||||||
const toggle = (info: EventClickArg) => {
|
const toggle = (info: EventClickArg) => {
|
||||||
const start = !info.event.start ? "" : info.event.start;
|
const start = !info.event.start ? null : info.event.start;
|
||||||
const end = !info.event.end ? "" : info.event.end;
|
const end = !info.event.end ? null : info.event.end;
|
||||||
|
|
||||||
if (op.value.visible) {
|
if (op.value.visible) {
|
||||||
clickedEvent.value = null;
|
clickedEvent.value = null;
|
||||||
@ -199,12 +208,13 @@ watch(mobilePage, () => {
|
|||||||
</FullCalendar>
|
</FullCalendar>
|
||||||
|
|
||||||
<OverlayPanel ref="op">
|
<OverlayPanel ref="op">
|
||||||
<div>
|
<div v-if="clickedEvent">
|
||||||
<h3>{{ clickedEvent.title }}</h3>
|
<h3>{{ clickedEvent.title }}</h3>
|
||||||
<p>Location: {{ clickedEvent.location }}</p>
|
<p><b>{{ $t("calendarViewer.location") }}:</b> {{ clickedEvent.location }}</p>
|
||||||
<p>Start: {{ clickedEvent.start?.toLocaleString() }}</p>
|
<p><b>{{ $t("calendarViewer.start") }}:</b> {{ clickedEvent.start ? $d(clickedEvent.start, "long") : ""}}</p>
|
||||||
<p>End: {{ clickedEvent.end?.toLocaleString() }}</p>
|
<p><b>{{ $t("calendarViewer.end") }}:</b> {{ clickedEvent.end ? $d(clickedEvent.end, "long") : "" }}</p>
|
||||||
<p>Notes: {{ clickedEvent.notes }}</p>
|
<p><b>{{ $t("calendarViewer.notes") }}:</b></p>
|
||||||
|
<p v-for="note in clickedEvent.notes.split('\n')" class="note-line" :key="note">{{ note }}</p>
|
||||||
</div>
|
</div>
|
||||||
</OverlayPanel>
|
</OverlayPanel>
|
||||||
</template>
|
</template>
|
||||||
@ -215,4 +225,9 @@ watch(mobilePage, () => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-line {
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 2rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -34,6 +34,56 @@ function setup() {
|
|||||||
de,
|
de,
|
||||||
ja,
|
ja,
|
||||||
},
|
},
|
||||||
|
datetimeFormats: {
|
||||||
|
en: {
|
||||||
|
short: {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
},
|
||||||
|
long: {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
weekday: "short",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
short: {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
},
|
||||||
|
long: {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
weekday: "short",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
hour12: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ja: {
|
||||||
|
short: {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
},
|
||||||
|
long: {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
weekday: "short",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return _i18n;
|
return _i18n;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,14 @@
|
|||||||
"copyToClipboard": "Link kopieren",
|
"copyToClipboard": "Link kopieren",
|
||||||
"toGoogleCalendar": "Google Kalender",
|
"toGoogleCalendar": "Google Kalender",
|
||||||
"toMicrosoftCalendar": "Microsoft Kalender",
|
"toMicrosoftCalendar": "Microsoft Kalender",
|
||||||
"toHTWKalendar": "HTWKalender"
|
"toHTWKalendar": "HTWKalender",
|
||||||
|
"share": "Teilen",
|
||||||
|
"shareTitle": "HTWKalender",
|
||||||
|
"shareText": "Ich habe diesen Stundenplan für dich mit dem HTWKalender erstellt. Schau ihn dir hier an: ",
|
||||||
|
"shareToastSummary": "Information",
|
||||||
|
"shareToastNotification": "Link zum Stundenplan erfolgreich geteilt",
|
||||||
|
"shareToastError": "Fehler",
|
||||||
|
"shareToastErrorDetail": "Link konnte nicht geteilt werden. Möglicherweise wird die Funktion nicht unterstützt."
|
||||||
},
|
},
|
||||||
"calendarPreview": {
|
"calendarPreview": {
|
||||||
"preview": "Vorschau",
|
"preview": "Vorschau",
|
||||||
@ -155,6 +162,12 @@
|
|||||||
"module": "Modul",
|
"module": "Modul",
|
||||||
"course": "Gruppe"
|
"course": "Gruppe"
|
||||||
},
|
},
|
||||||
|
"calendarViewer": {
|
||||||
|
"location": "Ort",
|
||||||
|
"start": "Beginn",
|
||||||
|
"end": "Ende",
|
||||||
|
"notes": "Notizen"
|
||||||
|
},
|
||||||
"faqView": {
|
"faqView": {
|
||||||
"headline": "Fragen und Antworten",
|
"headline": "Fragen und Antworten",
|
||||||
"firstQuestion": "Wie funktioniert das Kalender erstellen mit dem HTWKalender?",
|
"firstQuestion": "Wie funktioniert das Kalender erstellen mit dem HTWKalender?",
|
||||||
@ -253,7 +266,8 @@
|
|||||||
"headline": "Dein Kalender",
|
"headline": "Dein Kalender",
|
||||||
"subTitle": "Hier findest du die Kalenderansicht von deinem persönlichen Feed.",
|
"subTitle": "Hier findest du die Kalenderansicht von deinem persönlichen Feed.",
|
||||||
"searchPlaceholder": "Token",
|
"searchPlaceholder": "Token",
|
||||||
"searchButton": "Kalender laden"
|
"searchButton": "Kalender laden",
|
||||||
|
"invalidToken": "Ungültiger Token"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"headline": "Einstellungen",
|
"headline": "Einstellungen",
|
||||||
|
@ -152,7 +152,14 @@
|
|||||||
"copyToClipboard": "copy to clipboard",
|
"copyToClipboard": "copy to clipboard",
|
||||||
"toGoogleCalendar": "Google Calendar",
|
"toGoogleCalendar": "Google Calendar",
|
||||||
"toMicrosoftCalendar": "Microsoft Calendar",
|
"toMicrosoftCalendar": "Microsoft Calendar",
|
||||||
"toHTWKalendar": "HTWKalender"
|
"toHTWKalendar": "HTWKalender",
|
||||||
|
"share": "Share",
|
||||||
|
"shareTitle": "HTWKalender",
|
||||||
|
"shareText": "I’ve created this timetable for you with HTWKalender. Check it out here: ",
|
||||||
|
"shareToastSummary": "Information",
|
||||||
|
"shareToastNotification": "Timetable link successfully shared",
|
||||||
|
"shareToastError": "Error",
|
||||||
|
"shareToastErrorDetail": "Link could not be shared. The feature might not be supported."
|
||||||
},
|
},
|
||||||
"calendarPreview": {
|
"calendarPreview": {
|
||||||
"preview": "preview",
|
"preview": "preview",
|
||||||
@ -160,6 +167,12 @@
|
|||||||
"module": "module",
|
"module": "module",
|
||||||
"course": "course"
|
"course": "course"
|
||||||
},
|
},
|
||||||
|
"calendarViewer": {
|
||||||
|
"location": "location",
|
||||||
|
"start": "start",
|
||||||
|
"end": "end",
|
||||||
|
"notes": "notes"
|
||||||
|
},
|
||||||
"faqView": {
|
"faqView": {
|
||||||
"headline": "faq",
|
"headline": "faq",
|
||||||
"firstQuestion": "How does calendar creation work with HTWKalender?",
|
"firstQuestion": "How does calendar creation work with HTWKalender?",
|
||||||
@ -258,7 +271,8 @@
|
|||||||
"headline": "user calendar",
|
"headline": "user calendar",
|
||||||
"subTitle": "Here you can find the calendar view of your personal feed.",
|
"subTitle": "Here you can find the calendar view of your personal feed.",
|
||||||
"searchPlaceholder": "calendar token",
|
"searchPlaceholder": "calendar token",
|
||||||
"searchButton": "load calendar"
|
"searchButton": "load calendar",
|
||||||
|
"invalidToken": "invalid token"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"headline": "Settings",
|
"headline": "Settings",
|
||||||
|
@ -147,7 +147,14 @@
|
|||||||
"copyToClipboard": "クリップボードにコピー",
|
"copyToClipboard": "クリップボードにコピー",
|
||||||
"toGoogleCalendar": "Googleカレンダー",
|
"toGoogleCalendar": "Googleカレンダー",
|
||||||
"toMicrosoftCalendar": "Microsoftカレンダー",
|
"toMicrosoftCalendar": "Microsoftカレンダー",
|
||||||
"toHTWKalendar": "HTWカレンダー"
|
"toHTWKalendar": "HTWカレンダー",
|
||||||
|
"share": "共有",
|
||||||
|
"shareTitle": "HTWカレンダー",
|
||||||
|
"shareText": "HTWカレンダーでこの時間割を作成しました。こちらで確認してください: ",
|
||||||
|
"shareToastSummary": "情報",
|
||||||
|
"shareToastNotification": "時間割のリンクが正常に共有されました",
|
||||||
|
"shareToastError": "エラー",
|
||||||
|
"shareToastErrorDetail": "リンクを共有できませんでした。機能がサポートされていない可能性があります。"
|
||||||
},
|
},
|
||||||
"calendarPreview": {
|
"calendarPreview": {
|
||||||
"preview": "プレビュー",
|
"preview": "プレビュー",
|
||||||
@ -155,6 +162,12 @@
|
|||||||
"module": "モジュール",
|
"module": "モジュール",
|
||||||
"course": "コース"
|
"course": "コース"
|
||||||
},
|
},
|
||||||
|
"calendarViewer": {
|
||||||
|
"location": "場所",
|
||||||
|
"start": "開始",
|
||||||
|
"end": "終了",
|
||||||
|
"notes": "メモ"
|
||||||
|
},
|
||||||
"faqView": {
|
"faqView": {
|
||||||
"headline": "よくある質問",
|
"headline": "よくある質問",
|
||||||
"firstQuestion": "HTWカレンダーを使用してカレンダーを作成するにはどうすればよいですか?",
|
"firstQuestion": "HTWカレンダーを使用してカレンダーを作成するにはどうすればよいですか?",
|
||||||
@ -253,7 +266,8 @@
|
|||||||
"headline": "ユーザーカレンダー",
|
"headline": "ユーザーカレンダー",
|
||||||
"subTitle": "ここでは、個人のフィードのカレンダー表示を見つけることができます。",
|
"subTitle": "ここでは、個人のフィードのカレンダー表示を見つけることができます。",
|
||||||
"searchPlaceholder": "カレンダートークン",
|
"searchPlaceholder": "カレンダートークン",
|
||||||
"searchButton": "ロードカレンダー"
|
"searchButton": "ロードカレンダー",
|
||||||
|
"invalidToken": "無効なトークン"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"headline": "設定",
|
"headline": "設定",
|
||||||
|
@ -22,6 +22,7 @@ import App from "./App.vue";
|
|||||||
import PrimeVue from "primevue/config";
|
import PrimeVue from "primevue/config";
|
||||||
import Badge from "primevue/badge";
|
import Badge from "primevue/badge";
|
||||||
import Button from "primevue/button";
|
import Button from "primevue/button";
|
||||||
|
import ButtonGroup from "primevue/buttongroup";
|
||||||
import Dropdown from "primevue/dropdown";
|
import Dropdown from "primevue/dropdown";
|
||||||
import Menu from "primevue/menu";
|
import Menu from "primevue/menu";
|
||||||
import Menubar from "primevue/menubar";
|
import Menubar from "primevue/menubar";
|
||||||
@ -85,6 +86,7 @@ i18n.setup();
|
|||||||
app.use(i18n.vueI18n);
|
app.use(i18n.vueI18n);
|
||||||
app.component("Badge", Badge);
|
app.component("Badge", Badge);
|
||||||
app.component("Button", Button);
|
app.component("Button", Button);
|
||||||
|
app.component("ButtonGroup", ButtonGroup);
|
||||||
app.component("Menu", Menu);
|
app.component("Menu", Menu);
|
||||||
app.component("Menubar", Menubar);
|
app.component("Menubar", Menubar);
|
||||||
app.component("Dialog", Dialog);
|
app.component("Dialog", Dialog);
|
||||||
|
@ -3,10 +3,11 @@ import CalendarViewer from "@/components/CalendarViewer.vue";
|
|||||||
import DynamicPage from "@/view/DynamicPage.vue";
|
import DynamicPage from "@/view/DynamicPage.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { extractToken } from "@/helpers/token.ts";
|
import { extractToken, isToken } from "@/helpers/token.ts";
|
||||||
import { useToast } from "primevue/usetoast";
|
import { useToast } from "primevue/usetoast";
|
||||||
import moduleStore from "@/store/moduleStore.ts";
|
import moduleStore from "@/store/moduleStore.ts";
|
||||||
import tokenStore from "@/store/tokenStore.ts";
|
import tokenStore from "@/store/tokenStore.ts";
|
||||||
|
import router from "@/router";
|
||||||
|
|
||||||
const { t } = useI18n({ useScope: "global" });
|
const { t } = useI18n({ useScope: "global" });
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
@ -49,6 +50,33 @@ function loadCalendar() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shareLink() {
|
||||||
|
let datePart = router.currentRoute.value.query.date;
|
||||||
|
if (datePart != undefined) {
|
||||||
|
datePart = "&date=" + datePart;
|
||||||
|
} else {
|
||||||
|
datePart = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = "https://" + window.location.hostname + "/calendar/view?token=" + token.value + datePart;
|
||||||
|
if (typeof navigator.share === "function" && navigator.canShare()) {
|
||||||
|
navigator.share({
|
||||||
|
title: t("calendarLink.shareLinkTitle"),
|
||||||
|
text: t("calendarLink.shareLinkText"),
|
||||||
|
url: link,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigator.clipboard.writeText(link).then(() => {
|
||||||
|
toast.add({
|
||||||
|
severity: "info",
|
||||||
|
summary: t("calendarLink.copyToastSummary"),
|
||||||
|
detail: t("calendarLink.copyToastNotification"),
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (token.value && token.value !== "") {
|
if (token.value && token.value !== "") {
|
||||||
//loadCalendar();
|
//loadCalendar();
|
||||||
@ -69,11 +97,23 @@ onMounted(() => {
|
|||||||
:class="flexSpecs"
|
:class="flexSpecs"
|
||||||
@keyup.enter="loadCalendar()"
|
@keyup.enter="loadCalendar()"
|
||||||
/>
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
:class="flexSpecs"
|
||||||
|
class="flex no-wrap"
|
||||||
|
:style="{ 'justify-content': 'space-between' }"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
:label="$t('userCalender.searchButton')"
|
:label="$t('userCalender.searchButton')"
|
||||||
icon="pi pi-refresh"
|
icon="pi pi-refresh"
|
||||||
|
class="flex-grow-1"
|
||||||
@click="loadCalendar()"
|
@click="loadCalendar()"
|
||||||
></Button>
|
></Button>
|
||||||
|
<Button
|
||||||
|
icon="pi pi-share-alt"
|
||||||
|
:disabled="!isToken(token)"
|
||||||
|
@click="shareLink()"
|
||||||
|
></Button>
|
||||||
|
</ButtonGroup>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<CalendarViewer ref="calendarViewerRef" :token="tokenStore().token" />
|
<CalendarViewer ref="calendarViewerRef" :token="tokenStore().token" />
|
||||||
|
Reference in New Issue
Block a user