🔍 CV search metadata wrangling
This commit is contained in:
@@ -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"],
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user