🏗️ Trying out react-query

This commit is contained in:
2023-10-30 13:47:35 -04:00
parent 2df0fce792
commit d45c53dff9
13 changed files with 117 additions and 393 deletions

View File

@@ -23,7 +23,11 @@ import {
AIRDCPP_DOWNLOAD_PROGRESS_TICK,
LS_SINGLE_IMPORT,
} from "../constants/action-types";
import { useDispatch, useSelector } from "react-redux";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
const queryClient = new QueryClient({});
/**
* Method that initializes an AirDC++ socket connection
@@ -32,128 +36,93 @@ import { useDispatch, useSelector } from "react-redux";
* @returns void
*/
const AirDCPPSocketComponent = (): ReactElement => {
const airDCPPConfiguration = useContext(AirDCPPSocketContext);
const dispatch = useDispatch();
useEffect(() => {
const initializeAirDCPPEventListeners = async () => {
if (
!isUndefined(airDCPPConfiguration.airDCPPState) &&
!isEmpty(airDCPPConfiguration.airDCPPState.settings) &&
!isEmpty(airDCPPConfiguration.airDCPPState.socket)
) {
await airDCPPConfiguration.airDCPPState.socket.addListener(
"queue",
"queue_bundle_added",
async (data) => {
console.log("JEMEN:", data);
},
);
// download tick listener
await airDCPPConfiguration.airDCPPState.socket.addListener(
`queue`,
"queue_bundle_tick",
async (downloadProgressData) => {
dispatch({
type: AIRDCPP_DOWNLOAD_PROGRESS_TICK,
downloadProgressData,
});
},
);
// download complete listener
await airDCPPConfiguration.airDCPPState.socket.addListener(
`queue`,
"queue_bundle_status",
async (bundleData) => {
let count = 0;
if (bundleData.status.completed && bundleData.status.downloaded) {
// dispatch the action for raw import, with the metadata
if (count < 1) {
console.log(`[AirDCPP]: Download complete.`);
dispatch({
type: LS_SINGLE_IMPORT,
meta: { remote: true },
data: bundleData,
});
count += 1;
}
}
},
);
console.log(
"[AirDCPP]: Listener registered - listening to queue bundle download ticks",
);
console.log(
"[AirDCPP]: Listener registered - listening to queue bundle changes",
);
console.log(
"[AirDCPP]: Listener registered - listening to transfer completion",
);
}
};
initializeAirDCPPEventListeners();
}, [airDCPPConfiguration]);
// const airDCPPConfiguration = useContext(AirDCPPSocketContext);
// const dispatch = useDispatch();
//
// useEffect(() => {
// const initializeAirDCPPEventListeners = async () => {
// if (
// !isUndefined(airDCPPConfiguration.airDCPPState) &&
// !isEmpty(airDCPPConfiguration.airDCPPState.settings) &&
// !isEmpty(airDCPPConfiguration.airDCPPState.socket)
// ) {
// await airDCPPConfiguration.airDCPPState.socket.addListener(
// "queue",
// "queue_bundle_added",
// async (data) => {
// console.log("JEMEN:", data);
// },
// );
// // download tick listener
// await airDCPPConfiguration.airDCPPState.socket.addListener(
// `queue`,
// "queue_bundle_tick",
// async (downloadProgressData) => {
// dispatch({
// type: AIRDCPP_DOWNLOAD_PROGRESS_TICK,
// downloadProgressData,
// });
// },
// );
// // download complete listener
// await airDCPPConfiguration.airDCPPState.socket.addListener(
// `queue`,
// "queue_bundle_status",
// async (bundleData) => {
// let count = 0;
// if (bundleData.status.completed && bundleData.status.downloaded) {
// // dispatch the action for raw import, with the metadata
// if (count < 1) {
// console.log(`[AirDCPP]: Download complete.`);
// dispatch({
// type: LS_SINGLE_IMPORT,
// meta: { remote: true },
// data: bundleData,
// });
// count += 1;
// }
// }
// },
// );
// console.log(
// "[AirDCPP]: Listener registered - listening to queue bundle download ticks",
// );
// console.log(
// "[AirDCPP]: Listener registered - listening to queue bundle changes",
// );
// console.log(
// "[AirDCPP]: Listener registered - listening to transfer completion",
// );
// }
// };
// initializeAirDCPPEventListeners();
// }, [airDCPPConfiguration]);
return <></>;
};
export const App = (): ReactElement => {
const dispatch = useDispatch();
useEffect(() => {
// Check if there is a sessionId in localStorage
const sessionId = localStorage.getItem("sessionId");
if (!isNil(sessionId)) {
// Resume the session
dispatch({
type: "RESUME_SESSION",
meta: { remote: true },
session: { sessionId },
});
} else {
// Inititalize the session and persist the sessionId to localStorage
socketIOConnectionInstance.on("sessionInitialized", (sessionId) => {
localStorage.setItem("sessionId", sessionId);
});
}
}, []);
// useEffect(() => {
// // Check if there is a sessionId in localStorage
// const sessionId = localStorage.getItem("sessionId");
// if (!isNil(sessionId)) {
// // Resume the session
// dispatch({
// type: "RESUME_SESSION",
// meta: { remote: true },
// session: { sessionId },
// });
// } else {
// // Inititalize the session and persist the sessionId to localStorage
// socketIOConnectionInstance.on("sessionInitialized", (sessionId) => {
// localStorage.setItem("sessionId", sessionId);
// });
// }
// }, []);
return (
<SocketIOProvider socket={socketIOConnectionInstance}>
<AirDCPPSocketContextProvider>
<div>
<AirDCPPSocketComponent />
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/import" element={<Import path={"./comics"} />} />
<Route
path="/library"
element={<TabulatedContentContainer category="library" />}
/>
<Route path="/library-grid" element={<LibraryGrid />} />
<Route path="/downloads" element={<Downloads data={{}} />} />
<Route path="/search" element={<Search />} />
<Route
path={"/comic/details/:comicObjectId"}
element={<ComicDetailContainer />}
/>
<Route
path={"/volume/details/:comicObjectId"}
element={<VolumeDetail />}
/>
<Route path="/settings" element={<Settings />} />
<Route
path="/pull-list/all"
element={<TabulatedContentContainer category="pullList" />}
/>
<Route
path="/wanted/all"
element={<TabulatedContentContainer category="wanted" />}
/>
<Route
path="/volumes/all"
element={<TabulatedContentContainer category="volumes" />}
/>
</Routes>
</div>
</AirDCPPSocketContextProvider>
</SocketIOProvider>
<QueryClientProvider client={queryClient}>
{/* The rest of your application */}
<ReactQueryDevtools initialIsOpen={true} />
{/* <AirDCPPSocketComponent /> */};
</QueryClientProvider>
);
};

