import React, { useMemo, ReactElement, useState, useEffect } from "react"; import PropTypes from "prop-types"; import { useNavigate } from "react-router-dom"; import { isEmpty, isNil, isUndefined } from "lodash"; import MetadataPanel from "../shared/MetadataPanel"; import T2Table from "../shared/T2Table"; import SearchBar from "../Library/SearchBar"; import ellipsize from "ellipsize"; import { useQuery, keepPreviousData, useQueryClient, } from "@tanstack/react-query"; import axios from "axios"; import { format, fromUnixTime, parseISO } from "date-fns"; /** * Component that tabulates the contents of the user's ThreeTwo Library. * * @component * @example * */ export const Library = (): ReactElement => { // Default page state // offset: 0 const [offset, setOffset] = useState(0); const [searchQuery, setSearchQuery] = useState({ query: {}, pagination: { size: 25, from: offset, }, type: "all", trigger: "libraryPage", }); const queryClient = useQueryClient(); /** * Method that queries the Elasticsearch index "comics" for issues specified by the query * @param searchQuery - A searchQuery object that contains the search term, type, and pagination params. */ const fetchIssues = async (searchQuery) => { const { pagination, query, type } = searchQuery; return await axios({ method: "POST", url: "http://localhost:3000/api/search/searchIssue", data: { query, pagination, type, }, }); }; const searchIssues = (e) => { queryClient.invalidateQueries({ queryKey: ["comics"] }); setSearchQuery({ query: { volumeName: e.search, }, pagination: { size: 15, from: 0, }, type: "volumeName", trigger: "libraryPage", }); }; const { data, isLoading, isError, isPlaceholderData } = useQuery({ queryKey: ["comics", offset, searchQuery], queryFn: () => fetchIssues(searchQuery), placeholderData: keepPreviousData, }); const searchResults = data?.data; // Programmatically navigate to comic detail const navigate = useNavigate(); const navigateToComicDetail = (row) => { navigate(`/comic/details/${row.original._id}`); }; const ComicInfoXML = (value) => { return value.data ? (
{/* Series Name */} {ellipsize(value.data.series[0], 45)}
{/* Pages */} Pages: {value.data.pagecount[0]} {/* Issue number */} {!isNil(value.data.number) && ( {parseInt(value.data.number[0], 10)} )}
) : null; }; const columns = useMemo( () => [ { header: "Comic Metadata", footer: 1, columns: [ { header: "File Details", id: "fileDetails", minWidth: 400, accessorKey: "_source", cell: (info) => { return ; }, }, { header: "ComicInfo.xml", accessorKey: "_source.sourcedMetadata.comicInfo", cell: (info) => !isEmpty(info.getValue()) ? ( ) : null, }, ], }, { header: "Additional Metadata", columns: [ { header: "Date of Import", accessorKey: "_source.createdAt", cell: (info) => { return !isNil(info.getValue()) ? (

{format(parseISO(info.getValue()), "dd MMMM, yyyy")}

{format(parseISO(info.getValue()), "h aaaa")}
) : null; }, }, { header: "Downloads", accessorKey: "_source.acquisition", cell: (info) => (
DC++: {info.getValue().directconnect.downloads.length} Torrent: {info.getValue().torrent.downloads.length}
), }, ], }, ], [], ); /** * Pagination control that fetches the next x (pageSize) items * based on the y (pageIndex) offset from the ThreeTwo Elasticsearch index * @param {number} pageIndex * @param {number} pageSize * @returns void * **/ const nextPage = (pageIndex: number, pageSize: number) => { if (!isPlaceholderData) { queryClient.invalidateQueries({ queryKey: ["comics"] }); setSearchQuery({ query: {}, pagination: { size: 15, from: pageSize * pageIndex + 1, }, type: "all", trigger: "libraryPage", }); // setOffset(pageSize * pageIndex + 1); } }; /** * Pagination control that fetches the previous x (pageSize) items * based on the y (pageIndex) offset from the ThreeTwo Elasticsearch index * @param {number} pageIndex * @param {number} pageSize * @returns void **/ const previousPage = (pageIndex: number, pageSize: number) => { let from = 0; if (pageIndex === 2) { from = (pageIndex - 1) * pageSize + 2 - (pageSize + 2); } else { from = (pageIndex - 1) * pageSize + 2 - (pageSize + 1); } queryClient.invalidateQueries({ queryKey: ["comics"] }); setSearchQuery({ query: {}, pagination: { size: 15, from, }, type: "all", trigger: "libraryPage", }); // setOffset(from); }; // ImportStatus.propTypes = { // value: PropTypes.bool.isRequired, // }; return (

Library

Browse your comic book collection.

{!isUndefined(searchResults?.hits) ? (
searchIssues(e)} />
) : (

No comics were found in the library, Elasticsearch reports no indices. Try importing a few comics into the library and come back.

                {!isUndefined(searchResults?.data?.meta?.body) ? (
                  

{JSON.stringify( searchResults?.data.meta.body.error.root_cause, null, 4, )}

) : null}
)}
); }; export default Library;