UI: Final surgical fix for iPhone XR - 480p Baseline 3.0, CSS filter removal, and structure repair
This commit is contained in:
parent
c3f9a4fc9a
commit
5f87c79b58
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
@ -291,19 +291,19 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
|||||||
onLoadedData={() => setIsVideoLoaded(true)}
|
onLoadedData={() => setIsVideoLoaded(true)}
|
||||||
onPlay={() => setIsVideoPlaying(true)}
|
onPlay={() => setIsVideoPlaying(true)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute inset-0 w-full h-full object-cover scale-110 brightness-[1.1] dark:brightness-[0.85] transition-all duration-[2000ms] ease-in-out",
|
"absolute inset-0 w-full h-full object-cover scale-110 transition-opacity duration-[1500ms] ease-in-out",
|
||||||
isVideoPlaying
|
isVideoPlaying
|
||||||
? "opacity-70 dark:opacity-50 blur-0"
|
? "opacity-70 dark:opacity-50"
|
||||||
: isVideoLoaded
|
: isVideoLoaded
|
||||||
? "opacity-30 blur-[4px]"
|
? "opacity-30"
|
||||||
: "opacity-10 blur-sm"
|
: "opacity-10"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<source src="/videos/smoke.mp4" type="video/mp4" />
|
<source src="/videos/smoke.mp4" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
{/* Vignette/Readability Overlay */}
|
{/* Vignette/Readability Overlay - Reinforced for contrast */}
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-black/10 via-transparent to-black/30 dark:from-black/40 dark:via-transparent dark:to-black/50" />
|
<div className="absolute inset-0 bg-gradient-to-b from-black/30 via-transparent to-black/50 dark:from-black/60 dark:via-transparent dark:to-black/70 mix-blend-multiply" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="container mx-auto px-4 h-16 sm:h-20 flex items-center justify-between relative z-50">
|
<div className="container mx-auto px-4 h-16 sm:h-20 flex items-center justify-between relative z-50">
|
||||||
@ -381,226 +381,226 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
{/* Side Menu Integration */}
|
{/* Side Menu Integration */}
|
||||||
<SideMenu
|
<SideMenu
|
||||||
isOpen={isSideMenuOpen}
|
isOpen={isSideMenuOpen}
|
||||||
onClose={() => setIsSideMenuOpen(false)}
|
onClose={() => setIsSideMenuOpen(false)}
|
||||||
user={user}
|
user={user}
|
||||||
userName={userName}
|
userName={userName}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Reminder Settings Dialog */}
|
{/* Reminder Settings Dialog */}
|
||||||
<Dialog open={showReminderDialog} onOpenChange={setShowReminderDialog}>
|
<Dialog open={showReminderDialog} onOpenChange={setShowReminderDialog}>
|
||||||
<DialogContent className="sm:max-w-md">
|
<DialogContent className="sm:max-w-md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center gap-2 font-bold tracking-tight">
|
<DialogTitle className="flex items-center gap-2 font-bold tracking-tight">
|
||||||
<Bell className="h-5 w-5 text-indigo-400" />
|
<Bell className="h-5 w-5 text-indigo-400" />
|
||||||
Notification Settings
|
Notification Settings
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="space-y-4 py-4 px-1">
|
<div className="space-y-4 py-4 px-1">
|
||||||
{/* Enable/Disable Toggle */}
|
{/* Enable/Disable Toggle */}
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
"flex items-center justify-between p-4 rounded-2xl border transition-all",
|
"flex items-center justify-between p-4 rounded-2xl border transition-all",
|
||||||
theme === 'light' ? "bg-slate-50 border-slate-100" : "bg-white/5 border-white/5"
|
theme === 'light' ? "bg-slate-50 border-slate-100" : "bg-white/5 border-white/5"
|
||||||
)}>
|
)}>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
"p-2.5 rounded-xl",
|
"p-2.5 rounded-xl",
|
||||||
reminderSettings.enabled ? "bg-indigo-500/20 text-indigo-400" : "bg-slate-500/20 text-slate-400"
|
reminderSettings.enabled ? "bg-indigo-500/20 text-indigo-400" : "bg-slate-500/20 text-slate-400"
|
||||||
)}>
|
)}>
|
||||||
{reminderSettings.enabled ? <BellRing className="h-5 w-5" /> : <BellOff className="h-5 w-5" />}
|
{reminderSettings.enabled ? <BellRing className="h-5 w-5" /> : <BellOff className="h-5 w-5" />}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-sm font-bold">
|
<span className="text-sm font-bold">
|
||||||
{reminderSettings.enabled ? 'Enabled' : 'Disabled'}
|
{reminderSettings.enabled ? 'Enabled' : 'Disabled'}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[10px] opacity-60">
|
<span className="text-[10px] opacity-60">
|
||||||
{reminderSettings.enabled ? 'Reminders active' : 'Turn on to get alerts'}
|
{reminderSettings.enabled ? 'Reminders active' : 'Turn on to get alerts'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
|
||||||
onClick={handleToggleReminders}
|
|
||||||
disabled={!isSupported || (permission === 'denied' && !reminderSettings.enabled)}
|
|
||||||
className={cn(
|
|
||||||
"relative w-12 h-6 rounded-full transition-all duration-300 shadow-inner",
|
|
||||||
reminderSettings.enabled ? "bg-indigo-500" : "bg-slate-400/30",
|
|
||||||
(!isSupported || (permission === 'denied' && !reminderSettings.enabled)) && "opacity-50 cursor-not-allowed"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className={cn(
|
|
||||||
"absolute top-1 w-4 h-4 rounded-full bg-white shadow-md transition-all duration-300",
|
|
||||||
reminderSettings.enabled ? "left-7" : "left-1"
|
|
||||||
)} />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={handleToggleReminders}
|
||||||
|
disabled={!isSupported || (permission === 'denied' && !reminderSettings.enabled)}
|
||||||
|
className={cn(
|
||||||
|
"relative w-12 h-6 rounded-full transition-all duration-300 shadow-inner",
|
||||||
|
reminderSettings.enabled ? "bg-indigo-500" : "bg-slate-400/30",
|
||||||
|
(!isSupported || (permission === 'denied' && !reminderSettings.enabled)) && "opacity-50 cursor-not-allowed"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={cn(
|
||||||
|
"absolute top-1 w-4 h-4 rounded-full bg-white shadow-md transition-all duration-300",
|
||||||
|
reminderSettings.enabled ? "left-7" : "left-1"
|
||||||
|
)} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Frequency Selection */}
|
{/* Frequency Selection */}
|
||||||
{reminderSettings.enabled && (
|
{reminderSettings.enabled && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Reminder Frequency</div>
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Reminder Frequency</div>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleFrequencyChange('daily')}
|
onClick={() => handleFrequencyChange('daily')}
|
||||||
className={cn(
|
|
||||||
"p-4 rounded-2xl border text-sm font-bold transition-all flex flex-col items-center gap-1",
|
|
||||||
localFrequency === 'daily'
|
|
||||||
? 'bg-indigo-500 border-indigo-500 text-white shadow-lg shadow-indigo-500/25 scale-[1.02]'
|
|
||||||
: 'bg-background border-border hover:border-indigo-500/50'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span>Daily</span>
|
|
||||||
<span className="text-[10px] font-normal opacity-70">Once a day</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => handleFrequencyChange('hourly')}
|
|
||||||
className={cn(
|
|
||||||
"p-4 rounded-2xl border text-sm font-bold transition-all flex flex-col items-center gap-1",
|
|
||||||
localFrequency === 'hourly'
|
|
||||||
? 'bg-indigo-500 border-indigo-500 text-white shadow-lg shadow-indigo-500/25 scale-[1.02]'
|
|
||||||
: 'bg-background border-border hover:border-indigo-500/50'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span>Hourly</span>
|
|
||||||
<span className="text-[10px] font-normal opacity-70">Window alerts</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Time Picker (Only for Daily) */}
|
|
||||||
{reminderSettings.enabled && localFrequency === 'daily' && (
|
|
||||||
<div className="space-y-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
|
||||||
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Preferred Time</div>
|
|
||||||
<div className="flex gap-2 p-1 bg-muted/30 rounded-2xl border border-border/50">
|
|
||||||
<div className="flex-1">
|
|
||||||
<Select
|
|
||||||
value={hourString}
|
|
||||||
onValueChange={(val) => updateTime(val, minuteString, currentAmpm)}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="border-none bg-transparent shadow-none hover:bg-white/5 h-12 rounded-xl">
|
|
||||||
<SelectValue placeholder="Hour" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent className="rounded-xl">
|
|
||||||
{hoursOptions.map((h) => (
|
|
||||||
<SelectItem key={h} value={h} className="rounded-lg">{h}</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-1">
|
|
||||||
<Select
|
|
||||||
value={minuteString}
|
|
||||||
onValueChange={(val) => updateTime(hourString, val, currentAmpm)}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="border-none bg-transparent shadow-none hover:bg-white/5 h-12 rounded-xl">
|
|
||||||
<SelectValue placeholder="Min" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent className="rounded-xl">
|
|
||||||
{minutesOptions.map((m) => (
|
|
||||||
<SelectItem key={m} value={m} className="rounded-lg">{m}</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-24 px-1">
|
|
||||||
<Select
|
|
||||||
value={currentAmpm}
|
|
||||||
onValueChange={(val) => updateTime(hourString, minuteString, val)}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="border-none bg-indigo-500/10 text-indigo-400 font-bold shadow-none hover:bg-indigo-500/20 h-10 mt-1 rounded-lg">
|
|
||||||
<SelectValue placeholder="AM/PM" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent className="rounded-xl">
|
|
||||||
<SelectItem value="AM" className="rounded-lg">AM</SelectItem>
|
|
||||||
<SelectItem value="PM" className="rounded-lg">PM</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Hourly Alerts Window */}
|
|
||||||
{reminderSettings.enabled && localFrequency === 'hourly' && (
|
|
||||||
<div className="space-y-4 animate-in fade-in slide-in-from-top-2 duration-300">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Start Time</div>
|
|
||||||
<HourlyTimePicker
|
|
||||||
value={reminderSettings.hourlyStart || '09:00'}
|
|
||||||
onChange={async (newTime) => {
|
|
||||||
const [h, m] = newTime.split(':');
|
|
||||||
const end = (reminderSettings.hourlyEnd || '21:00').split(':');
|
|
||||||
const newSettings = { ...reminderSettings, hourlyStart: newTime, hourlyEnd: `${end[0]}:${m}` };
|
|
||||||
setReminderSettings(newSettings);
|
|
||||||
await saveReminderSettings(newSettings);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
|
||||||
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">End Time</div>
|
|
||||||
<HourlyTimePicker
|
|
||||||
value={reminderSettings.hourlyEnd || '21:00'}
|
|
||||||
onChange={async (newTime) => {
|
|
||||||
const [h, m] = newTime.split(':');
|
|
||||||
const start = (reminderSettings.hourlyStart || '09:00').split(':');
|
|
||||||
const newSettings = { ...reminderSettings, hourlyEnd: newTime, hourlyStart: `${start[0]}:${m}` };
|
|
||||||
setReminderSettings(newSettings);
|
|
||||||
await saveReminderSettings(newSettings);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-2 p-3 bg-indigo-500/5 rounded-2xl border border-indigo-500/10">
|
|
||||||
<Sparkles className="h-4 w-4 text-indigo-400" />
|
|
||||||
<p className="text-[10px] text-indigo-400 uppercase font-black tracking-widest">Reminders every 60 minutes</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Notification Permission Sync */}
|
|
||||||
{reminderSettings.enabled && isSupported && (
|
|
||||||
<div className="pt-2">
|
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
const result = await requestPermission();
|
|
||||||
if (result === 'granted') {
|
|
||||||
try {
|
|
||||||
const res = await fetch('/api/notifications/test', { method: 'POST' });
|
|
||||||
if (res.ok) alert("Success! Push notifications active.");
|
|
||||||
} catch (err) { console.error(err); }
|
|
||||||
} else alert("Please enable notifications in settings.");
|
|
||||||
}}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full h-12 rounded-2xl font-bold transition-all shadow-md group",
|
"p-4 rounded-2xl border text-sm font-bold transition-all flex flex-col items-center gap-1",
|
||||||
permission === 'granted'
|
localFrequency === 'daily'
|
||||||
? 'bg-emerald-500/10 text-emerald-500 hover:bg-emerald-500/20'
|
? 'bg-indigo-500 border-indigo-500 text-white shadow-lg shadow-indigo-500/25 scale-[1.02]'
|
||||||
: 'bg-emerald-600 text-white hover:bg-emerald-500 hover:scale-[1.02]'
|
: 'bg-background border-border hover:border-indigo-500/50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Bell className="mr-2 h-4 w-4 group-hover:animate-bounce" />
|
<span>Daily</span>
|
||||||
{permission === 'granted' ? 'Permissions Verified' : 'Enable Push Alerts'}
|
<span className="text-[10px] font-normal opacity-70">Once a day</span>
|
||||||
</Button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleFrequencyChange('hourly')}
|
||||||
|
className={cn(
|
||||||
|
"p-4 rounded-2xl border text-sm font-bold transition-all flex flex-col items-center gap-1",
|
||||||
|
localFrequency === 'hourly'
|
||||||
|
? 'bg-indigo-500 border-indigo-500 text-white shadow-lg shadow-indigo-500/25 scale-[1.02]'
|
||||||
|
: 'bg-background border-border hover:border-indigo-500/50'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span>Hourly</span>
|
||||||
|
<span className="text-[10px] font-normal opacity-70">Window alerts</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{permission === 'denied' && (
|
{/* Time Picker (Only for Daily) */}
|
||||||
<div className="p-4 bg-red-500/10 border border-red-500/20 rounded-2xl">
|
{reminderSettings.enabled && localFrequency === 'daily' && (
|
||||||
<p className="text-xs text-red-500 text-center font-medium leading-relaxed">
|
<div className="space-y-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
Browser notifications are currently blocked. To get reminders, please update your site settings.
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Preferred Time</div>
|
||||||
</p>
|
<div className="flex gap-2 p-1 bg-muted/30 rounded-2xl border border-border/50">
|
||||||
|
<div className="flex-1">
|
||||||
|
<Select
|
||||||
|
value={hourString}
|
||||||
|
onValueChange={(val) => updateTime(val, minuteString, currentAmpm)}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="border-none bg-transparent shadow-none hover:bg-white/5 h-12 rounded-xl">
|
||||||
|
<SelectValue placeholder="Hour" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="rounded-xl">
|
||||||
|
{hoursOptions.map((h) => (
|
||||||
|
<SelectItem key={h} value={h} className="rounded-lg">{h}</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1">
|
||||||
|
<Select
|
||||||
|
value={minuteString}
|
||||||
|
onValueChange={(val) => updateTime(hourString, val, currentAmpm)}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="border-none bg-transparent shadow-none hover:bg-white/5 h-12 rounded-xl">
|
||||||
|
<SelectValue placeholder="Min" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="rounded-xl">
|
||||||
|
{minutesOptions.map((m) => (
|
||||||
|
<SelectItem key={m} value={m} className="rounded-lg">{m}</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-24 px-1">
|
||||||
|
<Select
|
||||||
|
value={currentAmpm}
|
||||||
|
onValueChange={(val) => updateTime(hourString, minuteString, val)}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="border-none bg-indigo-500/10 text-indigo-400 font-bold shadow-none hover:bg-indigo-500/20 h-10 mt-1 rounded-lg">
|
||||||
|
<SelectValue placeholder="AM/PM" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="rounded-xl">
|
||||||
|
<SelectItem value="AM" className="rounded-lg">AM</SelectItem>
|
||||||
|
<SelectItem value="PM" className="rounded-lg">PM</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
{/* Hourly Alerts Window */}
|
||||||
</header>
|
{reminderSettings.enabled && localFrequency === 'hourly' && (
|
||||||
|
<div className="space-y-4 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Start Time</div>
|
||||||
|
<HourlyTimePicker
|
||||||
|
value={reminderSettings.hourlyStart || '09:00'}
|
||||||
|
onChange={async (newTime) => {
|
||||||
|
const [h, m] = newTime.split(':');
|
||||||
|
const end = (reminderSettings.hourlyEnd || '21:00').split(':');
|
||||||
|
const newSettings = { ...reminderSettings, hourlyStart: newTime, hourlyEnd: `${end[0]}:${m}` };
|
||||||
|
setReminderSettings(newSettings);
|
||||||
|
await saveReminderSettings(newSettings);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">End Time</div>
|
||||||
|
<HourlyTimePicker
|
||||||
|
value={reminderSettings.hourlyEnd || '21:00'}
|
||||||
|
onChange={async (newTime) => {
|
||||||
|
const [h, m] = newTime.split(':');
|
||||||
|
const start = (reminderSettings.hourlyStart || '09:00').split(':');
|
||||||
|
const newSettings = { ...reminderSettings, hourlyEnd: newTime, hourlyStart: `${start[0]}:${m}` };
|
||||||
|
setReminderSettings(newSettings);
|
||||||
|
await saveReminderSettings(newSettings);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 p-3 bg-indigo-500/5 rounded-2xl border border-indigo-500/10">
|
||||||
|
<Sparkles className="h-4 w-4 text-indigo-400" />
|
||||||
|
<p className="text-[10px] text-indigo-400 uppercase font-black tracking-widest">Reminders every 60 minutes</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Notification Permission Sync */}
|
||||||
|
{reminderSettings.enabled && isSupported && (
|
||||||
|
<div className="pt-2">
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
const result = await requestPermission();
|
||||||
|
if (result === 'granted') {
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/notifications/test', { method: 'POST' });
|
||||||
|
if (res.ok) alert("Success! Push notifications active.");
|
||||||
|
} catch (err) { console.error(err); }
|
||||||
|
} else alert("Please enable notifications in settings.");
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"w-full h-12 rounded-2xl font-bold transition-all shadow-md group",
|
||||||
|
permission === 'granted'
|
||||||
|
? 'bg-emerald-500/10 text-emerald-500 hover:bg-emerald-500/20'
|
||||||
|
: 'bg-emerald-600 text-white hover:bg-emerald-500 hover:scale-[1.02]'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Bell className="mr-2 h-4 w-4 group-hover:animate-bounce" />
|
||||||
|
{permission === 'granted' ? 'Permissions Verified' : 'Enable Push Alerts'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{permission === 'denied' && (
|
||||||
|
<div className="p-4 bg-red-500/10 border border-red-500/20 rounded-2xl">
|
||||||
|
<p className="text-xs text-red-500 text-center font-medium leading-relaxed">
|
||||||
|
Browser notifications are currently blocked. To get reminders, please update your site settings.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user