157 lines
5.2 KiB
TypeScript

import { Badge } from '@/components/ui/badge'
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination'
import { Author, Book, Genre } from '@/payload-types'
import { Avatar } from '../avatar'
import { PaginatedDocs } from 'payload'
import Link from 'next/link'
import Image from 'next/image'
type Props = {
books: PaginatedDocs<Book>
}
const makeAuthorsLabel = (book: Book) => {
const authors = book.authors as Author[] // TODO: endure this type safety
const translators = authors?.filter((a) => a.role === 'Translator').map((t) => t.lf)
const editors = authors?.filter((a) => a.role === 'Editor').map((e) => e.lf)
const actualAuthors = authors
?.filter((a) => !editors.includes(a.lf) && !translators.includes(a.lf))
.map((a) => a.lf)
return (
<ul>
<li>{actualAuthors.join(', ')}</li>
{!!translators?.length && <li>Translators: {translators.join(', ')}</li>}
{!!editors?.length && <li>Editors: {editors.join(', ')}</li>}
</ul>
)
}
const makeGenreBadges = (book: Book) => {
return (book.genre as Genre[])?.map((g) => (
<Badge key={g.name + book.title + book.id} className="text-[9px] px-0.5 py-0 ml-0.5">
{g.name}
</Badge>
))
}
export default function BookList(props: Props) {
const { docs, hasNextPage, hasPrevPage, limit, totalPages, page, prevPage, nextPage, totalDocs } =
props.books
const currentPage = page || 0
const books = docs
return (
<section id="user-repositories">
<ul role="list" className="divide-y divide-gray-800">
{books?.map((b) => (
<li key={b.lcc + (b.title || '')}>
<Link href={`/books/${b.id}`} className="grid grid-cols-9 gap-x-4 py-5">
<Image
alt=""
className="w-18 h-22 flex-none bg-gray-800 col-span-2"
width={180}
height={220}
src={
b.isbn
? `https://covers.openlibrary.org/b/isbn/${b.isbn}-M.jpg`
: '/images/book-48.svg'
}
/>
<div className="min-w-0 flex-auto col-span-7">
<p className="text-sm/6 dark:data-[state=active]:text-foreground ">
<span className="block sm:inline">{b.title}</span>
<small className="ml-1 italic font-thin">{b.lcc}</small>
</p>
<p className="mt-1 truncate text-xs/5 dark:data-[state=active]:text-foreground">
{makeGenreBadges(b)}
</p>
</div>
<div className="flex flex-col mt-2 col-span-9 sm:items-end">
<p className="text-sm/6 text-foreground font-semibold">{makeAuthorsLabel(b)}</p>
{!b.copies?.docs?.length ? (
<p className="mt-1 text-xs/5 text-gray-400">No copies found</p>
) : (
<div className="mt-1 flex items-center gap-x-1.5">
<div className="flex-none rounded-full bg-emerald-500/20 p-1">
<div className="size-1.5 rounded-full bg-emerald-500" />
</div>
<p className="text-xs/5 text-gray-400">
{b.copies?.docs?.length} {b.copies?.docs?.length > 1 ? 'copy' : 'copies'}
</p>
</div>
)}
</div>
</Link>
</li>
))}
</ul>
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href={prevPage ? `/books?limit=${limit}&page=${prevPage}` : ''} />
</PaginationItem>
{hasPrevPage && currentPage > totalPages / 2 && (
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
)}
{prevPage && (
<PaginationItem>
<PaginationLink href={`/books?limit=${limit}&page=${prevPage}`}>
{prevPage}
</PaginationLink>
</PaginationItem>
)}
<PaginationItem>
<PaginationLink href="#" isActive>
{currentPage}
</PaginationLink>
</PaginationItem>
{nextPage && (
<PaginationItem>
<PaginationLink href={`/books?limit=${limit}&page=${nextPage}`}>
{nextPage}
</PaginationLink>
</PaginationItem>
)}
{hasNextPage && currentPage < totalPages / 2 && (
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
)}
<PaginationItem>
<PaginationNext href={nextPage ? `/books?limit=${limit}&page=${nextPage}` : ''} />
</PaginationItem>
</PaginationContent>
</Pagination>
<p className="flex justify-center mt-2 gap-2 mx-auto text-muted-foreground">
<span>viewing</span>
<span className="text-foreground">
{currentPage * limit - limit + 1}-{currentPage * limit}
</span>
<span>of</span>
<span className="text-foreground">{totalDocs}</span>
</p>
</section>
)
}