View File

@@ -15,7 +15,6 @@ import { isEmpty, isNil } from "lodash";
import Header from "../shared/Header";
export const Dashboard = (): ReactElement => {
const dispatch = useDispatch();
// useEffect(() => {
// dispatch(fetchVolumeGroups());
// dispatch(

View File

@@ -1,13 +1,10 @@
import React, { ReactElement, useCallback } from "react";
import { saveSettings } from "../../../actions/settings.actions";
import { ConnectionForm } from "../../shared/ConnectionForm/ConnectionForm";
import { useConnectToQBittorrentClientQuery } from "../../../services/torrents.api";
export const QbittorrentConnectionForm = (): ReactElement => {
const { data, isLoading } = useConnectToQBittorrentClientQuery({});
const onSubmit = useCallback(async (values) => {
try {
dispatch(saveSettings(values, "bittorrent"));
} catch (error) {
console.log(error);
}
@@ -15,13 +12,11 @@ export const QbittorrentConnectionForm = (): ReactElement => {
return (
<>
{!isLoading && (
<ConnectionForm
initialData={data?.bittorrent.client.host}
submitHandler={onSubmit}
formHeading={"Qbittorrent Configuration"}
/>
)}
<ConnectionForm
initialData={data?.bittorrent.client.host}
submitHandler={onSubmit}
formHeading={"Qbittorrent Configuration"}
/>
<pre>{JSON.stringify(data?.qbittorrentClientInfo, null, 2)}</pre>
</>
);

View File

@@ -7,22 +7,18 @@ import { ServiceStatuses } from "../ServiceStatuses/ServiceStatuses";
import settingsObject from "../../constants/settings/settingsMenu.json";
import { isUndefined, map } from "lodash";
interface ISettingsProps { }
interface ISettingsProps {}
export const Settings = (props: ISettingsProps): ReactElement => {
const [active, setActive] = useState("gen-db");
const settingsContent = [
{
id: "adc-hubs",
content: <div key="adc-hubs">{<AirDCPPHubsForm />}</div>,
content: <div key="adc-hubs">{/* <AirDCPPHubsForm /> */}</div>,
},
{
id: "adc-connection",
content: (
<div key="adc-connection">
<AirDCPPSettingsForm />
</div>
),
content: <div key="adc-connection">{/* <AirDCPPSettingsForm /> */}</div>,
},
{
id: "qbt-connection",
@@ -34,15 +30,11 @@ export const Settings = (props: ISettingsProps): ReactElement => {
},
{
id: "core-service",
content: <ServiceStatuses />,
content: <>a</>,
},
{
id: "flushdb",
content: (
<div key="flushdb">
<SystemSettingsForm />
</div>
),
content: <div key="flushdb">{/* <SystemSettingsForm /> */}</div>,
},
];
return (

View File

@@ -2,46 +2,10 @@ import React, { useContext } from "react";
import { SearchBar } from "../GlobalSearchBar/SearchBar";
import { DownloadProgressTick } from "../ComicDetail/DownloadProgressTick";
import { Link } from "react-router-dom";
import { useSelector } from "react-redux";
import { isUndefined } from "lodash";
import { format, fromUnixTime } from "date-fns";
const Navbar: React.FunctionComponent = (props) => {
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 qBittorrentConnectionInfo = useSelector(
(state: RootState) => state.settings.data,
);
const socketDisconnectionReason = useSelector(
(state: RootState) => state.airdcpp.socketDisconnectionReason,
);
// Import-related selector hooks
const successfulImportJobCount = useSelector(
(state: RootState) => state.fileOps.successfulJobCount,
);
const failedImportJobCount = useSelector(
(state: RootState) => state.fileOps.failedJobCount,
);
const lastQueueJob = useSelector(
(state: RootState) => state.fileOps.lastQueueJob,
);
const libraryQueueImportStatus = useSelector(
(state: RootState) => state.fileOps.LSQueueImportStatus,
);
const allImportJobResults = useSelector(
(state: RootState) => state.fileOps.importJobStatistics,
);
return (
<nav className="navbar is-fixed-top">
<div className="navbar-brand">
@@ -91,8 +55,6 @@ const Navbar: React.FunctionComponent = (props) => {
Downloads
</Link>
<SearchBar />
<Link to="/search" className="navbar-item">
Search ComicVine
</Link>
@@ -101,102 +63,7 @@ const Navbar: React.FunctionComponent = (props) => {
<div className="navbar-end">
<a className="navbar-item is-hidden-desktop-only"></a>
<div className="navbar-item has-dropdown is-hoverable">
<a className="navbar-link is-arrowless">
<i className="fa-solid fa-download"></i>
{downloadProgressTick && <div className="pulsating-circle"></div>}
</a>
{!isUndefined(downloadProgressTick) ? (
<div className="navbar-dropdown is-right is-boxed">
<a className="navbar-item">
<DownloadProgressTick data={downloadProgressTick} />
</a>
</div>
) : null}
</div>
{!isUndefined(libraryQueueImportStatus) &&
location.hash !== "#/import" ? (
<div className="navbar-item has-dropdown is-hoverable">
<a className="navbar-link is-arrowless">
<i className="fa-solid fa-file-import has-text-warning-dark"></i>
</a>
<div className="navbar-dropdown is-right is-boxed">
<a className="navbar-item">
<ul>
{successfulImportJobCount > 0 ? (
<li className="mb-2">
<span className="tag is-success mr-2">
{successfulImportJobCount}
</span>
imported.
</li>
) : null}
{failedImportJobCount > 0 ? (
<li>
<span className="tag is-danger mr-2">
{failedImportJobCount}
</span>
failed to import.
</li>
) : null}
</ul>
</a>
</div>
</div>
) : null}
{/* AirDC++ socket connection status */}
<div className="navbar-item has-dropdown is-hoverable">
{airDCPPSocketConnectionStatus ? (
<>
<a className="navbar-link is-arrowless">
<i className="fa-solid fa-tower-cell"></i>
</a>
<div className="navbar-dropdown pr-2 pl-2 is-right airdcpp-status is-boxed">
{/* AirDC++ Session Information */}
<p>
Last login was{" "}
<span className="tag">
{format(
fromUnixTime(airDCPPSessionInfo.user.last_login),
"dd MMMM, yyyy",
)}
</span>
</p>
<hr className="navbar-divider" />
<p>
<span className="tag has-text-success">
{airDCPPSessionInfo.user.username}
</span>
connected to{" "}
<span className="tag has-text-success">
{airDCPPSessionInfo.system_info.client_version}
</span>{" "}
with session ID{" "}
<span className="tag has-text-success">
{airDCPPSessionInfo.session_id}
</span>
</p>
{/* <pre>{JSON.stringify(airDCPPSessionInfo, null, 2)}</pre> */}
</div>
</>
) : (
<>
<a className="navbar-link is-arrowless has-text-danger">
<i className="fa-solid fa-bolt"></i>
</a>
<div className="navbar-dropdown pr-2 pl-2 is-right is-boxed">
<pre>
{JSON.stringify(socketDisconnectionReason, null, 2)}
</pre>
</div>
</>
)}
</div>
<div className="navbar-item has-dropdown is-hoverable is-mega">
<div className="navbar-link flex">Blog</div>