import React, { useState, useEffect, useCallback, ReactElement } from "react"; import PropTypes from "prop-types"; import { useParams } from "react-router-dom"; import Card from "./Carda"; import MatchResult from "./MatchResult"; import ComicVineSearchForm from "./ComicVineSearchForm"; import AcquisitionPanel from "./AcquisitionPanel"; import DownloadsPanel from "./DownloadsPanel"; import SlidingPane from "react-sliding-pane"; import Select, { components } from "react-select"; import "react-sliding-pane/dist/react-sliding-pane.css"; import "react-loader-spinner/dist/loader/css/react-spinner-loader.css"; import Loader from "react-loader-spinner"; import { isEmpty, isUndefined, isNil } from "lodash"; import { RootState } from "threetwo-ui-typings"; import { fetchComicVineMatches } from "../actions/fileops.actions"; import { getComicBookDetailById } from "../actions/comicinfo.actions"; import { detectTradePaperbacks } from "../shared/utils/tradepaperback.utils"; import dayjs from "dayjs"; const prettyBytes = require("pretty-bytes"); import { useDispatch, useSelector } from "react-redux"; import { removeLeadingPeriod, escapePoundSymbol, } from "../shared/utils/formatting.utils"; type ComicDetailProps = {}; /** * Component for displaying the metadata for a comic in greater detail. * * @component * @example * return ( * * ) */ export const ComicDetail = ({}: ComicDetailProps): ReactElement => { const [page, setPage] = useState(1); const [visible, setVisible] = useState(false); const comicVineSearchResults = useSelector( (state: RootState) => state.comicInfo.searchResults, ); const comicVineSearchQueryObject = useSelector( (state: RootState) => state.comicInfo.searchQuery, ); const comicVineAPICallProgress = useSelector( (state: RootState) => state.comicInfo.inProgress, ); const comicBookDetailData = useSelector( (state: RootState) => state.comicInfo.comicBookDetail, ); const { comicObjectId } = useParams<{ comicObjectId: string }>(); const dispatch = useDispatch(); useEffect(() => { dispatch(getComicBookDetailById(comicObjectId)); }, [page, dispatch]); const openDrawerWithCVMatches = useCallback(() => { setVisible(true); dispatch(fetchComicVineMatches(comicBookDetailData)); }, [dispatch, comicBookDetailData]); const [active, setActive] = useState(1); const createDescriptionMarkup = (html) => { return { __html: html }; }; const isComicBookMetadataAvailable = comicBookDetailData.sourcedMetadata && !isUndefined(comicBookDetailData.sourcedMetadata.comicvine) && !isEmpty(comicBookDetailData.sourcedMetadata); // Tab content and header details const tabGroup = [ { id: 1, name: "Volume Information", icon: , content: isComicBookMetadataAvailable ? (
Is a part of{" "} { comicBookDetailData.sourcedMetadata.comicvine .volumeInformation.name }
Published by {" "} { comicBookDetailData.sourcedMetadata.comicvine .volumeInformation.publisher.name }
Total issues in this volume: { comicBookDetailData.sourcedMetadata.comicvine .volumeInformation.count_of_issues }
) : null, }, { id: 2, icon: , name: "Other Metadata", content:
bastard
, }, { id: 3, icon: , name: "Acquisition", content: ( ), }, { id: 4, icon: null, name: !isNil(comicBookDetailData) && !isEmpty(comicBookDetailData) ? ( Downloads ) : ( "Downloads" ), content: !isNil(comicBookDetailData) && !isEmpty(comicBookDetailData) && ( ), }, ]; // Tabs const MetadataTabGroup = () => { return ( <>
{tabGroup.map(({ id, content }) => { return active === id ? content : null; })} ); }; const RawFileDetails = (props) => (
Raw File Details
{props.data.containedIn}
{props.data.path}
Size {prettyBytes(props.data.fileSize)}
Extension {props.data.extension}
); const ComicVineDetails = (props) => (
ComicVine Metadata
Last scraped on{" "} {dayjs(props.updatedAt).format("MMM D YYYY [at] h:mm a")}
{props.data.name}
{props.data.number}
{!isEmpty( detectTradePaperbacks( comicBookDetailData.sourcedMetadata.comicvine.volumeInformation .description, ), ) ? (
Detected Type Trade Paperback
) : (
Type {props.data.resource_type}
)}
ComicVine Issue ID {props.data.id}
); ComicVineDetails.propTypes = { updatedAt: PropTypes.string, data: PropTypes.shape({ name: PropTypes.string, number: PropTypes.string, resource_type: PropTypes.string, id: PropTypes.number, }), }; RawFileDetails.propTypes = { data: PropTypes.shape({ containedIn: PropTypes.string, fileSize: PropTypes.number, path: PropTypes.string, extension: PropTypes.string, }), }; // Determine which cover image to use: // 1. from the locally imported, non-CV-scraped version, or // 2. from the CV-scraped version let imagePath = ""; let comicBookTitle = ""; if (!isNil(comicBookDetailData.rawFileDetails)) { const encodedFilePath = encodeURI( "http://localhost:3000" + removeLeadingPeriod(comicBookDetailData.rawFileDetails.path), ); imagePath = escapePoundSymbol(encodedFilePath); comicBookTitle = comicBookDetailData.rawFileDetails.name; } else if ( !isNil(comicBookDetailData.sourcedMetadata) && !isNil(comicBookDetailData.sourcedMetadata.comicvine) ) { imagePath = comicBookDetailData.sourcedMetadata.comicvine.image.small_url; comicBookTitle = comicBookDetailData.sourcedMetadata.comicvine.name; } // Actions menu options and handler const CVMatchLabel = ( Match on ComicVine ); const editLabel = ( Edit Metadata ); const deleteLabel = ( Delete Comic ); const Placeholder = (props) => { return ; }; const actionOptions = [ { value: "match-on-comic-vine", label: CVMatchLabel }, { value: "edit-metdata", label: editLabel }, { value: "delete-comic", label: deleteLabel }, ]; const handleActionSelection = (action) => { switch (action.value) { case "match-on-comic-vine": openDrawerWithCVMatches(); break; default: console.log("No valid action selected."); break; } }; return (
{!isNil(comicBookDetailData) && !isEmpty(comicBookDetailData) && ( <>

{comicBookTitle}

{/* raw file details */}
{!isNil(comicBookDetailData.rawFileDetails) && ( <> )} {/* comic vine scraped metadata */} {!isNil(comicBookDetailData.sourcedMetadata.comicvine) && ( )}
{/* action dropdown */}