import React from "react"; import { FlatList, Pressable, View } from "react-native"; import { ActivityIndicator, Text } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; import { useNavigation } from "@react-navigation/native"; import { parseBibleReference } from "../utils/bibleReferences.js"; import GlobalState from "../contexts/GlobalState.js"; const BibleChapterView = ({ route }) => { const navigation = useNavigation(); const reference = route?.params?.reference || ""; const selectable = route?.params?.selectable === true; const { chapterReference, verse: selectedVerse } = parseBibleReference(reference); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(""); const [chapterData, setChapterData] = React.useState(null); const listRef = React.useRef(null); const autoScrolledRef = React.useRef(false); React.useEffect(() => { let mounted = true; const loadChapter = async () => { setLoading(true); setError(""); try { const response = await fetch(`https://bible-api.com/${encodeURIComponent(chapterReference)}`); if (!response.ok) throw new Error("Failed chapter request"); const payload = await response.json(); if (!mounted) return; setChapterData(payload); } catch (_error) { if (!mounted) return; setError("Unable to load chapter."); setChapterData(null); } finally { if (mounted) setLoading(false); } }; loadChapter(); return () => { mounted = false; }; }, [chapterReference]); const verses = Array.isArray(chapterData?.verses) ? chapterData.verses : []; const selectedVerseNumber = Number(selectedVerse || 1); const selectedIndex = verses.findIndex((item) => Number(item?.verse || 0) === selectedVerseNumber); React.useEffect(() => { autoScrolledRef.current = false; }, [chapterReference, selectedVerseNumber]); const scrollToSelectedVerse = React.useCallback((animated = false) => { if (autoScrolledRef.current) return; if (!listRef.current || selectedIndex < 0 || !verses.length) return; try { listRef.current.scrollToIndex({ index: selectedIndex, animated, viewPosition: 0.35, }); autoScrolledRef.current = true; } catch (_error) { // FlatList can throw before enough measurements are available. } }, [selectedIndex, verses.length]); if (loading) { return ( ); } if (error) { return ( {error} ); } const handleVersePress = (verseNumber) => { if (!selectable) return; GlobalState.bibleChapterSelection = { ...parseBibleReference(`${chapterReference}:${verseNumber}`), ts: Date.now(), }; navigation.goBack(); }; return ( {chapterData?.reference || chapterReference} {chapterData?.translation_name || chapterData?.translation_id || "KJV"} {selectable ? ( Tap a verse to select it. ) : null} `${item?.verse || idx}`} initialNumToRender={24} onLayout={() => { setTimeout(() => scrollToSelectedVerse(false), 40); }} onContentSizeChange={() => { setTimeout(() => scrollToSelectedVerse(false), 40); }} onScrollToIndexFailed={({ index, averageItemLength }) => { if (!listRef.current) return; listRef.current.scrollToOffset({ offset: Math.max(0, (averageItemLength || 36) * index), animated: false, }); setTimeout(() => { scrollToSelectedVerse(false); }, 120); }} renderItem={({ item }) => { const verseNumber = Number(item?.verse || 0); const isSelected = verseNumber === selectedVerseNumber; return ( handleVersePress(verseNumber)} style={{ paddingVertical: 8, paddingHorizontal: 10, borderRadius: 8, marginBottom: 6, backgroundColor: isSelected ? "#fff3cd" : "transparent", borderWidth: isSelected ? 1 : 0, borderColor: isSelected ? "#f59e0b" : "transparent", }} > {verseNumber} {item?.text || ""} ); }} /> ); }; export default BibleChapterView;