Add enhanced search/filtering and push notifications for prayer reminders

This commit is contained in:
nmemmert committed 2025-11-03 08:04:19 -05:00
1 parent aa3f42479f
commit 1a160135d7
5 files changed
+294 -38

No files matched your search

+84 -1
View File
@@ -2,7 +2,7 @@
import { useState, useEffect, useCallback } from 'react';
import { useAuth } from '@/context/AuthContext';
import { storage, db } from '@/lib/firebase';
import { storage, db, requestNotificationPermission, onMessageListener } from '@/lib/firebase';
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { doc, getDoc, updateDoc } from 'firebase/firestore';
import { useTheme } from 'next-themes';
@@ -12,6 +12,8 @@ interface UserProfile {
avatarUrl?: string;
theme?: string;
categories?: string[];
notificationsEnabled?: boolean;
fcmToken?: string;
}
export default function Profile() {
@@ -20,6 +22,7 @@ export default function Profile() {
const [profile, setProfile] = useState<UserProfile>({});
const [uploading, setUploading] = useState(false);
const [newCategory, setNewCategory] = useState('');
const [notificationsEnabled, setNotificationsEnabled] = useState(false);
const loadProfile = useCallback(async () => {
if (!user) return;
@@ -28,6 +31,7 @@ export default function Profile() {
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
setProfile(docSnap.data() as UserProfile);
setNotificationsEnabled(docSnap.data().notificationsEnabled);
}
} catch (error) {
console.error('Error loading profile:', error);
@@ -40,6 +44,27 @@ export default function Profile() {
}
}, [user, loadProfile]);
// Load notification settings
useEffect(() => {
if (profile.notificationsEnabled !== undefined) {
setNotificationsEnabled(profile.notificationsEnabled);
}
}, [profile.notificationsEnabled]);
// Listen for FCM messages
useEffect(() => {
if (notificationsEnabled) {
onMessageListener().then((payload: any) => {
console.log('Message received:', payload);
// Handle incoming messages (e.g., show notification)
new Notification(payload.notification.title, {
body: payload.notification.body,
icon: '/icon-192x192.png'
});
}).catch(err => console.log('Failed to listen for messages:', err));
}
}, [notificationsEnabled]);
const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file || !user) return;
@@ -66,6 +91,35 @@ export default function Profile() {
}
};
const handleNotificationToggle = async (enabled: boolean) => {
if (!user) return;
try {
if (enabled) {
const token = await requestNotificationPermission();
if (token) {
await updateDoc(doc(db, 'users', user.uid), {
notificationsEnabled: true,
fcmToken: token
});
setProfile(prev => ({ ...prev, notificationsEnabled: true, fcmToken: token }));
setNotificationsEnabled(true);
} else {
alert('Notification permission denied. Please enable notifications in your browser settings.');
}
} else {
await updateDoc(doc(db, 'users', user.uid), {
notificationsEnabled: false,
fcmToken: null
});
setProfile(prev => ({ ...prev, notificationsEnabled: false, fcmToken: undefined }));
setNotificationsEnabled(false);
}
} catch (error) {
console.error('Error updating notification settings:', error);
}
};
const addCategory = async () => {
if (!newCategory.trim() || !user) return;
const updatedCategories = [...(profile.categories || []), newCategory.trim()];
@@ -81,6 +135,16 @@ export default function Profile() {
setProfile(prev => ({ ...prev, categories: updatedCategories }));
};
const toggleNotifications = async () => {
if (!user) return;
const newStatus = !notificationsEnabled;
setNotificationsEnabled(newStatus);
await updateDoc(doc(db, 'users', user.uid), { notificationsEnabled: newStatus });
if (newStatus) {
requestNotificationPermission();
}
};
return (
<div className="max-w-md mx-auto mb-8 p-6 bg-gray-800 rounded-lg">
<h2 className="text-2xl font-bold mb-6">Profile</h2>
@@ -115,6 +179,25 @@ export default function Profile() {
</select>
</div>
{/* Notifications */}
<div className="mb-6">
<label className="block mb-2 text-lg">Notifications</label>
<div className="flex items-center mb-4">
<input
type="checkbox"
checked={notificationsEnabled}
onChange={(e) => handleNotificationToggle(e.target.checked)}
className="w-6 h-6 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
/>
<label className="ml-3 text-base font-medium">
Enable push notifications for prayer reminders
</label>
</div>
<p className="text-sm text-gray-400">
Get notified about your prayer schedule and when prayers are answered.
</p>
</div>
{/* Categories */}
<div className="mb-6">
<label className="block mb-2 text-lg">Prayer Categories</label>