🦟 Fixed 404s upon page refresh
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
|||||||
IMAGETRANSFORMATION_SERVICE_BASE_URI,
|
IMAGETRANSFORMATION_SERVICE_BASE_URI,
|
||||||
LIBRARY_SERVICE_BASE_URI,
|
LIBRARY_SERVICE_BASE_URI,
|
||||||
LIBRARY_SERVICE_HOST,
|
LIBRARY_SERVICE_HOST,
|
||||||
|
SEARCH_SERVICE_BASE_URI,
|
||||||
} from "../constants/endpoints";
|
} from "../constants/endpoints";
|
||||||
import {
|
import {
|
||||||
IMS_COMIC_BOOK_GROUPS_FETCHED,
|
IMS_COMIC_BOOK_GROUPS_FETCHED,
|
||||||
@@ -257,7 +258,14 @@ export const extractComicArchive =
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const searchIssue = (options) => async (dispatch) => {};
|
export const searchIssue = (query) => async (dispatch) => {
|
||||||
|
const foo = await axios({
|
||||||
|
url: `${SEARCH_SERVICE_BASE_URI}/searchIssue`,
|
||||||
|
method: "POST",
|
||||||
|
data: query,
|
||||||
|
});
|
||||||
|
console.log(foo);
|
||||||
|
};
|
||||||
export const analyzeImage =
|
export const analyzeImage =
|
||||||
(imageFilePath: string | Buffer) => async (dispatch) => {
|
(imageFilePath: string | Buffer) => async (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import DownloadsPanel from "./ComicDetail/DownloadsPanel";
|
|||||||
import { EditMetadataPanel } from "./ComicDetail/EditMetadataPanel";
|
import { EditMetadataPanel } from "./ComicDetail/EditMetadataPanel";
|
||||||
import { Menu } from "./ComicDetail/ActionMenu/Menu";
|
import { Menu } from "./ComicDetail/ActionMenu/Menu";
|
||||||
|
|
||||||
import { isEmpty, isUndefined, isNil, findIndex } from "lodash";
|
import { isEmpty, isUndefined, isNil } from "lodash";
|
||||||
import { RootState } from "threetwo-ui-typings";
|
import { RootState } from "threetwo-ui-typings";
|
||||||
|
|
||||||
import { getComicBookDetailById } from "../actions/comicinfo.actions";
|
import { getComicBookDetailById } from "../actions/comicinfo.actions";
|
||||||
@@ -117,6 +117,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// check for the availability of CV metadata
|
||||||
const isComicBookMetadataAvailable =
|
const isComicBookMetadataAvailable =
|
||||||
comicBookDetailData.sourcedMetadata &&
|
comicBookDetailData.sourcedMetadata &&
|
||||||
!isUndefined(comicBookDetailData.sourcedMetadata.comicvine) &&
|
!isUndefined(comicBookDetailData.sourcedMetadata.comicvine) &&
|
||||||
@@ -125,6 +126,29 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
) &&
|
) &&
|
||||||
!isEmpty(comicBookDetailData.sourcedMetadata);
|
!isEmpty(comicBookDetailData.sourcedMetadata);
|
||||||
|
|
||||||
|
// check for the availability of rawFileDetails
|
||||||
|
const areRawFileDetailsAvailable =
|
||||||
|
!isUndefined(comicBookDetailData.rawFileDetails) &&
|
||||||
|
!isEmpty(comicBookDetailData.rawFileDetails.cover);
|
||||||
|
|
||||||
|
// query for airdc++
|
||||||
|
const airDCPPQuery = {};
|
||||||
|
if (isComicBookMetadataAvailable) {
|
||||||
|
Object.assign(airDCPPQuery, {
|
||||||
|
issue: {
|
||||||
|
name: comicBookDetailData.sourcedMetadata.comicvine.volumeInformation
|
||||||
|
.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (areRawFileDetailsAvailable) {
|
||||||
|
Object.assign(airDCPPQuery, {
|
||||||
|
issue: {
|
||||||
|
name: comicBookDetailData.inferredMetadata.issue.name,
|
||||||
|
number: comicBookDetailData.inferredMetadata.issue.number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Tab content and header details
|
// Tab content and header details
|
||||||
const tabGroup = [
|
const tabGroup = [
|
||||||
{
|
{
|
||||||
@@ -134,7 +158,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
content: isComicBookMetadataAvailable ? (
|
content: isComicBookMetadataAvailable ? (
|
||||||
<VolumeInformation data={comicBookDetailData} key={1} />
|
<VolumeInformation data={comicBookDetailData} key={1} />
|
||||||
) : null,
|
) : null,
|
||||||
include: isComicBookMetadataAvailable,
|
shouldShow: isComicBookMetadataAvailable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
@@ -156,8 +180,8 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
include:
|
shouldShow:
|
||||||
!isNil(comicBookDetailData.sourcedMetadata) &&
|
!isUndefined(comicBookDetailData.sourcedMetadata) &&
|
||||||
!isEmpty(comicBookDetailData.sourcedMetadata.comicInfo),
|
!isEmpty(comicBookDetailData.sourcedMetadata.comicInfo),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -165,18 +189,14 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
icon: <i className="fa-regular fa-file-archive"></i>,
|
icon: <i className="fa-regular fa-file-archive"></i>,
|
||||||
name: "Archive Operations",
|
name: "Archive Operations",
|
||||||
content: <ArchiveOperations data={comicBookDetailData} key={3} />,
|
content: <ArchiveOperations data={comicBookDetailData} key={3} />,
|
||||||
include:
|
shouldShow: areRawFileDetailsAvailable,
|
||||||
!isUndefined(comicBookDetailData.rawFileDetails) &&
|
|
||||||
!isEmpty(comicBookDetailData.rawFileDetails.cover),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
icon: <i className="fa-solid fa-floppy-disk"></i>,
|
icon: <i className="fa-solid fa-floppy-disk"></i>,
|
||||||
name: "Acquisition",
|
name: "Acquisition",
|
||||||
content: (
|
content: <AcquisitionPanel query={airDCPPQuery} key={4} />,
|
||||||
<AcquisitionPanel comicBookMetadata={comicBookDetailData} key={4} />
|
shouldShow: true,
|
||||||
),
|
|
||||||
include: !isNil(comicBookDetailData.rawFileDetails),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
@@ -194,12 +214,11 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
key={5}
|
key={5}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
include: !isNil(comicBookDetailData.rawFileDetails),
|
shouldShow: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
// filtered Tabs
|
// filtered Tabs
|
||||||
const filteredTabs = tabGroup.filter((tab) => tab.include);
|
const filteredTabs = tabGroup.filter((tab) => tab.shouldShow);
|
||||||
|
|
||||||
|
|
||||||
// Tabs
|
// Tabs
|
||||||
const MetadataTabGroup = () => {
|
const MetadataTabGroup = () => {
|
||||||
@@ -245,10 +264,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
|
|||||||
// 2. from the CV-scraped version
|
// 2. from the CV-scraped version
|
||||||
let imagePath = "";
|
let imagePath = "";
|
||||||
let comicBookTitle = "";
|
let comicBookTitle = "";
|
||||||
if (
|
if (areRawFileDetailsAvailable) {
|
||||||
!isUndefined(comicBookDetailData.rawFileDetails) &&
|
|
||||||
!isEmpty(comicBookDetailData.rawFileDetails.cover)
|
|
||||||
) {
|
|
||||||
const encodedFilePath = encodeURI(
|
const encodedFilePath = encodeURI(
|
||||||
`${LIBRARY_SERVICE_HOST}/${comicBookDetailData.rawFileDetails.cover.filePath}`,
|
`${LIBRARY_SERVICE_HOST}/${comicBookDetailData.rawFileDetails.cover.filePath}`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,16 +16,15 @@ import ellipsize from "ellipsize";
|
|||||||
import { isEmpty, isNil, map } from "lodash";
|
import { isEmpty, isNil, map } from "lodash";
|
||||||
import { AirDCPPSocketContext } from "../../context/AirDCPPSocket";
|
import { AirDCPPSocketContext } from "../../context/AirDCPPSocket";
|
||||||
interface IAcquisitionPanelProps {
|
interface IAcquisitionPanelProps {
|
||||||
comicBookMetadata: any;
|
query: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AcquisitionPanel = (
|
export const AcquisitionPanel = (
|
||||||
props: IAcquisitionPanelProps,
|
props: IAcquisitionPanelProps,
|
||||||
): ReactElement => {
|
): ReactElement => {
|
||||||
const volumeName =
|
console.log(props);
|
||||||
props.comicBookMetadata.sourcedMetadata.comicvine.volumeInformation.name;
|
const issueName = props.query.issue.name;
|
||||||
const sanitizedVolumeName = volumeName.replace(/[^a-zA-Z0-9 ]/g, " ");
|
const sanitizedIssueName = issueName.replace(/[^a-zA-Z0-9 ]/g, " ");
|
||||||
const issueName = props.comicBookMetadata.sourcedMetadata.comicvine.name;
|
|
||||||
|
|
||||||
// Selectors for picking state
|
// Selectors for picking state
|
||||||
const airDCPPSearchResults = useSelector((state: RootState) => {
|
const airDCPPSearchResults = useSelector((state: RootState) => {
|
||||||
@@ -51,7 +50,7 @@ export const AcquisitionPanel = (
|
|||||||
// AirDC++ search query
|
// AirDC++ search query
|
||||||
const dcppSearchQuery = {
|
const dcppSearchQuery = {
|
||||||
query: {
|
query: {
|
||||||
pattern: `${sanitizedVolumeName.replace(/#/g, "")}`,
|
pattern: `${sanitizedIssueName.replace(/#/g, "")}`,
|
||||||
extensions: ["cbz", "cbr"],
|
extensions: ["cbz", "cbr"],
|
||||||
},
|
},
|
||||||
hub_urls: map(
|
hub_urls: map(
|
||||||
|
|||||||
@@ -191,151 +191,154 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
|
|||||||
<h1 className="title">Library</h1>
|
<h1 className="title">Library</h1>
|
||||||
{/* Search bar */}
|
{/* Search bar */}
|
||||||
<SearchBar />
|
<SearchBar />
|
||||||
<div>
|
{!isUndefined(data) ? (
|
||||||
<div className="library">
|
<div>
|
||||||
<table {...getTableProps()} className="table is-hoverable">
|
<div className="library">
|
||||||
<thead>
|
<table {...getTableProps()} className="table is-hoverable">
|
||||||
{headerGroups.map((headerGroup, idx) => (
|
<thead>
|
||||||
<tr key={idx} {...headerGroup.getHeaderGroupProps()}>
|
{headerGroups.map((headerGroup, idx) => (
|
||||||
{headerGroup.headers.map((column, idx) => (
|
<tr key={idx} {...headerGroup.getHeaderGroupProps()}>
|
||||||
<th key={idx} {...column.getHeaderProps()}>
|
{headerGroup.headers.map((column, idx) => (
|
||||||
{column.render("Header")}
|
<th key={idx} {...column.getHeaderProps()}>
|
||||||
</th>
|
{column.render("Header")}
|
||||||
))}
|
</th>
|
||||||
</tr>
|
))}
|
||||||
))}
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody {...getTableBodyProps()}>
|
|
||||||
{page.map((row, idx) => {
|
|
||||||
prepareRow(row);
|
|
||||||
return (
|
|
||||||
<tr
|
|
||||||
key={idx}
|
|
||||||
{...row.getRowProps()}
|
|
||||||
onClick={() => navigateToComicDetail(row.original._id)}
|
|
||||||
>
|
|
||||||
{row.cells.map((cell, idx) => {
|
|
||||||
return (
|
|
||||||
<td
|
|
||||||
key={idx}
|
|
||||||
{...cell.getCellProps()}
|
|
||||||
className="is-vcentered"
|
|
||||||
>
|
|
||||||
{cell.render("Cell")}
|
|
||||||
</td>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tr>
|
</tr>
|
||||||
);
|
))}
|
||||||
})}
|
</thead>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{/* pagination controls */}
|
<tbody {...getTableBodyProps()}>
|
||||||
<nav
|
{page.map((row, idx) => {
|
||||||
className="pagination"
|
prepareRow(row);
|
||||||
role="navigation"
|
return (
|
||||||
aria-label="pagination"
|
<tr
|
||||||
>
|
key={idx}
|
||||||
{/* x of total indicator */}
|
{...row.getRowProps()}
|
||||||
<div>
|
onClick={() => navigateToComicDetail(row.original._id)}
|
||||||
Page {pageIndex} of {Math.ceil(pageTotal / pageSize)}
|
>
|
||||||
(Total resources: {pageTotal})
|
{row.cells.map((cell, idx) => {
|
||||||
</div>
|
return (
|
||||||
|
<td
|
||||||
|
key={idx}
|
||||||
|
{...cell.getCellProps()}
|
||||||
|
className="is-vcentered"
|
||||||
|
>
|
||||||
|
{cell.render("Cell")}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
{/* previous page and next page controls */}
|
{/* pagination controls */}
|
||||||
<div className="field has-addons">
|
<nav
|
||||||
<p className="control">
|
className="pagination"
|
||||||
<button
|
role="navigation"
|
||||||
className="button"
|
aria-label="pagination"
|
||||||
onClick={() => previousPage()}
|
|
||||||
disabled={!canPreviousPage}
|
|
||||||
>
|
|
||||||
Previous Page
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<p className="control">
|
|
||||||
<button
|
|
||||||
className="button"
|
|
||||||
onClick={() => nextPage()}
|
|
||||||
disabled={!canNextPage}
|
|
||||||
>
|
|
||||||
<span>Next Page</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* first and last page controls */}
|
|
||||||
<div className="field has-addons">
|
|
||||||
<p className="control">
|
|
||||||
<button
|
|
||||||
className="button"
|
|
||||||
onClick={() => gotoPage(1)}
|
|
||||||
disabled={!canPreviousPage}
|
|
||||||
>
|
|
||||||
<i className="fas fa-angle-double-left"></i>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<p className="control">
|
|
||||||
<button
|
|
||||||
className="button"
|
|
||||||
onClick={() => gotoPage(Math.ceil(pageTotal / pageSize))}
|
|
||||||
disabled={!canNextPage}
|
|
||||||
>
|
|
||||||
<i className="fas fa-angle-double-right"></i>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* page selector */}
|
|
||||||
<span>
|
|
||||||
Go to page:
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
className="input"
|
|
||||||
defaultValue={pageIndex}
|
|
||||||
onChange={(e) => {
|
|
||||||
const page = e.target.value ? Number(e.target.value) : 0;
|
|
||||||
gotoPage(page);
|
|
||||||
}}
|
|
||||||
style={{ width: "100px" }}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{/* page size selector */}
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"dropdown " + (isPageSizeDropdownCollapsed ? "is-active" : "")
|
|
||||||
}
|
|
||||||
onBlur={() => togglePageSizeDropdown()}
|
|
||||||
>
|
>
|
||||||
<div className="dropdown-trigger">
|
{/* x of total indicator */}
|
||||||
<button
|
<div>
|
||||||
className="button"
|
Page {pageIndex} of {Math.ceil(pageTotal / pageSize)}
|
||||||
aria-haspopup="true"
|
(Total resources: {pageTotal})
|
||||||
aria-controls="dropdown-menu"
|
|
||||||
onClick={() => togglePageSizeDropdown()}
|
|
||||||
>
|
|
||||||
<span>Select Page Size</span>
|
|
||||||
<span className="icon is-small">
|
|
||||||
<i className="fas fa-angle-down" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="dropdown-menu" id="dropdown-menu" role="menu">
|
|
||||||
<div className="dropdown-content">
|
{/* previous page and next page controls */}
|
||||||
{[10, 20, 30, 40, 50].map((pageSize) => (
|
<div className="field has-addons">
|
||||||
<a href="#" className="dropdown-item" key={pageSize}>
|
<p className="control">
|
||||||
Show {pageSize}
|
<button
|
||||||
</a>
|
className="button"
|
||||||
))}
|
onClick={() => previousPage()}
|
||||||
|
disabled={!canPreviousPage}
|
||||||
|
>
|
||||||
|
Previous Page
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
<p className="control">
|
||||||
|
<button
|
||||||
|
className="button"
|
||||||
|
onClick={() => nextPage()}
|
||||||
|
disabled={!canNextPage}
|
||||||
|
>
|
||||||
|
<span>Next Page</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* first and last page controls */}
|
||||||
|
<div className="field has-addons">
|
||||||
|
<p className="control">
|
||||||
|
<button
|
||||||
|
className="button"
|
||||||
|
onClick={() => gotoPage(1)}
|
||||||
|
disabled={!canPreviousPage}
|
||||||
|
>
|
||||||
|
<i className="fas fa-angle-double-left"></i>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
<p className="control">
|
||||||
|
<button
|
||||||
|
className="button"
|
||||||
|
onClick={() => gotoPage(Math.ceil(pageTotal / pageSize))}
|
||||||
|
disabled={!canNextPage}
|
||||||
|
>
|
||||||
|
<i className="fas fa-angle-double-right"></i>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* page selector */}
|
||||||
|
<span>
|
||||||
|
Go to page:
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="input"
|
||||||
|
defaultValue={pageIndex}
|
||||||
|
onChange={(e) => {
|
||||||
|
const page = e.target.value ? Number(e.target.value) : 0;
|
||||||
|
gotoPage(page);
|
||||||
|
}}
|
||||||
|
style={{ width: "100px" }}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* page size selector */}
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"dropdown " +
|
||||||
|
(isPageSizeDropdownCollapsed ? "is-active" : "")
|
||||||
|
}
|
||||||
|
onBlur={() => togglePageSizeDropdown()}
|
||||||
|
>
|
||||||
|
<div className="dropdown-trigger">
|
||||||
|
<button
|
||||||
|
className="button"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-controls="dropdown-menu"
|
||||||
|
onClick={() => togglePageSizeDropdown()}
|
||||||
|
>
|
||||||
|
<span>Select Page Size</span>
|
||||||
|
<span className="icon is-small">
|
||||||
|
<i className="fas fa-angle-down" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="dropdown-menu" id="dropdown-menu" role="menu">
|
||||||
|
<div className="dropdown-content">
|
||||||
|
{[10, 20, 30, 40, 50].map((pageSize) => (
|
||||||
|
<a href="#" className="dropdown-item" key={pageSize}>
|
||||||
|
Show {pageSize}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</nav>
|
||||||
</nav>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,30 +1,47 @@
|
|||||||
import React, { ReactElement } from "react";
|
import React, { ReactElement, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Form, Field } from "react-final-form";
|
import { Form, Field } from "react-final-form";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { searchIssue } from "../../actions/fileops.actions";
|
||||||
|
|
||||||
export const SearchBar = (): ReactElement => {
|
export const SearchBar = (): ReactElement => {
|
||||||
const foo = () => {};
|
const dispatch = useDispatch();
|
||||||
|
const handleSubmit = useCallback((e) => {
|
||||||
|
console.log(e);
|
||||||
|
dispatch(
|
||||||
|
searchIssue({
|
||||||
|
queryObject: {
|
||||||
|
volumeName: e.search,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
return (
|
return (
|
||||||
<div className="box sticky">
|
<div className="box sticky">
|
||||||
<Form
|
<Form
|
||||||
onSubmit={foo}
|
onSubmit={handleSubmit}
|
||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
render={({ handleSubmit, form, submitting, pristine, values }) => (
|
render={({ handleSubmit, form, submitting, pristine, values }) => (
|
||||||
<div className="column is-three-quarters search">
|
<form onSubmit={handleSubmit}>
|
||||||
<label>Search</label>
|
<div className="column is-three-quarters search">
|
||||||
<Field name="search">
|
<label>Search</label>
|
||||||
{({ input, meta }) => {
|
<Field name="search">
|
||||||
return (
|
{({ input, meta }) => {
|
||||||
<input
|
return (
|
||||||
{...input}
|
<input
|
||||||
className="input main-search-bar is-medium"
|
{...input}
|
||||||
placeholder="Type an issue/volume name"
|
className="input main-search-bar is-medium"
|
||||||
/>
|
placeholder="Type an issue/volume name"
|
||||||
);
|
/>
|
||||||
}}
|
);
|
||||||
</Field>
|
}}
|
||||||
</div>
|
</Field>
|
||||||
|
<button className="button" type="submit">
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="column one-fifth">
|
<div className="column one-fifth">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useMemo, ReactElement } from "react";
|
import React, { useState, useEffect, useMemo, ReactElement } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useHistory } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import {
|
import {
|
||||||
removeLeadingPeriod,
|
removeLeadingPeriod,
|
||||||
escapePoundSymbol,
|
escapePoundSymbol,
|
||||||
@@ -10,7 +10,7 @@ import prettyBytes from "pretty-bytes";
|
|||||||
import ellipsize from "ellipsize";
|
import ellipsize from "ellipsize";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { getComicBooks } from "../actions/fileops.actions";
|
import { getComicBooks } from "../actions/fileops.actions";
|
||||||
import { isNil, isEmpty } from "lodash";
|
import { isNil, isEmpty, isUndefined } from "lodash";
|
||||||
import Masonry from "react-masonry-css";
|
import Masonry from "react-masonry-css";
|
||||||
import Card from "./Carda";
|
import Card from "./Carda";
|
||||||
import { detectIssueTypes } from "../shared/utils/tradepaperback.utils";
|
import { detectIssueTypes } from "../shared/utils/tradepaperback.utils";
|
||||||
@@ -45,7 +45,7 @@ export const LibraryGrid = (libraryGridProps: ILibraryGridProps) => {
|
|||||||
{data.map(({ _id, rawFileDetails, sourcedMetadata }) => {
|
{data.map(({ _id, rawFileDetails, sourcedMetadata }) => {
|
||||||
let imagePath = "";
|
let imagePath = "";
|
||||||
let comicName = "";
|
let comicName = "";
|
||||||
if (!isNil(rawFileDetails)) {
|
if (!isEmpty(rawFileDetails.cover)) {
|
||||||
const encodedFilePath = encodeURI(
|
const encodedFilePath = encodeURI(
|
||||||
`${LIBRARY_SERVICE_HOST}/${removeLeadingPeriod(
|
`${LIBRARY_SERVICE_HOST}/${removeLeadingPeriod(
|
||||||
rawFileDetails.cover.filePath,
|
rawFileDetails.cover.filePath,
|
||||||
@@ -71,7 +71,7 @@ export const LibraryGrid = (libraryGridProps: ILibraryGridProps) => {
|
|||||||
title={comicName ? titleElement : null}
|
title={comicName ? titleElement : null}
|
||||||
>
|
>
|
||||||
<div className="content is-flex is-flex-direction-row">
|
<div className="content is-flex is-flex-direction-row">
|
||||||
{!isNil(sourcedMetadata.comicvine) && (
|
{!isEmpty(sourcedMetadata.comicvine) && (
|
||||||
<span className="icon cv-icon is-small">
|
<span className="icon cv-icon is-small">
|
||||||
<img src="/dist/img/cvlogo.svg" />
|
<img src="/dist/img/cvlogo.svg" />
|
||||||
</span>
|
</span>
|
||||||
@@ -81,13 +81,13 @@ export const LibraryGrid = (libraryGridProps: ILibraryGridProps) => {
|
|||||||
<i className="fas fa-adjust" />
|
<i className="fas fa-adjust" />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!isNil(sourcedMetadata.comicvine) &&
|
{!isUndefined(sourcedMetadata.comicvine.volumeInformation) &&
|
||||||
!isEmpty(
|
!isEmpty(
|
||||||
detectIssueTypes(
|
detectIssueTypes(
|
||||||
sourcedMetadata.comicvine.volumeInformation.description,
|
sourcedMetadata.comicvine.volumeInformation.description,
|
||||||
),
|
),
|
||||||
) ? (
|
) ? (
|
||||||
<span className="tag is-warning">
|
<span className="tag is-warning ml-1">
|
||||||
{
|
{
|
||||||
detectIssueTypes(
|
detectIssueTypes(
|
||||||
sourcedMetadata.comicvine.volumeInformation
|
sourcedMetadata.comicvine.volumeInformation
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ const VolumeDetails = (props): ReactElement => {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!isUndefined(comicBookDetails.sourcedMetadata) &&
|
!isUndefined(comicBookDetails.sourcedMetadata) &&
|
||||||
!isUndefined(comicBookDetails.sourcedMetadata.comicvine)
|
!isUndefined(comicBookDetails.sourcedMetadata.comicvine.volumeInformation)
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<div className="container volume-details">
|
<div className="container volume-details">
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ export const LIBRARY_SERVICE_BASE_URI = hostURIBuilder({
|
|||||||
port: "3000",
|
port: "3000",
|
||||||
apiPath: "/api/library",
|
apiPath: "/api/library",
|
||||||
});
|
});
|
||||||
|
export const SEARCH_SERVICE_BASE_URI = hostURIBuilder({
|
||||||
|
protocol: "http",
|
||||||
|
host: process.env.UNDERLYING_HOSTNAME || "localhost",
|
||||||
|
port: "3000",
|
||||||
|
apiPath: "/api/search",
|
||||||
|
});
|
||||||
|
|
||||||
export const SETTINGS_SERVICE_BASE_URI = hostURIBuilder({
|
export const SETTINGS_SERVICE_BASE_URI = hostURIBuilder({
|
||||||
protocol: "http",
|
protocol: "http",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createStore, combineReducers, applyMiddleware } from "redux";
|
import { createStore, combineReducers, applyMiddleware } from "redux";
|
||||||
import { createBrowserHistory } from "history";
|
import { createHashHistory } from "history";
|
||||||
import { composeWithDevTools } from "redux-devtools-extension";
|
import { composeWithDevTools } from "redux-devtools-extension";
|
||||||
import thunk from "redux-thunk";
|
import thunk from "redux-thunk";
|
||||||
import { createReduxHistoryContext } from "redux-first-history";
|
import { createReduxHistoryContext } from "redux-first-history";
|
||||||
@@ -12,7 +12,7 @@ const socketConnection = io(SOCKET_BASE_URI, { transports: ["websocket"] });
|
|||||||
|
|
||||||
const { createReduxHistory, routerMiddleware, routerReducer } =
|
const { createReduxHistory, routerMiddleware, routerReducer } =
|
||||||
createReduxHistoryContext({
|
createReduxHistoryContext({
|
||||||
history: createBrowserHistory(),
|
history: createHashHistory(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const store = createStore(
|
export const store = createStore(
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ module.exports = () => {
|
|||||||
aliasFields: ["browser", "browser.esm"],
|
aliasFields: ["browser", "browser.esm"],
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
|
hot: true,
|
||||||
port: 3050,
|
port: 3050,
|
||||||
open: true,
|
open: true,
|
||||||
hot: true,
|
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api/**": {
|
"/api/**": {
|
||||||
target: "http://localhost:8050",
|
target: "http://localhost:8050",
|
||||||
|
|||||||
Reference in New Issue
Block a user