🔍 CV search metadata wrangling

This commit is contained in:
2024-04-14 00:25:17 -04:00
parent 6de8517bb5
commit 1de01e7dbd
6 changed files with 141 additions and 80 deletions

View File

@@ -21,13 +21,15 @@ export const Dashboard = (): ReactElement => {
limit: 5, limit: 5,
sort: { updatedAt: "-1" }, sort: { updatedAt: "-1" },
}, },
predicate: { "acquisition.source.wanted": false }, predicate: {
wanted: { $exists: false },
},
comicStatus: "recent", comicStatus: "recent",
}, },
}), }),
queryKey: ["recentComics"], queryKey: ["recentComics"],
}); });
// Wanted Comics
const { data: wantedComics } = useQuery({ const { data: wantedComics } = useQuery({
queryFn: async () => queryFn: async () =>
await axios({ await axios({
@@ -39,7 +41,9 @@ export const Dashboard = (): ReactElement => {
limit: 5, limit: 5,
sort: { updatedAt: "-1" }, sort: { updatedAt: "-1" },
}, },
predicate: { "acquisition.source.wanted": true }, predicate: {
wanted: { $exists: true, $ne: null },
},
}, },
}), }),
queryKey: ["wantedComics"], queryKey: ["wantedComics"],

View File

@@ -18,6 +18,7 @@ type RecentlyImportedProps = {
export const RecentlyImported = ( export const RecentlyImported = (
comics: RecentlyImportedProps, comics: RecentlyImportedProps,
): ReactElement => { ): ReactElement => {
console.log(comics);
return ( return (
<div> <div>
<Header <Header
@@ -33,9 +34,7 @@ export const RecentlyImported = (
rawFileDetails, rawFileDetails,
sourcedMetadata: { comicvine, comicInfo, locg }, sourcedMetadata: { comicvine, comicInfo, locg },
inferredMetadata, inferredMetadata,
acquisition: { wanted: { source } = {},
source: { name },
},
}, },
idx, idx,
) => { ) => {
@@ -45,11 +44,14 @@ export const RecentlyImported = (
comicInfo, comicInfo,
locg, locg,
}); });
const { issue, coverURL, icon } = determineExternalMetadata(name, { const { issue, coverURL, icon } = determineExternalMetadata(
comicvine, source,
comicInfo, {
locg, comicvine,
}); comicInfo,
locg,
},
);
const isComicVineMetadataAvailable = const isComicVineMetadataAvailable =
!isUndefined(comicvine) && !isUndefined(comicvine) &&
!isUndefined(comicvine.volumeInformation); !isUndefined(comicvine.volumeInformation);

View File

@@ -31,10 +31,9 @@ export const WantedComicsList = ({
_id, _id,
rawFileDetails, rawFileDetails,
sourcedMetadata: { comicvine, comicInfo, locg }, sourcedMetadata: { comicvine, comicInfo, locg },
wanted,
}) => { }) => {
const isComicBookMetadataAvailable = const isComicBookMetadataAvailable = !isUndefined(comicvine);
!isUndefined(comicvine) &&
!isUndefined(comicvine.volumeInformation);
const consolidatedComicMetadata = { const consolidatedComicMetadata = {
rawFileDetails, rawFileDetails,
comicvine, comicvine,
@@ -42,12 +41,15 @@ export const WantedComicsList = ({
locg, locg,
}; };
const { issueName, url } = determineCoverFile( const {
consolidatedComicMetadata, issueName,
); url,
publisher = null,
} = determineCoverFile(consolidatedComicMetadata);
const titleElement = ( const titleElement = (
<Link to={"/comic/details/" + _id}> <Link to={"/comic/details/" + _id}>
{ellipsize(issueName, 20)} {ellipsize(issueName, 20)}
<p>{publisher}</p>
</Link> </Link>
); );
return ( return (
@@ -61,9 +63,7 @@ export const WantedComicsList = ({
<div className="pb-1"> <div className="pb-1">
{/* Issue type */} {/* Issue type */}
{isComicBookMetadataAvailable && {isComicBookMetadataAvailable &&
!isNil( !isNil(detectIssueTypes(comicvine.description)) ? (
detectIssueTypes(comicvine.volumeInformation.description),
) ? (
<div className="my-2"> <div className="my-2">
<span className="inline-flex items-center bg-slate-50 text-slate-800 text-xs font-medium px-2.5 py-0.5 rounded-md dark:text-slate-900 dark:bg-slate-400"> <span className="inline-flex items-center bg-slate-50 text-slate-800 text-xs font-medium px-2.5 py-0.5 rounded-md dark:text-slate-900 dark:bg-slate-400">
<span className="pr-1 pt-1"> <span className="pr-1 pt-1">
@@ -71,11 +71,7 @@ export const WantedComicsList = ({
</span> </span>
<span className="text-md text-slate-500 dark:text-slate-900"> <span className="text-md text-slate-500 dark:text-slate-900">
{ {detectIssueTypes(comicvine.description).displayName}
detectIssueTypes(
comicvine.volumeInformation.description,
).displayName
}
</span> </span>
</span> </span>
</div> </div>

View File

@@ -49,7 +49,7 @@ export const Search = ({}: ISearchProps): ReactElement => {
limit: "10", limit: "10",
offset: "0", offset: "0",
field_list: field_list:
"id,name,deck,api_detail_url,image,description,volume,cover_date,start_year,count_of_issues", "id,name,deck,api_detail_url,image,description,volume,cover_date,start_year,count_of_issues,publisher",
resources: resource, resources: resource,
}, },
}); });
@@ -57,17 +57,49 @@ export const Search = ({}: ISearchProps): ReactElement => {
}); });
// add to library // add to library
const { data: additionResult } = useQuery({ const { data: additionResult, mutate: addToWantedList } = useMutation({
queryFn: async () => mutationFn: async ({
await axios({ source,
comicObject,
markEntireVolumeWanted,
resourceType,
}) => {
console.log("jigni", comicObject);
let volumeInformation = {};
let issues = [];
switch (resourceType) {
case "issue":
const { id, api_detail_url, image } = comicObject;
// Add issue metadata
issues.push({ id, api_detail_url, image });
// Get volume metadata from CV
console.log("volume", comicObject.volume.id);
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,count_of_issues,publisher,first_issue,last_issue",
},
});
console.log("boogie", response.data);
volumeInformation = response.data?.results;
break;
case "volume":
volumeInformation = comicObject;
break;
default:
break;
}
return await axios({
url: `${LIBRARY_SERVICE_BASE_URI}/rawImportToDb`, url: `${LIBRARY_SERVICE_BASE_URI}/rawImportToDb`,
method: "POST", method: "POST",
data: { data: {
importType: "new", importType: "new",
payload: { payload: {
rawFileDetails: {
name: "",
},
importStatus: { importStatus: {
isImported: true, isImported: true,
tagged: false, tagged: false,
@@ -75,14 +107,17 @@ export const Search = ({}: ISearchProps): ReactElement => {
score: "0", score: "0",
}, },
}, },
sourcedMetadata: wanted: {
{ comicvine: comicVineMetadata?.comicData } || null, source,
acquisition: { source: { wanted: true, name: "comicvine" } }, markEntireVolumeWanted,
issues,
volume: {},
},
sourcedMetadata: { comicvine: volumeInformation } || null,
}, },
}, },
}), });
queryKey: ["additionResult"], },
enabled: !isNil(comicVineMetadata.comicData),
}); });
const addToLibrary = (sourceName: string, comicData) => const addToLibrary = (sourceName: string, comicData) =>
@@ -93,11 +128,9 @@ export const Search = ({}: ISearchProps): ReactElement => {
}; };
const onSubmit = async (values) => { const onSubmit = async (values) => {
// Include the selected resource value in the form data
const formData = { ...values, resource: selectedResource }; const formData = { ...values, resource: selectedResource };
try { try {
mutate(formData); mutate(formData);
// Handle response
} catch (error) { } catch (error) {
// Handle error // Handle error
} }
@@ -260,13 +293,17 @@ export const Search = ({}: ISearchProps): ReactElement => {
)} )}
</p> </p>
<div className="mt-2"> <div className="mt-2">
<button <PopoverButton
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" content={`This will add ${result.volume.name} to your wanted list.`}
onClick={() => addToLibrary("comicvine", result)} clickHandler={() =>
> addToWantedList({
<i className="icon-[solar--add-square-bold-duotone] w-6 h-6 mr-2"></i>{" "} source: "comicvine",
Mark as Wanted comicObject: result,
</button> markEntireVolumeWanted: false,
resourceType: "issue",
})
}
/>
</div> </div>
</div> </div>
</div> </div>
@@ -365,8 +402,15 @@ export const Search = ({}: ISearchProps): ReactElement => {
count: result.count_of_issues, count: result.count_of_issues,
}, },
)} to your wanted list.`} )} to your wanted list.`}
clickHandler={() =>
addToWantedList({
source: "comicvine",
comicObject: result,
markEntireVolumeWanted: true,
resourceType: "volume",
})
}
/> />
{/* onClick={() => addToLibrary("comicvine", result) */}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { useFloating, offset, flip } from "@floating-ui/react-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import "../../shared/utils/i18n.util"; // Ensure you import your i18n configuration import "../../shared/utils/i18n.util"; // Ensure you import your i18n configuration
const PopoverButton = ({ content }) => { const PopoverButton = ({ content, clickHandler }) => {
const [isVisible, setIsVisible] = useState(false); const [isVisible, setIsVisible] = useState(false);
// Use destructuring to obtain the reference and floating setters, among other values. // Use destructuring to obtain the reference and floating setters, among other values.
const { x, y, refs, strategy, floatingStyles } = useFloating({ const { x, y, refs, strategy, floatingStyles } = useFloating({
@@ -23,6 +23,7 @@ const PopoverButton = ({ content }) => {
onBlur={() => setIsVisible(false)} onBlur={() => setIsVisible(false)}
aria-describedby="popover" aria-describedby="popover"
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" 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={clickHandler}
> >
<i className="icon-[solar--add-square-bold-duotone] w-6 h-6 mr-2"></i>{" "} <i className="icon-[solar--add-square-bold-duotone] w-6 h-6 mr-2"></i>{" "}
Mark as Wanted Mark as Wanted

View File

@@ -1,11 +1,12 @@
import { filter, isEmpty, isUndefined, min, minBy } from "lodash"; import { filter, isEmpty, isNil, isUndefined, min, minBy } from "lodash";
import { LIBRARY_SERVICE_HOST } from "../../constants/endpoints"; import { LIBRARY_SERVICE_HOST } from "../../constants/endpoints";
import { escapePoundSymbol } from "./formatting.utils"; import { escapePoundSymbol } from "./formatting.utils";
export const determineCoverFile = (data) => { export const determineCoverFile = (data): any => {
/* For a payload like this: /* For a payload like this:
const foo = { const foo = {
rawFileDetails: {}, // #1 rawFileDetails: {}, // #1
wanted: {},
comicInfo: {}, comicInfo: {},
comicvine: {}, // #2 comicvine: {}, // #2
locg: {}, // #3 locg: {}, // #3
@@ -19,36 +20,44 @@ export const determineCoverFile = (data) => {
issueName: "", issueName: "",
publisher: "", publisher: "",
}, },
wanted: {
objectReference: "wanted",
priority: 2,
url: "",
issueName: "",
publisher: "",
},
comicvine: { comicvine: {
objectReference: "comicvine", objectReference: "comicvine",
priority: 2, priority: 3,
url: "", url: "",
issueName: "", issueName: "",
publisher: "", publisher: "",
}, },
locg: { locg: {
objectReference: "locg", objectReference: "locg",
priority: 3, priority: 4,
url: "", url: "",
issueName: "", issueName: "",
publisher: "", publisher: "",
}, },
}; };
if ( // comicvine
!isUndefined(data.comicvine) && if (!isUndefined(data.comicvine)) {
!isUndefined(data.comicvine.volumeInformation) coverFile.comicvine.url = data?.comicvine?.image.small_url;
) {
coverFile.comicvine.url = data.comicvine.image.small_url;
coverFile.comicvine.issueName = data.comicvine.name; coverFile.comicvine.issueName = data.comicvine.name;
coverFile.comicvine.publisher = data.comicvine.volumeInformation.publisher; coverFile.comicvine.publisher = data.comicvine.publisher.name;
} }
if (!isEmpty(data.rawFileDetails.cover)) { // rawFileDetails
if (!isEmpty(data.rawFileDetails)) {
const encodedFilePath = encodeURI( const encodedFilePath = encodeURI(
`${LIBRARY_SERVICE_HOST}/${data.rawFileDetails.cover.filePath}`, `${LIBRARY_SERVICE_HOST}/${data.rawFileDetails.cover.filePath}`,
); );
coverFile.rawFile.url = escapePoundSymbol(encodedFilePath); coverFile.rawFile.url = escapePoundSymbol(encodedFilePath);
coverFile.rawFile.issueName = data.rawFileDetails.name; coverFile.rawFile.issueName = data.rawFileDetails.name;
} }
// wanted
if (!isUndefined(data.locg)) { if (!isUndefined(data.locg)) {
coverFile.locg.url = data.locg.cover; coverFile.locg.url = data.locg.cover;
coverFile.locg.issueName = data.locg.name; coverFile.locg.issueName = data.locg.name;
@@ -69,25 +78,30 @@ export const determineCoverFile = (data) => {
export const determineExternalMetadata = ( export const determineExternalMetadata = (
metadataSource: string, metadataSource: string,
source: any source: any,
) => { ): any => {
switch (metadataSource) { if (!isNil(source)) {
case "comicvine": switch (metadataSource) {
return { case "comicvine":
coverURL: source.comicvine.image.small_url, return {
issue: source.comicvine.name, coverURL:
icon: "cvlogo.svg", source.comicvine?.image.small_url ||
}; source.comicvine.volumeInformation?.image.small_url,
case "locg": issue: source.comicvine.name,
return { icon: "cvlogo.svg",
coverURL: source.locg.cover, };
issue: source.locg.name, case "locg":
icon: "locglogo.svg", return {
}; coverURL: source.locg.cover,
case undefined: issue: source.locg.name,
return {}; icon: "locglogo.svg",
};
case undefined:
return {};
default: default:
break; break;
}
} }
}; return null;
};