diff --git a/src/client/actions/comicinfo.actions.tsx b/src/client/actions/comicinfo.actions.tsx index 92ddae0..8b91894 100644 --- a/src/client/actions/comicinfo.actions.tsx +++ b/src/client/actions/comicinfo.actions.tsx @@ -12,8 +12,8 @@ import { IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_SUCCESS, IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_IN_PROGRESS, CV_ISSUES_METADATA_CALL_IN_PROGRESS, - CV_ISSUES_METADATA_FETCH_SUCCESS, CV_CLEANUP, + IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED, } from "../constants/action-types"; import { COMICBOOKINFO_SERVICE_URI, @@ -103,6 +103,25 @@ export const getComicBookDetailById = }); }; +export const getComicBooksDetailsByIds = + (comicBookObjectIds: Array) => async (dispatch) => { + dispatch({ + type: IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS, + IMS_inProgress: true, + }); + const result = await axios.request({ + url: `${IMPORT_SERVICE_BASE_URI}/getComicBooksByIds`, + method: "POST", + data: { + ids: comicBookObjectIds, + }, + }); + dispatch({ + type: IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED, + comicBooks: result.data, + }); + }; + export const applyComicVineMatch = (match, comicObjectId) => async (dispatch) => { dispatch({ diff --git a/src/client/assets/scss/App.scss b/src/client/assets/scss/App.scss index 8a09c9e..f09d3eb 100644 --- a/src/client/assets/scss/App.scss +++ b/src/client/assets/scss/App.scss @@ -5,6 +5,8 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts"; @import "../../../../node_modules/@fortawesome/fontawesome-free/scss/solid.scss"; $bg-color: yellow; $border-color: red; + +$volume-color: #f2f1f9; $size-8: 0.9rem; .is-size-8 { @@ -129,7 +131,7 @@ $size-8: 0.9rem; box-shadow: 1px 8px 23px 7px rgba(0, 0, 0, 0.12); .green-border { - border:2px dotted #999; + border:2px dotted #168B64; border-radius: 0.3rem; } @@ -346,13 +348,18 @@ $size-8: 0.9rem; // Volume detail .volume-details { + .is-volume-related { + $tag-background-color: $volume-color; + } .issues-container { display: -webkit-box; /* Not needed if autoprefixing */ display: -ms-flexbox; /* Not needed if autoprefixing */ display: flex; + // margin-left: -30px; /* gutter size offset */ width: auto; .issues-column { - padding: 10px; + max-width:102px; + margin: 10px; background-clip: padding-box; & > div { /* change div to reference your elements you put in */ @@ -362,6 +369,12 @@ $size-8: 0.9rem; } } +// Potential issue matches in library slideout panel +.potential-matches-container { + .generic-card { + max-width: 90px; + } +} // comicvine search results .search-results-container { diff --git a/src/client/components/ComicDetail.tsx b/src/client/components/ComicDetail.tsx index 8d00847..860f68b 100644 --- a/src/client/components/ComicDetail.tsx +++ b/src/client/components/ComicDetail.tsx @@ -41,6 +41,7 @@ type ComicDetailProps = {}; */ export const ComicDetail = ({}: ComicDetailProps): ReactElement => { + const [active, setActive] = useState(1); const [page, setPage] = useState(1); const [visible, setVisible] = useState(false); const [slidingPanelContentId, setSlidingPanelContentId] = useState(""); @@ -116,8 +117,6 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => { }, }; - const [active, setActive] = useState(1); - const isComicBookMetadataAvailable = comicBookDetailData.sourcedMetadata && !isUndefined(comicBookDetailData.sourcedMetadata.comicvine) && diff --git a/src/client/components/ComicDetail/AcquisitionPanel.tsx b/src/client/components/ComicDetail/AcquisitionPanel.tsx index 8ff55fb..1f868cc 100644 --- a/src/client/components/ComicDetail/AcquisitionPanel.tsx +++ b/src/client/components/ComicDetail/AcquisitionPanel.tsx @@ -24,7 +24,7 @@ export const AcquisitionPanel = ( ): ReactElement => { const volumeName = props.comicBookMetadata.sourcedMetadata.comicvine.volumeInformation.name; - const sanitizedVolumeName = volumeName.replace(/[^a-zA-Z0-9 ]/g, ""); + const sanitizedVolumeName = volumeName.replace(/[^a-zA-Z0-9 ]/g, " "); const issueName = props.comicBookMetadata.sourcedMetadata.comicvine.name; // Selectors for picking state diff --git a/src/client/components/MatchResult.tsx b/src/client/components/MatchResult.tsx index 9839d72..16f4a3c 100644 --- a/src/client/components/MatchResult.tsx +++ b/src/client/components/MatchResult.tsx @@ -15,7 +15,6 @@ const handleBrokenImage = (e) => { }; export const MatchResult = (props: MatchResultProps) => { - console.log(props); const dispatch = useDispatch(); const applyCVMatch = useCallback( (match, comicObjectId) => { diff --git a/src/client/components/VolumeDetail/PotentialLibraryMatches.tsx b/src/client/components/VolumeDetail/PotentialLibraryMatches.tsx new file mode 100644 index 0000000..cad286c --- /dev/null +++ b/src/client/components/VolumeDetail/PotentialLibraryMatches.tsx @@ -0,0 +1,77 @@ +import { isArray, map } from "lodash"; +import React, { useEffect, ReactElement } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { getComicBooksDetailsByIds } from "../../actions/comicinfo.actions"; +import { Card } from "../Carda"; +import ellipsize from "ellipsize"; +import { IMPORT_SERVICE_HOST } from "../../constants/endpoints"; +import { escapePoundSymbol } from "../../shared/utils/formatting.utils"; + +const PotentialLibraryMatches = (props): ReactElement => { + const dispatch = useDispatch(); + const comicBooks = useSelector( + (state: RootState) => state.comicInfo.comicBooksDetails, + ); + useEffect(() => { + dispatch(getComicBooksDetailsByIds(props.matches)); + }, []); + return ( +
+ {isArray(comicBooks) ? ( + map(comicBooks, (match) => { + const encodedFilePath = encodeURI( + `${IMPORT_SERVICE_HOST}/${match.rawFileDetails.cover.filePath}`, + ); + const filePath = escapePoundSymbol(encodedFilePath); + return ( + <> + {/*
{JSON.stringify(match, undefined, 2)}
*/} + +
+
+ +
+ +
+
{match.rawFileDetails.name}
+ + {match.rawFileDetails.cover.filePath} + +
+
+
+ File Type + + {match.rawFileDetails.extension} + +
+
+
+
+ File Size + + {match.rawFileDetails.fileSize} + +
+
+
+ {/*
+ {ellipsize(issueDescription, 300)} +
*/} +
+
+ + ); + }) + ) : ( +
asdasd
+ )} +
+ ); +}; + +export default PotentialLibraryMatches; diff --git a/src/client/components/VolumeDetail/VolumeDetail.tsx b/src/client/components/VolumeDetail/VolumeDetail.tsx index 9f7c7d6..8f0cf59 100644 --- a/src/client/components/VolumeDetail/VolumeDetail.tsx +++ b/src/client/components/VolumeDetail/VolumeDetail.tsx @@ -1,4 +1,4 @@ -import { isEmpty, isNil, isUndefined, map } from "lodash"; +import { isEmpty, isUndefined, map, partialRight, pick } from "lodash"; import React, { useEffect, ReactElement, useState, useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useParams } from "react-router"; @@ -6,35 +6,33 @@ import { getComicBookDetailById, findIssuesForSeriesInLibrary, } from "../../actions/comicinfo.actions"; +import PotentialLibraryMatches from "./PotentialLibraryMatches"; import Masonry from "react-masonry-css"; import { Card } from "../Carda"; import SlidingPane from "react-sliding-pane"; +import { convert } from "html-to-text"; +import ellipsize from "ellipsize"; const VolumeDetails = (props): ReactElement => { const breakpointColumnsObj = { - default: 5, + default: 6, 1100: 4, - 700: 2, - 600: 1, + 700: 3, + 600: 2, }; // sliding panel config const [visible, setVisible] = useState(false); const [slidingPanelContentId, setSlidingPanelContentId] = useState(""); const [matches, setMatches] = useState([]); + const [active, setActive] = useState(1); // sliding panel init const contentForSlidingPanel = { potentialMatchesInLibrary: { content: () => { - console.log(matches); - - return ( -
- {map(matches, (match) => ( -
{JSON.stringify(match, undefined, 2)}
- ))} -
- ); + const ids = map(matches, partialRight(pick, "_id")); + const matchIds = ids.map((id:any) => id._id); + return ; }, }, }; @@ -61,6 +59,90 @@ const VolumeDetails = (props): ReactElement => { const { comicObjectId } = useParams<{ comicObjectId: string }>(); + const IssuesInVolume = () => ( + + {!isUndefined(issuesForVolume) && !isEmpty(issuesForVolume) + ? issuesForVolume.map((issue) => { + return ( + openPotentialLibraryMatchesPanel(issue.matches)} + > + {!isEmpty(issue.matches) ? ( + <> + + + + + {issue.issue.issue_number} + + + ) : null} + + ); + }) + : "loading"} + + ); + + // Tab content and header details + const tabGroup = [ + { + id: 1, + name: "Issues in Volume", + icon: , + content: , + }, + { + id: 2, + icon: , + name: "Characters", + content:
asdasd
, + }, + { + id: 3, + icon: , + name: "Arcs", + content:
asdasd
, + }, + ]; + + // Tabs + const MetadataTabGroup = () => { + return ( + <> +
+ +
+ {tabGroup.map(({ id, content }) => { + return active === id ? content : null; + })} + + ); + }; + if ( !isUndefined(comicBookDetails.sourcedMetadata) && !isUndefined(comicBookDetails.sourcedMetadata.comicvine) @@ -68,11 +150,13 @@ const VolumeDetails = (props): ReactElement => { return (
+ {/* Title */}

{comicBookDetails.sourcedMetadata.comicvine.volumeInformation.name}

-
+ {/* Volume cover */} +
{ hasDetails={false} />
- - {!isUndefined(issuesForVolume) && !isEmpty(issuesForVolume) - ? issuesForVolume.map((issue) => { - return ( - <> - - openPotentialLibraryMatchesPanel(issue.matches) - } - > - {!isEmpty(issue.matches) ? ( - - - - ) : null} - - {/* { JSON.stringify(issue, undefined, 2)} */} - - ); - }) - : "loading"} - + +
+
+ {/* Comicvine Id */} +
+
+ ComicVine Id + + { + comicBookDetails.sourcedMetadata.comicvine + .volumeInformation.id + } + +
+
+ {/* Publisher */} +
+
+ Publisher + + { + comicBookDetails.sourcedMetadata.comicvine + .volumeInformation.publisher.name + } + +
+
+
+ + {/* Deck */} +
+ {!isEmpty( + comicBookDetails.sourcedMetadata.comicvine.volumeInformation + .description, + ) + ? ellipsize( + convert( + comicBookDetails.sourcedMetadata.comicvine + .volumeInformation.description, + { + baseElements: { + selectors: ["p"], + }, + }, + ), + 300, + ) + : null} +
+
+ {/*
{JSON.stringify(issuesForVolume, undefined, 2)}
*/}
+