🔧 🏗️ Massive tables refactor
Abstracted a table component that can be configured to display issues, volumes or pull list items
This commit is contained in:
@@ -32,6 +32,8 @@ import {
|
||||
SS_SEARCH_FAILED,
|
||||
SS_SEARCH_RESULTS_FETCHED_SPECIAL,
|
||||
WANTED_COMICS_FETCHED,
|
||||
VOLUMES_FETCHED,
|
||||
CV_WEEKLY_PULLLIST_FETCHED,
|
||||
} from "../constants/action-types";
|
||||
import { success } from "react-notification-system-redux";
|
||||
import { removeLeadingPeriod } from "../shared/utils/formatting.utils";
|
||||
@@ -316,12 +318,16 @@ export const searchIssue = (query, options) => async (dispatch) => {
|
||||
data: response.data.body,
|
||||
});
|
||||
break;
|
||||
case "volumesPage":
|
||||
dispatch({
|
||||
type: VOLUMES_FETCHED,
|
||||
data: response.data.body,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
export const analyzeImage =
|
||||
(imageFilePath: string | Buffer) => async (dispatch) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import Dashboard from "./Dashboard/Dashboard";
|
||||
|
||||
import Import from "./Import";
|
||||
import { ComicDetailContainer } from "./ComicDetail/ComicDetailContainer";
|
||||
import LibraryContainer from "./Library/LibraryContainer";
|
||||
import TabulatedContentContainer from "./Library/TabulatedContentContainer";
|
||||
import LibraryGrid from "./Library/LibraryGrid";
|
||||
import Search from "./Search";
|
||||
import Settings from "./Settings";
|
||||
@@ -92,7 +92,7 @@ export const App = (): ReactElement => {
|
||||
<Routes>
|
||||
<Route path="/" element={<Dashboard />} />
|
||||
<Route path="/import" element={<Import path={"./comics"} />} />
|
||||
<Route path="/library" element={<LibraryContainer />} />
|
||||
<Route path="/library" element={<TabulatedContentContainer category="library" />} />
|
||||
<Route path="/library-grid" element={<LibraryGrid />} />
|
||||
<Route path="/downloads" element={<Downloads data={{}} />} />
|
||||
<Route path="/search" element={<Search />} />
|
||||
@@ -105,9 +105,9 @@ export const App = (): ReactElement => {
|
||||
element={<VolumeDetail />}
|
||||
/>
|
||||
<Route path="/settings" element={<Settings />} />
|
||||
<Route path="/pull-list/all" element={<PullList />} />
|
||||
<Route path="/wanted/all" element={<WantedComics />} />
|
||||
<Route path="/volumes/all" element={<Volumes />} />
|
||||
<Route path="/pull-list/all" element={<TabulatedContentContainer category="pullList" />} />
|
||||
<Route path="/wanted/all" element={<TabulatedContentContainer category="wanted" />} />
|
||||
<Route path="/volumes/all" element={<TabulatedContentContainer category="volumes" />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</AirDCPPSocketContextProvider>
|
||||
|
||||
@@ -20,7 +20,7 @@ export const PullList = ({ issues }: PullListProps): ReactElement => {
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getWeeklyPullList({
|
||||
startDate: "2022-11-9",
|
||||
startDate: "2022-11-15",
|
||||
pageSize: "15",
|
||||
currentPage: "1",
|
||||
}),
|
||||
@@ -127,7 +127,7 @@ export const PullList = ({ issues }: PullListProps): ReactElement => {
|
||||
<Slider {...settings} ref={(c) => (sliderRef = c)}>
|
||||
{!isNil(pullList) &&
|
||||
pullList &&
|
||||
map(pullList, (issue, idx) => {
|
||||
map(pullList, ({issue}, idx) => {
|
||||
return (
|
||||
<Card
|
||||
key={idx}
|
||||
|
||||
@@ -81,7 +81,7 @@ export const Library = (): ReactElement => {
|
||||
const WantedStatus = ({ value }) => {
|
||||
return !value ? <span className="tag is-info is-light">Wanted</span> : null;
|
||||
};
|
||||
const columns = React.useMemo(() => [
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
header: "Comic Metadata",
|
||||
footer: 1,
|
||||
|
||||
@@ -1,39 +1,34 @@
|
||||
import { isEmpty, isUndefined } from "lodash";
|
||||
import React, { ReactElement, useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { searchIssue } from "../../actions/fileops.actions";
|
||||
import React, { ReactElement } from "react";
|
||||
import PullList from "../PullList/PullList";
|
||||
import { Volumes } from "../Volumes/Volumes";
|
||||
import WantedComics from "../WantedComics/WantedComics";
|
||||
import { Library } from "./Library";
|
||||
|
||||
const LibraryContainer = (): ReactElement => {
|
||||
// const dispatch = useDispatch();
|
||||
// useEffect(() => {
|
||||
// dispatch(
|
||||
// searchIssue(
|
||||
// {
|
||||
// query: {},
|
||||
// },
|
||||
// {
|
||||
// pagination: {
|
||||
// size: 25,
|
||||
// from: 0,
|
||||
// },
|
||||
// type: "all",
|
||||
// trigger: "libraryPage"
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }, []);
|
||||
interface ITabulatedContentContainerProps {
|
||||
category: string;
|
||||
}
|
||||
|
||||
// const searchResults = useSelector(
|
||||
// (state: RootState) => state.fileOps.libraryComics,
|
||||
// );
|
||||
// const searchError = useSelector(
|
||||
// (state: RootState) => state.fileOps.librarySearchError,
|
||||
// );
|
||||
const TabulatedContentContainer = (
|
||||
props: ITabulatedContentContainerProps,
|
||||
): ReactElement => {
|
||||
const { category } = props;
|
||||
const renderTabulatedContent = () => {
|
||||
switch (category) {
|
||||
case "library":
|
||||
return <Library />;
|
||||
case "pullList":
|
||||
return <PullList />;
|
||||
case "wanted":
|
||||
return <WantedComics />;
|
||||
case "volumes":
|
||||
return <Volumes />;
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Library />)
|
||||
// : (
|
||||
return renderTabulatedContent();
|
||||
// : (
|
||||
// <div className="container">
|
||||
// <section className="section is-small">
|
||||
// <div className="columns">
|
||||
@@ -59,4 +54,4 @@ const LibraryContainer = (): ReactElement => {
|
||||
// );
|
||||
};
|
||||
|
||||
export default LibraryContainer;
|
||||
export default TabulatedContentContainer;
|
||||
@@ -4,18 +4,19 @@ import { getWeeklyPullList } from "../../actions/comicinfo.actions";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Card from "../Carda";
|
||||
import ellipsize from "ellipsize";
|
||||
import { isNil, isUndefined } from "lodash";
|
||||
|
||||
export const PullList = (): ReactElement => {
|
||||
const pullListComics = useSelector(
|
||||
(state: RootState) => state.comicInfo.pullList,
|
||||
);
|
||||
console.log(pullListComics);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getWeeklyPullList({
|
||||
startDate: "2022-6-1",
|
||||
pageSize: "100",
|
||||
startDate: "2022-11-15",
|
||||
pageSize: "15",
|
||||
currentPage: "1",
|
||||
}),
|
||||
);
|
||||
@@ -25,24 +26,25 @@ export const PullList = (): ReactElement => {
|
||||
const columnData = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: "Comic Information",
|
||||
header: "Comic Information",
|
||||
columns: [
|
||||
{
|
||||
Header: "Details",
|
||||
header: "Details",
|
||||
id: "comicDetails",
|
||||
minWidth: 450,
|
||||
accessor: (row) => {
|
||||
console.log(row);
|
||||
accessorKey: "issue",
|
||||
cell: (row) => {
|
||||
const item = row.getValue();
|
||||
return (
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
<div className="column is-three-quarters">
|
||||
<div className="comic-detail issue-metadata">
|
||||
<dl>
|
||||
<dd>
|
||||
<div className="columns mt-2">
|
||||
<div className="column is-3">
|
||||
<Card
|
||||
imageUrl={row.cover}
|
||||
imageUrl={item.cover}
|
||||
orientation={"vertical"}
|
||||
hasDetails={false}
|
||||
// cardContainerStyle={{ maxWidth: 200 }}
|
||||
@@ -52,18 +54,20 @@ export const PullList = (): ReactElement => {
|
||||
<dl>
|
||||
<dt>
|
||||
<h6 className="name has-text-weight-medium mb-1">
|
||||
{row.name}
|
||||
{item.name}
|
||||
</h6>
|
||||
</dt>
|
||||
<dd className="is-size-7">
|
||||
published by{" "}
|
||||
<span className="has-text-weight-semibold">
|
||||
{row.publisher}
|
||||
{item.publisher}
|
||||
</span>
|
||||
</dd>
|
||||
|
||||
<dd className="is-size-7">
|
||||
<span>{ellipsize(row.description, 190)}</span>
|
||||
<span>
|
||||
{ellipsize(item.description, 190)}
|
||||
</span>
|
||||
</dd>
|
||||
|
||||
<dd className="is-size-7 mt-2">
|
||||
@@ -71,10 +75,10 @@ export const PullList = (): ReactElement => {
|
||||
<div className="control">
|
||||
<span className="tags">
|
||||
<span className="tag is-success is-light has-text-weight-semibold">
|
||||
{row.price}
|
||||
{item.price}
|
||||
</span>
|
||||
<span className="tag is-success is-light">
|
||||
{row.pulls}
|
||||
{item.pulls}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -99,16 +103,24 @@ export const PullList = (): ReactElement => {
|
||||
return (
|
||||
<section className="container">
|
||||
<div className="section">
|
||||
<h1 className="title">Weekly Pull List</h1>
|
||||
<T2Table
|
||||
rowData={pullListComics}
|
||||
columns={columnData}
|
||||
totalPages={pullListComics.length}
|
||||
paginationHandlers={{
|
||||
nextPage: nextPageHandler,
|
||||
previousPage: previousPageHandler,
|
||||
}}
|
||||
/>
|
||||
<div className="header-area">
|
||||
<h1 className="title">Weekly Pull List</h1>
|
||||
</div>
|
||||
{!isNil(pullListComics) && (
|
||||
<div>
|
||||
<div className="library">
|
||||
<T2Table
|
||||
sourceData={pullListComics}
|
||||
columns={columnData}
|
||||
totalPages={pullListComics.length}
|
||||
paginationHandlers={{
|
||||
nextPage: nextPageHandler,
|
||||
previousPage: previousPageHandler,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -2,16 +2,13 @@ import React, { ReactElement, useEffect, useMemo } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { searchIssue } from "../../actions/fileops.actions";
|
||||
import Card from "../Carda";
|
||||
import SearchBar from "../Library/SearchBar";
|
||||
import T2Table from "../shared/T2Table";
|
||||
import ellipsize from "ellipsize";
|
||||
import { isUndefined } from "lodash";
|
||||
import { convert } from "html-to-text";
|
||||
import { isUndefined } from "lodash";
|
||||
|
||||
export const Volumes = (props): ReactElement => {
|
||||
const volumes = useSelector(
|
||||
(state: RootState) => state.fileOps.librarySearchResults,
|
||||
);
|
||||
const volumes = useSelector((state: RootState) => state.fileOps.volumes);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
@@ -25,19 +22,20 @@ export const Volumes = (props): ReactElement => {
|
||||
from: 0,
|
||||
},
|
||||
type: "volumes",
|
||||
trigger: "volumesPage",
|
||||
},
|
||||
),
|
||||
);
|
||||
}, []);
|
||||
console.log(volumes);
|
||||
|
||||
const columnData = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: "Volume Details",
|
||||
header: "Volume Details",
|
||||
id: "volumeDetails",
|
||||
minWidth: 450,
|
||||
accessor: (row) => {
|
||||
accessorKey: "_source",
|
||||
cell: (row) => {
|
||||
const foo = row.getValue();
|
||||
return (
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
@@ -45,11 +43,11 @@ export const Volumes = (props): ReactElement => {
|
||||
<dl>
|
||||
<dd>
|
||||
<div className="columns mt-2">
|
||||
<div className="column is-3">
|
||||
<div className="">
|
||||
<Card
|
||||
imageUrl={
|
||||
row._source.sourcedMetadata.comicvine
|
||||
.volumeInformation.image.thumb_url
|
||||
foo.sourcedMetadata.comicvine.volumeInformation
|
||||
.image.thumb_url
|
||||
}
|
||||
orientation={"vertical"}
|
||||
hasDetails={false}
|
||||
@@ -61,7 +59,7 @@ export const Volumes = (props): ReactElement => {
|
||||
<dt>
|
||||
<h6 className="name has-text-weight-medium mb-1">
|
||||
{
|
||||
row._source.sourcedMetadata.comicvine
|
||||
foo.sourcedMetadata.comicvine
|
||||
.volumeInformation.name
|
||||
}
|
||||
</h6>
|
||||
@@ -70,7 +68,7 @@ export const Volumes = (props): ReactElement => {
|
||||
published by{" "}
|
||||
<span className="has-text-weight-semibold">
|
||||
{
|
||||
row._source.sourcedMetadata.comicvine
|
||||
foo.sourcedMetadata.comicvine
|
||||
.volumeInformation.publisher.name
|
||||
}
|
||||
</span>
|
||||
@@ -80,7 +78,7 @@ export const Volumes = (props): ReactElement => {
|
||||
<span>
|
||||
{ellipsize(
|
||||
convert(
|
||||
row._source.sourcedMetadata.comicvine
|
||||
foo.sourcedMetadata.comicvine
|
||||
.volumeInformation.description,
|
||||
{
|
||||
baseElements: {
|
||||
@@ -102,7 +100,7 @@ export const Volumes = (props): ReactElement => {
|
||||
</span>
|
||||
<span className="tag is-success is-light">
|
||||
{
|
||||
row._source.sourcedMetadata.comicvine
|
||||
foo.sourcedMetadata.comicvine
|
||||
.volumeInformation.count_of_issues
|
||||
}
|
||||
</span>
|
||||
@@ -122,36 +120,35 @@ export const Volumes = (props): ReactElement => {
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: "Download Status",
|
||||
header: "Download Status",
|
||||
columns: [
|
||||
{
|
||||
Header: "Files",
|
||||
accessor: "_source.acquisition.directconnect",
|
||||
header: "Files",
|
||||
accessorKey: "_source.acquisition.directconnect",
|
||||
align: "right",
|
||||
Cell: (props) => {
|
||||
cell: (props) => {
|
||||
const row = props.getValue();
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
// flexDirection: "column",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{props.cell.value.length > 0 ? (
|
||||
<span className="tag is-warning">
|
||||
{props.cell.value.length}
|
||||
</span>
|
||||
{row.length > 0 ? (
|
||||
<span className="tag is-warning">{row.length}</span>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: "Type",
|
||||
header: "Type",
|
||||
id: "Air",
|
||||
},
|
||||
{
|
||||
Header: "Type",
|
||||
header: "Type",
|
||||
id: "dcc",
|
||||
},
|
||||
],
|
||||
@@ -162,16 +159,24 @@ export const Volumes = (props): ReactElement => {
|
||||
return (
|
||||
<section className="container">
|
||||
<div className="section">
|
||||
{volumes.hits ? (
|
||||
<div className="header-area">
|
||||
<h1 className="title">Volumes</h1>
|
||||
</div>
|
||||
{!isUndefined(volumes.hits) && (
|
||||
<div>
|
||||
<div className="library">
|
||||
<h1 className="title">Volumes</h1>
|
||||
{/* Search bar */}
|
||||
<SearchBar />
|
||||
<T2Table rowData={volumes.hits.hits} columns={columnData} />
|
||||
<T2Table
|
||||
sourceData={volumes?.hits?.hits}
|
||||
totalPages={volumes.hits.hits.length}
|
||||
paginationHandlers={{
|
||||
nextPage: () => {},
|
||||
previousPage: () => {},
|
||||
}}
|
||||
columns={columnData}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -20,6 +20,7 @@ export const T2Table = (tableOptions): ReactElement => {
|
||||
pageIndex: 1,
|
||||
pageSize: 15,
|
||||
});
|
||||
console.log(sourceData)
|
||||
|
||||
|
||||
const pagination = useMemo(
|
||||
|
||||
@@ -51,6 +51,7 @@ export const IMS_COMIC_BOOK_GROUPS_CALL_IN_PROGRESS =
|
||||
"IMS_COMIC_BOOK_GROUPS_CALL_IN_PROGRESS";
|
||||
export const IMS_COMIC_BOOK_GROUPS_CALL_FAILED =
|
||||
"IMS_COMIC_BOOK_GROUPS_CALL_FAILED";
|
||||
export const VOLUMES_FETCHED="VOLUMES_FETCHED";
|
||||
|
||||
// search results from the Search service
|
||||
export const SS_SEARCH_RESULTS_FETCHED = "SS_SEARCH_RESULTS_FETCHED";
|
||||
|
||||
@@ -109,10 +109,14 @@ function comicinfoReducer(state = initialState, action) {
|
||||
...state,
|
||||
};
|
||||
case CV_WEEKLY_PULLLIST_FETCHED: {
|
||||
const foo = [];
|
||||
action.data.map((item) => {
|
||||
foo.push({issue: item})
|
||||
});
|
||||
return {
|
||||
...state,
|
||||
inProgress: false,
|
||||
pullList: [...action.data],
|
||||
pullList: foo,
|
||||
};
|
||||
}
|
||||
case LIBRARY_STATISTICS_CALL_IN_PROGRESS:
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
LS_IMPORT_CALL_IN_PROGRESS,
|
||||
SS_SEARCH_FAILED,
|
||||
SS_SEARCH_RESULTS_FETCHED_SPECIAL,
|
||||
VOLUMES_FETCHED,
|
||||
} from "../constants/action-types";
|
||||
const initialState = {
|
||||
IMSCallInProgress: false,
|
||||
@@ -45,6 +46,7 @@ const initialState = {
|
||||
recentComics: [],
|
||||
wantedComics: [],
|
||||
libraryComics: [],
|
||||
volumes: [],
|
||||
librarySearchResultsFormatted: [],
|
||||
librarySearchResultCount: 0,
|
||||
libraryQueueResults: [],
|
||||
@@ -188,7 +190,6 @@ function fileOpsReducer(state = initialState, action) {
|
||||
}
|
||||
|
||||
case SS_SEARCH_RESULTS_FETCHED: {
|
||||
console.log(action.data);
|
||||
return {
|
||||
...state,
|
||||
libraryComics: action.data,
|
||||
@@ -221,6 +222,13 @@ function fileOpsReducer(state = initialState, action) {
|
||||
SSCallInProgress: false,
|
||||
};
|
||||
}
|
||||
|
||||
case VOLUMES_FETCHED:
|
||||
return {
|
||||
...state,
|
||||
volumes: action.data,
|
||||
SSCallInProgress: false,
|
||||
};
|
||||
|
||||
case SS_SEARCH_FAILED: {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user