feat: add daily prayer reminder push notifications with time picker

This commit is contained in:
nmemmert committed 2026-01-16 10:07:45 -05:00
1 parent 49d1bdb47d
commit a3de1aaa1a
2 files changed
+129 -1

No files matched your search

+128
View File
@@ -18,6 +18,86 @@ export default function AboutPage({ userEmail }: AboutPageProps) {
const [deleteError, setDeleteError] = useState('');
const [verificationMessage, setVerificationMessage] = useState('');
const [sendingVerification, setSendingVerification] = useState(false);
const [notificationsEnabled, setNotificationsEnabled] = useState(false);
const [reminderTime, setReminderTime] = useState('09:00');
const [notificationPermission, setNotificationPermission] = useState<NotificationPermission>('default');
React.useEffect(() => {
// Check current notification permission
if ('Notification' in window) {
setNotificationPermission(Notification.permission);
}
// Load saved settings
const savedEnabled = localStorage.getItem('prayerRemindersEnabled') === 'true';
const savedTime = localStorage.getItem('prayerReminderTime') || '09:00';
setNotificationsEnabled(savedEnabled);
setReminderTime(savedTime);
}, []);
const requestNotificationPermission = async () => {
if ('Notification' in window) {
const permission = await Notification.requestPermission();
setNotificationPermission(permission);
if (permission === 'granted') {
setNotificationsEnabled(true);
localStorage.setItem('prayerRemindersEnabled', 'true');
scheduleNotification();
}
}
};
const toggleNotifications = async () => {
if (!notificationsEnabled && notificationPermission !== 'granted') {
await requestNotificationPermission();
} else {
setNotificationsEnabled(!notificationsEnabled);
localStorage.setItem('prayerRemindersEnabled', String(!notificationsEnabled));
if (!notificationsEnabled) {
scheduleNotification();
}
}
};
const handleTimeChange = (newTime: string) => {
setReminderTime(newTime);
localStorage.setItem('prayerReminderTime', newTime);
if (notificationsEnabled) {
scheduleNotification();
}
};
const scheduleNotification = () => {
if ('serviceWorker' in navigator && notificationsEnabled) {
// Calculate time until next reminder
const [hours, minutes] = reminderTime.split(':').map(Number);
const now = new Date();
const scheduledTime = new Date();
scheduledTime.setHours(hours, minutes, 0, 0);
// If time has passed today, schedule for tomorrow
if (scheduledTime <= now) {
scheduledTime.setDate(scheduledTime.getDate() + 1);
}
const timeUntilNotification = scheduledTime.getTime() - now.getTime();
// Schedule notification
setTimeout(() => {
if (Notification.permission === 'granted') {
new Notification('🙏 Time to Pray', {
body: 'Take a moment to connect with God and pray.',
icon: '/icon-192x192.png',
badge: '/icon-192x192.png',
tag: 'prayer-reminder',
requireInteraction: false,
});
// Reschedule for next day
setTimeout(scheduleNotification, 24 * 60 * 60 * 1000);
}
}, timeUntilNotification);
}
};
return (
<div className="min-h-screen bg-gradient-to-b from-slate-900 to-slate-800 p-4 pb-32 pt-8">
@@ -108,6 +188,54 @@ export default function AboutPage({ userEmail }: AboutPageProps) {
</div>
</div>
{/* Prayer Reminders Section */}
<div className="border-b border-slate-700 pb-6">
<h2 className="text-lg font-semibold text-white mb-4">Prayer Reminders</h2>
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-300">Daily Reminders</p>
<p className="text-xs text-slate-400">Get notified to pray each day</p>
</div>
<button
onClick={toggleNotifications}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
notificationsEnabled ? 'bg-blue-600' : 'bg-slate-600'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
notificationsEnabled ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
{notificationPermission === 'denied' && (
<div className="bg-red-900 border border-red-700 text-red-200 px-3 py-2 rounded-lg text-xs">
Notifications are blocked. Please enable them in your browser settings.
</div>
)}
{notificationsEnabled && (
<div>
<label className="block text-sm font-medium text-slate-300 mb-2">
Reminder Time
</label>
<input
type="time"
value={reminderTime}
onChange={(e) => handleTimeChange(e.target.value)}
className="w-full p-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
<p className="text-xs text-slate-400 mt-2">
You'll receive a notification at {reminderTime} each day
</p>
</div>
)}
</div>
</div>
{/* App Info Section */}
<div className="border-b border-slate-700 pb-6">
<h2 className="text-lg font-semibold text-white mb-4">App Info</h2>