Add enhanced search/filtering and push notifications for prayer reminders
This commit is contained in:
1 parent
aa3f42479f
commit
1a160135d7
5 files changed
+294
-38
No files matched your search
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user