upd: web push
Deskripsi: - install package - table database - nb : masih blm bisa No Issues
This commit is contained in:
15
src/lib/prisma.ts
Normal file
15
src/lib/prisma.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prismaClientSingleton = () => {
|
||||
return new PrismaClient()
|
||||
}
|
||||
|
||||
declare const globalThis: {
|
||||
prismaGlobal: ReturnType<typeof prismaClientSingleton>;
|
||||
} & typeof global;
|
||||
|
||||
const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()
|
||||
|
||||
export default prisma
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma
|
||||
13
src/lib/urlB64ToUint8Array.ts
Normal file
13
src/lib/urlB64ToUint8Array.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const urlB64ToUint8Array = (base64String: string) => {
|
||||
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;
|
||||
};
|
||||
|
||||
46
src/lib/usePWAInstall.ts
Normal file
46
src/lib/usePWAInstall.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export function usePWAInstall() {
|
||||
const [deferredPrompt, setDeferredPrompt] = useState<any>(null);
|
||||
const [isAppInstalled, setIsAppInstalled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const beforeInstallHandler = (e: any) => {
|
||||
e.preventDefault();
|
||||
setDeferredPrompt(e);
|
||||
};
|
||||
|
||||
|
||||
const appInstalledHandler = () => {
|
||||
setIsAppInstalled(true);
|
||||
};
|
||||
|
||||
window.addEventListener("beforeinstallprompt", beforeInstallHandler);
|
||||
window.addEventListener("appinstalled", appInstalledHandler);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("beforeinstallprompt", beforeInstallHandler);
|
||||
window.removeEventListener("appinstalled", appInstalledHandler);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleInstallClick = () => {
|
||||
if (deferredPrompt) {
|
||||
deferredPrompt.prompt();
|
||||
deferredPrompt.userChoice.then((choiceResult: any) => {
|
||||
if (choiceResult.outcome === "accepted") {
|
||||
console.log("User accepted the install prompt");
|
||||
} else {
|
||||
console.log("User dismissed the install prompt");
|
||||
}
|
||||
setDeferredPrompt(null);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
deferredPrompt,
|
||||
isAppInstalled,
|
||||
handleInstallClick,
|
||||
};
|
||||
}
|
||||
75
src/lib/usePushNotifications.ts
Normal file
75
src/lib/usePushNotifications.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { urlB64ToUint8Array } from "./urlB64ToUint8Array";
|
||||
|
||||
export function usePushNotifications(publicKey: string) {
|
||||
const [isSupported, setIsSupported] = useState(false);
|
||||
const [subscription, setSubscription] = useState<PushSubscription | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if ("serviceWorker" in navigator && "PushManager" in window) {
|
||||
setIsSupported(true);
|
||||
registerServiceWorker();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const registerServiceWorker = async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register(
|
||||
"/wibu_worker.js",
|
||||
{
|
||||
scope: "/",
|
||||
updateViaCache: "none"
|
||||
}
|
||||
);
|
||||
const sub = await registration.pushManager.getSubscription();
|
||||
if (sub) {
|
||||
setSubscription(sub);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Service Worker registration failed:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const subscribeToPush = async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
const sub = await registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlB64ToUint8Array(publicKey)
|
||||
});
|
||||
|
||||
const res = await fetch("/api/set-subscribe", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sub: sub.toJSON() })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
setSubscription(sub);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Subscription error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const unsubscribeFromPush = async () => {
|
||||
if (subscription) {
|
||||
await subscription.unsubscribe();
|
||||
setSubscription(null);
|
||||
await fetch("/api/unsubscribe", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sub: subscription.toJSON() })
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isSupported,
|
||||
subscription,
|
||||
subscribeToPush,
|
||||
unsubscribeFromPush
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user