feat: add notifications
All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m42s
All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m42s
This commit is contained in:
parent
f3d5601d00
commit
7831f61fb9
4 changed files with 242 additions and 116 deletions
|
|
@ -25,7 +25,7 @@ export default function SettingsPage({ user }: { user: User }) {
|
||||||
value: "notifications",
|
value: "notifications",
|
||||||
label: "Notifications",
|
label: "Notifications",
|
||||||
icon: <Bell className="h-4 w-4" />,
|
icon: <Bell className="h-4 w-4" />,
|
||||||
content: <NotificationSettings user={user} />,
|
content: <NotificationSettings />,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
|
@ -23,8 +23,60 @@ import InstallApp, { isInstalled } from "./install-app";
|
||||||
import {
|
import {
|
||||||
isNotificationEnabled,
|
isNotificationEnabled,
|
||||||
registerNotification,
|
registerNotification,
|
||||||
|
STORAGE_KEY,
|
||||||
unregisterNotification,
|
unregisterNotification,
|
||||||
} from "~/lib/notification";
|
} from "~/lib/notification";
|
||||||
|
import {
|
||||||
|
testNotification,
|
||||||
|
unsubscribe,
|
||||||
|
updateSubscription,
|
||||||
|
useNotifications,
|
||||||
|
type Event,
|
||||||
|
} from "~/lib/api";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
const EVENTS = [
|
||||||
|
{
|
||||||
|
id: "SYSTEM",
|
||||||
|
label: "Système",
|
||||||
|
description:
|
||||||
|
"Soyez informé des mises à jour et des nouveautés de Khollisé.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "COLLE_ADDED",
|
||||||
|
label: "Colle ajoutée",
|
||||||
|
description:
|
||||||
|
"Recevez une notification lorsqu'une nouvelle colle est ajoutée par votre CDT.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "COLLE_REMOVED",
|
||||||
|
label: "Colle supprimée",
|
||||||
|
description: "Recevez une notification lorsqu'une colle est supprimée.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "COLLE_UPDATED",
|
||||||
|
label: "Colle modifiée",
|
||||||
|
description:
|
||||||
|
"Soyez averti lorsqu'un colleur modifie le contenu d'une colle.",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: "GRADE_ADDED",
|
||||||
|
label: "Note ajoutée",
|
||||||
|
description: "Recevez une notification lorsqu'une colle est notée.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "GRADE_UPDATED",
|
||||||
|
label: "Note modifiée",
|
||||||
|
description: "Soyez averti lorsqu'une note est modifiée.",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: "ROOM_UPDATED",
|
||||||
|
label: "Salle modifiée",
|
||||||
|
description: "Soyez averti lorsqu'une colle change de salle.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function NotificationSettings() {
|
export default function NotificationSettings() {
|
||||||
const [pushEnabled, setPushEnabled] = useState(isNotificationEnabled());
|
const [pushEnabled, setPushEnabled] = useState(isNotificationEnabled());
|
||||||
|
|
@ -36,7 +88,7 @@ export default function NotificationSettings() {
|
||||||
// Unregister notifications
|
// Unregister notifications
|
||||||
unregisterNotification()
|
unregisterNotification()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setPushEnabled(true);
|
setPushEnabled(false);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Failed to unregister notifications:", error);
|
console.error("Failed to unregister notifications:", error);
|
||||||
|
|
@ -51,7 +103,7 @@ export default function NotificationSettings() {
|
||||||
if ("error" in result && result.error) {
|
if ("error" in result && result.error) {
|
||||||
console.error("Failed to register notifications:", result.error);
|
console.error("Failed to register notifications:", result.error);
|
||||||
} else {
|
} else {
|
||||||
setPushEnabled(false);
|
setPushEnabled(true);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
@ -63,38 +115,9 @@ export default function NotificationSettings() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with actual user data
|
const [events, setEvents] = useState<Event[]>([]);
|
||||||
const [events, setEvents] = useState([
|
// TODO: Loader and error handling
|
||||||
{ id: "new-message", label: "New Message", enabled: true },
|
const { notifications, isError, isLoading } = useNotifications();
|
||||||
{ id: "comment-reply", label: "Comment Reply", enabled: true },
|
|
||||||
{ id: "app-update", label: "App Update", enabled: false },
|
|
||||||
{ id: "weekly-digest", label: "Weekly Digest", enabled: true },
|
|
||||||
{ id: "security-alert", label: "Security Alert", enabled: true },
|
|
||||||
{ id: "friend-request", label: "Friend Request", enabled: false },
|
|
||||||
]);
|
|
||||||
const [subscriptions] = useState([
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
name: "iPhone 15 Pro",
|
|
||||||
type: "mobile",
|
|
||||||
status: "active",
|
|
||||||
lastSeen: "2 hours ago",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
name: "MacBook Pro",
|
|
||||||
type: "desktop",
|
|
||||||
status: "active",
|
|
||||||
lastSeen: "5 minutes ago",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "3",
|
|
||||||
name: "Chrome on Windows",
|
|
||||||
type: "desktop",
|
|
||||||
status: "revoked",
|
|
||||||
lastSeen: "3 days ago",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const toggleEvent = (eventId: string) => {
|
const toggleEvent = (eventId: string) => {
|
||||||
setEvents(
|
setEvents(
|
||||||
|
|
@ -103,6 +126,17 @@ export default function NotificationSettings() {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const hasEvent = (eventId: string) => {
|
||||||
|
return events.some((event) => event.id === eventId && event.enabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentSubscriptionId = localStorage.getItem(STORAGE_KEY);
|
||||||
|
const currentSubscription = notifications.find(
|
||||||
|
(sub) => sub.id === currentSubscriptionId
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
setEvents(currentSubscription?.events || []);
|
||||||
|
}, [currentSubscription]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto space-y-6 sm:space-y-8">
|
<div className="max-w-4xl mx-auto space-y-6 sm:space-y-8">
|
||||||
|
|
@ -173,52 +207,67 @@ export default function NotificationSettings() {
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Select Notification Events Section */}
|
{/* Select Notification Events Section */}
|
||||||
<Card>
|
{currentSubscription && (
|
||||||
<CardHeader>
|
<Card>
|
||||||
<CardTitle>Select Notification Events</CardTitle>
|
<CardHeader>
|
||||||
<CardDescription>
|
<CardTitle>Select Notification Events</CardTitle>
|
||||||
Choose which events you want to receive notifications for
|
<CardDescription>
|
||||||
</CardDescription>
|
Choose which events you want to receive notifications for
|
||||||
</CardHeader>
|
</CardDescription>
|
||||||
<CardContent>
|
</CardHeader>
|
||||||
<div className="space-y-3 sm:space-y-4">
|
<CardContent>
|
||||||
{events.map((event, index) => (
|
<div className="space-y-3 sm:space-y-4">
|
||||||
<div key={event.id}>
|
{EVENTS.map((event, index) => (
|
||||||
<div className="flex items-start sm:items-center justify-between py-2 gap-4">
|
<div key={event.id}>
|
||||||
<div className="space-y-1 flex-1 min-w-0">
|
<div className="flex items-start sm:items-center justify-between py-2 gap-4">
|
||||||
<p className="font-medium text-sm sm:text-base">
|
<div className="space-y-1 flex-1 min-w-0">
|
||||||
{event.label}
|
<p className="font-medium text-sm sm:text-base">
|
||||||
</p>
|
{event.label}
|
||||||
<p className="text-xs sm:text-sm text-muted-foreground leading-relaxed">
|
</p>
|
||||||
{event.id === "new-message" &&
|
<p className="text-xs sm:text-sm text-muted-foreground leading-relaxed">
|
||||||
"Get notified when you receive a new message"}
|
{event.description}
|
||||||
{event.id === "comment-reply" &&
|
</p>
|
||||||
"Get notified when someone replies to your comment"}
|
</div>
|
||||||
{event.id === "app-update" &&
|
<Switch
|
||||||
"Get notified when a new app version is available"}
|
checked={hasEvent(event.id)}
|
||||||
{event.id === "weekly-digest" &&
|
onCheckedChange={() => toggleEvent(event.id)}
|
||||||
"Receive a weekly summary of your activity"}
|
aria-label={`Toggle ${event.label} notifications`}
|
||||||
{event.id === "security-alert" &&
|
className="flex-shrink-0"
|
||||||
"Important security notifications and alerts"}
|
/>
|
||||||
{event.id === "friend-request" &&
|
|
||||||
"Get notified when someone sends you a friend request"}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
{index < events.length - 1 && (
|
||||||
checked={event.enabled}
|
<Separator className="mt-3 sm:mt-4" />
|
||||||
onCheckedChange={() => toggleEvent(event.id)}
|
)}
|
||||||
aria-label={`Toggle ${event.label} notifications`}
|
|
||||||
className="flex-shrink-0"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{index < events.length - 1 && (
|
))}
|
||||||
<Separator className="mt-3 sm:mt-4" />
|
<Button
|
||||||
)}
|
variant="outline"
|
||||||
</div>
|
className="w-full mt-4"
|
||||||
))}
|
onClick={() =>
|
||||||
</div>
|
updateSubscription(
|
||||||
</CardContent>
|
currentSubscription.id,
|
||||||
</Card>
|
events.map((event) => event.id)
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
toast.success(
|
||||||
|
"Vos préférences de notification ont été mises à jour."
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed to update subscription:", error);
|
||||||
|
toast.error(
|
||||||
|
"Échec de la mise à jour des préférences de notification."
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Send className="h-4 w-4 mr-2" />
|
||||||
|
Enregistrer
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Manage Subscriptions Section */}
|
{/* Manage Subscriptions Section */}
|
||||||
<Card>
|
<Card>
|
||||||
|
|
@ -230,23 +279,23 @@ export default function NotificationSettings() {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-3 sm:space-y-4">
|
<div className="space-y-3 sm:space-y-4">
|
||||||
{subscriptions.map((subscription, index) => (
|
{notifications.map((subscription, index) => (
|
||||||
<div key={subscription.id}>
|
<div key={subscription.id}>
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 sm:gap-4">
|
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 sm:gap-4">
|
||||||
<div className="flex items-center gap-3 flex-1 min-w-0">
|
<div className="flex items-center gap-3 flex-1 min-w-0">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
{subscription.type === "mobile" ? (
|
<Smartphone className="h-4 w-4 sm:h-5 sm:w-5 text-muted-foreground" />
|
||||||
<Smartphone className="h-4 w-4 sm:h-5 sm:w-5 text-muted-foreground" />
|
|
||||||
) : (
|
|
||||||
<Monitor className="h-4 w-4 sm:h-5 sm:w-5 text-muted-foreground" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 flex-1 min-w-0">
|
<div className="space-y-1 flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<p className="font-medium text-sm sm:text-base truncate">
|
<p className="font-medium text-sm sm:text-base truncate">
|
||||||
{subscription.name}
|
{subscription.device}
|
||||||
</p>
|
</p>
|
||||||
{subscription.status === "revoked" && (
|
{subscription.enabled ? (
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
Active
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
<Badge
|
<Badge
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
className="flex items-center gap-1 text-xs"
|
className="flex items-center gap-1 text-xs"
|
||||||
|
|
@ -255,22 +304,31 @@ export default function NotificationSettings() {
|
||||||
Revoked
|
Revoked
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{subscription.status === "active" && (
|
|
||||||
<Badge variant="secondary" className="text-xs">
|
|
||||||
Active
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs sm:text-sm text-muted-foreground">
|
|
||||||
Last seen {subscription.lastSeen}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 sm:gap-2 self-start sm:self-center">
|
<div className="flex items-center gap-2 sm:gap-2 self-start sm:self-center">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={subscription.status === "revoked"}
|
disabled={!subscription.enabled}
|
||||||
|
onClick={() => {
|
||||||
|
testNotification(subscription.id)
|
||||||
|
.then(() => {
|
||||||
|
toast.success(
|
||||||
|
"Vous allez recevoir une notification de test sur votre appareil..."
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(
|
||||||
|
"Failed to send test notification:",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
toast.error(
|
||||||
|
"Échec de l'envoi de la notification de test."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
className="flex items-center gap-1 bg-transparent text-xs sm:text-sm px-2 sm:px-3"
|
className="flex items-center gap-1 bg-transparent text-xs sm:text-sm px-2 sm:px-3"
|
||||||
>
|
>
|
||||||
<Send className="h-3 w-3 sm:h-4 sm:w-4" />
|
<Send className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
|
|
@ -280,26 +338,41 @@ export default function NotificationSettings() {
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="flex items-center gap-1 text-destructive hover:text-destructive bg-transparent text-xs sm:text-sm px-2 sm:px-3"
|
className="flex items-center gap-1 text-destructive hover:text-destructive bg-transparent text-xs sm:text-sm px-2 sm:px-3"
|
||||||
|
onClick={() => {
|
||||||
|
unsubscribe(subscription.id)
|
||||||
|
.then(() => {
|
||||||
|
toast.success(
|
||||||
|
"L'appareil a été désabonné des notifications."
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed to unsubscribe:", error);
|
||||||
|
toast.error(
|
||||||
|
"Échec de la désinscription de l'appareil."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Trash2 className="h-3 w-3 sm:h-4 sm:w-4" />
|
<Trash2 className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
<span className="hidden xs:inline">Delete</span>
|
<span className="hidden xs:inline">Delete</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{index < subscriptions.length - 1 && (
|
{index < notifications.length - 1 && (
|
||||||
<Separator className="mt-3 sm:mt-4" />
|
<Separator className="mt-3 sm:mt-4" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{subscriptions.length === 0 && (
|
{notifications.length === 0 && (
|
||||||
<div className="text-center py-6 sm:py-8 text-muted-foreground">
|
<div className="text-center py-6 sm:py-8 text-muted-foreground">
|
||||||
<Bell className="h-10 w-10 sm:h-12 sm:w-12 mx-auto mb-3 sm:mb-4 opacity-50" />
|
<Bell className="h-10 w-10 sm:h-12 sm:w-12 mx-auto mb-3 sm:mb-4 opacity-50" />
|
||||||
<p className="text-sm sm:text-base">
|
<p className="text-sm sm:text-base">
|
||||||
No subscribed devices found
|
Aucun appareil n'est actuellement abonné aux notifications.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs sm:text-sm">
|
<p className="text-xs sm:text-sm">
|
||||||
Enable push notifications to add this device
|
Vous pouvez activer les notifications pour recevoir des
|
||||||
|
alertes sur vos appareils.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -320,16 +320,68 @@ export const useSubjects = () => {
|
||||||
*/
|
*/
|
||||||
export const subscribe = async (data: any) => {
|
export const subscribe = async (data: any) => {
|
||||||
return makePostRequest(
|
return makePostRequest(
|
||||||
"/notifications/subscribe",
|
"/notifications",
|
||||||
data,
|
data,
|
||||||
"Échec de l'abonnement aux notifications"
|
"Échec de l'abonnement aux notifications"
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const unsubscribe = async (data: any) => {
|
export const unsubscribe = async (id: string) => {
|
||||||
return makePostRequest(
|
return makePostRequest(
|
||||||
"/notifications/unsubscribe",
|
`/notifications/${id}/unsubscribe`,
|
||||||
data,
|
{},
|
||||||
"Échec de la désinscription des notifications"
|
"Échec de la désinscription des notifications"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const updateSubscription = async (id: string, events: string[]) => {
|
||||||
|
return makePostRequest(
|
||||||
|
`/notifications/${id}`,
|
||||||
|
{ events },
|
||||||
|
"Échec de la mise à jour de l'abonnement aux notifications"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNotifications = async () => {
|
||||||
|
return makeRequest(
|
||||||
|
"/notifications",
|
||||||
|
"Échec de la récupération des notifications"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface Event {
|
||||||
|
id: string;
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Subscription {
|
||||||
|
id: string;
|
||||||
|
device: string;
|
||||||
|
events: Event[];
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNotifications = () => {
|
||||||
|
const { data, ...props } = useQuery({
|
||||||
|
queryKey: ["notifications"],
|
||||||
|
queryFn: getNotifications,
|
||||||
|
staleTime: Duration.fromObject({
|
||||||
|
hours: 1, // 1 hour
|
||||||
|
}).toMillis(),
|
||||||
|
gcTime: Duration.fromObject({
|
||||||
|
days: 3, // 3 days
|
||||||
|
}).toMillis(),
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
notifications: (data as Subscription[]) || [],
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const testNotification = async (id: string) => {
|
||||||
|
return makePostRequest(
|
||||||
|
`/notifications/${id}/test`,
|
||||||
|
{},
|
||||||
|
"Échec de l'envoi de la notification de test"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { subscribe, unsubscribe } from "./api";
|
import { subscribe, unsubscribe } from "./api";
|
||||||
|
|
||||||
const STORAGE_KEY = "notification_enabled";
|
export const STORAGE_KEY = "notification_enabled";
|
||||||
|
|
||||||
export async function registerNotification() {
|
export async function registerNotification() {
|
||||||
const permission = await Notification.requestPermission();
|
const permission = await Notification.requestPermission();
|
||||||
|
|
@ -20,9 +20,9 @@ export async function registerNotification() {
|
||||||
userVisibleOnly: true,
|
userVisibleOnly: true,
|
||||||
applicationServerKey: import.meta.env.VITE_PUBLIC_VAPID_KEY,
|
applicationServerKey: import.meta.env.VITE_PUBLIC_VAPID_KEY,
|
||||||
});
|
});
|
||||||
await subscribe(subscription);
|
const data = await subscribe(subscription);
|
||||||
// Store to local storage
|
// Store to local storage
|
||||||
localStorage.setItem(STORAGE_KEY, "true");
|
localStorage.setItem(STORAGE_KEY, data.id?.toString());
|
||||||
return subscription;
|
return subscription;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -32,15 +32,16 @@ export async function registerNotification() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNotificationEnabled() {
|
export function isNotificationEnabled() {
|
||||||
return localStorage.getItem(STORAGE_KEY) === "true";
|
return !!localStorage.getItem(STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function unregisterNotification() {
|
export async function unregisterNotification() {
|
||||||
const registration = await navigator.serviceWorker.ready;
|
const subscriptionId = localStorage.getItem(STORAGE_KEY);
|
||||||
const subscription = await registration.pushManager.getSubscription();
|
if (!subscriptionId) {
|
||||||
if (subscription) {
|
return {
|
||||||
await subscription.unsubscribe();
|
error: "E_NOT_REGISTERED",
|
||||||
localStorage.removeItem(STORAGE_KEY);
|
};
|
||||||
await unsubscribe(subscription);
|
|
||||||
}
|
}
|
||||||
|
await unsubscribe(subscriptionId);
|
||||||
|
localStorage.removeItem(STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue