mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: replace context with slice
This commit is contained in:
parent
1f72bb6138
commit
1bf2c8faf9
12 changed files with 93 additions and 110 deletions
|
@ -1,17 +1,12 @@
|
|||
import { userAuthRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services/hydra-api";
|
||||
import { WindowManager } from "@main/services";
|
||||
|
||||
const signout = async (_event: Electron.IpcMainInvokeEvent): Promise<void> => {
|
||||
await Promise.all([
|
||||
userAuthRepository.delete({ id: 1 }),
|
||||
HydraApi.post("/auth/logout"),
|
||||
]).finally(() => {
|
||||
if (WindowManager.mainWindow) {
|
||||
WindowManager.mainWindow.webContents.send("on-signout");
|
||||
}
|
||||
});
|
||||
]);
|
||||
};
|
||||
|
||||
registerEvent("signout", signout);
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
toggleDraggingDisabled,
|
||||
closeToast,
|
||||
} from "@renderer/features";
|
||||
import { useUserAuth } from "./hooks/use-user-auth";
|
||||
|
||||
export interface AppProps {
|
||||
children: React.ReactNode;
|
||||
|
@ -67,6 +68,23 @@ export function App() {
|
|||
};
|
||||
}, [clearDownload, setLastPacket, updateLibrary]);
|
||||
|
||||
const { updateUserAuth, clearUserAuth } = useUserAuth();
|
||||
|
||||
useEffect(() => {
|
||||
const listeners = [
|
||||
window.electron.onSignIn(() => {
|
||||
updateUserAuth();
|
||||
}),
|
||||
window.electron.onSignOut(() => {
|
||||
clearUserAuth();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
listeners.forEach((unsubscribe) => unsubscribe());
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSearch = useCallback(
|
||||
(query: string) => {
|
||||
dispatch(setSearch(query));
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { useContext } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { PersonIcon } from "@primer/octicons-react";
|
||||
import { userAuthContext } from "@renderer/context/user-auth/user-auth.context";
|
||||
import * as styles from "./sidebar.css";
|
||||
import { useUserAuth } from "@renderer/hooks/use-user-auth";
|
||||
|
||||
export function SidebarProfile() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { userAuth, isLoading } = useContext(userAuthContext);
|
||||
const { userAuth, isLoading } = useUserAuth();
|
||||
|
||||
const handleClickProfile = () => {
|
||||
navigate(`/user/${userAuth!.id}`);
|
||||
|
|
|
@ -14,7 +14,6 @@ import { buildGameDetailsPath } from "@renderer/helpers";
|
|||
|
||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||
import { SidebarProfile } from "./sidebar-profile";
|
||||
import { UserAuthContextProvider } from "@renderer/context/user-auth/user-auth.context";
|
||||
|
||||
const SIDEBAR_MIN_WIDTH = 200;
|
||||
const SIDEBAR_INITIAL_WIDTH = 250;
|
||||
|
@ -155,9 +154,7 @@ export function Sidebar() {
|
|||
maxWidth: sidebarWidth,
|
||||
}}
|
||||
>
|
||||
<UserAuthContextProvider>
|
||||
<SidebarProfile />
|
||||
</UserAuthContextProvider>
|
||||
<SidebarProfile />
|
||||
|
||||
<div
|
||||
className={styles.content({
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
import { createContext, useEffect, useState } from "react";
|
||||
import { UserAuthContext } from "./user-auth.context.types";
|
||||
import { UserAuth } from "@types";
|
||||
|
||||
export const userAuthContext = createContext<UserAuthContext>({
|
||||
userAuth: null,
|
||||
isLoading: false,
|
||||
signout: async () => {},
|
||||
updateMe: async () => {},
|
||||
});
|
||||
|
||||
const { Provider } = userAuthContext;
|
||||
export const { Consumer: UserAuthContextConsumer } = userAuthContext;
|
||||
|
||||
export interface UserAuthContextProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function UserAuthContextProvider({ children }: UserAuthContextProps) {
|
||||
const [userAuth, setUserAuth] = useState<UserAuth | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const updateMe = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
return window.electron
|
||||
.getMe()
|
||||
.then((user) => {
|
||||
setUserAuth(user);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateMe();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const listeners = [
|
||||
window.electron.onSignIn(() => {
|
||||
updateMe();
|
||||
}),
|
||||
window.electron.onSignOut(() => {
|
||||
setUserAuth(null);
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
listeners.forEach((unsubscribe) => unsubscribe());
|
||||
};
|
||||
}, []);
|
||||
|
||||
const signout = () => {
|
||||
return window.electron.signout().finally(() => {
|
||||
setUserAuth(null);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Provider
|
||||
value={{
|
||||
userAuth,
|
||||
signout,
|
||||
updateMe,
|
||||
isLoading,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Provider>
|
||||
);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import { UserAuth } from "@types";
|
||||
|
||||
export interface UserAuthContext {
|
||||
userAuth: UserAuth | null;
|
||||
isLoading: boolean;
|
||||
updateMe: () => Promise<void>;
|
||||
signout: () => Promise<void>;
|
||||
}
|
|
@ -4,3 +4,4 @@ export * from "./use-preferences-slice";
|
|||
export * from "./download-slice";
|
||||
export * from "./window-slice";
|
||||
export * from "./toast-slice";
|
||||
export * from "./user-auth-slice";
|
||||
|
|
22
src/renderer/src/features/user-auth-slice.ts
Normal file
22
src/renderer/src/features/user-auth-slice.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import type { UserAuth } from "@types";
|
||||
|
||||
export interface UserAuthState {
|
||||
userAuth: UserAuth | null;
|
||||
}
|
||||
|
||||
const initialState: UserAuthState = {
|
||||
userAuth: null,
|
||||
};
|
||||
|
||||
export const userAuthSlice = createSlice({
|
||||
name: "user-auth",
|
||||
initialState,
|
||||
reducers: {
|
||||
setUserAuth: (state, userAuth: PayloadAction<UserAuth | null>) => {
|
||||
state.userAuth = userAuth.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setUserAuth } = userAuthSlice.actions;
|
33
src/renderer/src/hooks/use-user-auth.ts
Normal file
33
src/renderer/src/hooks/use-user-auth.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { useCallback, useState } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "./redux";
|
||||
import { setUserAuth } from "@renderer/features";
|
||||
|
||||
export function useUserAuth() {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const { userAuth } = useAppSelector((state) => state.userAuth);
|
||||
|
||||
const signOut = useCallback(async () => {
|
||||
dispatch(setUserAuth(null));
|
||||
return window.electron.signout();
|
||||
}, [dispatch]);
|
||||
|
||||
const updateUserAuth = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
return window.electron
|
||||
.getMe()
|
||||
.then((userAuth) => dispatch(setUserAuth(userAuth)))
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
const clearUserAuth = useCallback(async () => {
|
||||
dispatch(setUserAuth(null));
|
||||
}, [dispatch]);
|
||||
|
||||
return { userAuth, isLoading, updateUserAuth, signOut, clearUserAuth };
|
||||
}
|
|
@ -2,7 +2,7 @@ import { ProfileGame, UserProfile } from "@types";
|
|||
import cn from "classnames";
|
||||
import * as styles from "./user.css";
|
||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||
import { useContext, useMemo } from "react";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||
import { useDate } from "@renderer/hooks";
|
||||
|
@ -10,7 +10,7 @@ import { useNavigate } from "react-router-dom";
|
|||
import { buildGameDetailsPath } from "@renderer/helpers";
|
||||
import { PersonIcon } from "@primer/octicons-react";
|
||||
import { Button } from "@renderer/components";
|
||||
import { userAuthContext } from "@renderer/context/user-auth/user-auth.context";
|
||||
import { useUserAuth } from "@renderer/hooks/use-user-auth";
|
||||
|
||||
const MAX_MINUTES_TO_SHOW_IN_PLAYTIME = 120;
|
||||
export interface ProfileContentProps {
|
||||
|
@ -20,7 +20,7 @@ export interface ProfileContentProps {
|
|||
export const UserContent = ({ userProfile }: ProfileContentProps) => {
|
||||
const { t, i18n } = useTranslation("user_profile");
|
||||
|
||||
const { userAuth, signout } = useContext(userAuthContext);
|
||||
const { userAuth, signOut } = useUserAuth();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
@ -54,7 +54,7 @@ export const UserContent = ({ userProfile }: ProfileContentProps) => {
|
|||
};
|
||||
|
||||
const handleSignout = async () => {
|
||||
await signout();
|
||||
await signOut();
|
||||
navigate("/");
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import { UserContent } from "./user-content";
|
|||
import { SkeletonTheme } from "react-loading-skeleton";
|
||||
import { vars } from "@renderer/theme.css";
|
||||
import * as styles from "./user.css";
|
||||
import { UserAuthContextProvider } from "@renderer/context/user-auth/user-auth.context";
|
||||
|
||||
export const User = () => {
|
||||
const { username } = useParams();
|
||||
|
@ -26,16 +25,14 @@ export const User = () => {
|
|||
}, [dispatch, username]);
|
||||
|
||||
return (
|
||||
<UserAuthContextProvider>
|
||||
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
||||
<div className={styles.wrapper}>
|
||||
{userProfile ? (
|
||||
<UserContent userProfile={userProfile} />
|
||||
) : (
|
||||
<UserSkeleton />
|
||||
)}
|
||||
</div>
|
||||
</SkeletonTheme>
|
||||
</UserAuthContextProvider>
|
||||
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
||||
<div className={styles.wrapper}>
|
||||
{userProfile ? (
|
||||
<UserContent userProfile={userProfile} />
|
||||
) : (
|
||||
<UserSkeleton />
|
||||
)}
|
||||
</div>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
searchSlice,
|
||||
userPreferencesSlice,
|
||||
toastSlice,
|
||||
userAuthSlice,
|
||||
} from "@renderer/features";
|
||||
|
||||
export const store = configureStore({
|
||||
|
@ -16,6 +17,7 @@ export const store = configureStore({
|
|||
userPreferences: userPreferencesSlice.reducer,
|
||||
download: downloadSlice.reducer,
|
||||
toast: toastSlice.reducer,
|
||||
userAuth: userAuthSlice.reducer,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue