🏗️ Refactoring Navbar to read from zustand store
This commit is contained in:
@@ -46,7 +46,7 @@ export const App = (): ReactElement => {
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// }, []);
|
// }, []);
|
||||||
return <>{/* The rest of your application */}</>;
|
return <>{/* <Navbar /> */}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
airDCPPDisconnectionInfo,
|
airDCPPDisconnectionInfo,
|
||||||
airDCPPSocketConnectionInformation,
|
airDCPPSocketConnectionInformation,
|
||||||
airDCPPClientConfiguration,
|
airDCPPClientConfiguration,
|
||||||
|
airDCPPSocketInstance,
|
||||||
} = useStore(
|
} = useStore(
|
||||||
useShallow((state) => ({
|
useShallow((state) => ({
|
||||||
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
||||||
@@ -21,9 +22,9 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
||||||
airDCPPSocketConnectionInformation:
|
airDCPPSocketConnectionInformation:
|
||||||
state.airDCPPSocketConnectionInformation,
|
state.airDCPPSocketConnectionInformation,
|
||||||
|
airDCPPSocketInstance: state.airDCPPSocketInstance,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSubmit = useCallback(async (values) => {
|
const onSubmit = useCallback(async (values) => {
|
||||||
try {
|
try {
|
||||||
// airDCPPSettings.setSettings(values);
|
// airDCPPSettings.setSettings(values);
|
||||||
|
|||||||
@@ -2,10 +2,61 @@ import React, { useContext } from "react";
|
|||||||
import { SearchBar } from "../GlobalSearchBar/SearchBar";
|
import { SearchBar } from "../GlobalSearchBar/SearchBar";
|
||||||
import { DownloadProgressTick } from "../ComicDetail/DownloadProgressTick";
|
import { DownloadProgressTick } from "../ComicDetail/DownloadProgressTick";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
import { isUndefined } from "lodash";
|
import { isUndefined } from "lodash";
|
||||||
import { format, fromUnixTime } from "date-fns";
|
import { format, fromUnixTime } from "date-fns";
|
||||||
|
import { useStore } from "../../store/index";
|
||||||
|
import { useShallow } from "zustand/react/shallow";
|
||||||
|
|
||||||
const Navbar: React.FunctionComponent = (props) => {
|
const Navbar: React.FunctionComponent = (props) => {
|
||||||
|
const {
|
||||||
|
airDCPPSocketConnected,
|
||||||
|
airDCPPDisconnectionInfo,
|
||||||
|
airDCPPSocketConnectionInformation,
|
||||||
|
airDCPPClientConfiguration,
|
||||||
|
airDCPPSocketInstance,
|
||||||
|
} = useStore(
|
||||||
|
useShallow((state) => ({
|
||||||
|
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
||||||
|
airDCPPDisconnectionInfo: state.airDCPPDisconnectionInfo,
|
||||||
|
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
||||||
|
airDCPPSocketConnectionInformation:
|
||||||
|
state.airDCPPSocketConnectionInformation,
|
||||||
|
airDCPPSocketInstance: state.airDCPPSocketInstance,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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 (
|
return (
|
||||||
<nav className="navbar is-fixed-top">
|
<nav className="navbar is-fixed-top">
|
||||||
<div className="navbar-brand">
|
<div className="navbar-brand">
|
||||||
@@ -55,6 +106,8 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
Downloads
|
Downloads
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
<SearchBar />
|
||||||
|
|
||||||
<Link to="/search" className="navbar-item">
|
<Link to="/search" className="navbar-item">
|
||||||
Search ComicVine
|
Search ComicVine
|
||||||
</Link>
|
</Link>
|
||||||
@@ -63,7 +116,102 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
<div className="navbar-end">
|
<div className="navbar-end">
|
||||||
<a className="navbar-item is-hidden-desktop-only"></a>
|
<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 */}
|
{/* AirDC++ socket connection status */}
|
||||||
|
<div className="navbar-item has-dropdown is-hoverable">
|
||||||
|
{airDCPPSocketConnectionStatus ? (
|
||||||
|
<>
|
||||||
|
<a className="navbar-link is-arrowless has-text-success">
|
||||||
|
<i className="fa-solid fa-bolt"></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-item has-dropdown is-hoverable is-mega">
|
||||||
<div className="navbar-link flex">Blog</div>
|
<div className="navbar-link flex">Blog</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import axios from "axios";
|
|||||||
|
|
||||||
export const useStore = create((set, get) => ({
|
export const useStore = create((set, get) => ({
|
||||||
// AirDC++ state
|
// AirDC++ state
|
||||||
|
airDCPPSocketInstance: {},
|
||||||
airDCPPSocketConnected: false,
|
airDCPPSocketConnected: false,
|
||||||
airDCPPDisconnectionInfo: {},
|
airDCPPDisconnectionInfo: {},
|
||||||
airDCPPClientConfiguration: {},
|
airDCPPClientConfiguration: {},
|
||||||
@@ -16,13 +17,18 @@ export const useStore = create((set, get) => ({
|
|||||||
getAirDCPPConnectionStatus: () => {
|
getAirDCPPConnectionStatus: () => {
|
||||||
const airDCPPSocketConnectionStatus = get().airDCPPSocketConnected;
|
const airDCPPSocketConnectionStatus = get().airDCPPSocketConnected;
|
||||||
},
|
},
|
||||||
|
airDCPPDownloadTick: {},
|
||||||
// Socket.io state
|
// Socket.io state
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { getState, setState } = useStore;
|
const { getState, setState } = useStore;
|
||||||
|
|
||||||
// Method to init AirDC++ Socket with supplied settings
|
/**
|
||||||
const initializeAirDCPPSocket = async (configuration) => {
|
* Method to init AirDC++ Socket with supplied settings
|
||||||
|
* @param configuration - credentials, and hostname details to init AirDC++ connection
|
||||||
|
* @returns Initialized AirDC++ connection socket instance
|
||||||
|
*/
|
||||||
|
const initializeAirDCPPSocket = async (configuration): Promise<any> => {
|
||||||
console.log("[AirDCPP]: Initializing socket...");
|
console.log("[AirDCPP]: Initializing socket...");
|
||||||
|
|
||||||
const initializedAirDCPPSocket = new AirDCPPSocket({
|
const initializedAirDCPPSocket = new AirDCPPSocket({
|
||||||
@@ -60,6 +66,9 @@ const initializeAirDCPPSocket = async (configuration) => {
|
|||||||
"queue_bundle_tick",
|
"queue_bundle_tick",
|
||||||
async (downloadProgressData) => {
|
async (downloadProgressData) => {
|
||||||
console.log(downloadProgressData);
|
console.log(downloadProgressData);
|
||||||
|
setState({
|
||||||
|
airDCPPDownloadTick: downloadProgressData,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
initializedAirDCPPSocket.addListener(
|
initializedAirDCPPSocket.addListener(
|
||||||
@@ -85,6 +94,7 @@ const initializeAirDCPPSocket = async (configuration) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
return initializedAirDCPPSocket;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. get settings from mongo
|
// 1. get settings from mongo
|
||||||
@@ -97,8 +107,11 @@ const directConnectConfiguration = data?.directConnect.client.host;
|
|||||||
|
|
||||||
// 2. If available, init AirDC++ Socket with those settings
|
// 2. If available, init AirDC++ Socket with those settings
|
||||||
if (!isEmpty(directConnectConfiguration)) {
|
if (!isEmpty(directConnectConfiguration)) {
|
||||||
initializeAirDCPPSocket(directConnectConfiguration);
|
const airDCPPSocketInstance = await initializeAirDCPPSocket(
|
||||||
|
directConnectConfiguration,
|
||||||
|
);
|
||||||
setState({
|
setState({
|
||||||
|
airDCPPSocketInstance,
|
||||||
airDCPPClientConfiguration: directConnectConfiguration,
|
airDCPPClientConfiguration: directConnectConfiguration,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user