📔 ComicVine matches populating in the flyout drawer

This commit is contained in:
2021-06-28 13:33:27 -07:00
parent a63669b306
commit 0fa0e78faf
7 changed files with 126 additions and 139 deletions

View File

@@ -6,7 +6,10 @@ import {
IMS_COMICBOOK_METADATA_FETCHED, IMS_COMICBOOK_METADATA_FETCHED,
IMS_SOCKET_CONNECTION_CONNECTED, IMS_SOCKET_CONNECTION_CONNECTED,
IMS_RECENT_COMICS_FETCHED, IMS_RECENT_COMICS_FETCHED,
CV_API_CALL_IN_PROGRESS,
CV_SEARCH_SUCCESS,
} from "../constants/action-types"; } from "../constants/action-types";
import { refineQuery } from "../shared/utils/nlp.utils"; import { refineQuery } from "../shared/utils/nlp.utils";
import { assign } from "lodash"; import { assign } from "lodash";
@@ -101,7 +104,7 @@ export const getRecentlyImportedComicBooks = (options) => async (dispatch) => {
}); });
}; };
export const fetchComicVineMatches = (searchPayload, options) => (dispatch) => { export const fetchComicVineMatches = (searchPayload) => (dispatch) => {
try { try {
const issueString = searchPayload.rawFileDetails.path.split("/").pop(); const issueString = searchPayload.rawFileDetails.path.split("/").pop();
let seriesSearchQuery = {}; let seriesSearchQuery = {};
@@ -111,10 +114,6 @@ export const fetchComicVineMatches = (searchPayload, options) => (dispatch) => {
searchPayload.rawFileDetails.containedIn.split("/").pop(), searchPayload.rawFileDetails.containedIn.split("/").pop(),
); );
} }
console.log({
issue: issueSearchQuery.searchParams,
series: seriesSearchQuery.searchParams,
});
axios axios
.request({ .request({
url: "http://localhost:3080/api/comicvine/fetchseries", url: "http://localhost:3080/api/comicvine/fetchseries",
@@ -130,9 +129,14 @@ export const fetchComicVineMatches = (searchPayload, options) => (dispatch) => {
}, },
}) })
.then((response) => { .then((response) => {
console.log("CV says to fuck off:", response); dispatch({
type: CV_SEARCH_SUCCESS,
searchResults: response.data,
});
}); });
return { issueSearchQuery, series: seriesSearchQuery.searchParams }; {
/* return { issueSearchQuery, series: seriesSearchQuery.searchParams }; */
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@@ -16316,6 +16316,19 @@ readers do not read off random characters that represent icons */
white-space: pre-wrap; white-space: pre-wrap;
} }
.card {
max-width: 200px;
}
.card .truncate {
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.card img {
max-width: 200px;
}
.card-container { .card-container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
@@ -16324,23 +16337,56 @@ readers do not read off random characters that represent icons */
} }
.card-container .card { .card-container .card {
max-width: 200px; max-width: 200px;
margin: 0 0 15px 0;
} }
.card-container .card .truncate { .card-container .card .is-horizontal {
width: 100px; flex-direction: row;
display: flex;
flex-basis: 50ex;
flex-grow: 0;
flex-shrink: 1;
box-shadow: none;
}
.card-container .card .is-horizontal .card-image {
align-self: center;
}
.card-container .card .is-horizontal .card-image .image {
max-width: 60px;
}
.card-container .card .is-horizontal .card-image .image img {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 0.25em;
border-bottom-left-radius: 0.25em;
}
.card-container .card .is-horizontal .card-content {
align-self: center;
flex: 1;
padding-left: 1em;
padding-top: 0;
padding-bottom: 0;
font-size: 0.8em;
}
.card-container .card .is-horizontal .card-content ul li.status {
margin-top: 10px;
}
.card-container .card .is-horizontal .card-content .truncate {
width: 400px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.card-container .card img { .card-container .card .is-horizontal .is-divider {
max-width: 200px; margin-top: 1.5rem;
margin-bottom: 1rem;
} }
.search-results-container { .search-results-container {
margin: 15px 0 0 0; margin: 15px 0 0 0;
border: 1px solid #fafafa;
border-radius: 10px;
overflow: hidden; overflow: hidden;
box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); }
.search-results-container table {
width: 100%;
} }
.search-results-container > :nth-of-type(odd) { .search-results-container > :nth-of-type(odd) {
background-color: #fafafa; background-color: #fafafa;

View File

@@ -114,11 +114,11 @@ $border-color: red;
// comicvine search results // comicvine search results
.search-results-container { .search-results-container {
margin: 15px 0 0 0; margin: 15px 0 0 0;
border: 1px solid hsl(0, 0%, 98%);
border-radius: 10px;
overflow: hidden; overflow: hidden;
box-shadow: $box-shadow;
table {
width: 100%;
}
> :nth-of-type(odd) { > :nth-of-type(odd) {
background-color: hsl(0, 0%, 98%); background-color: hsl(0, 0%, 98%);
} }

View File

@@ -1,13 +1,16 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useCallback } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import axios from "axios"; import axios from "axios";
import Card from "./Card"; import Card from "./Card";
import MatchResult from "./MatchResult";
import { isEmpty, isUndefined } from "lodash"; import { isEmpty, isUndefined } from "lodash";
import { IExtractedComicBookCoverFile } from "threetwo-ui-typings"; import { IExtractedComicBookCoverFile, RootState } from "threetwo-ui-typings";
import { fetchComicVineMatches } from "../actions/fileops.actions"; import { fetchComicVineMatches } from "../actions/fileops.actions";
import { Drawer } from "antd"; import { Drawer } from "antd";
import "antd/dist/antd.css"; import "antd/dist/antd.css";
import { useDispatch, useSelector } from "react-redux";
type ComicDetailProps = {}; type ComicDetailProps = {};
export const ComicDetail = ({}: ComicDetailProps) => { export const ComicDetail = ({}: ComicDetailProps) => {
@@ -16,15 +19,11 @@ export const ComicDetail = ({}: ComicDetailProps) => {
const [comicDetail, setComicDetail] = useState<{ const [comicDetail, setComicDetail] = useState<{
rawFileDetails: IExtractedComicBookCoverFile; rawFileDetails: IExtractedComicBookCoverFile;
}>(); }>();
const comicVineSearchResults = useSelector(
(state: RootState) => state.comicInfo.searchResults,
);
const { comicObjectId } = useParams<{ comicObjectId: string }>(); const { comicObjectId } = useParams<{ comicObjectId: string }>();
const showDrawer = () => {
setVisible(true);
};
const onClose = () => {
setVisible(false);
};
useEffect(() => { useEffect(() => {
axios axios
.request({ .request({
@@ -36,12 +35,22 @@ export const ComicDetail = ({}: ComicDetailProps) => {
}, },
}) })
.then((response) => { .then((response) => {
console.log("fetched", response);
setComicDetail(response.data); setComicDetail(response.data);
}) })
.catch((error) => console.log(error)); .catch((error) => console.log(error));
}, [page]); }, [page]);
const dispatch = useDispatch();
const openDrawerWithCVMatches = useCallback(() => {
setVisible(true);
dispatch(fetchComicVineMatches(comicDetail));
}, [dispatch, comicDetail, comicVineSearchResults]);
const onClose = () => {
setVisible(false);
};
return ( return (
<section className="container"> <section className="container">
{!isEmpty(comicDetail) && !isUndefined(comicDetail) && ( {!isEmpty(comicDetail) && !isUndefined(comicDetail) && (
@@ -52,7 +61,7 @@ export const ComicDetail = ({}: ComicDetailProps) => {
<Card comicBookCoversMetadata={comicDetail.rawFileDetails} /> <Card comicBookCoversMetadata={comicDetail.rawFileDetails} />
</div> </div>
<div className="column"> <div className="column">
<button className="button" onClick={showDrawer}> <button className="button" onClick={openDrawerWithCVMatches}>
<span className="icon"> <span className="icon">
<i className="fas fa-magic"></i> <i className="fas fa-magic"></i>
</span> </span>
@@ -69,9 +78,11 @@ export const ComicDetail = ({}: ComicDetailProps) => {
onClose={onClose} onClose={onClose}
visible={visible} visible={visible}
> >
<p>Some contents...</p> <div className="search-results-container">
<p>Some contents...</p> {!isEmpty(comicVineSearchResults) && (
<p>Some contents...</p> <MatchResult matchData={comicVineSearchResults} />
)}
</div>
</Drawer> </Drawer>
</> </>
)} )}

View File

@@ -1,4 +1,3 @@
//@ts-ignore
import * as React from "react"; import * as React from "react";
import { isUndefined } from "lodash"; import { isUndefined } from "lodash";
import { connect } from "react-redux"; import { connect } from "react-redux";

View File

@@ -1,113 +1,42 @@
import * as React from "react"; import React, { useState, useEffect, useCallback } from "react";
import { IComicVineSearchMatch, IFolderData } from "threetwo-ui-typings"; import { IComicVineSearchMatch, IFolderData } from "threetwo-ui-typings";
import _ from "lodash"; import { map } from "lodash";
import { autoMatcher } from "../shared/utils/query.transformer";
interface IProps { interface MatchResultProps {
matchData: unknown; matchData: any;
visible: boolean;
queryData: IFolderData;
} }
interface IState {} export const MatchResult = (props: MatchResultProps) => {
useEffect(() => {
console.log("match", props.matchData);
}, [props.matchData]);
class MatchResult extends React.Component<IProps, IState> { return (
constructor(props: IProps) { <>
super(props); <table>
} <thead>
<tr>
public componentDidMount() { <th></th>
console.log(this.props); </tr>
autoMatcher(this.props.queryData, this.props.matchData.results); </thead>
} <tbody>
{map(props.matchData, (match, idx) => {
public render() {
{
/*
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Format</th>
<th>Is File</th>
</tr>
{!_.isUndefined(this.state.folderWalkResults) &&
this.state.folderWalkResults.map((result, idx) => (
<tr key={idx}>
<td>
{!result.isLink && !result.isFile ? (
<span className="icon-text">
<span className="icon">
<i className="fas fa-folder"></i>
</span>
<span>{result.name}</span>
</span>
) : (
<span className="ml-5">{result.name}</span>
)}
{this.state.searchPaneIndex === idx &&
!_.isUndefined(this.props.matches) ? (
<MatchResult
queryData={result}
matchData={this.props.matches}
visible={true}
/>
) : null}
</td>
<td>
{!_.isEmpty(result.extension) ? (
<span className="tag is-info">
{result.extension}
</span>
) : null}
</td>
<td>{result.isFile.toString()}</td>
<td>
<button
key={idx}
className="button is-small is-primary is-outlined"
onClick={(e) => {
this.props.findMatches(e, result);
this.toggleSearchResultsPane(idx);
}}
>
Find Match
</button>
</td>
</tr>
))}
</thead>
</table>
*/
}
return this.props.visible ? (
<div>
<h3>Matches</h3>
<div className="search-results-container">
{this.props.matchData.results.map((result, idx) => {
return ( return (
<div key={idx} className="search-result"> <tr className="search-result">
<img className="cover-image" src={result.image.thumb_url} /> <td key={idx}>
<div className="search-result-details"> <img className="cover-image" src={match.image.thumb_url} />
<h5>{result.volume.name}</h5> </td>
<td className="search-result-details">
{!_.isEmpty(result.extension) ? ( <h4>{match.name}</h4>
<span className="tag is-info">{result.extension}</span> <h5>{match.volume.name}</h5>
) : null} </td>
</tr>
<span className="tag is-info">
Issue Number: {result.issue_number}
</span>
<p>{result.site_detail_url}</p>
</div>
</div>
); );
})} })}
</div> </tbody>
</div> </table>
) : null; </>
} );
} };
export default MatchResult; export default MatchResult;

View File

@@ -3,7 +3,7 @@ import {
CV_SEARCH_SUCCESS, CV_SEARCH_SUCCESS,
} from "../constants/action-types"; } from "../constants/action-types";
const initialState = { const initialState = {
showResultsPane: false, searchResults: [],
}; };
function comicinfoReducer(state = initialState, action) { function comicinfoReducer(state = initialState, action) {
@@ -12,13 +12,11 @@ function comicinfoReducer(state = initialState, action) {
return { return {
...state, ...state,
result: {}, result: {},
showResultsPane: false,
}; };
case CV_SEARCH_SUCCESS: case CV_SEARCH_SUCCESS:
return { return {
...state, ...state,
searchResults: action.result, searchResults: action.searchResults.results,
showResultsPane: true,
}; };
default: default:
return state; return state;