🏗️ Refactoring Volume groups and wanted panel

This commit is contained in:
2024-01-24 18:14:49 -05:00
parent c86d0d8b15
commit ada803d3cb
5 changed files with 106 additions and 77 deletions

View File

@@ -44,6 +44,22 @@ export const Dashboard = (): ReactElement => {
queryKey: ["recentComics"], queryKey: ["recentComics"],
}); });
const { data: wantedComics } = useQuery({
queryFn: async () =>
await axios({
url: `${LIBRARY_SERVICE_BASE_URI}/getComicBooks`,
method: "POST",
data: {
paginationOptions: {
page: 0,
limit: 5,
sort: { updatedAt: "-1" },
},
predicate: { "acquisition.source.wanted": true },
},
}),
queryKey: ["wantedComics"],
});
const { data: volumeGroups } = useQuery({ const { data: volumeGroups } = useQuery({
queryFn: async () => queryFn: async () =>
await axios({ await axios({
@@ -201,9 +217,9 @@ export const Dashboard = (): ReactElement => {
)} )}
</div> </div>
</section> </section>
{/* Wanted comics */}
<WantedComicsList comics={wantedComics?.data?.docs} />
{/* Volume groups */} {/* Volume groups */}
<VolumeGroups volumeGroups={volumeGroups?.data} /> <VolumeGroups volumeGroups={volumeGroups?.data} />
</div> </div>
); );

View File

@@ -5,12 +5,6 @@ import { Link, useNavigate } from "react-router-dom";
import Card from "../shared/Carda"; import Card from "../shared/Carda";
export const VolumeGroups = (props): ReactElement => { export const VolumeGroups = (props): ReactElement => {
const breakpointColumnsObj = {
default: 5,
1100: 4,
700: 2,
500: 1,
};
// Till mongo gives us back the deduplicated results with the ObjectId // Till mongo gives us back the deduplicated results with the ObjectId
const deduplicatedGroups = unionBy(props.volumeGroups, "volumes.id"); const deduplicatedGroups = unionBy(props.volumeGroups, "volumes.id");
const navigate = useNavigate(); const navigate = useNavigate();
@@ -19,29 +13,29 @@ export const VolumeGroups = (props): ReactElement => {
}; };
return ( return (
<section className="volumes-container mt-4"> <section className="mt-7">
<div className="content"> <div className="">
<a className="mb-1" onClick={navigateToVolumes}> <a className="" onClick={navigateToVolumes}>
<span className="is-size-4 has-text-weight-semibold"> <span className="text-xl">
<i className="fa-solid fa-layer-group"></i> Volumes <i className="fa-solid fa-layer-group"></i> Volumes
</span> </span>
<span className="icon mt-1"> <span className="icon mt-1">
<i className="fa-solid fa-angle-right"></i> <i className="fa-solid fa-angle-right"></i>
</span> </span>
</a> </a>
<p className="subtitle is-7">Based on ComicVine Volume information</p> <p className="">Based on ComicVine Volume information</p>
</div> </div>
<div className="grid grid-cols-5 gap-6"> <div className="grid grid-cols-5 gap-6 mt-3">
{map(deduplicatedGroups, (data) => { {map(deduplicatedGroups, (data) => {
return ( return (
<div className="max-w-sm py-8 mx-auto" key={data._id}> <div className="max-w-sm mx-auto" key={data._id}>
<Card <Card
orientation="vertical-2" orientation="vertical-2"
key={data._id} key={data._id}
imageUrl={data.volumes.image.small_url} imageUrl={data.volumes.image.small_url}
hasDetails hasDetails
> >
<div className="py-2"> <div className="py-3">
<div className="text-sm"> <div className="text-sm">
<Link to={`/volume/details/${data._id}`}> <Link to={`/volume/details/${data._id}`}>
{ellipsize(data.volumes.name, 48)} {ellipsize(data.volumes.name, 48)}

View File

@@ -4,7 +4,6 @@ import { Link, useNavigate } from "react-router-dom";
import ellipsize from "ellipsize"; import ellipsize from "ellipsize";
import { isEmpty, isNil, isUndefined, map } from "lodash"; import { isEmpty, isNil, isUndefined, map } from "lodash";
import { detectIssueTypes } from "../../shared/utils/tradepaperback.utils"; import { detectIssueTypes } from "../../shared/utils/tradepaperback.utils";
import Masonry from "react-masonry-css";
import { determineCoverFile } from "../../shared/utils/metadata.utils"; import { determineCoverFile } from "../../shared/utils/metadata.utils";
type WantedComicsListProps = { type WantedComicsListProps = {
@@ -14,37 +13,25 @@ type WantedComicsListProps = {
export const WantedComicsList = ({ export const WantedComicsList = ({
comics, comics,
}: WantedComicsListProps): ReactElement => { }: WantedComicsListProps): ReactElement => {
const breakpointColumnsObj = { console.log("yolo", comics);
default: 5,
1100: 4,
700: 2,
500: 1,
};
const navigate = useNavigate(); const navigate = useNavigate();
const navigateToWantedComics = (row) => { const navigateToWantedComics = (row) => {
navigate(`/wanted/all`); navigate(`/wanted/all`);
}; };
return ( return (
<> <>
<div className="content mt-6"> <div className="mt-7">
<a className="mb-1" onClick={navigateToWantedComics}> <a className="" onClick={navigateToWantedComics}>
<span className="is-size-4 has-text-weight-semibold"> <span className="text-xl">
<i className="fa-solid fa-asterisk"></i> Wanted Comics <i className=""></i> Wanted Comics
</span> </span>
<span className="icon mt-1"> <span className="">
<i className="fa-solid fa-angle-right"></i> <i className=""></i>
</span> </span>
</a> </a>
<p className="subtitle is-7"> <p className="">Comics marked as wanted from various sources.</p>
Comics marked as wanted from various sources.
</p>
</div> </div>
<Masonry <div className="grid grid-cols-5 gap-6 mt-3">
breakpointCols={breakpointColumnsObj}
className="recent-comics-container"
columnClassName="recent-comics-column"
>
{map( {map(
comics, comics,
({ ({
@@ -73,29 +60,32 @@ export const WantedComicsList = ({
return ( return (
<Card <Card
key={_id} key={_id}
orientation={"vertical"} orientation={"vertical-2"}
imageUrl={url} imageUrl={url}
hasDetails hasDetails
title={issueName ? titleElement : <span>No Name</span>} title={issueName ? titleElement : <span>No Name</span>}
> >
<div className="content is-flex is-flex-direction-row"> <div className="pb-1">
{/* comicVine metadata presence */} {/* comicVine metadata presence */}
{isComicBookMetadataAvailable && ( {isComicBookMetadataAvailable && (
<span className="icon custom-icon"> <img
<img src="/src/client/assets/img/cvlogo.svg" /> src="/src/client/assets/img/cvlogo.svg"
</span> alt={"ComicVine metadata detected."}
className="w-7 h-7"
/>
)} )}
{!isEmpty(locg) && ( {!isEmpty(locg) && (
<span className="icon custom-icon"> <img
<img src="/src/client/assets/img/locglogo.svg" /> src="/src/client/assets/img/locglogo.svg"
</span> className="w-7 h-7"
/>
)} )}
{/* Issue type */} {/* Issue type */}
{isComicBookMetadataAvailable && {isComicBookMetadataAvailable &&
!isNil( !isNil(
detectIssueTypes(comicvine.volumeInformation.description), detectIssueTypes(comicvine.volumeInformation.description),
) ? ( ) ? (
<span className="tag is-warning"> <span className="">
{ {
detectIssueTypes( detectIssueTypes(
comicvine.volumeInformation.description, comicvine.volumeInformation.description,
@@ -108,7 +98,7 @@ export const WantedComicsList = ({
); );
}, },
)} )}
</Masonry> </div>
</> </>
); );
}; };

View File

@@ -10,7 +10,10 @@ import ellipsize from "ellipsize";
import { convert } from "html-to-text"; import { convert } from "html-to-text";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { COMICVINE_SERVICE_URI } from "../../constants/endpoints"; import {
COMICVINE_SERVICE_URI,
LIBRARY_SERVICE_BASE_URI,
} from "../../constants/endpoints";
import axios from "axios"; import axios from "axios";
interface ISearchProps {} interface ISearchProps {}
@@ -21,6 +24,7 @@ export const Search = ({}: ISearchProps): ReactElement => {
}; };
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [comicVineMetadata, setComicVineMetadata] = useState({});
const getCVSearchResults = (searchQuery) => { const getCVSearchResults = (searchQuery) => {
console.log(searchQuery); console.log(searchQuery);
setSearchQuery(searchQuery.search); setSearchQuery(searchQuery.search);
@@ -50,16 +54,40 @@ export const Search = ({}: ISearchProps): ReactElement => {
queryKey: ["comicvineSearchResults", searchQuery], queryKey: ["comicvineSearchResults", searchQuery],
enabled: !isNil(searchQuery), enabled: !isNil(searchQuery),
}); });
console.log(comicVineSearchResults);
const addToLibrary = useCallback(
(sourceName: string, comicData) =>
importToDB(sourceName, { comicvine: comicData }),
[],
);
// const comicVineSearchResults = useSelector( // add to library
// (state: RootState) => state.comicInfo.searchResults, const { data: additionResult } = useQuery({
// ); queryFn: async () =>
await axios({
url: `${LIBRARY_SERVICE_BASE_URI}/rawImportToDb`,
method: "POST",
data: {
importType: "new",
payload: {
rawFileDetails: {
name: "",
},
importStatus: {
isImported: true,
tagged: false,
matchedResult: {
score: "0",
},
},
sourcedMetadata:
{ comicvine: comicVineMetadata?.comicData } || null,
acquisition: { source: { wanted: true, name: "comicvine" } },
},
},
}),
queryKey: ["additionResult"],
enabled: !isNil(comicVineMetadata.comicData),
});
console.log(comicVineMetadata);
const addToLibrary = (sourceName: string, comicData) =>
setComicVineMetadata({ sourceName, comicData });
const createDescriptionMarkup = (html) => { const createDescriptionMarkup = (html) => {
return { __html: html }; return { __html: html };
}; };
@@ -67,8 +95,8 @@ export const Search = ({}: ISearchProps): ReactElement => {
return ( return (
<> <>
<section className="container"> <section className="container">
<div className="section search"> <div className="">
<h1 className="title">Search</h1> <h1 className="">Search</h1>
<Form <Form
onSubmit={getCVSearchResults} onSubmit={getCVSearchResults}
@@ -76,8 +104,8 @@ export const Search = ({}: ISearchProps): ReactElement => {
...formData, ...formData,
}} }}
render={({ handleSubmit, form, submitting, pristine, values }) => ( render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit} className="form columns search"> <form onSubmit={handleSubmit}>
<div className="column is-three-quarters search"> <div>
<Field name="search"> <Field name="search">
{({ input, meta }) => { {({ input, meta }) => {
return ( return (
@@ -103,16 +131,15 @@ export const Search = ({}: ISearchProps): ReactElement => {
<div className=""> <div className="">
{comicVineSearchResults.data.results.map((result) => { {comicVineSearchResults.data.results.map((result) => {
return isSuccess ? ( return isSuccess ? (
<div key={result.id} className=""> <div key={result.id} className="mb-5">
<div className="flex flex-row"> <div className="flex flex-row">
<div className="max-w-150 mr-5"> <div className="mr-5">
<Card <Card
key={result.id} key={result.id}
orientation={"vertical-2"} orientation={"cover-only"}
imageUrl={result.image.small_url} imageUrl={result.image.small_url}
title={result.name}
hasDetails={false} hasDetails={false}
></Card> />
</div> </div>
<div className="column"> <div className="column">
<div className="text-xl"> <div className="text-xl">

View File

@@ -90,17 +90,19 @@ const renderCard = (props: ICardProps): ReactElement => {
className="rounded-t-md object-cover" className="rounded-t-md object-cover"
/> />
<div className="mt-2 px-2"> {props.title ? (
<dl> <div className="px-3 pt-3 mb-2">
<div> <dd className="text-sm text-slate-500 dark:text-black">
<dd className="text-sm text-slate-500 dark:text-black"> {props.title}
{props.title} </dd>
</dd> </div>
</div> ) : null}
</dl>
{props.hasDetails && <>{props.children}</>} {props.hasDetails ? (
</div> <div className="px-2">
<>{props.children}</>
</div>
) : null}
</div> </div>
); );