🔧 Fixed table pagination controls and counts
This commit is contained in:
@@ -137,15 +137,18 @@ $border-color: red;
|
||||
// Library
|
||||
.library {
|
||||
table {
|
||||
td {
|
||||
border: 0 none;
|
||||
.card {
|
||||
margin: 8px 0 7px 0;
|
||||
.name {
|
||||
margin: 0 0 4px 0;
|
||||
tr{
|
||||
td {
|
||||
border: 0 none;
|
||||
.card {
|
||||
margin: 8px 0 7px 0;
|
||||
.name {
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
tbody {
|
||||
padding: 10px 0 0 0;
|
||||
}
|
||||
|
||||
@@ -65,14 +65,15 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
||||
return { __html: html };
|
||||
};
|
||||
const isComicBookMetadataAvailable =
|
||||
!isNil(comicBookDetailData.sourcedMetadata) &&
|
||||
comicBookDetailData.sourcedMetadata &&
|
||||
!isUndefined(comicBookDetailData.sourcedMetadata.comicvine) &&
|
||||
!isEmpty(comicBookDetailData.sourcedMetadata);
|
||||
// Tab groups for ComicVine metadata
|
||||
const tabGroup = [
|
||||
{
|
||||
id: 0,
|
||||
name: "Volume Information",
|
||||
content: isComicBookMetadataAvailable && (
|
||||
content: isComicBookMetadataAvailable ? (
|
||||
<>
|
||||
<div className="columns">
|
||||
<div className="column is-narrow">
|
||||
@@ -126,7 +127,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
||||
></div>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
) : null,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
@@ -249,7 +250,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MetadataTabGroup />
|
||||
{isComicBookMetadataAvailable ? <MetadataTabGroup /> : null}
|
||||
|
||||
<Drawer
|
||||
title="ComicVine Search Results"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect, useMemo, ReactElement } from "react";
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
import { useHistory } from "react-router";
|
||||
import {
|
||||
removeLeadingPeriod,
|
||||
escapePoundSymbol,
|
||||
@@ -16,27 +17,68 @@ interface IComicBookLibraryProps {
|
||||
}
|
||||
|
||||
export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
||||
const [comicPage, setComicPage] = useState(1);
|
||||
const [isPageSizeDropdownCollapsed, collapsePageSizeDropdown] =
|
||||
useState(false);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getComicBooks({
|
||||
paginationOptions: {
|
||||
page: comicPage,
|
||||
limit: 15,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}, [comicPage, dispatch]);
|
||||
|
||||
const data = useSelector(
|
||||
(state: RootState) => state.fileOps.recentComics.docs,
|
||||
);
|
||||
const pageTotal = useSelector(
|
||||
(state: RootState) => state.fileOps.recentComics.totalDocs,
|
||||
);
|
||||
const togglePageSizeDropdown = () =>
|
||||
collapsePageSizeDropdown(!isPageSizeDropdownCollapsed);
|
||||
|
||||
// programatically navigate to comic detail
|
||||
const history = useHistory();
|
||||
const navigateToComicDetail = (id) => {
|
||||
history.push(`/comic/details/${id}`);
|
||||
};
|
||||
// raw file details
|
||||
const RawFileDetails = ({ value }) => {
|
||||
const encodedFilePath = encodeURI(
|
||||
"http://localhost:3000" + removeLeadingPeriod(value.path),
|
||||
);
|
||||
const filePath = escapePoundSymbol(encodedFilePath);
|
||||
return (
|
||||
<div className="card-container">
|
||||
<div className="card">
|
||||
<div className="is-horizontal">
|
||||
<div className="card-image">
|
||||
<figure>
|
||||
<img className="image" src={filePath} />
|
||||
</figure>
|
||||
</div>
|
||||
<ul className="card-content">
|
||||
<li className="name has-text-weight-medium">
|
||||
{ellipsize(value.name, 18)}
|
||||
</li>
|
||||
<li>
|
||||
<div className="control">
|
||||
<div className="tags has-addons">
|
||||
<span className="tag is-primary is-light">
|
||||
{value.extension}
|
||||
</span>
|
||||
<span className="tag is-info is-light">
|
||||
{prettyBytes(value.fileSize)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const ImportStatus = ({ value }) => {
|
||||
return `${value.toString()}` ? (
|
||||
<span className="tag is-info is-light">Imported</span>
|
||||
) : (
|
||||
"Not Imported"
|
||||
);
|
||||
};
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -45,55 +87,12 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
||||
{
|
||||
Header: "File Details",
|
||||
accessor: "rawFileDetails",
|
||||
// eslint-disable-next-line react/display-name
|
||||
Cell(props) {
|
||||
const encodedFilePath = encodeURI(
|
||||
"http://localhost:3000" +
|
||||
removeLeadingPeriod(props.cell.value.path),
|
||||
);
|
||||
const filePath = escapePoundSymbol(encodedFilePath);
|
||||
return (
|
||||
<div className="card-container">
|
||||
<div className="card">
|
||||
<div className="is-horizontal">
|
||||
<div className="card-image">
|
||||
<figure>
|
||||
<img className="image" src={filePath} />
|
||||
</figure>
|
||||
</div>
|
||||
<ul className="card-content">
|
||||
<li className="name has-text-weight-medium">
|
||||
{ellipsize(props.cell.value.name, 18)}
|
||||
</li>
|
||||
<li>
|
||||
<div className="control">
|
||||
<div className="tags has-addons">
|
||||
<span className="tag is-primary is-light">
|
||||
{props.cell.value.extension}
|
||||
</span>
|
||||
<span className="tag is-info is-light">
|
||||
{prettyBytes(props.cell.value.fileSize)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
Cell: RawFileDetails,
|
||||
},
|
||||
{
|
||||
Header: "Import Status",
|
||||
accessor: "importStatus.isImported",
|
||||
Cell(props) {
|
||||
return `${props.cell.value.toString()}` ? (
|
||||
<span className="tag is-info is-light">Imported</span>
|
||||
) : (
|
||||
"Not Imported"
|
||||
);
|
||||
},
|
||||
Cell: ImportStatus,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -165,29 +164,57 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
||||
[],
|
||||
);
|
||||
|
||||
columns[0].columns[0].Cell.propTypes = {
|
||||
value: PropTypes.object.isRequired,
|
||||
RawFileDetails.propTypes = {
|
||||
name: PropTypes.string,
|
||||
path: PropTypes.string,
|
||||
fileSize: PropTypes.number,
|
||||
extension: PropTypes.string,
|
||||
};
|
||||
|
||||
ImportStatus.propTypes = {
|
||||
value: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
page,
|
||||
prepareRow,
|
||||
pageOptions,
|
||||
pageCount,
|
||||
state: { pageIndex, pageSize },
|
||||
gotoPage,
|
||||
previousPage,
|
||||
nextPage,
|
||||
setPageSize,
|
||||
page,
|
||||
canPreviousPage,
|
||||
canNextPage,
|
||||
pageOptions,
|
||||
pageCount,
|
||||
gotoPage,
|
||||
nextPage,
|
||||
previousPage,
|
||||
setPageSize,
|
||||
state: { pageIndex, pageSize },
|
||||
} = useTable(
|
||||
{ columns, data, initialState: { pageIndex: 0 } },
|
||||
{
|
||||
columns,
|
||||
data,
|
||||
manualPagination: true,
|
||||
initialState: {
|
||||
pageIndex: 1,
|
||||
pageSize: 15,
|
||||
},
|
||||
pageCount: pageTotal,
|
||||
},
|
||||
usePagination,
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getComicBooks({
|
||||
paginationOptions: {
|
||||
page: pageIndex,
|
||||
limit: pageSize,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}, [pageIndex, pageSize]);
|
||||
const comicBookLibraryItems = React.useMemo(() => {});
|
||||
|
||||
return (
|
||||
@@ -216,7 +243,11 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
||||
{page.map((row, idx) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<tr key={idx} {...row.getRowProps()}>
|
||||
<tr
|
||||
key={idx}
|
||||
{...row.getRowProps()}
|
||||
onClick={() => navigateToComicDetail(row.original._id)}
|
||||
>
|
||||
{row.cells.map((cell, idx) => {
|
||||
return (
|
||||
<td
|
||||
@@ -240,7 +271,8 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
||||
aria-label="pagination"
|
||||
>
|
||||
<div>
|
||||
Page {pageIndex + 1} of {pageOptions.length}
|
||||
Page {pageIndex} of {Math.ceil(pageTotal / pageSize)}
|
||||
(Total resources: {pageTotal})
|
||||
</div>
|
||||
<div className="field has-addons">
|
||||
<p className="control">
|
||||
@@ -288,11 +320,9 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
||||
<input
|
||||
type="number"
|
||||
className="input"
|
||||
defaultValue={pageIndex + 1}
|
||||
defaultValue={pageIndex}
|
||||
onChange={(e) => {
|
||||
const page = e.target.value
|
||||
? Number(e.target.value) - 1
|
||||
: 0;
|
||||
const page = e.target.value ? Number(e.target.value) : 0;
|
||||
gotoPage(page);
|
||||
}}
|
||||
style={{ width: "100px" }}
|
||||
|
||||
@@ -59,7 +59,7 @@ export const Search = ({}: ISearchProps): ReactElement => {
|
||||
onSubmit={() =>
|
||||
getDCPPSearchResults({
|
||||
query: {
|
||||
pattern: "secret wars",
|
||||
pattern: "wolverine",
|
||||
// file_type: "compressed",
|
||||
extensions: ["cbz", "cbr"],
|
||||
},
|
||||
|
||||
32
yarn.lock
32
yarn.lock
@@ -2304,15 +2304,15 @@ aggregate-error@^3.0.0:
|
||||
clean-stack "^2.0.0"
|
||||
indent-string "^4.0.0"
|
||||
|
||||
airdcpp-apisocket@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/airdcpp-apisocket/-/airdcpp-apisocket-2.4.1.tgz#eb2dc28eecd9d6306b25ef8239545d90d6ad005f"
|
||||
integrity sha512-3mkEvbChG4aRe8F2ZFTi2Z0FG319toex/HquRxWlo6s6Rg69s5bPo0VwGte3NlZ4fnHoBD9vk5KavHgOMkJgZg==
|
||||
airdcpp-apisocket@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/airdcpp-apisocket/-/airdcpp-apisocket-2.4.2.tgz#884d02ff7768cb452cd92e1083c05f618b892fc0"
|
||||
integrity sha512-OxrrYe/iNOfle4RhqgaoUNJrgc7LDWCK+WhMQyfprDRxRqkvgPDuWjOavlmf89cAMIgwJ7x5DESpJKWvNGaS/w==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
events "^3.2.0"
|
||||
chalk "^4.1.2"
|
||||
events "^3.3.0"
|
||||
invariant "^2.2.4"
|
||||
is-in-browser "^1.1.3"
|
||||
is-in-browser "^2.0.0"
|
||||
promise "^8.1.0"
|
||||
|
||||
ajv-errors@^1.0.0:
|
||||
@@ -3661,6 +3661,14 @@ chalk@^4.0.0, chalk@^4.1.0:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
dependencies:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
char-regex@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
||||
@@ -5450,7 +5458,7 @@ eventemitter3@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
||||
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
|
||||
|
||||
events@^3.2.0:
|
||||
events@^3.2.0, events@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
|
||||
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
|
||||
@@ -7281,10 +7289,10 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-in-browser@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
|
||||
integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=
|
||||
is-in-browser@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-2.0.0.tgz#a2343a18d8f8a600e8a20cb3022183a251e30355"
|
||||
integrity sha512-/NUv5pqj+krUJalhGpj0lyy+x7vrD9jt1PlAfkoIDEXqE+xZgFJ4FU8e9m99WuHbCqsBZVf+nzvAjNso+SO80A==
|
||||
|
||||
is-installed-globally@^0.1.0:
|
||||
version "0.1.0"
|
||||
|
||||
Reference in New Issue
Block a user