diff --git a/public/stuve-logo.png b/public/stuve-logo.png new file mode 100644 index 0000000..d6925bb Binary files /dev/null and b/public/stuve-logo.png differ diff --git a/src/pages/chat/components/ChatNavIcon.tsx b/src/pages/chat/components/ChatNavIcon.tsx index 51357a9..3394b99 100644 --- a/src/pages/chat/components/ChatNavIcon.tsx +++ b/src/pages/chat/components/ChatNavIcon.tsx @@ -2,37 +2,76 @@ import {ActionIcon, Indicator} from "@mantine/core"; import {Link, useMatch} from "react-router-dom"; import {IconMessageCircle} from "@tabler/icons-react"; import {usePB} from "@/lib/pocketbase.tsx"; -import {useState} from "react"; +import {useEffect, useState} from "react"; import {useTimeout} from "@mantine/hooks"; import {MessagesModel} from "@/models/MessageTypes.ts"; +import {APP_NAME, APP_URL} from "../../../../config.ts"; + +/** + * Parse HTML string and return text content + * @param html - HTML string + */ +const parseHtmlString = (html: string): string => { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + return doc.body.textContent || ''; +} + +const sendDesktopNotification = (body: string, url: string) => { + if ("Notification" in window && Notification.permission === 'granted') { + const notification = new Notification(APP_NAME, { + body: body, + icon: `${APP_URL}/stuve-logo.svg`, + vibrate: [200, 100, 200], + data: {url: url} + }) + notification.onclick = () => { + window.focus() + window.open(notification.data.url); + } + } +} export default function ChatNavIcon() { - const [newMessage, setNewMessage] = useState(null); - const {start} = useTimeout(() => setNewMessage(null), 5000); + const [notificationUrl, setNotificationUrl] = useState(null); + const {start} = useTimeout(() => setNotificationUrl(null), 5000); const {user, useSubscription} = usePB() const match = useMatch("/chat/:listId") + useEffect(() => { + // Request notification permission on component mount + if ("Notification" in window && Notification.permission !== 'granted') { + Notification.requestPermission().then(() => { + sendDesktopNotification( + "Willkommen bei StuVe! Du kannst jetzt Desktop Benachrichtigungen erhalten.", + `${APP_URL}/chat` + ) + }) + } + }, []) + useSubscription({ idOrName: "messages", topic: "*", callback: (event) => { if (event.action == "create") { - if (event.record.isAnnouncement) { - start() - setNewMessage("announcements") - } else if ( - event.record.eventList - && - match?.params.listId !== event.record.eventList // check if chat page is not already open - && - event.record.sender !== user?.id // check if sender is not the user - ) { - start() - setNewMessage(event.record.eventList) + // check if chat page is not already open and if sender is not the user + if (match?.params.listId === event.record.eventList && event.record.sender === user?.id) { + return } + + const notificationUrl = `/chat/${event.record.isAnnouncement ? "announcements" : event.record.eventList}` + + setNotificationUrl(notificationUrl) + start() + + sendDesktopNotification( + parseHtmlString(event.record.content), + `${APP_URL}${notificationUrl}` + ) } } }) @@ -42,12 +81,12 @@ export default function ChatNavIcon() { } return <> -