import { ref } from 'vue' import type { SearchHit } from '~/types' interface ParagraphDoc { id?: string document_id: string text: string raw?: string number: number locale: string type: string } export interface TypesenseParagraphHit { document: ParagraphDoc highlights?: unknown[] highlight?: Record } export interface DocumentDoc { id?: string code: string locale: string type: string title: string timestamp: number date: string place?: string city?: string state?: string country?: string thumbnail?: string files?: { youtube?: string; video?: string; audio?: string; booklet?: string; simple?: string } slug?: string body?: string draft?: boolean [key: string]: unknown } // Maps the favorites/history collection name → Typesense main + paragraphs collections. const COLLECTION_CONFIG: Record = { 'bible-studies-ts': { main: 'activities', paragraphs: 'activities_paragraphs' }, 'conferences-ts': { main: 'conferences', paragraphs: 'conferences_paragraphs' }, } export function usePublicationFetch() { const detailDocument = ref(null) const detailDocumentLoading = ref(false) const detailParagraphs = ref([]) const detailParagraphsLoading = ref(false) const { documentsApi } = useTypesenseClient() const { fetchDocumentDetail } = useDocumentDetailFetch() let fetchSeq = 0 let fetchController: AbortController | null = null function isAbortError(err: unknown): boolean { return (err as { name?: string } | null)?.name === 'AbortError' } async function fetchDetail(hit: SearchHit, favoritesCollection: string) { const config = COLLECTION_CONFIG[favoritesCollection] const docId = String(hit._id || hit.id || '') if (!config || !docId) { detailDocument.value = null detailParagraphs.value = [] return } const seq = ++fetchSeq fetchController?.abort() const controller = new AbortController() fetchController = controller detailDocumentLoading.value = true detailParagraphsLoading.value = true detailDocument.value = null detailParagraphs.value = [] try { const detail = await fetchDocumentDetail(documentsApi, config.main, config.paragraphs, docId, controller.signal) if (seq !== fetchSeq) return if (detail) { const rawParagraphs = detail.paragraphs as unknown as ParagraphDoc[] detailDocument.value = detail.document as unknown as DocumentDoc detailParagraphs.value = [...rawParagraphs] .sort((a, b) => (a.number ?? 0) - (b.number ?? 0)) .map(p => ({ document: p })) } } catch (err) { if (seq !== fetchSeq) return if (isAbortError(err)) return console.error('[usePublicationFetch] Error fetching publication detail', err) detailDocument.value = null detailParagraphs.value = [] } finally { if (seq === fetchSeq) { detailDocumentLoading.value = false detailParagraphsLoading.value = false } } } function clearDetail() { detailDocument.value = null detailParagraphs.value = [] } return { detailDocument, detailDocumentLoading, detailParagraphs, detailParagraphsLoading, fetchDetail, clearDetail, } }