import React, { ReactElement, useState } from "react"; import { isNil, isEmpty, isUndefined } from "lodash"; import { IExtractedComicBookCoverFile, RootState } from "threetwo-ui-typings"; import { detectIssueTypes } from "../../shared/utils/tradepaperback.utils"; import { Form, Field } from "react-final-form"; import Card from "../shared/Carda"; import ellipsize from "ellipsize"; import { convert } from "html-to-text"; import { useTranslation } from "react-i18next"; import "../../shared/utils/i18n.util"; import PopoverButton from "../shared/PopoverButton"; import dayjs from "dayjs"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { COMICVINE_SERVICE_URI, LIBRARY_SERVICE_BASE_URI, } from "../../constants/endpoints"; import axios from "axios"; import type { SearchPageProps } from "../../types"; export const Search = ({}: SearchPageProps): ReactElement => { const queryClient = useQueryClient(); const formData = { search: "", }; const [comicVineMetadata, setComicVineMetadata] = useState({}); const [selectedResource, setSelectedResource] = useState("volume"); const { t } = useTranslation(); const handleResourceChange = (value) => { setSelectedResource(value); }; const { mutate, data: comicVineSearchResults, isPending, isSuccess, } = useMutation({ mutationFn: async (data: { search: string; resource: string }) => { const { search, resource } = data; return await axios({ url: `${COMICVINE_SERVICE_URI}/search`, method: "GET", params: { api_key: "a5fa0663683df8145a85d694b5da4b87e1c92c69", query: search, format: "json", limit: "10", offset: "0", field_list: "id,name,deck,api_detail_url,image,description,volume,cover_date,start_year,count_of_issues,publisher,issue_number", resources: resource, }, }); }, }); // add to library const { data: additionResult, mutate: addToWantedList } = useMutation({ mutationFn: async ({ source, comicObject, markEntireVolumeWanted, resourceType, }) => { let volumeInformation = {}; let issues = []; switch (resourceType) { case "issue": const { id, api_detail_url, image, cover_date, issue_number } = comicObject; // Add issue metadata issues.push({ id, url: api_detail_url, image, coverDate: cover_date, issueNumber: issue_number, }); // Get volume metadata from CV const response = await axios({ url: `${COMICVINE_SERVICE_URI}/getVolumes`, method: "POST", data: { volumeURI: comicObject.volume.api_detail_url, fieldList: "id,name,deck,api_detail_url,image,description,start_year,year,count_of_issues,publisher,first_issue,last_issue", }, }); // set volume metadata key volumeInformation = response.data?.results; break; case "volume": const { id: volumeId, api_detail_url: apiUrl, image: volumeImage, name, publisher, } = comicObject; volumeInformation = { id: volumeId, url: apiUrl, image: volumeImage, name, publisher, }; break; default: break; } // Add to wanted list return await axios({ url: `${LIBRARY_SERVICE_BASE_URI}/rawImportToDb`, method: "POST", data: { importType: "new", payload: { importStatus: { isImported: false, // wanted, but not acquired yet. tagged: false, matchedResult: { score: "0", }, }, wanted: { source, markEntireVolumeWanted, issues, volume: volumeInformation, }, sourcedMetadata: { comicvine: volumeInformation }, }, }, }); }, onSuccess: () => { // Invalidate and refetch wanted comics queries queryClient.invalidateQueries({ queryKey: ["wantedComics"] }); }, }); const addToLibrary = (sourceName: string, comicData) => setComicVineMetadata({ sourceName, comicData }); const createDescriptionMarkup = (html) => { return { __html: html }; }; const onSubmit = async (values) => { const formData = { ...values, resource: selectedResource }; try { mutate(formData); } catch (error) { // Handle error } }; return (

Search

Browse your comic book collection.

(
{({ input, meta }) => { return ( ); }}
{/* resource type selection: volume, issue etc. */}
{({ input: volumesInput, meta }) => (
handleResourceChange("volume")} className="peer hidden" />
)}
{({ input: issuesInput, meta }) => (
handleResourceChange("issue")} className="peer hidden" />
)}
)} />
{isPending && (
Loading results...
)} {!isEmpty(comicVineSearchResults?.data?.results) ? (
{comicVineSearchResults.data.results.map((result) => { return result.resource_type === "issue" ? (
{!isEmpty(result.volume.name) ? ( result.volume.name ) : ( No Name )}
{result.cover_date && (

Cover date {dayjs(result.cover_date).format("MMM D, YYYY")}

)}

{result.id}

{result.api_detail_url}

{ellipsize( convert(result.description, { baseElements: { selectors: ["p", "div"], }, }), 320, )}

addToWantedList({ source: "comicvine", comicObject: result, markEntireVolumeWanted: false, resourceType: "issue", }) } />
) : ( result.resource_type === "volume" && (
{!isEmpty(result.name) ? ( result.name ) : ( No Name )} {result.start_year && <> ({result.start_year})}
{/* issue count */} {result.count_of_issues && (
{t("issueWithCount", { count: result.count_of_issues, })}
)} {/* type: TPB, one-shot, graphic novel etc. */} {!isNil(result.description) && !isUndefined(result.description) && ( <> {!isEmpty( detectIssueTypes(result.description), ) && (
{ detectIssueTypes(result.description) .displayName }
)} )}
{result.id}

{result.api_detail_url}

{/* description */}

{ellipsize( convert(result.description, { baseElements: { selectors: ["p", "div"], }, }), 320, )}

addToWantedList({ source: "comicvine", comicObject: result, markEntireVolumeWanted: true, resourceType: "volume", }) } />
) ); })}
) : (

Search the ComicVine database

Note that you need an instance of AirDC++ already running to use this form to connect to it.

Search and add issues, series and trade paperbacks to your library. Then, download them using the configured AirDC++ or torrent clients.

)}
); }; export default Search;