Add Bible picker flow and chapter navigation UI

This commit is contained in:
Adolfo Reyna
2026-02-24 15:56:48 -05:00
parent ba28289783
commit ccfeed3c92
9 changed files with 865 additions and 12 deletions

229
utils/bibleReferences.js Normal file
View File

@@ -0,0 +1,229 @@
const BIBLE_TOKEN_REGEX = /@bible:([^\s]+)/gi;
const normalizeReference = (value = "") => {
try {
return decodeURIComponent(String(value || ""))
.replace(/_/g, " ")
.replace(/\s+/g, " ")
.trim();
} catch (_error) {
return String(value || "").replace(/_/g, " ").replace(/\s+/g, " ").trim();
}
};
export const encodeBibleReference = (reference = "") => {
return String(reference || "").replace(/\s+/g, "_").trim();
};
export const createBibleToken = (reference = "") => {
const encoded = encodeBibleReference(reference);
if (!encoded) return "";
return `@bible:${encoded}`;
};
export const extractBibleReferences = (content = "") => {
const seen = new Set();
const refs = [];
if (!content || typeof content !== "string") return refs;
let match;
while ((match = BIBLE_TOKEN_REGEX.exec(content)) !== null) {
const normalized = normalizeReference(match[1]);
if (!normalized || seen.has(normalized)) continue;
seen.add(normalized);
refs.push(normalized);
}
return refs;
};
export const stripBibleTokens = (content = "") => {
if (!content || typeof content !== "string") return "";
return content
.replace(BIBLE_TOKEN_REGEX, "")
.replace(/[ \t]{2,}/g, " ")
.replace(/[ \t]+\n/g, "\n")
.trim();
};
export const fetchBiblePassage = async (reference = "") => {
const safeReference = normalizeReference(reference);
if (!safeReference) {
throw new Error("Missing Bible reference");
}
const response = await fetch(`https://bible-api.com/${encodeURIComponent(safeReference)}`);
if (!response.ok) {
throw new Error("Failed to load Bible passage");
}
const payload = await response.json();
return {
reference: payload?.reference || safeReference,
text: (payload?.text || "").trim(),
translation: payload?.translation_name || payload?.translation_id || "KJV",
};
};
export const parseBibleReference = (reference = "") => {
const normalized = normalizeReference(reference);
const match = normalized.match(/^(.*)\s+(\d+)(?::(\d+)(?:-\d+)?)?$/);
if (!match) {
return {
reference: normalized,
book: normalized,
chapter: 1,
verse: 1,
chapterReference: normalized,
};
}
const book = (match[1] || "").trim();
const chapter = Number(match[2] || "1");
const verse = Number(match[3] || "1");
return {
reference: normalized,
book,
chapter,
verse,
chapterReference: `${book} ${chapter}`,
};
};
export const BIBLE_BOOKS = [
"Genesis",
"Exodus",
"Leviticus",
"Numbers",
"Deuteronomy",
"Joshua",
"Judges",
"Ruth",
"1 Samuel",
"2 Samuel",
"1 Kings",
"2 Kings",
"1 Chronicles",
"2 Chronicles",
"Ezra",
"Nehemiah",
"Esther",
"Job",
"Psalms",
"Proverbs",
"Ecclesiastes",
"Song of Solomon",
"Isaiah",
"Jeremiah",
"Lamentations",
"Ezekiel",
"Daniel",
"Hosea",
"Joel",
"Amos",
"Obadiah",
"Jonah",
"Micah",
"Nahum",
"Habakkuk",
"Zephaniah",
"Haggai",
"Zechariah",
"Malachi",
"Matthew",
"Mark",
"Luke",
"John",
"Acts",
"Romans",
"1 Corinthians",
"2 Corinthians",
"Galatians",
"Ephesians",
"Philippians",
"Colossians",
"1 Thessalonians",
"2 Thessalonians",
"1 Timothy",
"2 Timothy",
"Titus",
"Philemon",
"Hebrews",
"James",
"1 Peter",
"2 Peter",
"1 John",
"2 John",
"3 John",
"Jude",
"Revelation",
];
export const BIBLE_BOOK_CHAPTERS = {
Genesis: 50,
Exodus: 40,
Leviticus: 27,
Numbers: 36,
Deuteronomy: 34,
Joshua: 24,
Judges: 21,
Ruth: 4,
"1 Samuel": 31,
"2 Samuel": 24,
"1 Kings": 22,
"2 Kings": 25,
"1 Chronicles": 29,
"2 Chronicles": 36,
Ezra: 10,
Nehemiah: 13,
Esther: 10,
Job: 42,
Psalms: 150,
Proverbs: 31,
Ecclesiastes: 12,
"Song of Solomon": 8,
Isaiah: 66,
Jeremiah: 52,
Lamentations: 5,
Ezekiel: 48,
Daniel: 12,
Hosea: 14,
Joel: 3,
Amos: 9,
Obadiah: 1,
Jonah: 4,
Micah: 7,
Nahum: 3,
Habakkuk: 3,
Zephaniah: 3,
Haggai: 2,
Zechariah: 14,
Malachi: 4,
Matthew: 28,
Mark: 16,
Luke: 24,
John: 21,
Acts: 28,
Romans: 16,
"1 Corinthians": 16,
"2 Corinthians": 13,
Galatians: 6,
Ephesians: 6,
Philippians: 4,
Colossians: 4,
"1 Thessalonians": 5,
"2 Thessalonians": 3,
"1 Timothy": 6,
"2 Timothy": 4,
Titus: 3,
Philemon: 1,
Hebrews: 13,
James: 5,
"1 Peter": 5,
"2 Peter": 3,
"1 John": 5,
"2 John": 1,
"3 John": 1,
Jude: 1,
Revelation: 22,
};
export const getBookChapterCount = (book = "") => {
return BIBLE_BOOK_CHAPTERS[book] || 1;
};