157 lines
5.2 KiB
TypeScript
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>
|
|
)
|
|
}
|