Files
website/layers/diary/app/composables/useDiary.ts
T
2026-09-30 19:15:57 +02:00

64 lines
2.3 KiB
TypeScript

import type { Entry } from '../types/entry'
const KIND_ORDER: Record<Entry['kind'], number> = { review: 0, note: 1 }
function toEntries(reviews: Review[], notes: Note[]): Entry[] {
return [
...reviews.map(review => ({ kind: 'review' as const, key: `review-${review.id}`, date: review.date, text: review.text, review })),
...notes.map(note => ({ kind: 'note' as const, key: `note-${note.id}`, date: note.date, text: note.text, note }))
]
}
function searchableText(entry: Entry): string {
const date = `${formatDate(entry.date)} ${entry.date}`
const text = entry.kind === 'review'
? `review ${entry.review.medium ?? ''} ${date} ${entry.review.title} ${entry.review.author ?? ''} ${entry.text}`
: `note ${date} ${entry.text}`
return text.toLowerCase()
}
function newestFirst(a: Entry, b: Entry): number {
return b.date.localeCompare(a.date) || KIND_ORDER[a.kind] - KIND_ORDER[b.kind] || b.key.localeCompare(a.key)
}
function entryIcon(entry: Entry): string {
if (entry.kind === 'note') return NOTE_ICON
return entry.review.medium ? MEDIUM_ICONS[entry.review.medium] : REVIEW_ICON
}
function groupByYear(entries: Entry[]) {
const years = new Map<string, Entry[]>()
for (const entry of entries) {
const year = entry.date.slice(0, 4)
years.set(year, [...(years.get(year) ?? []), entry])
}
return [...years].map(([year, entries]) => ({
year,
items: entries.map(entry => ({ value: entry.key, icon: entryIcon(entry), entry }))
}))
}
export function useDiary(search: Ref<string>) {
const { data: reviews, error: reviewsError } = useFetch<Review[]>('/api/diary/reviews', { key: 'diary-reviews', default: () => [] })
const { data: notes, error: notesError } = useFetch<Note[]>('/api/diary/notes', { key: 'diary-notes', default: () => [] })
const years = computed(() => {
const terms = searchTerms(search.value)
const matches = toEntries(reviews.value, notes.value)
.filter(entry => entry.text)
.filter((entry) => {
const text = searchableText(entry)
return terms.every(term => text.includes(term))
})
.toSorted(newestFirst)
return groupByYear(matches)
})
const errors = computed(() => [
{ what: 'reviews', error: reviewsError.value },
{ what: 'notes', error: notesError.value }
].filter(({ error }) => error))
return { years, errors }
}