🔍 Improvements to CV search results

This commit is contained in:
2024-04-09 17:38:14 -04:00
parent 9315ad7454
commit 8fe49f7034
4 changed files with 179 additions and 54 deletions

View File

@@ -7,7 +7,7 @@ import Card from "../shared/Carda";
import ellipsize from "ellipsize"; 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 { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { import {
COMICVINE_SERVICE_URI, COMICVINE_SERVICE_URI,
LIBRARY_SERVICE_BASE_URI, LIBRARY_SERVICE_BASE_URI,
@@ -23,32 +23,31 @@ export const Search = ({}: ISearchProps): ReactElement => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [comicVineMetadata, setComicVineMetadata] = useState({}); const [comicVineMetadata, setComicVineMetadata] = useState({});
const getCVSearchResults = (searchQuery) => {
setSearchQuery(searchQuery.search);
};
const { const {
mutate,
data: comicVineSearchResults, data: comicVineSearchResults,
isLoading, isPending,
isSuccess, isSuccess,
} = useQuery({ } = useMutation({
queryFn: async () => mutationFn: async (data: { search: string; resource: string }) => {
await axios({ const { search, resource } = data;
console.log(data);
return await axios({
url: `${COMICVINE_SERVICE_URI}/search`, url: `${COMICVINE_SERVICE_URI}/search`,
method: "GET", method: "GET",
params: { params: {
api_key: "a5fa0663683df8145a85d694b5da4b87e1c92c69", api_key: "a5fa0663683df8145a85d694b5da4b87e1c92c69",
query: searchQuery, query: search,
format: "json", format: "json",
limit: "10", limit: "10",
offset: "0", offset: "0",
field_list: field_list:
"id,name,deck,api_detail_url,image,description,volume,cover_date", "id,name,deck,api_detail_url,image,description,volume,cover_date,count_of_issues",
resources: "issue", resources: resource,
}, },
}), });
queryKey: ["comicvineSearchResults", searchQuery], },
enabled: !isNil(searchQuery),
}); });
// add to library // add to library
@@ -107,7 +106,7 @@ export const Search = ({}: ISearchProps): ReactElement => {
</header> </header>
<div className="mx-auto max-w-screen-sm px-4 py-4 sm:px-6 sm:py-8 lg:px-8"> <div className="mx-auto max-w-screen-sm px-4 py-4 sm:px-6 sm:py-8 lg:px-8">
<Form <Form
onSubmit={getCVSearchResults} onSubmit={mutate}
initialValues={{ initialValues={{
...formData, ...formData,
}} }}
@@ -139,19 +138,62 @@ export const Search = ({}: ISearchProps): ReactElement => {
Search Search
</button> </button>
</div> </div>
{/* resource type selection: volume, issue etc. */}
<div className="flex flex-row gap-3 mt-4">
<Field name="resource" type="radio" value="volume">
{({ input: volumesInput, meta }) => (
<div className="w-fit rounded-xl">
<div>
<input
{...volumesInput}
type="radio"
id="volume"
className="peer hidden"
/>
<label
htmlFor="volume"
className="block cursor-pointer select-none rounded-xl p-2 text-center peer-checked:bg-blue-500 peer-checked:font-bold peer-checked:text-white"
>
Volumes
</label>
</div>
</div>
)}
</Field>
<Field name="resource" type="radio" value="issue">
{({ input: issuesInput, meta }) => (
<div className="w-fit rounded-xl">
<div>
<input
{...issuesInput}
type="radio"
id="issue"
className="peer hidden"
/>
<label
htmlFor="issue"
className="block cursor-pointer select-none rounded-xl p-2 text-center peer-checked:bg-blue-500 peer-checked:font-bold peer-checked:text-white"
>
Issues
</label>
</div>
</div>
)}
</Field>
</div>
</form> </form>
)} )}
/> />
</div> </div>
{isLoading && <>Loading kaka...</>} {isPending && <>Loading results...</>}
{!isNil(comicVineSearchResults?.data.results) && {!isEmpty(comicVineSearchResults?.data?.results) ? (
!isEmpty(comicVineSearchResults?.data.results) ? (
<div className="mx-auto max-w-screen-xl px-4 py-4 sm:px-6 sm:py-8 lg:px-8"> <div className="mx-auto max-w-screen-xl px-4 py-4 sm:px-6 sm:py-8 lg:px-8">
{comicVineSearchResults.data.results.map((result) => { {comicVineSearchResults.data.results.map((result) => {
return isSuccess ? ( return result.resource_type === "issue" ? (
<div key={result.id} className="mb-5"> <div key={result.id} className="mb-5">
<div className="flex flex-row"> <div className="flex flex-row">
<div className="mr-5"> <div className="mr-5 min-w-[200px] max-w-[25%]">
<Card <Card
key={result.id} key={result.id}
orientation={"cover-only"} orientation={"cover-only"}
@@ -159,7 +201,7 @@ export const Search = ({}: ISearchProps): ReactElement => {
hasDetails={false} hasDetails={false}
/> />
</div> </div>
<div className="column"> <div className="w-3/4">
<div className="text-xl"> <div className="text-xl">
{!isEmpty(result.volume.name) ? ( {!isEmpty(result.volume.name) ? (
result.volume.name result.volume.name
@@ -167,22 +209,14 @@ export const Search = ({}: ISearchProps): ReactElement => {
<span className="is-size-3">No Name</span> <span className="is-size-3">No Name</span>
)} )}
</div> </div>
<div className="field is-grouped mt-1"> {result.cover_date && (
<div className="control"> <p>
<div className="tags has-addons"> <span className="tag is-light">Cover date</span>
<span className="tag is-light">Cover date</span> {dayjs(result.cover_date).format("MMM D, YYYY")}
<span className="tag is-info is-light"> </p>
{dayjs(result.cover_date).format("MMM D, YYYY")} )}
</span>
</div>
</div>
<div className="control"> <p className="tag is-warning">{result.id}</p>
<div className="tags has-addons">
<span className="tag is-warning">{result.id}</span>
</div>
</div>
</div>
<a href={result.api_detail_url}> <a href={result.api_detail_url}>
{result.api_detail_url} {result.api_detail_url}
@@ -210,7 +244,72 @@ export const Search = ({}: ISearchProps): ReactElement => {
</div> </div>
</div> </div>
) : ( ) : (
<div>Loading</div> result.resource_type === "volume" && (
<div key={result.id} className="mb-5">
<div className="flex flex-row">
<div className="mr-5">
<Card
key={result.id}
orientation={"cover-only"}
imageUrl={result.image.small_url}
hasDetails={false}
/>
</div>
<div className="column">
<div className="text-xl">
{!isEmpty(result.name) ? (
result.name
) : (
<span className="is-size-3">No Name</span>
)}
</div>
<div className="field is-grouped mt-1">
<div className="control">
<div className="tags has-addons">
<span className="tag is-light">
Number of issues
</span>
<span className="tag is-info is-light">
{result.count_of_issues}
</span>
</div>
</div>
<div className="control">
<div className="tags has-addons">
<span className="tag is-warning">
{result.id}
</span>
</div>
</div>
</div>
<a href={result.api_detail_url}>
{result.api_detail_url}
</a>
<p>
{ellipsize(
convert(result.description, {
baseElements: {
selectors: ["p", "div"],
},
}),
320,
)}
</p>
<div className="mt-2">
<button
className="flex space-x-1 sm:mt-0 sm:flex-row sm:items-center rounded-lg border border-green-400 dark:border-green-200 bg-green-200 px-2 py-2 text-gray-500 hover:bg-transparent hover:text-green-600 focus:outline-none focus:ring active:text-indigo-500"
onClick={() => addToLibrary("comicvine", result)}
>
<i className="icon-[solar--add-square-bold-duotone] w-6 h-6 mr-2"></i>{" "}
Mark as Wanted
</button>
</div>
</div>
</div>
</div>
)
); );
})} })}
</div> </div>

View File

@@ -48,13 +48,11 @@ export const SystemSettingsForm = (): ReactElement => {
</article> </article>
<button <button
className={ className="flex space-x-1 sm:mt-0 sm:flex-row sm:items-center rounded-lg border border-red-400 dark:border-red-200 bg-red-200 px-4 py-2 text-gray-500 hover:bg-transparent hover:text-red-600 focus:outline-none focus:ring active:text-indigo-500"
isLoading ? "button is-danger is-loading" : "button is-danger"
}
onClick={() => flushDb()} onClick={() => flushDb()}
> >
<span className="icon"> <span className="pt-1 px-1">
<i className="fas fa-eraser"></i> <i className="icon-[solar--trash-bin-trash-bold-duotone] w-7 h-7"></i>
</span> </span>
<span>Flush DB & Temporary Folders</span> <span>Flush DB & Temporary Folders</span>
</button> </button>

View File

@@ -61,7 +61,7 @@ const VolumeDetails = (props): ReactElement => {
}), }),
queryKey: ["comicObject"], queryKey: ["comicObject"],
}); });
console.log(comicObject);
// get issues for a series // get issues for a series
const { const {
data: issuesForSeries, data: issuesForSeries,
@@ -108,7 +108,6 @@ const VolumeDetails = (props): ReactElement => {
status, status,
} = useGetStoryArcs(); } = useGetStoryArcs();
console.log("jihya", issuesForSeries);
const IssuesInVolume = () => ( const IssuesInVolume = () => (
<> <>
{!isUndefined(issuesForSeries) ? ( {!isUndefined(issuesForSeries) ? (
@@ -146,13 +145,42 @@ const VolumeDetails = (props): ReactElement => {
const Issues = () => ( const Issues = () => (
<> <>
as <article
<ul> role="alert"
className="mt-4 rounded-lg text-sm max-w-screen-md border-s-4 border-blue-500 bg-blue-50 p-4 dark:border-s-4 dark:border-blue-600 dark:bg-blue-300 dark:text-slate-600"
>
<div>
You can add a single issue or the whole volume, and it will be added
to the list of `Wanted` items.
</div>
</article>
<div className="flex flex-wrap">
{isSuccess && {isSuccess &&
issuesForSeries?.data.map((issue) => { issuesForSeries?.data.map((issue) => {
return <li>{JSON.stringify(issue, null, 2)}</li>; return (
<div className="my-3 dark:bg-slate-400 bg-slate-300 p-4 rounded-lg w-3/4">
<div className="flex flex-row gap-4 mb-2">
<div className="w-fit">
<img
src={issue.image.thumb_url}
className="w-full rounded-md"
/>
</div>
<div className="w-3/4">
<p className="text-xl">{issue.name}</p>
<p className="text-sm">
{convert(issue.description, {
baseElements: {
selectors: ["p"],
},
})}
</p>
</div>
</div>
</div>
);
})} })}
</ul> </div>
</> </>
); );
@@ -265,9 +293,9 @@ const VolumeDetails = (props): ReactElement => {
/> />
<div> <div>
<div className="field is-grouped mt-2"> <div className="field is-grouped">
{/* Title */} {/* Title */}
<span className="text-xl"> <span className="text-2xl">
{sourcedMetadata.comicvine.volumeInformation.name} {sourcedMetadata.comicvine.volumeInformation.name}
</span> </span>
{/* Comicvine Id */} {/* Comicvine Id */}

View File

@@ -58,10 +58,10 @@ export const Volumes = (props): ReactElement => {
hasDetails={false} hasDetails={false}
/> />
</Link> </Link>
<div className="dark:bg-[#647587] bg-slate-200 p-3 rounded-lg h-fit"> <div className="dark:bg-[#647587] bg-slate-200 rounded-lg w-3/4 h-fit p-3">
<span className="text-xl mb-1"> <div className="text-xl mb-1 w-fit">
{sourcedMetadata.comicvine.volumeInformation.name} {sourcedMetadata.comicvine.volumeInformation.name}
</span> </div>
<p> <p>
{ellipsize( {ellipsize(
convert( convert(
@@ -72,7 +72,7 @@ export const Volumes = (props): ReactElement => {
}, },
}, },
), ),
120, 180,
)} )}
</p> </p>
</div> </div>