import type { Entry } from '~/types/entry' const KIND_ORDER: Record = { 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() 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) { const { data: reviews, error: reviewsError } = useFetch('/api/reviews', { key: 'reviews', default: () => [] }) const { data: notes, error: notesError } = useFetch('/api/notes', { key: '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 } }