changes in translations files and add filter by bible_study

This commit is contained in:
Esteban Paz 2026-07-19 08:28:50 -05:00
parent dfcce7b2ed
commit 4a50969892
7 changed files with 163 additions and 10 deletions

View File

@ -15,11 +15,13 @@ interface Props {
emptyDetailText: string emptyDetailText: string
showDraft?: boolean showDraft?: boolean
author?: string author?: string
showBibleStudyFilter?: boolean
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
showDraft: false, showDraft: false,
author: '' author: '',
showBibleStudyFilter: false
}) })
const QUERY_BY = 'text' const QUERY_BY = 'text'
@ -28,7 +30,14 @@ const { $i18n } = useNuxtApp()
const t = $i18n.t const t = $i18n.t
const { locale } = useI18n() const { locale } = useI18n()
const filterBy = computed(() => `locale:=${locale.value}`) const filterBy = computed(() => {
let base = `locale:=${locale.value}`
if (activeBibleStudies.value.length > 0) {
const ids = activeBibleStudies.value.map(bs => bs.id).join(',')
base += ` && $${props.mainCollection}(bible_study:=[${ids}])`
}
return base
})
const REQUEST_TIMEOUT_MS = 15000 const REQUEST_TIMEOUT_MS = 15000
const settings = useSettingsStore() const settings = useSettingsStore()
@ -145,6 +154,80 @@ const colors = computed(() => {
const exactSearch = ref(false) const exactSearch = ref(false)
const sortMode = ref<'relevance' | 'date'>('relevance') const sortMode = ref<'relevance' | 'date'>('relevance')
// ---- Filtro bible_study multi-chip (solo para Estudios) --------------------
interface BibleStudyChip {
id: number
title: string
}
const bibleStudyInput = ref<number | null>(null)
const activeBibleStudies = ref<BibleStudyChip[]>([])
const isValidating = ref(false)
async function applyBibleStudyFilter() {
const val = bibleStudyInput.value
if (val === null || val <= 0) return
if (activeBibleStudies.value.some(bs => bs.id === val)) {
toast.add({ title: 'Estudio ya agregado', description: `El estudio #${val} ya está en el filtro`, color: 'info' })
bibleStudyInput.value = null
return
}
isValidating.value = true
try {
const res = await documentsApi.multiSearch({
multiSearchParameters: {},
multiSearchSearchesParameter: {
searches: [{
collection: props.mainCollection,
q: '*',
queryBy: 'title',
filterBy: `bible_study:=${val}`,
perPage: 1,
includeFields: 'bible_study,title'
}]
}
})
const hit = (res?.results?.[0] as { hits?: Array<{ document: { title?: string } }> })?.hits?.[0]
if (hit) {
activeBibleStudies.value = [...activeBibleStudies.value, { id: val, title: hit.document.title || '' }]
bibleStudyInput.value = null
refetchResults()
} else {
toast.add({ title: 'Estudio no encontrado', description: `No existe el estudio #${val}`, color: 'warning' })
}
} catch (err) {
console.error('Error validando bible_study', err)
} finally {
isValidating.value = false
}
}
function removeBibleStudyFilter(id: number) {
activeBibleStudies.value = activeBibleStudies.value.filter(bs => bs.id !== id)
refetchResults()
}
function clearAllBibleStudyFilters() {
activeBibleStudies.value = []
refetchResults()
}
function refetchResults() {
if (!debouncedQuery.value.trim()) {
browseItems.value = []
runBrowse(1, false)
} else {
groupedHits.value = []
currentPage.value = 1
runSearch(query.value, 1, false)
}
}
// ----------------------------------------------------------------------------
const groupedHits = ref<SearchGroup[]>([]) const groupedHits = ref<SearchGroup[]>([])
const total = ref(0) const total = ref(0)
const currentPage = ref(1) const currentPage = ref(1)
@ -204,6 +287,7 @@ const totalPages = computed(() =>
const docCache = ref<Record<string, DocMeta>>({}) const docCache = ref<Record<string, DocMeta>>({})
const { documentsApi } = useTypesenseApi() const { documentsApi } = useTypesenseApi()
const toast = useToast()
// ---- Batch fetch de metadatos --------------------------------------------- // ---- Batch fetch de metadatos ---------------------------------------------
@ -631,9 +715,8 @@ function metaLocation(meta: DocMeta | undefined): string {
>{{ t('search.phrase') }}</button> >{{ t('search.phrase') }}</button>
</div> </div>
</div> </div>
<div class="px-4 sm:px-6 py-3"> <div v-if="query.trim()" class="px-4 sm:px-6 py-3">
<USelect <USelect
v-if="query.trim()"
v-model="sortMode" v-model="sortMode"
:items="[ :items="[
{ label: t('search.sort.relevance'), value: 'relevance' }, { label: t('search.sort.relevance'), value: 'relevance' },
@ -644,6 +727,59 @@ function metaLocation(meta: DocMeta | undefined): string {
/> />
</div> </div>
<div v-if="showBibleStudyFilter" class="px-4 sm:px-6 py-2 border-b border-default space-y-2">
<div class="flex items-center gap-2">
<UInput
v-model="bibleStudyInput"
type="number"
min="1"
:placeholder="$t('search.bible_study_placeholder')"
size="sm"
class="w-36"
@keyup.enter="applyBibleStudyFilter"
/>
<UButton
size="sm"
color="neutral"
variant="outline"
:loading="isValidating"
:disabled="bibleStudyInput === null || bibleStudyInput <= 0"
@click="applyBibleStudyFilter"
>
+ {{ $t('search.filter') }}
</UButton>
</div>
<div v-if="activeBibleStudies.length > 0" class="flex flex-wrap items-center gap-1.5">
<UBadge
v-for="bs in activeBibleStudies"
:key="bs.id"
size="sm"
variant="subtle"
color="primary"
class="max-w-full"
>
<span class="truncate">{{ $t('search.bible_study_chip', { number: bs.id }) }}</span>
<UButton
icon="i-lucide-x"
size="2xs"
color="neutral"
variant="ghost"
class="ml-1 shrink-0"
@click="removeBibleStudyFilter(bs.id)"
/>
</UBadge>
<UButton
size="2xs"
color="neutral"
variant="ghost"
class="text-xs"
@click="clearAllBibleStudyFilters"
>
{{ $t('search.bible_study_clear') }}
</UButton>
</div>
</div>
<UAlert <UAlert
v-if="errorMsg" v-if="errorMsg"
:title="errorMsg" :title="errorMsg"

View File

@ -10,5 +10,6 @@
:empty-detail-text="$t('ui.empty_bible_studies')" :empty-detail-text="$t('ui.empty_bible_studies')"
:show-draft="true" :show-draft="true"
author="Dr. José Benjamín Pérez Matos" author="Dr. José Benjamín Pérez Matos"
:show-bible-study-filter="true"
/> />
</template> </template>

View File

@ -52,7 +52,7 @@ const links = ref<ButtonProps[]>([
<div> <div>
<h1 class="text-3xl sm:text-4xl font-bold text-highlighted tracking-tight"> <h1 class="text-3xl sm:text-4xl font-bold text-highlighted tracking-tight">
Buscador Carpa {{ $t('nav.search_title') }}
</h1> </h1>
<p class="mt-3 text-base text-muted leading-relaxed"> <p class="mt-3 text-base text-muted leading-relaxed">
{{ $t('home.instructions') }} {{ $t('home.instructions') }}

View File

@ -10,7 +10,8 @@
"my_list": "My List", "my_list": "My List",
"history": "History", "history": "History",
"settings": "Settings", "settings": "Settings",
"changelog": "What's New" "changelog": "What's New",
"search_title": "Search of La Gran Carpa Catedral"
}, },
"search": { "search": {
"sort": { "sort": {
@ -19,6 +20,9 @@
}, },
"word": "Word", "word": "Word",
"phrase": "Phrase", "phrase": "Phrase",
"bible_study_placeholder": "Study no...",
"bible_study_chip": "Study #{number} {title}",
"bible_study_clear": "Clear filters",
"placeholder": "Search for...", "placeholder": "Search for...",
"searching": "Searching...", "searching": "Searching...",
"tip": "Tip: wrap in \"quotes\" for exact phrase in that order.", "tip": "Tip: wrap in \"quotes\" for exact phrase in that order.",

View File

@ -11,7 +11,8 @@
"settings": "Configuración", "settings": "Configuración",
"changelog": "Novedades", "changelog": "Novedades",
"tour": "Toma el tour", "tour": "Toma el tour",
"localeselector": "Selector de idioma" "localeselector": "Selector de idioma",
"search_title": "Buscador de La Gran Carpa Catedral"
}, },
"tour": { "tour": {
"progress": "{current} de {total}", "progress": "{current} de {total}",
@ -34,7 +35,7 @@
"favorites_button": "Botón de favoritos" "favorites_button": "Botón de favoritos"
}, },
"home": { "home": {
"instructions": "Bienvenidos, aquí podrán buscar, entre los Estudios Bíblicos, las conferencias y las entrelíneas que están disponibles en el material de archivo de La Gran Carpa Catedral." "instructions": "Bienvenidos, aquí podrán buscar, entre los Estudios de las escrituras, las conferencias y las entrelíneas que están disponibles en el material de archivo de La Gran Carpa Catedral."
}, },
"search": { "search": {
"placeholder": "Buscar...", "placeholder": "Buscar...",
@ -63,6 +64,9 @@
"phrase": "Frase", "phrase": "Frase",
"words": "palabras", "words": "palabras",
"phrases": "frases", "phrases": "frases",
"bible_study_placeholder": "N° de estudio...",
"bible_study_chip": "Estudio #{number} {title}",
"bible_study_clear": "Limpiar filtros",
"words_tooltip": "Buscar por palabras", "words_tooltip": "Buscar por palabras",
"phrases_tooltip": "Buscar por frases", "phrases_tooltip": "Buscar por frases",
"instructions": "Selecciona un resultado de búsqueda...", "instructions": "Selecciona un resultado de búsqueda...",

View File

@ -10,13 +10,17 @@
"my_list": "Ma liste", "my_list": "Ma liste",
"history": "Historique", "history": "Historique",
"settings": "Paramètres", "settings": "Paramètres",
"changelog": "Nouveautés" "changelog": "Nouveautés",
"search_title": "Buscador de La Gran Carpa Catedral"
}, },
"search": { "search": {
"sort": { "sort": {
"relevance": "Normal", "relevance": "Normal",
"date": "Plus récents" "date": "Plus récents"
}, },
"bible_study_placeholder": "N° d'étude...",
"bible_study_chip": "Étude #{number} {title}",
"bible_study_clear": "Effacer les filtres",
"word": "Mot", "word": "Mot",
"phrase": "Phrase", "phrase": "Phrase",
"placeholder": "Rechercher des activités", "placeholder": "Rechercher des activités",

View File

@ -10,13 +10,17 @@
"my_list": "Minha lista", "my_list": "Minha lista",
"history": "Registro", "history": "Registro",
"settings": "Configurações", "settings": "Configurações",
"changelog": "Novidades" "changelog": "Novidades",
"search_title": "Buscador de La Gran Carpa Catedral"
}, },
"search": { "search": {
"sort": { "sort": {
"relevance": "Normal", "relevance": "Normal",
"date": "Mais recentes" "date": "Mais recentes"
}, },
"bible_study_placeholder": "N° do estudo...",
"bible_study_chip": "Estudo #{number} {title}",
"bible_study_clear": "Limpar filtros",
"word": "Palavra", "word": "Palavra",
"phrase": "Frase", "phrase": "Frase",
"placeholder": "Digite para pesquisar...", "placeholder": "Digite para pesquisar...",