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

39 lines
1.6 KiB
TypeScript

export type WishlistSort = 'title' | 'author'
/** "Last, First" -> "First Last" */
export function wishlistAuthorName(author: string): string {
const [last, first] = author.split(/,\s*/, 2)
return first ? `${first} ${last}` : author
}
function searchableText(book: WishlistBook): string {
const authors = book.authors.flatMap(author => [author, wishlistAuthorName(author)])
return [book.title, ...authors, book.isbn, book.isbn.replace(/-/g, ''), book.thalia ?? ''].join(' ').toLowerCase()
}
const collator = new Intl.Collator('de', { sensitivity: 'base', numeric: true })
function compare(sort: WishlistSort) {
const byTitle = (a: WishlistBook, b: WishlistBook) => collator.compare(a.title, b.title)
const byAuthor = (a: WishlistBook, b: WishlistBook) => collator.compare(a.authors[0] ?? '', b.authors[0] ?? '')
return sort === 'title'
? (a: WishlistBook, b: WishlistBook) => byTitle(a, b) || byAuthor(a, b)
: (a: WishlistBook, b: WishlistBook) => byAuthor(a, b) || byTitle(a, b)
}
export function useWishlist(search: Ref<string>, sort: Ref<WishlistSort>) {
const { data, error, status } = useFetch<WishlistBook[]>('/api/wishlist/books', { key: 'wishlist-books', default: () => [] })
const books = computed(() => {
const terms = search.value.trim().toLowerCase().split(/\s+/).filter(Boolean)
return data.value
.filter((book) => {
const text = searchableText(book)
return terms.every(term => text.includes(term))
})
.toSorted(compare(sort.value))
})
return { books, total: computed(() => data.value.length), error, status }
}