search/app/composables/usePublicationFetch.ts

116 lines
3.3 KiB
TypeScript

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<string, unknown>
}
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<string, { main: string; paragraphs: string }> = {
'bible-studies-ts': { main: 'activities', paragraphs: 'activities_paragraphs' },
'conferences-ts': { main: 'conferences', paragraphs: 'conferences_paragraphs' },
}
export function usePublicationFetch() {
const detailDocument = ref<DocumentDoc | null>(null)
const detailDocumentLoading = ref(false)
const detailParagraphs = ref<TypesenseParagraphHit[]>([])
const detailParagraphsLoading = ref(false)
const typesenseClient = 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(typesenseClient, 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,
}
}