From 0024660f2ebe594d9f3e068654f169b434c544eb Mon Sep 17 00:00:00 2001 From: Rishi Ghan Date: Wed, 10 Apr 2024 22:35:25 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=8D=20Refining=20CV=20search=20UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- src/client/components/Search/Search.tsx | 130 ++++--- src/client/components/shared/Card.tsx | 70 ---- src/client/components/shared/DatePicker.tsx | 89 ++--- src/client/components/shared/Navbar.tsx | 312 ---------------- .../components/shared/PopoverButton.tsx | 42 +++ src/client/context/SocketIOContext.tsx | 11 - src/client/hooks/useBlazeSlider.tsx | 16 - src/client/reducers/airdcpp.reducer.ts | 133 ------- src/client/reducers/comicinfo.reducer.ts | 138 -------- src/client/reducers/fileops.reducer.ts | 334 ------------------ src/client/reducers/index.js | 11 - src/client/reducers/settings.reducer.ts | 67 ---- .../shared/middleware/SocketIOMiddleware.tsx | 11 - src/client/shared/socket.io/instance.tsx | 10 - .../shared/utils/tradepaperback.utils.ts | 1 + yarn.lock | 42 ++- 17 files changed, 193 insertions(+), 1227 deletions(-) delete mode 100644 src/client/components/shared/Card.tsx delete mode 100644 src/client/components/shared/Navbar.tsx create mode 100644 src/client/components/shared/PopoverButton.tsx delete mode 100644 src/client/context/SocketIOContext.tsx delete mode 100644 src/client/hooks/useBlazeSlider.tsx delete mode 100644 src/client/reducers/airdcpp.reducer.ts delete mode 100644 src/client/reducers/comicinfo.reducer.ts delete mode 100644 src/client/reducers/fileops.reducer.ts delete mode 100644 src/client/reducers/index.js delete mode 100644 src/client/reducers/settings.reducer.ts delete mode 100644 src/client/shared/middleware/SocketIOMiddleware.tsx delete mode 100644 src/client/shared/socket.io/instance.tsx diff --git a/package.json b/package.json index 241dcbd..4fdc1c9 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.1", + "@floating-ui/react": "^0.26.12", + "@floating-ui/react-dom": "^2.0.8", "@fortawesome/fontawesome-free": "^6.3.0", "@popperjs/core": "^2.11.8", "@rollup/plugin-node-resolve": "^15.0.1", @@ -58,7 +60,6 @@ "react-final-form-arrays": "^3.1.4", "react-loader-spinner": "^4.0.0", "react-modal": "^3.15.1", - "react-popper": "^2.3.0", "react-router": "^6.9.0", "react-router-dom": "^6.9.0", "react-select": "^5.8.0", diff --git a/src/client/components/Search/Search.tsx b/src/client/components/Search/Search.tsx index 5d3fb6d..b1feb81 100644 --- a/src/client/components/Search/Search.tsx +++ b/src/client/components/Search/Search.tsx @@ -1,13 +1,14 @@ -import React, { useCallback, ReactElement, useState } from "react"; -import { isNil, isEmpty } from "lodash"; +import React, { ReactElement, useState } from "react"; +import { isNil, isEmpty, isUndefined } from "lodash"; import { IExtractedComicBookCoverFile, RootState } from "threetwo-ui-typings"; - +import { detectIssueTypes } from "../../shared/utils/tradepaperback.utils"; import { Form, Field } from "react-final-form"; import Card from "../shared/Carda"; import ellipsize from "ellipsize"; import { convert } from "html-to-text"; +import PopoverButton from "../shared/PopoverButton"; import dayjs from "dayjs"; -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery } from "@tanstack/react-query"; import { COMICVINE_SERVICE_URI, LIBRARY_SERVICE_BASE_URI, @@ -20,9 +21,12 @@ export const Search = ({}: ISearchProps): ReactElement => { const formData = { search: "", }; - const queryClient = useQueryClient(); - const [searchQuery, setSearchQuery] = useState(""); const [comicVineMetadata, setComicVineMetadata] = useState({}); + const [selectedResource, setSelectedResource] = useState("volume"); + + const handleResourceChange = (value) => { + setSelectedResource(value); + }; const { mutate, @@ -43,7 +47,7 @@ export const Search = ({}: ISearchProps): ReactElement => { limit: "10", offset: "0", field_list: - "id,name,deck,api_detail_url,image,description,volume,cover_date,count_of_issues", + "id,name,deck,api_detail_url,image,description,volume,cover_date,start_year,count_of_issues", resources: resource, }, }); @@ -86,6 +90,17 @@ export const Search = ({}: ISearchProps): ReactElement => { return { __html: html }; }; + const onSubmit = async (values) => { + // Include the selected resource value in the form data + const formData = { ...values, resource: selectedResource }; + try { + mutate(formData); + // Handle response + } catch (error) { + // Handle error + } + }; + return (
@@ -106,7 +121,7 @@ export const Search = ({}: ISearchProps): ReactElement => {
{ {...volumesInput} type="radio" id="volume" + checked={selectedResource === "volume"} + onChange={() => handleResourceChange("volume")} className="peer hidden" />
- {isPending && <>Loading results...} + {isPending && ( +
+ Loading results... +
+ )} {!isEmpty(comicVineSearchResults?.data?.results) ? (
{comicVineSearchResults.data.results.map((result) => { return result.resource_type === "issue" ? ( -
+
-
+
{ {result.api_detail_url} -

+

{ellipsize( convert(result.description, { baseElements: { @@ -245,9 +271,12 @@ export const Search = ({}: ISearchProps): ReactElement => {

) : ( result.resource_type === "volume" && ( -
+
-
+
{ hasDetails={false} />
-
+
{!isEmpty(result.name) ? ( result.name ) : ( - No Name + No Name )} + {result.start_year && <> ({result.start_year})}
-
-
-
- - Number of issues +
+ {/* issue count */} +
+ + + - - {result.count_of_issues} - -
-
-
-
- - {result.id} + + {result.count_of_issues} issues -
+
+ {/* type: TPB, one-shot, graphic novel etc. */} + {!isNil(result.description) && + !isUndefined(result.description) && ( + <> + {!isEmpty( + detectIssueTypes(result.description), + ) && ( +
+ + + + + + + { + detectIssueTypes(result.description) + .displayName + } + + +
+ )} + + )}
- - {result.api_detail_url} - + {result.id}

+ + {result.api_detail_url} + +

+ + {/* description */} +

{ellipsize( convert(result.description, { baseElements: { @@ -298,13 +351,8 @@ export const Search = ({}: ISearchProps): ReactElement => { )}

- + + {/* onClick={() => addToLibrary("comicvine", result) */}
diff --git a/src/client/components/shared/Card.tsx b/src/client/components/shared/Card.tsx deleted file mode 100644 index b4db0ed..0000000 --- a/src/client/components/shared/Card.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import * as React from "react"; -import { IExtractedComicBookCoverFile } from "threetwo-ui-typings"; -import { - removeLeadingPeriod, - escapePoundSymbol, -} from "../shared/utils/formatting.utils"; -import { isUndefined, isEmpty, isNil } from "lodash"; -import { Link } from "react-router-dom"; -import { LIBRARY_SERVICE_HOST } from "../constants/endpoints"; -import ellipsize from "ellipsize"; - -interface IProps { - comicBookCoversMetadata?: IExtractedComicBookCoverFile; - mongoObjId?: number; - hasTitle: boolean; - title?: string; - isHorizontal: boolean; -} -interface IState {} - -class Card extends React.Component { - constructor(props: IProps) { - super(props); - } - - public drawCoverCard = ( - metadata: IExtractedComicBookCoverFile, - ): JSX.Element => { - const encodedFilePath = encodeURI( - `${LIBRARY_SERVICE_HOST}` + removeLeadingPeriod(metadata.path), - ); - const filePath = escapePoundSymbol(encodedFilePath); - return ( -
-
-
-
-
- Placeholder image -
-
- {this.props.hasTitle && ( -
-
    - -
  • - {ellipsize(metadata.name, 18)} -
  • - -
-
- )} -
-
-
- ); - }; - - public render() { - return ( - <> - {!isUndefined(this.props.comicBookCoversMetadata) && - !isEmpty(this.props.comicBookCoversMetadata) && - this.drawCoverCard(this.props.comicBookCoversMetadata)} - - ); - } -} - -export default Card; diff --git a/src/client/components/shared/DatePicker.tsx b/src/client/components/shared/DatePicker.tsx index 221bd6a..4a94d92 100644 --- a/src/client/components/shared/DatePicker.tsx +++ b/src/client/components/shared/DatePicker.tsx @@ -1,71 +1,42 @@ -import React, { ChangeEventHandler, useRef, useState } from "react"; - -import { format, isValid, parse, parseISO } from "date-fns"; +import React, { useRef, useState } from "react"; +import { format } from "date-fns"; import FocusTrap from "focus-trap-react"; -import { DayPicker, SelectSingleEventHandler } from "react-day-picker"; -import { usePopper } from "react-popper"; +import { ClassNames, DayPicker } from "react-day-picker"; +import { useFloating, offset, flip, autoUpdate } from "@floating-ui/react-dom"; +import styles from "react-day-picker/dist/style.module.css"; export const DatePickerDialog = (props) => { const { setter, apiAction } = props; const [selected, setSelected] = useState(); const [isPopperOpen, setIsPopperOpen] = useState(false); - const popperRef = useRef(null); - const buttonRef = useRef(null); - const [popperElement, setPopperElement] = useState( - null, - ); - - const customStyles = { - container: { - // Style for the entire container - border: "1px solid #ccc", - borderRadius: "4px", - padding: "10px", - width: "300px", - }, - day: { - // Style for individual days - - padding: "5px", - margin: "2px", - }, - selected: { - // Style for selected days - backgroundColor: "#007bff", - color: "#fff", - }, - disabled: { - // Style for disabled days - color: "#ccc", - }, - today: { - // Style for today's date - backgroundColor: "#f0f0f0", - }, - dayWrapper: { - // Style for the wrapper around each day - display: "inline-block", - }, + const classNames: ClassNames = { + ...styles, + head: "custom-head", }; - - const popper = usePopper(popperRef.current, popperElement, { - placement: "bottom-start", + const buttonRef = useRef(null); + const { x, y, reference, floating, strategy, refs, update } = useFloating({ + placement: "bottom-end", + middleware: [offset(10), flip()], + strategy: "absolute", }); const closePopper = () => { setIsPopperOpen(false); - buttonRef?.current?.focus(); + buttonRef.current?.focus(); }; const handleButtonClick = () => { setIsPopperOpen(true); + if (refs.reference.current && refs.floating.current) { + autoUpdate(refs.reference.current, refs.floating.current, update); + } }; - const handleDaySelect: SelectSingleEventHandler = (date) => { + const handleDaySelect = (date) => { setSelected(date); if (date) { - setter(format(date, "M-dd-yyyy")); + setter(format(date, "yyyy-MM-dd")); apiAction(); closePopper(); } else { @@ -75,17 +46,14 @@ export const DatePickerDialog = (props) => { return (
-
+
@@ -101,11 +69,14 @@ export const DatePickerDialog = (props) => { }} >
@@ -115,7 +86,7 @@ export const DatePickerDialog = (props) => { defaultMonth={selected} selected={selected} onSelect={handleDaySelect} - styles={customStyles} + classNames={classNames} />
diff --git a/src/client/components/shared/Navbar.tsx b/src/client/components/shared/Navbar.tsx deleted file mode 100644 index 1fdeeed..0000000 --- a/src/client/components/shared/Navbar.tsx +++ /dev/null @@ -1,312 +0,0 @@ -import React from "react"; -import { SearchBar } from "../GlobalSearchBar/SearchBar"; -import { DownloadProgressTick } from "../ComicDetail/DownloadProgressTick"; -import { Link } from "react-router-dom"; -import { isEmpty, isNil, isUndefined } from "lodash"; -import { format, fromUnixTime } from "date-fns"; -import { useStore } from "../../store/index"; -import { useShallow } from "zustand/react/shallow"; - -const Navbar: React.FunctionComponent = (props) => { - const { - airDCPPSocketConnected, - airDCPPDisconnectionInfo, - airDCPPSessionInformation, - airDCPPDownloadTick, - importJobQueue, - } = useStore( - useShallow((state) => ({ - airDCPPSocketConnected: state.airDCPPSocketConnected, - airDCPPDisconnectionInfo: state.airDCPPDisconnectionInfo, - airDCPPSessionInformation: state.airDCPPSessionInformation, - airDCPPDownloadTick: state.airDCPPDownloadTick, - importJobQueue: state.importJobQueue, - })), - ); - // const downloadProgressTick = useSelector( - // (state: RootState) => state.airdcpp.downloadProgressData, - // ); - // - // const airDCPPSocketConnectionStatus = useSelector( - // (state: RootState) => state.airdcpp.isAirDCPPSocketConnected, - // ); - // const airDCPPSessionInfo = useSelector( - // (state: RootState) => state.airdcpp.airDCPPSessionInfo, - // ); - // const socketDisconnectionReason = useSelector( - // (state: RootState) => state.airdcpp.socketDisconnectionReason, - // ); - - return ( - - ); -}; - -export default Navbar; diff --git a/src/client/components/shared/PopoverButton.tsx b/src/client/components/shared/PopoverButton.tsx new file mode 100644 index 0000000..aa723ac --- /dev/null +++ b/src/client/components/shared/PopoverButton.tsx @@ -0,0 +1,42 @@ +import React, { useState } from "react"; +import { useFloating, offset, flip } from "@floating-ui/react-dom"; + +const PopoverButton = ({ issuesCount }) => { + const [isVisible, setIsVisible] = useState(false); + // Use destructuring to obtain the reference and floating setters, among other values. + const { x, y, refs, strategy, floatingStyles } = useFloating({ + placement: "right", + middleware: [offset(8), flip()], + strategy: "absolute", + }); + return ( +
+ {/* Apply the reference setter directly to the ref prop */} + + {isVisible && ( +
+ Adding this volume will add all {issuesCount} issues to your wanted + list. +
+ )} +
+ ); +}; + +export default PopoverButton; diff --git a/src/client/context/SocketIOContext.tsx b/src/client/context/SocketIOContext.tsx deleted file mode 100644 index a75f521..0000000 --- a/src/client/context/SocketIOContext.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { createContext } from "react"; - -export const SocketIOContext = createContext({}); - -export const SocketIOProvider = ({ children, socket }) => { - return ( - - {children} - - ); -}; diff --git a/src/client/hooks/useBlazeSlider.tsx b/src/client/hooks/useBlazeSlider.tsx deleted file mode 100644 index d891ccb..0000000 --- a/src/client/hooks/useBlazeSlider.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { useEffect } from "react"; -import BlazeSlider from "blaze-slider"; - -export const useBlazeSlider = (config) => { - const sliderRef = React.useRef(); - const elRef = React.useRef(); - - useEffect(() => { - // if not already initialized - if (!sliderRef.current) { - sliderRef.current = new BlazeSlider(elRef.current, config); - } - }, []); - - return elRef; -}; diff --git a/src/client/reducers/airdcpp.reducer.ts b/src/client/reducers/airdcpp.reducer.ts deleted file mode 100644 index 883b442..0000000 --- a/src/client/reducers/airdcpp.reducer.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { - AIRDCPP_SEARCH_IN_PROGRESS, - AIRDCPP_SEARCH_RESULTS_ADDED, - AIRDCPP_SEARCH_RESULTS_UPDATED, - AIRDCPP_HUB_SEARCHES_SENT, - AIRDCPP_RESULT_DOWNLOAD_INITIATED, - AIRDCPP_DOWNLOAD_PROGRESS_TICK, - AIRDCPP_FILE_DOWNLOAD_COMPLETED, - AIRDCPP_BUNDLES_FETCHED, - AIRDCPP_TRANSFERS_FETCHED, - LIBRARY_ISSUE_BUNDLES, - AIRDCPP_SOCKET_CONNECTED, - AIRDCPP_SOCKET_DISCONNECTED, -} from "../constants/action-types"; -import { LOCATION_CHANGE } from "redux-first-history"; -import { isNil, isUndefined } from "lodash"; -import { difference } from "../shared/utils/object.utils"; - -const initialState = { - searchResults: [], - isAirDCPPSearchInProgress: false, - searchInfo: null, - searchInstance: null, - downloadResult: null, - bundleDBImportResult: null, - downloadFileStatus: {}, - bundles: [], - transfers: [], - isAirDCPPSocketConnected: false, - airDCPPSessionInfo: {}, - socketDisconnectionReason: {}, -}; - -function airdcppReducer(state = initialState, action) { - switch (action.type) { - case AIRDCPP_SEARCH_RESULTS_ADDED: - return { - ...state, - searchResults: [...state.searchResults, action.groupedResult], - isAirDCPPSearchInProgress: true, - }; - case AIRDCPP_SEARCH_RESULTS_UPDATED: - const bundleToUpdateIndex = state.searchResults.findIndex( - (bundle) => bundle.result.id === action.groupedResult.result.id, - ); - const updatedState = [...state.searchResults]; - - if ( - !isNil( - difference(updatedState[bundleToUpdateIndex], action.groupedResult), - ) - ) { - updatedState[bundleToUpdateIndex] = action.groupedResult; - } - - return { - ...state, - searchResults: updatedState, - }; - case AIRDCPP_SEARCH_IN_PROGRESS: - return { - ...state, - isAirDCPPSearchInProgress: true, - }; - case AIRDCPP_HUB_SEARCHES_SENT: - return { - ...state, - isAirDCPPSearchInProgress: false, - searchInfo: action.searchInfo, - searchInstance: action.instance, - }; - case AIRDCPP_RESULT_DOWNLOAD_INITIATED: - return { - ...state, - downloadResult: action.downloadResult, - bundleDBImportResult: action.bundleDBImportResult, - }; - case AIRDCPP_DOWNLOAD_PROGRESS_TICK: - return { - ...state, - downloadProgressData: action.downloadProgressData, - }; - case AIRDCPP_BUNDLES_FETCHED: - return { - ...state, - bundles: action.bundles, - }; - case LIBRARY_ISSUE_BUNDLES: - return { - ...state, - issue_bundles: action.issue_bundles, - }; - case AIRDCPP_FILE_DOWNLOAD_COMPLETED: - console.log("COMPLETED", action); - return { - ...state, - }; - case AIRDCPP_TRANSFERS_FETCHED: - return { - ...state, - transfers: action.bundles, - }; - - case AIRDCPP_SOCKET_CONNECTED: - return { - ...state, - isAirDCPPSocketConnected: true, - airDCPPSessionInfo: action.data, - }; - - case AIRDCPP_SOCKET_DISCONNECTED: - return { - ...state, - isAirDCPPSocketConnected: false, - socketDisconnectionReason: action.data, - }; - case LOCATION_CHANGE: - return { - ...state, - searchResults: [], - isAirDCPPSearchInProgress: false, - searchInfo: null, - searchInstance: null, - downloadResult: null, - bundleDBImportResult: null, - // bundles: [], - }; - default: - return state; - } -} - -export default airdcppReducer; diff --git a/src/client/reducers/comicinfo.reducer.ts b/src/client/reducers/comicinfo.reducer.ts deleted file mode 100644 index c3d8809..0000000 --- a/src/client/reducers/comicinfo.reducer.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { isEmpty } from "lodash"; -import { - CV_API_CALL_IN_PROGRESS, - CV_SEARCH_SUCCESS, - CV_CLEANUP, - IMS_COMIC_BOOK_DB_OBJECT_FETCHED, - IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED, - IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS, - CV_ISSUES_METADATA_CALL_IN_PROGRESS, - CV_ISSUES_MATCHES_IN_LIBRARY_FETCHED, - CV_ISSUES_FOR_VOLUME_IN_LIBRARY_SUCCESS, - CV_WEEKLY_PULLLIST_FETCHED, - CV_WEEKLY_PULLLIST_CALL_IN_PROGRESS, - LIBRARY_STATISTICS_CALL_IN_PROGRESS, - LIBRARY_STATISTICS_FETCHED, -} from "../constants/action-types"; - -const initialState = { - pullList: [], - libraryStatistics: [], - searchResults: [], - searchQuery: {}, - inProgress: false, - comicBookDetail: {}, - comicBooksDetails: [], - issuesForVolume: [], - IMS_inProgress: false, -}; - -function comicinfoReducer(state = initialState, action) { - switch (action.type) { - case CV_API_CALL_IN_PROGRESS: - return { - ...state, - inProgress: true, - }; - case CV_SEARCH_SUCCESS: - return { - ...state, - searchResults: action.searchResults, - searchQuery: action.searchQueryObject, - inProgress: false, - }; - case IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS: - return { - ...state, - IMS_inProgress: true, - }; - - case IMS_COMIC_BOOK_DB_OBJECT_FETCHED: - return { - ...state, - comicBookDetail: action.comicBookDetail, - IMS_inProgress: false, - }; - case IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED: - return { - ...state, - comicBooksDetails: action.comicBooks, - IMS_inProgress: false, - }; - case CV_CLEANUP: - return { - ...state, - searchResults: [], - searchQuery: {}, - issuesForVolume: [], - }; - case CV_ISSUES_METADATA_CALL_IN_PROGRESS: - return { - inProgress: true, - ...state, - }; - - case CV_ISSUES_FOR_VOLUME_IN_LIBRARY_SUCCESS: - return { - ...state, - issuesForVolume: action.issues, - inProgress: false, - }; - - case CV_ISSUES_MATCHES_IN_LIBRARY_FETCHED: - const updatedState = [...state.issuesForVolume]; - action.matches.map((match) => { - updatedState.map((issue, idx) => { - const matches = []; - if (!isEmpty(match.hits.hits)) { - return match.hits.hits.map((hit) => { - if ( - parseInt(issue.issue_number, 10) === - hit._source.inferredMetadata.issue.number - ) { - matches.push(hit); - const updatedIssueResult = { ...issue, matches }; - updatedState[idx] = updatedIssueResult; - } - }); - } - }); - }); - return { - ...state, - issuesForVolume: updatedState, - }; - - case CV_WEEKLY_PULLLIST_CALL_IN_PROGRESS: - return { - inProgress: true, - ...state, - }; - case CV_WEEKLY_PULLLIST_FETCHED: { - const foo = []; - action.data.map((item) => { - foo.push({issue: item}) - }); - return { - ...state, - inProgress: false, - pullList: foo, - }; - } - case LIBRARY_STATISTICS_CALL_IN_PROGRESS: - return { - inProgress: true, - ...state, - }; - case LIBRARY_STATISTICS_FETCHED: - return { - ...state, - inProgress: false, - libraryStatistics: action.data, - }; - default: - return state; - } -} - -export default comicinfoReducer; diff --git a/src/client/reducers/fileops.reducer.ts b/src/client/reducers/fileops.reducer.ts deleted file mode 100644 index 6c8a17d..0000000 --- a/src/client/reducers/fileops.reducer.ts +++ /dev/null @@ -1,334 +0,0 @@ -import { isUndefined, map } from "lodash"; -import { LOCATION_CHANGE } from "redux-first-history"; -import { determineCoverFile } from "../shared/utils/metadata.utils"; -import { - IMS_COMICBOOK_METADATA_FETCHED, - IMS_RAW_IMPORT_SUCCESSFUL, - IMS_RAW_IMPORT_FAILED, - IMS_RECENT_COMICS_FETCHED, - IMS_WANTED_COMICS_FETCHED, - WANTED_COMICS_FETCHED, - IMS_CV_METADATA_IMPORT_SUCCESSFUL, - IMS_CV_METADATA_IMPORT_FAILED, - IMS_CV_METADATA_IMPORT_CALL_IN_PROGRESS, - IMS_COMIC_BOOK_GROUPS_CALL_IN_PROGRESS, - IMS_COMIC_BOOK_GROUPS_FETCHED, - IMS_COMIC_BOOK_GROUPS_CALL_FAILED, - IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_IN_PROGRESS, - LS_IMPORT, - LS_COVER_EXTRACTED, - LS_COVER_EXTRACTION_FAILED, - LS_COMIC_ADDED, - IMG_ANALYSIS_CALL_IN_PROGRESS, - IMG_ANALYSIS_DATA_FETCH_SUCCESS, - SS_SEARCH_RESULTS_FETCHED, - SS_SEARCH_IN_PROGRESS, - FILEOPS_STATE_RESET, - LS_IMPORT_CALL_IN_PROGRESS, - SS_SEARCH_FAILED, - SS_SEARCH_RESULTS_FETCHED_SPECIAL, - VOLUMES_FETCHED, - COMICBOOK_EXTRACTION_SUCCESS, - LIBRARY_SERVICE_HEALTH, - LS_IMPORT_QUEUE_DRAINED, - LS_SET_QUEUE_STATUS, - RESTORE_JOB_COUNTS_AFTER_SESSION_RESTORATION, - LS_IMPORT_JOB_STATISTICS_FETCHED, -} from "../constants/action-types"; -import { removeLeadingPeriod } from "../shared/utils/formatting.utils"; -import { LIBRARY_SERVICE_HOST } from "../constants/endpoints"; - -const initialState = { - IMSCallInProgress: false, - IMGCallInProgress: false, - SSCallInProgress: false, - imageAnalysisResults: {}, - comicBookExtractionInProgress: false, - LSQueueImportStatus: undefined, - comicBookMetadata: [], - comicVolumeGroups: [], - isSocketConnected: false, - isComicVineMetadataImportInProgress: false, - comicVineMetadataImportError: {}, - rawImportError: {}, - extractedComicBookArchive: { - reading: [], - analysis: [], - }, - recentComics: [], - wantedComics: [], - libraryComics: [], - volumes: [], - librarySearchResultsFormatted: [], - lastQueueJob: "", - successfulJobCount: 0, - failedJobCount: 0, - importJobStatistics: [], - libraryQueueResults: [], - librarySearchError: {}, - libraryServiceStatus: {}, -}; -function fileOpsReducer(state = initialState, action) { - switch (action.type) { - case IMS_COMICBOOK_METADATA_FETCHED: - return { - ...state, - comicBookMetadata: [...state.comicBookMetadata, action.data], - IMSCallInProgress: false, - }; - - case LS_IMPORT_CALL_IN_PROGRESS: { - return { - ...state, - IMSCallInProgress: true, - }; - } - case IMS_RAW_IMPORT_SUCCESSFUL: - return { - ...state, - rawImportDetails: action.rawImportDetails, - }; - case IMS_RAW_IMPORT_FAILED: - return { - ...state, - rawImportErorr: action.rawImportError, - }; - case IMS_RECENT_COMICS_FETCHED: - return { - ...state, - recentComics: action.data.docs, - }; - case IMS_WANTED_COMICS_FETCHED: - return { - ...state, - wantedComics: action.data, - }; - case IMS_CV_METADATA_IMPORT_SUCCESSFUL: - return { - ...state, - isComicVineMetadataImportInProgress: false, - comicVineMetadataImportDetails: action.importResult, - }; - case IMS_CV_METADATA_IMPORT_CALL_IN_PROGRESS: - return { - ...state, - isComicVineMetadataImportInProgress: true, - }; - case IMS_CV_METADATA_IMPORT_FAILED: - return { - ...state, - isComicVineMetadataImportInProgress: false, - comicVineMetadataImportError: action.importError, - }; - case IMS_COMIC_BOOK_GROUPS_CALL_IN_PROGRESS: { - return { - ...state, - IMSCallInProgress: true, - }; - } - case IMS_COMIC_BOOK_GROUPS_FETCHED: { - return { - ...state, - comicVolumeGroups: action.data, - IMSCallInProgress: false, - }; - } - case IMS_COMIC_BOOK_GROUPS_CALL_FAILED: { - return { - ...state, - IMSCallInProgress: false, - error: action.error, - }; - } - case IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_IN_PROGRESS: { - return { - ...state, - comicBookExtractionInProgress: true, - }; - } - - case LOCATION_CHANGE: { - return { - ...state, - extractedComicBookArchive: [], - }; - } - - case LS_IMPORT: { - return { - ...state, - LSQueueImportStatus: "running", - }; - } - - case LS_COVER_EXTRACTED: { - if (state.recentComics.length === 5) { - state.recentComics.pop(); - } - return { - ...state, - successfulJobCount: action.completedJobCount, - lastQueueJob: action.importResult.rawFileDetails.name, - recentComics: [...state.recentComics, action.importResult], - }; - } - - case LS_COVER_EXTRACTION_FAILED: { - return { - ...state, - failedJobCount: action.failedJobCount, - }; - } - - case LS_IMPORT_QUEUE_DRAINED: { - localStorage.removeItem("sessionId"); - return { - ...state, - LSQueueImportStatus: "drained", - }; - } - - case RESTORE_JOB_COUNTS_AFTER_SESSION_RESTORATION: { - console.log("Restoring state for an active import in progress..."); - return { - ...state, - successfulJobCount: action.completedJobCount, - failedJobCount: action.failedJobCount, - LSQueueImportStatus: action.queueStatus, - }; - } - - case LS_SET_QUEUE_STATUS: { - return { - ...state, - LSQueueImportStatus: action.data.queueStatus, - }; - } - - case LS_IMPORT_JOB_STATISTICS_FETCHED: { - return { - ...state, - importJobStatistics: action.data, - }; - } - - case COMICBOOK_EXTRACTION_SUCCESS: { - const comicBookPages: string[] = []; - map(action.result.files, (page) => { - const pageFilePath = removeLeadingPeriod(page); - const imagePath = encodeURI(`${LIBRARY_SERVICE_HOST}${pageFilePath}`); - comicBookPages.push(imagePath); - }); - - switch (action.result.purpose) { - case "reading": - return { - ...state, - extractedComicBookArchive: { - reading: comicBookPages, - }, - comicBookExtractionInProgress: false, - }; - - case "analysis": - return { - ...state, - extractedComicBookArchive: { - analysis: comicBookPages, - }, - comicBookExtractionInProgress: false, - }; - } - } - - case LS_COMIC_ADDED: { - return { - ...state, - }; - } - case IMG_ANALYSIS_CALL_IN_PROGRESS: { - return { - ...state, - IMGCallInProgress: true, - }; - } - case IMG_ANALYSIS_DATA_FETCH_SUCCESS: { - return { - ...state, - imageAnalysisResults: action.result, - }; - } - - case SS_SEARCH_IN_PROGRESS: { - return { - ...state, - SSCallInProgress: true, - }; - } - - case SS_SEARCH_RESULTS_FETCHED: { - return { - ...state, - libraryComics: action.data, - SSCallInProgress: false, - }; - } - case SS_SEARCH_RESULTS_FETCHED_SPECIAL: { - const foo = []; - if (!isUndefined(action.data.hits)) { - map(action.data.hits, ({ _source }) => { - foo.push(_source); - }); - } - return { - ...state, - librarySearchResultsFormatted: foo, - SSCallInProgress: false, - }; - } - case WANTED_COMICS_FETCHED: { - const foo = []; - if (!isUndefined(action.data.hits)) { - map(action.data.hits, ({ _source }) => { - foo.push(_source); - }); - } - return { - ...state, - wantedComics: foo, - SSCallInProgress: false, - }; - } - - case VOLUMES_FETCHED: - return { - ...state, - volumes: action.data, - SSCallInProgress: false, - }; - - case SS_SEARCH_FAILED: { - return { - ...state, - librarySearchError: action.data, - SSCallInProgress: false, - }; - } - case LIBRARY_SERVICE_HEALTH: { - return { - ...state, - libraryServiceStatus: action.status, - }; - } - case FILEOPS_STATE_RESET: { - return { - ...state, - imageAnalysisResults: {}, - }; - } - default: - return state; - } -} - -export default fileOpsReducer; diff --git a/src/client/reducers/index.js b/src/client/reducers/index.js deleted file mode 100644 index 897e6f0..0000000 --- a/src/client/reducers/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import comicinfoReducer from "../reducers/comicinfo.reducer"; -import fileOpsReducer from "../reducers/fileops.reducer"; -import airdcppReducer from "../reducers/airdcpp.reducer"; -// import settingsReducer from "../reducers/settings.reducer"; - -export const reducers = { - comicInfo: comicinfoReducer, - fileOps: fileOpsReducer, - airdcpp: airdcppReducer, - // settings: settingsReducer, -}; diff --git a/src/client/reducers/settings.reducer.ts b/src/client/reducers/settings.reducer.ts deleted file mode 100644 index c04ceb0..0000000 --- a/src/client/reducers/settings.reducer.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -import { RootState } from "../store"; -import { isUndefined } from "lodash"; -import { SETTINGS_SERVICE_BASE_URI } from "../constants/endpoints"; - -export interface InitialState { - data: object; - inProgress: boolean; - dbFlushed: boolean; - torrentsList: Array; -} -const initialState: InitialState = { - data: {}, - inProgress: false, - dbFlushed: false, - torrentsList: [], -}; - -export const settingsSlice = createSlice({ - name: "settings", - initialState, - reducers: { - SETTINGS_CALL_IN_PROGRESS: (state) => { - state.inProgress = true; - }, - - SETTINGS_OBJECT_FETCHED: (state, action) => { - state.data = action.payload; - state.inProgress = false; - }, - - SETTINGS_OBJECT_DELETED: (state, action) => { - state.data = action.payload; - state.inProgress = false; - }, - - SETTINGS_DB_FLUSH_SUCCESS: (state, action) => { - state.dbFlushed = action.payload; - state.inProgress = false; - }, - - SETTINGS_QBITTORRENT_TORRENTS_LIST_FETCHED: (state, action) => { - console.log(state); - console.log(action); - state.torrentsList = action.payload; - }, - }, -}); - -export const { - SETTINGS_CALL_IN_PROGRESS, - SETTINGS_OBJECT_FETCHED, - SETTINGS_OBJECT_DELETED, - SETTINGS_DB_FLUSH_SUCCESS, - SETTINGS_QBITTORRENT_TORRENTS_LIST_FETCHED, -} = settingsSlice.actions; - -// Other code such as selectors can use the imported `RootState` type -export const torrentsList = (state: RootState) => state.settings.torrentsList; -export const qBittorrentSettings = (state: RootState) => { - console.log(state); - if (!isUndefined(state.settings?.data?.bittorrent)) { - return state.settings?.data?.bittorrent.client.host; - } -}; -export default settingsSlice.reducer; diff --git a/src/client/shared/middleware/SocketIOMiddleware.tsx b/src/client/shared/middleware/SocketIOMiddleware.tsx deleted file mode 100644 index b6e1e39..0000000 --- a/src/client/shared/middleware/SocketIOMiddleware.tsx +++ /dev/null @@ -1,11 +0,0 @@ -const socketIOMiddleware = (socket) => { - return (store) => (next) => (action) => { - if (action.type === "EMIT_SOCKET_EVENT") { - const { event, data } = action.payload; - socket.emit(event, data); - } - return next(action); - }; -}; - -export default socketIOMiddleware; diff --git a/src/client/shared/socket.io/instance.tsx b/src/client/shared/socket.io/instance.tsx deleted file mode 100644 index deb6514..0000000 --- a/src/client/shared/socket.io/instance.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import io from "socket.io-client"; -import { SOCKET_BASE_URI } from "../../constants/endpoints"; -const sessionId = localStorage.getItem("sessionId"); -const socketIOConnectionInstance = io(SOCKET_BASE_URI, { - transports: ["websocket"], - withCredentials: true, - query: { sessionId }, -}); - -export default socketIOConnectionInstance; diff --git a/src/client/shared/utils/tradepaperback.utils.ts b/src/client/shared/utils/tradepaperback.utils.ts index 1dd8b4a..729bfc0 100644 --- a/src/client/shared/utils/tradepaperback.utils.ts +++ b/src/client/shared/utils/tradepaperback.utils.ts @@ -16,6 +16,7 @@ export const detectIssueTypes = (deck: string): any => { const matches = map(issueTypeMatchers, (matcher) => { return getIssueTypeDisplayName(deck, matcher.regex, matcher.displayName); }); + return compact(matches)[0]; }; diff --git a/yarn.lock b/yarn.lock index a372414..be40be5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1509,7 +1509,7 @@ resolved "https://registry.yarnpkg.com/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz#c05ed35ad82df8e6ac616c68b92c2282bd083ba4" integrity sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ== -"@floating-ui/core@^1.6.0": +"@floating-ui/core@^1.0.0", "@floating-ui/core@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== @@ -1524,6 +1524,14 @@ "@floating-ui/core" "^1.6.0" "@floating-ui/utils" "^0.2.1" +"@floating-ui/dom@^1.6.1": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef" + integrity sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw== + dependencies: + "@floating-ui/core" "^1.0.0" + "@floating-ui/utils" "^0.2.0" + "@floating-ui/react-dom@^2.0.0": version "2.0.7" resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.7.tgz#873e0a55a25d8ddbbccd159d6ab4a4b98eb05494" @@ -1531,7 +1539,23 @@ dependencies: "@floating-ui/dom" "^1.6.0" -"@floating-ui/utils@^0.2.1": +"@floating-ui/react-dom@^2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" + integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== + dependencies: + "@floating-ui/dom" "^1.6.1" + +"@floating-ui/react@^0.26.12": + version "0.26.12" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.12.tgz#6908f774d8e3167d89b37fd83be975c7e5d8be99" + integrity sha512-D09o62HrWdIkstF2kGekIKAC0/N/Dl6wo3CQsnLcOmO3LkW6Ik8uIb3kw8JYkwxNCcg+uJ2bpWUiIijTBep05w== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@floating-ui/utils" "^0.2.0" + tabbable "^6.0.0" + +"@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== @@ -8997,7 +9021,7 @@ react-element-to-jsx-string@^15.0.0: is-plain-object "5.0.0" react-is "18.1.0" -react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: +react-fast-compare@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== @@ -9070,14 +9094,6 @@ react-modal@^3.14.3, react-modal@^3.15.1: react-lifecycles-compat "^3.0.0" warning "^4.0.3" -react-popper@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba" - integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q== - dependencies: - react-fast-compare "^3.0.1" - warning "^4.0.2" - react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -10023,7 +10039,7 @@ synchronous-promise@^2.0.15: resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.17.tgz#38901319632f946c982152586f2caf8ddc25c032" integrity sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g== -tabbable@^6.2.0: +tabbable@^6.0.0, tabbable@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== @@ -10673,7 +10689,7 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -warning@^4.0.2, warning@^4.0.3: +warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==