import dayjs, { Dayjs } from 'dayjs'; import React, { useEffect, useState, useRef } from 'react'; import { View, Text, FlatList, StyleSheet, Alert } from 'react-native'; import * as Location from 'expo-location'; import * as Notifications from 'expo-notifications'; type PrayerTime = { name: string; time: string; }; type PrayerTimeDate = { name: string; time: Dayjs; }; type PrayerData = { location: string; date: string; times: PrayerTime[]; timesAsDates: PrayerTimeDate[]; sunriseTime: string; hanafiAsr: string; }; export default function PrayersScreen() { const [prayerData, setPrayerData] = useState(null); const [nextPrayer, setNextPrayer] = useState<{ name: string; countdown: string } | null>(null); const intervalRef = useRef(null); const getCoords = async () => { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== 'granted') { throw new Error('Permission to access location was denied'); } const location = await Location.getCurrentPositionAsync({}); return location.coords; }; const fetchPrayerTimes = async () => { try { const coords = await getCoords(); const today = dayjs(); const yyyy = today.year(); const mm = String(today.month() + 1).padStart(2, '0'); // month() is 0-based const dd = String(today.date()).padStart(2, '0'); const formattedDate = `${yyyy}-${mm}-${dd}`; const res = await fetch( `https://api.aladhan.com/v1/timings/${formattedDate}?latitude=${coords.latitude}&longitude=${coords.longitude}&method=2`); const hanafiRes = await fetch( `https://api.aladhan.com/v1/timings/${formattedDate}?latitude=${coords.latitude}&longitude=${coords.longitude}&method=2&school=1`); const data = await res.json(); const hanafiData = await hanafiRes.json(); const hanafiTiming = hanafiData.data.timings.Asr; const timings = data.data.timings; const formattedTimes = [ { name: 'Fajr', time: timings.Fajr }, { name: 'Dhuhr', time: timings.Dhuhr }, { name: 'Asr', time: timings.Asr }, { name: 'Maghrib', time: timings.Maghrib }, { name: 'Isha', time: timings.Isha }, ]; setPrayerData({ location: data.data.meta.timezone, date: `${data.data.date.gregorian.date} / ${data.data.date.hijri.date}`, times: formattedTimes, timesAsDates: getPrayerDateTimes(formattedTimes), sunriseTime: timings.Sunrise, hanafiAsr: hanafiTiming }); } catch (err) { console.error('Error fetching prayer times:', err); Alert.alert('Error', 'Failed to fetch prayer times.'); } }; // Helper: convert prayer times into Date objects for today const getPrayerDateTimes = (times: PrayerTime[]) => { const now = dayjs(); return times.map(({ name, time }) => { const [hours, minutes] = time.split(':').map(Number); // Create a Dayjs object for today with set hours and minutes const prayerTime = now.hour(hours).minute(minutes).second(0).millisecond(0); return { name, time: prayerTime }; }); }; const schedulePrayerNotification = async (prayerName: string, prayerTime: dayjs.Dayjs) => { const triggerTime = prayerTime.subtract(10, 'minute'); await Notifications.scheduleNotificationAsync({ content: { title: `Upcoming Prayer: ${prayerName}`, body: `Time for ${prayerName} is in 10 minutes.`, sound: true, }, trigger: { type: 'date', date: triggerTime.toDate(), } as Notifications.DateTriggerInput, }); }; const isCurrentPrayer = (prayerTimes: PrayerData, prayerName: string): boolean => { const times = prayerTimes.timesAsDates; const now = dayjs(); // Sort times just in case times.sort((a, b) => a.time.valueOf() - b.time.valueOf()); for (let i = times.length - 1; i >= 0; i--) { if (now.isAfter(times[i].time) || now.isSame(times[i].time)) { // Check if the current prayer matches the prayerName return times[i].name === prayerName; } } // If none matched, compare to last prayer (optional fallback) return times.length > 0 ? times[times.length - 1].name === prayerName : false; }; // Find the next prayer based on current time const findNextPrayer = (prayerTimes: PrayerTimeDate[]) => { const now = dayjs(); // Find next prayer with time > now const next = prayerTimes.find((p) => dayjs(p.time).isAfter(now)); if (next) { return next; } // If none found, all prayers passed — fallback to first prayer tomorrow (Fajr) // So add 1 day to first prayer time const tomorrowFajr = prayerTimes[0].time.add(1, 'day'); return { name: prayerTimes[0].name, time: tomorrowFajr }; }; // Update countdown every second const startCountdown = (prayerTimes: PrayerTimeDate[]) => { if (intervalRef.current) clearInterval(intervalRef.current); intervalRef.current = setInterval(() => { const now = dayjs(); const next = findNextPrayer(prayerTimes); const diff = next.time.diff(now); // If countdown hits zero or negative, just continue to next prayer immediately const safeDiff = diff > 0 ? diff : 0; const hrs = String(Math.floor(safeDiff / (1000 * 60 * 60))).padStart(2, '0'); const mins = String(Math.floor((safeDiff / (1000 * 60)) % 60)).padStart(2, '0'); const secs = String(Math.floor((safeDiff / 1000) % 60)).padStart(2, '0'); setNextPrayer({ name: next.name, countdown: `${hrs}:${mins}:${secs}`, }); }, 1000) as any; }; // Initial fetch useEffect(() => { fetchPrayerTimes(); }, []); // Start countdown when prayerData changes useEffect(() => { if (prayerData?.times) { startCountdown(prayerData.timesAsDates); const now = dayjs(); // Only schedule notifications for prayers that haven't passed yet prayerData.timesAsDates .filter(prayer => prayer.time.isAfter(now)) .forEach(prayer => { schedulePrayerNotification(prayer.name, prayer.time); }); } return () => { if (intervalRef.current) clearInterval(intervalRef.current); }; }, [prayerData]); return ( Today's Prayer Times {prayerData && ( <> {prayerData.date} )} {nextPrayer ? ( Next prayer: {nextPrayer.name} in {nextPrayer.countdown} ) : ( Calculating next prayer... )} {prayerData ? ( item.name} renderItem={({ item }) => { const isCurrent = isCurrentPrayer(prayerData, item.name); return ( {item.name} {item.time} {/* Fajr Sunrise */} {item.name === 'Fajr' && prayerData.sunriseTime && ( Sunrise {prayerData.sunriseTime} )} {/* Asr (Hanafi) */} {item.name === 'Asr' && prayerData.hanafiAsr && ( Asr (Hanafi) {prayerData.hanafiAsr} )} ); }} contentContainerStyle={{ paddingVertical: 10 }} /> ) : ( Loading... )} ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#FFEEE7' }, title: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', color: '#333', marginBottom: 6, // reduce space below title }, sunriseRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 4, }, subtitle: { textAlign: 'center', fontSize: 14, color: '#555', }, date: { textAlign: 'center', fontSize: 14, color: '#888', marginBottom: 2, // keep this small }, nextPrayer: { textAlign: 'center', fontSize: 16, color: '#008060', marginTop: 4, // reduce gap above next prayer marginBottom: 10, fontWeight: '600', }, card: { padding: 15, borderWidth: 1, borderColor: '#ddd', borderRadius: 8, marginBottom: 12, backgroundColor: '#fff', // changed to white }, currentPrayerCard: { backgroundColor: '#fff', // keep current prayer tab white too borderColor: '#4CAF50', borderWidth: 2, }, specialPrayerName: { color: '#00796b', // Teal }, specialPrayerTime: { fontWeight: 'bold', }, prayerName: { fontSize: 16, fontWeight: '600' }, prayerTime: { fontSize: 16 }, });