feat: instant meeting browser notifcations (#16480)

* feat: instant meeting browser notifcations

* chore: support multiple notifications

* chore: save progress

* fix: add test notification and move file

* fix: type err

* chore: feedback improvements

* chore: undo DENY
This commit is contained in:
Udit Takkar authored and GitHub committed 2024-09-11 18:02:14 +04:00
1 parent 5bc0e1265d
commit 860d173f0a
9 files changed
+220 -37

No files matched your search

@@ -12,7 +12,6 @@ import type { filterQuerySchema } from "@calcom/features/bookings/lib/useFilterQ
import { useFilterQuery } from "@calcom/features/bookings/lib/useFilterQuery";
import Shell from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useNotifications, ButtonState } from "@calcom/lib/hooks/useNotifications";
import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
@@ -145,27 +144,6 @@ export default function Bookings() {
)[0] || [];
const [animationParentRef] = useAutoAnimate<HTMLDivElement>();
const { buttonToShow, isLoading, enableNotifications, disableNotifications } = useNotifications();
const actions = (
<div>
{buttonToShow && (
<Button
color="primary"
onClick={buttonToShow === ButtonState.ALLOW ? enableNotifications : disableNotifications}
loading={isLoading}
disabled={buttonToShow === ButtonState.DENIED}
tooltipSide="bottom"
tooltip={buttonToShow === ButtonState.DENIED ? t("you_have_denied_notifications") : undefined}>
{t(
buttonToShow === ButtonState.DISABLE
? "disable_browser_notifications"
: "allow_browser_notifications"
)}
</Button>
)}
</div>
);
return (
<Shell
@@ -174,8 +152,7 @@ export default function Bookings() {
heading={t("bookings")}
subtitle={t("bookings_description")}
title="Bookings"
description="Create events to share for people to book on your calendar."
actions={actions}>
description="Create events to share for people to book on your calendar.">
<div className="flex flex-col">
<div className="flex flex-row flex-wrap justify-between">
<HorizontalTabs tabs={tabs} />
+60 -8
View File
@@ -1,16 +1,68 @@
self.addEventListener("push", (event) => {
self.addEventListener("push", async (event) => {
let notificationData = event.data.json();
const title = notificationData.title || "You have new notification from Cal.com";
const image ="/cal-com-icon.svg";
const options = {
...notificationData.options,
const allClients = await clients.matchAll({
type: 'window',
includeUncontrolled: true
});
if(!allClients.length) {
console.log("No open tabs, skipping the push notification.");
return;
}
const title = notificationData.title || "You have a new notification from Cal.com";
const image = "https://cal.com/api/logo?type=icon";
const newNotificationOptions = {
requireInteraction: true,
...notificationData,
icon: image,
badge: image,
data: {
url: notificationData.data?.url || "https://app.cal.com",
},
silent: false,
vibrate: [300, 100, 400],
tag: `notification-${Date.now()}-${Math.random()}`,
};
self.registration.showNotification(title, options);
const existingNotifications = await self.registration.getNotifications();
// Display each existing notification again to make sure old ones can still be clicked
existingNotifications.forEach((notification) => {
const options = {
body: notification.body,
icon: notification.icon,
badge: notification.badge,
data: notification.data,
silent: notification.silent,
vibrate: notification.vibrate,
requireInteraction: notification.requireInteraction,
tag: notification.tag,
};
self.registration.showNotification(notification.title, options);
});
// Show the new notification
self.registration.showNotification(title, newNotificationOptions);
});
self.addEventListener("notificationclick", (event) => {
event.notification.close();
event.waitUntil(self.clients.openWindow(event.notification.data.targetURL || "https://app.cal.com"));
if (!event.action) {
// Normal Notification Click
event.notification.close();
const url = event.notification.data.url;
event.waitUntil(self.clients.openWindow(url));
}
switch (event.action) {
case 'connect-action':
event.notification.close();
const url = event.notification.data.url;
event.waitUntil(self.clients.openWindow(url));
break;
}
});