ui update and some backend functionality adding in accordance with research on adhd and ux design
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import api from '@/lib/api';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export default function PushNotificationToggle() {
|
||||
const [supported, setSupported] = useState(false);
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const check = async () => {
|
||||
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
setSupported(true);
|
||||
|
||||
try {
|
||||
const reg = await navigator.serviceWorker.ready;
|
||||
const sub = await reg.pushManager.getSubscription();
|
||||
setEnabled(!!sub);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
check();
|
||||
}, []);
|
||||
|
||||
const toggle = async () => {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const reg = await navigator.serviceWorker.ready;
|
||||
|
||||
if (enabled) {
|
||||
// Unsubscribe
|
||||
const sub = await reg.pushManager.getSubscription();
|
||||
if (sub) {
|
||||
await api.notifications.unsubscribe(sub.endpoint);
|
||||
await sub.unsubscribe();
|
||||
}
|
||||
setEnabled(false);
|
||||
} else {
|
||||
// Subscribe
|
||||
const permission = await Notification.requestPermission();
|
||||
if (permission !== 'granted') {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const { public_key } = await api.notifications.getVapidPublicKey();
|
||||
const sub = await reg.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlBase64ToUint8Array(public_key).buffer as ArrayBuffer,
|
||||
});
|
||||
|
||||
const subJson = sub.toJSON();
|
||||
await api.notifications.subscribe(subJson);
|
||||
setEnabled(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Push notification toggle failed:', err);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
if (!supported) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between bg-white rounded-xl p-4 shadow-sm">
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900 text-sm">Push Notifications</h3>
|
||||
<p className="text-xs text-gray-500">Get reminders on this device</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={toggle}
|
||||
disabled={loading}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
|
||||
enabled ? 'bg-indigo-600' : 'bg-gray-300'
|
||||
} ${loading ? 'opacity-50' : ''}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
|
||||
enabled ? 'translate-x-6' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user