mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 04:11:12 -05:00
289 lines
10 KiB
TypeScript
289 lines
10 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { useForm } from 'react-hook-form';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Switch } from '@/components/ui/switch';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Separator } from '@/components/ui/separator';
|
|
import { useToast } from '@/hooks/use-toast';
|
|
import { useAuth } from '@/hooks/useAuth';
|
|
import { supabase } from '@/integrations/supabase/client';
|
|
import { Bell, Mail, Smartphone, Volume2 } from 'lucide-react';
|
|
interface EmailNotifications {
|
|
review_replies: boolean;
|
|
new_followers: boolean;
|
|
system_announcements: boolean;
|
|
weekly_digest: boolean;
|
|
monthly_digest: boolean;
|
|
}
|
|
interface PushNotifications {
|
|
browser_enabled: boolean;
|
|
new_content: boolean;
|
|
social_updates: boolean;
|
|
}
|
|
export function NotificationsTab() {
|
|
const {
|
|
user
|
|
} = useAuth();
|
|
const {
|
|
toast
|
|
} = useToast();
|
|
const [loading, setLoading] = useState(false);
|
|
const [emailNotifications, setEmailNotifications] = useState<EmailNotifications>({
|
|
review_replies: true,
|
|
new_followers: true,
|
|
system_announcements: true,
|
|
weekly_digest: false,
|
|
monthly_digest: true
|
|
});
|
|
const [pushNotifications, setPushNotifications] = useState<PushNotifications>({
|
|
browser_enabled: false,
|
|
new_content: true,
|
|
social_updates: true
|
|
});
|
|
useEffect(() => {
|
|
fetchNotificationPreferences();
|
|
}, [user]);
|
|
const fetchNotificationPreferences = async () => {
|
|
if (!user) return;
|
|
try {
|
|
const {
|
|
data,
|
|
error
|
|
} = await supabase.from('user_preferences').select('email_notifications, push_notifications').eq('user_id', user.id).maybeSingle();
|
|
if (error && error.code !== 'PGRST116') {
|
|
console.error('Error fetching notification preferences:', error);
|
|
return;
|
|
}
|
|
if (data) {
|
|
if (data.email_notifications) {
|
|
setEmailNotifications(data.email_notifications as unknown as EmailNotifications);
|
|
}
|
|
if (data.push_notifications) {
|
|
setPushNotifications(data.push_notifications as unknown as PushNotifications);
|
|
}
|
|
} else {
|
|
// Initialize preferences if they don't exist
|
|
await initializePreferences();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching notification preferences:', error);
|
|
}
|
|
};
|
|
const initializePreferences = async () => {
|
|
if (!user) return;
|
|
try {
|
|
const {
|
|
error
|
|
} = await supabase.from('user_preferences').insert([{
|
|
user_id: user.id,
|
|
email_notifications: emailNotifications as any,
|
|
push_notifications: pushNotifications as any
|
|
}]);
|
|
if (error) throw error;
|
|
} catch (error) {
|
|
console.error('Error initializing preferences:', error);
|
|
}
|
|
};
|
|
const updateEmailNotification = (key: keyof EmailNotifications, value: boolean) => {
|
|
setEmailNotifications(prev => ({
|
|
...prev,
|
|
[key]: value
|
|
}));
|
|
};
|
|
const updatePushNotification = (key: keyof PushNotifications, value: boolean) => {
|
|
setPushNotifications(prev => ({
|
|
...prev,
|
|
[key]: value
|
|
}));
|
|
};
|
|
const saveNotificationPreferences = async () => {
|
|
if (!user) return;
|
|
setLoading(true);
|
|
try {
|
|
const {
|
|
error
|
|
} = await supabase.from('user_preferences').upsert([{
|
|
user_id: user.id,
|
|
email_notifications: emailNotifications as any,
|
|
push_notifications: pushNotifications as any,
|
|
updated_at: new Date().toISOString()
|
|
}]);
|
|
if (error) throw error;
|
|
toast({
|
|
title: 'Preferences saved',
|
|
description: 'Your notification preferences have been updated.'
|
|
});
|
|
} catch (error: any) {
|
|
toast({
|
|
title: 'Error',
|
|
description: error.message || 'Failed to save notification preferences',
|
|
variant: 'destructive'
|
|
});
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
const requestPushPermission = async () => {
|
|
if ('Notification' in window) {
|
|
const permission = await Notification.requestPermission();
|
|
if (permission === 'granted') {
|
|
updatePushNotification('browser_enabled', true);
|
|
toast({
|
|
title: 'Push notifications enabled',
|
|
description: 'You will now receive browser push notifications.'
|
|
});
|
|
} else {
|
|
toast({
|
|
title: 'Permission denied',
|
|
description: 'Push notifications require permission to work.',
|
|
variant: 'destructive'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
return <div className="space-y-8">
|
|
{/* Email Notifications */}
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-2">
|
|
<Mail className="w-5 h-5" />
|
|
<h3 className="text-lg font-medium">Email Notifications</h3>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardDescription>
|
|
Choose which email notifications you'd like to receive.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>Review Replies</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Get notified when someone replies to your reviews
|
|
</p>
|
|
</div>
|
|
<Switch checked={emailNotifications.review_replies} onCheckedChange={checked => updateEmailNotification('review_replies', checked)} />
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>New Followers</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Get notified when someone follows you
|
|
</p>
|
|
</div>
|
|
<Switch checked={emailNotifications.new_followers} onCheckedChange={checked => updateEmailNotification('new_followers', checked)} />
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>System Announcements</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Important updates and announcements from ThrillWiki
|
|
</p>
|
|
</div>
|
|
<Switch checked={emailNotifications.system_announcements} onCheckedChange={checked => updateEmailNotification('system_announcements', checked)} />
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>Weekly Digest</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Weekly summary of new parks, rides, and community activity
|
|
</p>
|
|
</div>
|
|
<Switch checked={emailNotifications.weekly_digest} onCheckedChange={checked => updateEmailNotification('weekly_digest', checked)} />
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>Monthly Digest</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Monthly roundup of popular content and your activity stats
|
|
</p>
|
|
</div>
|
|
<Switch checked={emailNotifications.monthly_digest} onCheckedChange={checked => updateEmailNotification('monthly_digest', checked)} />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* Push Notifications */}
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-2">
|
|
<Smartphone className="w-5 h-5" />
|
|
<h3 className="text-lg font-medium">Push Notifications</h3>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardDescription>
|
|
Receive instant notifications in your browser when important events happen.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>Browser Notifications</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Enable push notifications in your browser
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
{!pushNotifications.browser_enabled && <Button variant="outline" size="sm" onClick={requestPushPermission}>
|
|
Enable
|
|
</Button>}
|
|
<Switch checked={pushNotifications.browser_enabled} onCheckedChange={checked => {
|
|
if (!checked) {
|
|
updatePushNotification('browser_enabled', false);
|
|
} else {
|
|
requestPushPermission();
|
|
}
|
|
}} />
|
|
</div>
|
|
</div>
|
|
|
|
{pushNotifications.browser_enabled && <>
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>New Content</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Notifications about new parks, rides, and reviews
|
|
</p>
|
|
</div>
|
|
<Switch checked={pushNotifications.new_content} onCheckedChange={checked => updatePushNotification('new_content', checked)} />
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label>Social Updates</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Notifications about followers, replies, and mentions
|
|
</p>
|
|
</div>
|
|
<Switch checked={pushNotifications.social_updates} onCheckedChange={checked => updatePushNotification('social_updates', checked)} />
|
|
</div>
|
|
</>}
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
|
|
|
|
{/* Sound Settings */}
|
|
|
|
|
|
{/* Save Button */}
|
|
<div className="flex justify-end">
|
|
<Button onClick={saveNotificationPreferences} disabled={loading}>
|
|
{loading ? 'Saving...' : 'Save Notification Preferences'}
|
|
</Button>
|
|
</div>
|
|
</div>;
|
|
} |