diff --git a/client/src/lib/utils.ts b/client/src/lib/utils.ts index bd0c391..0ac5eb8 100644 --- a/client/src/lib/utils.ts +++ b/client/src/lib/utils.ts @@ -4,3 +4,19 @@ import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } + +// Convert base64 string to Uint8Array for web push +export function urlBase64ToUint8Array(base64String: string): Uint8Array { + const padding = '='.repeat((4 - base64String.length % 4) % 4); + const base64 = (base64String + padding) + .replace(/\-/g, '+') + .replace(/_/g, '/'); + + const rawData = window.atob(base64); + const outputArray = new Uint8Array(rawData.length); + + for (let i = 0; i < rawData.length; ++i) { + outputArray[i] = rawData.charCodeAt(i); + } + return outputArray; +} \ No newline at end of file diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 5db7d9f..eae8bbe 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -4,6 +4,7 @@ import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/com import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; +import { urlBase64ToUint8Array } from "@/lib/utils"; import { Search, ExternalLink, @@ -89,9 +90,15 @@ export default function Home() { } const registration = await navigator.serviceWorker.ready; + const vapidPublicKey = import.meta.env.VITE_VAPID_PUBLIC_KEY; + if (!vapidPublicKey) { + throw new Error('VAPID public key is not configured'); + } + + const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey); const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: import.meta.env.VITE_VAPID_PUBLIC_KEY + applicationServerKey: convertedVapidKey }); await apiRequest('POST', '/api/subscriptions', subscription); @@ -100,7 +107,7 @@ export default function Home() { title: "Subscribed!", description: "You'll receive notifications for new newsletters", }); - } catch (error) { + } catch (error: any) { toast({ title: "Error", description: error.message || "Failed to subscribe to notifications",