96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { usePushNotifications } from '@/hooks/usePushNotifications';
|
|
|
|
interface NotificationToggleProps {
|
|
roomSlug: string;
|
|
syncUrl?: string;
|
|
}
|
|
|
|
export default function NotificationToggle({ roomSlug, syncUrl }: NotificationToggleProps) {
|
|
const {
|
|
isSupported,
|
|
isSubscribed,
|
|
isLoading,
|
|
permission,
|
|
error,
|
|
toggleSubscription,
|
|
} = usePushNotifications({ roomSlug, syncUrl });
|
|
|
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
|
|
if (!isSupported) {
|
|
return null; // Don't show if not supported
|
|
}
|
|
|
|
const handleClick = async () => {
|
|
try {
|
|
await toggleSubscription();
|
|
} catch (err) {
|
|
console.error('Failed to toggle notifications:', err);
|
|
}
|
|
};
|
|
|
|
const getStatusText = () => {
|
|
if (isLoading) return 'Loading...';
|
|
if (error) return error;
|
|
if (permission === 'denied') return 'Notifications blocked';
|
|
if (isSubscribed) return 'Notifications on';
|
|
return 'Enable notifications';
|
|
};
|
|
|
|
const getIcon = () => {
|
|
if (isSubscribed) {
|
|
return (
|
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
|
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z" />
|
|
</svg>
|
|
);
|
|
}
|
|
return (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
|
|
/>
|
|
</svg>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="relative">
|
|
<button
|
|
onClick={handleClick}
|
|
disabled={isLoading || permission === 'denied'}
|
|
onMouseEnter={() => setShowTooltip(true)}
|
|
onMouseLeave={() => setShowTooltip(false)}
|
|
className={`p-2 rounded-lg transition-colors ${
|
|
isSubscribed
|
|
? 'bg-rmaps-primary text-white'
|
|
: 'bg-white/10 text-white/60 hover:bg-white/20 hover:text-white'
|
|
} ${isLoading ? 'opacity-50 cursor-wait' : ''} ${
|
|
permission === 'denied' ? 'opacity-30 cursor-not-allowed' : ''
|
|
}`}
|
|
title={getStatusText()}
|
|
>
|
|
{isLoading ? (
|
|
<div className="w-5 h-5 border-2 border-current border-t-transparent rounded-full animate-spin" />
|
|
) : (
|
|
getIcon()
|
|
)}
|
|
</button>
|
|
|
|
{/* Tooltip */}
|
|
{showTooltip && (
|
|
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-black/90 text-white text-xs rounded whitespace-nowrap z-50">
|
|
{getStatusText()}
|
|
<div className="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-black/90" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|