🏗️ Refactored the action menu
This commit is contained in:
@@ -1,157 +1,13 @@
|
|||||||
import { filter, isEmpty, isNil, isUndefined } from "lodash";
|
import React, { ReactElement } from "react";
|
||||||
import React, { ReactElement, useCallback, useState } from "react";
|
import Select from "react-select";
|
||||||
import Select, { components } from "react-select";
|
|
||||||
import { fetchComicVineMatches } from "../../../actions/fileops.actions";
|
|
||||||
import { refineQuery } from "filename-parser";
|
|
||||||
import { COMICVINE_SERVICE_URI } from "../../../constants/endpoints";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export const Menu = (props): ReactElement => {
|
export const Menu = (props): ReactElement => {
|
||||||
const { data } = props;
|
const {
|
||||||
const { setSlidingPanelContentId, setVisible } = props.handlers;
|
filteredActionOptions,
|
||||||
const [comicVineMatches, setComicVineMatches] = useState([]);
|
customStyles,
|
||||||
|
handleActionSelection,
|
||||||
const fetchComicVineMatches = async (
|
Placeholder,
|
||||||
searchPayload,
|
} = props.configuration;
|
||||||
issueSearchQuery,
|
|
||||||
seriesSearchQuery,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
await axios
|
|
||||||
.request({
|
|
||||||
url: `${COMICVINE_SERVICE_URI}/volumeBasedSearch`,
|
|
||||||
method: "POST",
|
|
||||||
data: {
|
|
||||||
format: "json",
|
|
||||||
// hack
|
|
||||||
query: issueSearchQuery.inferredIssueDetails.name
|
|
||||||
.replace(/[^a-zA-Z0-9 ]/g, "")
|
|
||||||
.trim(),
|
|
||||||
limit: "100",
|
|
||||||
page: 1,
|
|
||||||
resources: "volume",
|
|
||||||
scorerConfiguration: {
|
|
||||||
searchParams: issueSearchQuery.inferredIssueDetails,
|
|
||||||
},
|
|
||||||
rawFileDetails: searchPayload.rawFileDetails,
|
|
||||||
},
|
|
||||||
transformResponse: (r) => {
|
|
||||||
const matches = JSON.parse(r);
|
|
||||||
return matches;
|
|
||||||
// return sortBy(matches, (match) => -match.score);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
let matches: any = [];
|
|
||||||
if (
|
|
||||||
!isNil(response.data.results) &&
|
|
||||||
response.data.results.length === 1
|
|
||||||
) {
|
|
||||||
matches = response.data.results;
|
|
||||||
} else {
|
|
||||||
matches = response.data.map((match) => match);
|
|
||||||
}
|
|
||||||
setComicVineMatches(matches);
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const openDrawerWithCVMatches = () => {
|
|
||||||
let seriesSearchQuery: IComicVineSearchQuery = {} as IComicVineSearchQuery;
|
|
||||||
let issueSearchQuery: IComicVineSearchQuery = {} as IComicVineSearchQuery;
|
|
||||||
|
|
||||||
if (!isUndefined(data.rawFileDetails)) {
|
|
||||||
issueSearchQuery = refineQuery(data.rawFileDetails.name);
|
|
||||||
} else if (!isEmpty(data.sourcedMetadata)) {
|
|
||||||
issueSearchQuery = refineQuery(data.sourcedMetadata.comicvine.name);
|
|
||||||
}
|
|
||||||
fetchComicVineMatches(data, issueSearchQuery, seriesSearchQuery);
|
|
||||||
setSlidingPanelContentId("CVMatches");
|
|
||||||
setVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const openEditMetadataPanel = useCallback(() => {
|
|
||||||
setSlidingPanelContentId("editComicBookMetadata");
|
|
||||||
setVisible(true);
|
|
||||||
}, []);
|
|
||||||
// Actions menu options and handler
|
|
||||||
const CVMatchLabel = (
|
|
||||||
<span className="inline-flex flex-row items-center gap-2">
|
|
||||||
<div className="w-6 h-6">
|
|
||||||
<i className="icon-[solar--magic-stick-3-bold-duotone] w-6 h-6"></i>
|
|
||||||
</div>
|
|
||||||
<div>Match on ComicVine</div>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
const editLabel = (
|
|
||||||
<span className="inline-flex flex-row items-center gap-2">
|
|
||||||
<div className="w-6 h-6">
|
|
||||||
<i className="icon-[solar--pen-2-bold-duotone] w-6 h-6"></i>
|
|
||||||
</div>
|
|
||||||
<div>Edit Metadata</div>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
const deleteLabel = (
|
|
||||||
<span className="inline-flex flex-row items-center gap-2">
|
|
||||||
<div className="w-6 h-6">
|
|
||||||
<i className="icon-[solar--trash-bin-trash-bold-duotone] w-6 h-6"></i>
|
|
||||||
</div>
|
|
||||||
<div>Delete Comic</div>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
const Placeholder = (props) => {
|
|
||||||
return <components.Placeholder {...props} />;
|
|
||||||
};
|
|
||||||
const actionOptions = [
|
|
||||||
{ value: "match-on-comic-vine", label: CVMatchLabel },
|
|
||||||
{ value: "edit-metdata", label: editLabel },
|
|
||||||
{ value: "delete-comic", label: deleteLabel },
|
|
||||||
];
|
|
||||||
|
|
||||||
const filteredActionOptions = filter(actionOptions, (item) => {
|
|
||||||
if (isUndefined(data.rawFileDetails)) {
|
|
||||||
return item.value !== "match-on-comic-vine";
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
const handleActionSelection = (action) => {
|
|
||||||
switch (action.value) {
|
|
||||||
case "match-on-comic-vine":
|
|
||||||
openDrawerWithCVMatches();
|
|
||||||
break;
|
|
||||||
case "edit-metdata":
|
|
||||||
openEditMetadataPanel();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log("No valid action selected.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const customStyles = {
|
|
||||||
menu: (base) => ({
|
|
||||||
...base,
|
|
||||||
backgroundColor: "rgb(156, 163, 175)",
|
|
||||||
}),
|
|
||||||
placeholder: (base) => ({
|
|
||||||
...base,
|
|
||||||
color: "black",
|
|
||||||
}),
|
|
||||||
option: (base, { data, isDisabled, isFocused, isSelected }) => ({
|
|
||||||
...base,
|
|
||||||
backgroundColor: isFocused ? "gray" : "rgb(156, 163, 175)",
|
|
||||||
}),
|
|
||||||
singleValue: (base) => ({
|
|
||||||
...base,
|
|
||||||
paddingTop: "0.4rem",
|
|
||||||
}),
|
|
||||||
control: (base) => ({
|
|
||||||
...base,
|
|
||||||
backgroundColor: "rgb(156, 163, 175)",
|
|
||||||
color: "black",
|
|
||||||
border: "1px solid rgb(156, 163, 175)",
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import AcquisitionPanel from "./AcquisitionPanel";
|
|||||||
import DownloadsPanel from "./DownloadsPanel";
|
import DownloadsPanel from "./DownloadsPanel";
|
||||||
import { VolumeInformation } from "./Tabs/VolumeInformation";
|
import { VolumeInformation } from "./Tabs/VolumeInformation";
|
||||||
|
|
||||||
import { isEmpty, isUndefined, isNil } from "lodash";
|
import { isEmpty, isUndefined, isNil, filter } from "lodash";
|
||||||
|
import { components } from "react-select";
|
||||||
import { RootState } from "threetwo-ui-typings";
|
import { RootState } from "threetwo-ui-typings";
|
||||||
|
|
||||||
import "react-sliding-pane/dist/react-sliding-pane.css";
|
import "react-sliding-pane/dist/react-sliding-pane.css";
|
||||||
@@ -27,6 +28,9 @@ import ComicViewer from "react-comic-viewer";
|
|||||||
|
|
||||||
import { extractComicArchive } from "../../actions/fileops.actions";
|
import { extractComicArchive } from "../../actions/fileops.actions";
|
||||||
import { determineCoverFile } from "../../shared/utils/metadata.utils";
|
import { determineCoverFile } from "../../shared/utils/metadata.utils";
|
||||||
|
import axios from "axios";
|
||||||
|
import { COMICVINE_SERVICE_URI } from "../../constants/endpoints";
|
||||||
|
import { refineQuery } from "filename-parser";
|
||||||
|
|
||||||
type ComicDetailProps = {};
|
type ComicDetailProps = {};
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +60,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [slidingPanelContentId, setSlidingPanelContentId] = useState("");
|
const [slidingPanelContentId, setSlidingPanelContentId] = useState("");
|
||||||
const [modalIsOpen, setIsOpen] = useState(false);
|
const [modalIsOpen, setIsOpen] = useState(false);
|
||||||
|
const [comicVineMatches, setComicVineMatches] = useState([]);
|
||||||
|
|
||||||
// const comicVineSearchResults = useSelector(
|
// const comicVineSearchResults = useSelector(
|
||||||
// (state: RootState) => state.comicInfo.searchResults,
|
// (state: RootState) => state.comicInfo.searchResults,
|
||||||
@@ -102,7 +107,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
CVMatches: {
|
CVMatches: {
|
||||||
content: (props) => (
|
content: (props) => (
|
||||||
<>
|
<>
|
||||||
{/* <div className="card search-criteria-card">
|
<div>
|
||||||
<div className="card-content">
|
<div className="card-content">
|
||||||
<ComicVineSearchForm data={rawFileDetails} />
|
<ComicVineSearchForm data={rawFileDetails} />
|
||||||
</div>
|
</div>
|
||||||
@@ -114,29 +119,13 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
<span className="tag"> # {inferredMetadata.issue.number} </span>
|
<span className="tag"> # {inferredMetadata.issue.number} </span>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{!comicVineAPICallProgress ? (
|
|
||||||
<ComicVineMatchPanel
|
<ComicVineMatchPanel
|
||||||
props={{
|
props={{
|
||||||
comicVineSearchQueryObject,
|
comicVineMatches,
|
||||||
comicVineAPICallProgress,
|
comicObjectId,
|
||||||
comicVineSearchResults,
|
}}
|
||||||
comicObjectId,
|
/>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="progress-indicator-container">
|
|
||||||
<div className="indicator">
|
|
||||||
<Loader
|
|
||||||
type="MutatingDots"
|
|
||||||
color="#CCC"
|
|
||||||
secondaryColor="#999"
|
|
||||||
height={100}
|
|
||||||
width={100}
|
|
||||||
visible={comicVineAPICallProgress}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -146,6 +135,154 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
|
||||||
|
const fetchComicVineMatches = async (
|
||||||
|
searchPayload,
|
||||||
|
issueSearchQuery,
|
||||||
|
seriesSearchQuery,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
await axios
|
||||||
|
.request({
|
||||||
|
url: `${COMICVINE_SERVICE_URI}/volumeBasedSearch`,
|
||||||
|
method: "POST",
|
||||||
|
data: {
|
||||||
|
format: "json",
|
||||||
|
// hack
|
||||||
|
query: issueSearchQuery.inferredIssueDetails.name
|
||||||
|
.replace(/[^a-zA-Z0-9 ]/g, "")
|
||||||
|
.trim(),
|
||||||
|
limit: "100",
|
||||||
|
page: 1,
|
||||||
|
resources: "volume",
|
||||||
|
scorerConfiguration: {
|
||||||
|
searchParams: issueSearchQuery.inferredIssueDetails,
|
||||||
|
},
|
||||||
|
rawFileDetails: searchPayload.rawFileDetails,
|
||||||
|
},
|
||||||
|
transformResponse: (r) => {
|
||||||
|
const matches = JSON.parse(r);
|
||||||
|
return matches;
|
||||||
|
// return sortBy(matches, (match) => -match.score);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
console.log(response);
|
||||||
|
let matches: any = [];
|
||||||
|
if (
|
||||||
|
!isNil(response.data.results) &&
|
||||||
|
response.data.results.length === 1
|
||||||
|
) {
|
||||||
|
matches = response.data.results;
|
||||||
|
} else {
|
||||||
|
matches = response.data.map((match) => match);
|
||||||
|
}
|
||||||
|
setComicVineMatches(matches);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Action event handlers
|
||||||
|
const openDrawerWithCVMatches = () => {
|
||||||
|
let seriesSearchQuery: IComicVineSearchQuery = {} as IComicVineSearchQuery;
|
||||||
|
let issueSearchQuery: IComicVineSearchQuery = {} as IComicVineSearchQuery;
|
||||||
|
|
||||||
|
if (!isUndefined(rawFileDetails)) {
|
||||||
|
issueSearchQuery = refineQuery(rawFileDetails.name);
|
||||||
|
} else if (!isEmpty(comicvine)) {
|
||||||
|
issueSearchQuery = refineQuery(comicvine.name);
|
||||||
|
}
|
||||||
|
fetchComicVineMatches(data, issueSearchQuery, seriesSearchQuery);
|
||||||
|
setSlidingPanelContentId("CVMatches");
|
||||||
|
setVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openEditMetadataPanel = useCallback(() => {
|
||||||
|
setSlidingPanelContentId("editComicBookMetadata");
|
||||||
|
setVisible(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Actions menu options and handler
|
||||||
|
const CVMatchLabel = (
|
||||||
|
<span className="inline-flex flex-row items-center gap-2">
|
||||||
|
<div className="w-6 h-6">
|
||||||
|
<i className="icon-[solar--magic-stick-3-bold-duotone] w-6 h-6"></i>
|
||||||
|
</div>
|
||||||
|
<div>Match on ComicVine</div>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
const editLabel = (
|
||||||
|
<span className="inline-flex flex-row items-center gap-2">
|
||||||
|
<div className="w-6 h-6">
|
||||||
|
<i className="icon-[solar--pen-2-bold-duotone] w-6 h-6"></i>
|
||||||
|
</div>
|
||||||
|
<div>Edit Metadata</div>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
const deleteLabel = (
|
||||||
|
<span className="inline-flex flex-row items-center gap-2">
|
||||||
|
<div className="w-6 h-6">
|
||||||
|
<i className="icon-[solar--trash-bin-trash-bold-duotone] w-6 h-6"></i>
|
||||||
|
</div>
|
||||||
|
<div>Delete Comic</div>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
const Placeholder = (props) => {
|
||||||
|
return <components.Placeholder {...props} />;
|
||||||
|
};
|
||||||
|
const actionOptions = [
|
||||||
|
{ value: "match-on-comic-vine", label: CVMatchLabel },
|
||||||
|
{ value: "edit-metdata", label: editLabel },
|
||||||
|
{ value: "delete-comic", label: deleteLabel },
|
||||||
|
];
|
||||||
|
|
||||||
|
const filteredActionOptions = filter(actionOptions, (item) => {
|
||||||
|
if (isUndefined(rawFileDetails)) {
|
||||||
|
return item.value !== "match-on-comic-vine";
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const handleActionSelection = (action) => {
|
||||||
|
switch (action.value) {
|
||||||
|
case "match-on-comic-vine":
|
||||||
|
openDrawerWithCVMatches();
|
||||||
|
break;
|
||||||
|
case "edit-metdata":
|
||||||
|
openEditMetadataPanel();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("No valid action selected.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const customStyles = {
|
||||||
|
menu: (base) => ({
|
||||||
|
...base,
|
||||||
|
backgroundColor: "rgb(156, 163, 175)",
|
||||||
|
}),
|
||||||
|
placeholder: (base) => ({
|
||||||
|
...base,
|
||||||
|
color: "black",
|
||||||
|
}),
|
||||||
|
option: (base, { data, isDisabled, isFocused, isSelected }) => ({
|
||||||
|
...base,
|
||||||
|
backgroundColor: isFocused ? "gray" : "rgb(156, 163, 175)",
|
||||||
|
}),
|
||||||
|
singleValue: (base) => ({
|
||||||
|
...base,
|
||||||
|
paddingTop: "0.4rem",
|
||||||
|
}),
|
||||||
|
control: (base) => ({
|
||||||
|
...base,
|
||||||
|
backgroundColor: "rgb(156, 163, 175)",
|
||||||
|
color: "black",
|
||||||
|
border: "1px solid rgb(156, 163, 175)",
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
// check for the availability of CV metadata
|
// check for the availability of CV metadata
|
||||||
const isComicBookMetadataAvailable =
|
const isComicBookMetadataAvailable =
|
||||||
!isUndefined(comicvine) && !isUndefined(comicvine.volumeInformation);
|
!isUndefined(comicvine) && !isUndefined(comicvine.volumeInformation);
|
||||||
@@ -285,6 +422,12 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
<Menu
|
<Menu
|
||||||
data={data.data}
|
data={data.data}
|
||||||
handlers={{ setSlidingPanelContentId, setVisible }}
|
handlers={{ setSlidingPanelContentId, setVisible }}
|
||||||
|
configuration={{
|
||||||
|
filteredActionOptions,
|
||||||
|
customStyles,
|
||||||
|
handleActionSelection,
|
||||||
|
Placeholder,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</RawFileDetails>
|
</RawFileDetails>
|
||||||
|
|||||||
@@ -2,22 +2,26 @@ import React, { ReactElement } from "react";
|
|||||||
import { ComicVineSearchForm } from "../ComicVineSearchForm";
|
import { ComicVineSearchForm } from "../ComicVineSearchForm";
|
||||||
import MatchResult from "./MatchResult";
|
import MatchResult from "./MatchResult";
|
||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
|
import { useStore } from "../../store";
|
||||||
|
import { useShallow } from "zustand/react/shallow";
|
||||||
|
|
||||||
export const ComicVineMatchPanel = (comicVineData): ReactElement => {
|
export const ComicVineMatchPanel = (comicVineData): ReactElement => {
|
||||||
const {
|
const { comicObjectId, comicVineMatches } = comicVineData.props;
|
||||||
comicObjectId,
|
const { comicvine } = useStore(
|
||||||
comicVineSearchQueryObject,
|
useShallow((state) => ({
|
||||||
comicVineAPICallProgress,
|
comicvine: state.comicvine,
|
||||||
comicVineSearchResults,
|
})),
|
||||||
} = comicVineData.props;
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="search-results-container">
|
<div>
|
||||||
{!isEmpty(comicVineSearchResults) && (
|
{!isEmpty(comicVineMatches) ? (
|
||||||
<MatchResult
|
<MatchResult
|
||||||
matchData={comicVineSearchResults}
|
matchData={comicVineMatches}
|
||||||
comicObjectId={comicObjectId}
|
comicObjectId={comicObjectId}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<>{comicvine.scrapingStatus}</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { useCallback } from "react";
|
import React from "react";
|
||||||
import { isNil, map } from "lodash";
|
import { isNil, map } from "lodash";
|
||||||
import { applyComicVineMatch } from "../../actions/comicinfo.actions";
|
|
||||||
import { convert } from "html-to-text";
|
import { convert } from "html-to-text";
|
||||||
import ellipsize from "ellipsize";
|
import ellipsize from "ellipsize";
|
||||||
|
import { LIBRARY_SERVICE_BASE_URI } from "../../constants/endpoints";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
interface MatchResultProps {
|
interface MatchResultProps {
|
||||||
matchData: any;
|
matchData: any;
|
||||||
@@ -14,12 +15,16 @@ const handleBrokenImage = (e) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const MatchResult = (props: MatchResultProps) => {
|
export const MatchResult = (props: MatchResultProps) => {
|
||||||
const applyCVMatch = useCallback(
|
const applyCVMatch = async (match, comicObjectId) => {
|
||||||
// (match, comicObjectId) => {
|
return await axios.request({
|
||||||
// dispatch(applyComicVineMatch(match, comicObjectId));
|
url: `${LIBRARY_SERVICE_BASE_URI}/applyComicVineMetadata`,
|
||||||
// },
|
method: "POST",
|
||||||
[],
|
data: {
|
||||||
);
|
match,
|
||||||
|
comicObjectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{map(props.matchData, (match, idx) => {
|
{map(props.matchData, (match, idx) => {
|
||||||
@@ -32,45 +37,29 @@ export const MatchResult = (props: MatchResultProps) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="search-result mb-4" key={idx}>
|
<div className="mb-4" key={idx}>
|
||||||
<div className="columns">
|
<div className="flex flex-row">
|
||||||
<div className="column is-one-fifth">
|
<div className="w-full mr-2">
|
||||||
<img
|
<img
|
||||||
className="cover-image"
|
className="rounded-md"
|
||||||
src={match.image.thumb_url}
|
src={match.image.thumb_url}
|
||||||
onError={handleBrokenImage}
|
onError={handleBrokenImage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div className="search-result-details column">
|
<div className="">{match.name}</div>
|
||||||
<div className="is-size-5">{match.name}</div>
|
<span>Number</span>
|
||||||
|
<span>{match.issue_number}</span>
|
||||||
<div className="field is-grouped is-grouped-multiline mt-1">
|
<span className="tag">Cover Date</span>
|
||||||
<div className="control">
|
<span className="tag is-warning">{match.cover_date}</span>
|
||||||
<div className="tags has-addons">
|
<div className="text-sm">
|
||||||
<span className="tag">Number</span>
|
|
||||||
<span className="tag is-primary">
|
|
||||||
{match.issue_number}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="control">
|
|
||||||
<div className="tags has-addons">
|
|
||||||
<span className="tag">Cover Date</span>
|
|
||||||
<span className="tag is-warning">{match.cover_date}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="is-size-7">
|
|
||||||
{ellipsize(issueDescription, 300)}
|
{ellipsize(issueDescription, 300)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="vertical-line"></div>
|
<div className="">
|
||||||
|
<div className="">
|
||||||
<div className="columns ml-6 volume-information">
|
|
||||||
<div className="column is-one-fifth">
|
|
||||||
<img
|
<img
|
||||||
src={match.volumeInformation.results.image.icon_url}
|
src={match.volumeInformation.results.image.icon_url}
|
||||||
className="cover-image"
|
className="cover-image"
|
||||||
@@ -78,42 +67,30 @@ export const MatchResult = (props: MatchResultProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="column">
|
<div className="">
|
||||||
<div className="is-size-6">{match.volume.name}</div>
|
<div className="">{match.volume.name}</div>
|
||||||
<div className="field is-grouped is-grouped-multiline mt-2">
|
<div className="">
|
||||||
<div className="control">
|
<span className="">Total Issues</span>
|
||||||
<div className="tags has-addons">
|
<span className="">
|
||||||
<span className="tag">Total Issues</span>
|
{match.volumeInformation.results.count_of_issues}
|
||||||
<span className="tag is-warning">
|
</span>
|
||||||
{match.volumeInformation.results.count_of_issues}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="control">
|
|
||||||
<div className="tags has-addons">
|
|
||||||
<span className="tag">Publisher</span>
|
|
||||||
<span className="tag is-warning">
|
|
||||||
{match.volumeInformation.results.publisher.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span className="tag">Publisher</span>
|
||||||
|
<span className="tag is-warning">
|
||||||
|
{match.volumeInformation.results.publisher.name}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="columns">
|
<button
|
||||||
<div className="column">
|
className="button is-normal is-outlined is-primary is-light is-pulled-right"
|
||||||
<button
|
onClick={() => applyCVMatch(match, props.comicObjectId)}
|
||||||
className="button is-normal is-outlined is-primary is-light is-pulled-right"
|
>
|
||||||
onClick={() => applyCVMatch(match, props.comicObjectId)}
|
<span className="icon is-size-5">
|
||||||
>
|
<i className="fas fa-clipboard-check"></i>
|
||||||
<span className="icon is-size-5">
|
</span>
|
||||||
<i className="fas fa-clipboard-check"></i>
|
<span>Apply Match</span>
|
||||||
</span>
|
</button>
|
||||||
<span>Apply Match</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { isEmpty, isNil, isUndefined } from "lodash";
|
import { isNil } from "lodash";
|
||||||
import io from "socket.io-client";
|
import io from "socket.io-client";
|
||||||
import { SOCKET_BASE_URI } from "../constants/endpoints";
|
import { SOCKET_BASE_URI } from "../constants/endpoints";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
@@ -28,6 +28,11 @@ export const useStore = create((set, get) => ({
|
|||||||
// Socket.io state
|
// Socket.io state
|
||||||
socketIOInstance: {},
|
socketIOInstance: {},
|
||||||
|
|
||||||
|
// ComicVine Scraping status
|
||||||
|
comicvine: {
|
||||||
|
scrapingStatus: "",
|
||||||
|
},
|
||||||
|
|
||||||
// Import job queue and associated statuses
|
// Import job queue and associated statuses
|
||||||
importJobQueue: {
|
importJobQueue: {
|
||||||
successfulJobCount: 0,
|
successfulJobCount: 0,
|
||||||
@@ -153,6 +158,16 @@ socketIOInstance.on("LS_IMPORT_QUEUE_DRAINED", (data) => {
|
|||||||
queryClient.invalidateQueries({ queryKey: ["allImportJobResults"] });
|
queryClient.invalidateQueries({ queryKey: ["allImportJobResults"] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ComicVine Scraping status
|
||||||
|
socketIOInstance.on("CV_SCRAPING_STATUS", (data) => {
|
||||||
|
setState((state) => ({
|
||||||
|
comicvine: {
|
||||||
|
...state.comicvine,
|
||||||
|
scrapingStatus: data.message,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to init AirDC++ Socket with supplied settings
|
* Method to init AirDC++ Socket with supplied settings
|
||||||
* @param configuration - credentials, and hostname details to init AirDC++ connection
|
* @param configuration - credentials, and hostname details to init AirDC++ connection
|
||||||
|
|||||||
Reference in New Issue
Block a user