From a8624058e48a7e189645b2ac01b93e3db09bdb94 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Tue, 18 Jun 2024 20:29:37 +0100 Subject: [PATCH] feat: adding user local storage cache --- src/renderer/src/app.tsx | 30 ++++-- .../components/sidebar/sidebar-profile.css.ts | 58 +++++++++++ .../components/sidebar/sidebar-profile.tsx | 58 ++++------- .../src/components/sidebar/sidebar.css.ts | 45 --------- src/renderer/src/declaration.d.ts | 2 +- .../src/features/user-details-slice.ts | 10 +- src/renderer/src/hooks/use-user-details.ts | 97 +++++++++---------- .../src/pages/user/user-edit-modal.tsx | 1 - 8 files changed, 152 insertions(+), 149 deletions(-) create mode 100644 src/renderer/src/components/sidebar/sidebar-profile.css.ts diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 792a2df2..e038d557 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -19,6 +19,8 @@ import { setUserPreferences, toggleDraggingDisabled, closeToast, + setUserDetails, + setProfileBackground, } from "@renderer/features"; export interface AppProps { @@ -31,7 +33,8 @@ export function App() { const { clearDownload, setLastPacket } = useDownload(); - const { updateUser, clearUser } = useUserDetails(); + const { fetchUserDetails, updateUserDetails, clearUserDetails } = + useUserDetails(); const dispatch = useAppDispatch(); @@ -73,23 +76,38 @@ export function App() { }, [clearDownload, setLastPacket, updateLibrary]); useEffect(() => { - updateUser(); - }, [updateUser]); + const cachedUserDetails = window.localStorage.getItem("userDetails"); + + if (cachedUserDetails) { + const { profileBackground, ...userDetails } = + JSON.parse(cachedUserDetails); + + dispatch(setUserDetails(userDetails)); + dispatch(setProfileBackground(profileBackground)); + } + + /* TODO: Check if user is logged in before calling this */ + fetchUserDetails().then((response) => { + if (response) setUserDetails(response); + }); + }, [dispatch, fetchUserDetails]); useEffect(() => { const listeners = [ window.electron.onSignIn(() => { - updateUser(); + fetchUserDetails().then((response) => { + if (response) updateUserDetails(response); + }); }), window.electron.onSignOut(() => { - clearUser(); + clearUserDetails(); }), ]; return () => { listeners.forEach((unsubscribe) => unsubscribe()); }; - }, [updateUser, clearUser]); + }, [fetchUserDetails, updateUserDetails, clearUserDetails]); const handleSearch = useCallback( (query: string) => { diff --git a/src/renderer/src/components/sidebar/sidebar-profile.css.ts b/src/renderer/src/components/sidebar/sidebar-profile.css.ts new file mode 100644 index 00000000..9681c866 --- /dev/null +++ b/src/renderer/src/components/sidebar/sidebar-profile.css.ts @@ -0,0 +1,58 @@ +import { style } from "@vanilla-extract/css"; + +import { SPACING_UNIT, vars } from "../../theme.css"; + +export const profileButton = style({ + display: "flex", + cursor: "pointer", + transition: "all ease 0.1s", + padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`, + color: vars.color.muted, + borderBottom: `solid 1px ${vars.color.border}`, + boxShadow: "0px 0px 15px 0px #000000", + ":hover": { + backgroundColor: "rgba(255, 255, 255, 0.15)", + }, +}); + +export const profileButtonContent = style({ + display: "flex", + alignItems: "center", + gap: `${SPACING_UNIT + SPACING_UNIT / 2}px`, + height: "40px", +}); + +export const profileAvatar = style({ + width: "35px", + height: "35px", + borderRadius: "50%", + display: "flex", + justifyContent: "center", + alignItems: "center", + backgroundColor: vars.color.background, + border: `solid 1px ${vars.color.border}`, + position: "relative", + objectFit: "cover", +}); + +export const profileButtonInformation = style({ + display: "flex", + flexDirection: "column", + alignItems: "flex-start", +}); + +export const statusBadge = style({ + width: "9px", + height: "9px", + borderRadius: "50%", + backgroundColor: vars.color.danger, + position: "absolute", + bottom: "-2px", + right: "-3px", + zIndex: "1", +}); + +export const profileButtonTitle = style({ + fontWeight: "bold", + fontSize: vars.size.body, +}); diff --git a/src/renderer/src/components/sidebar/sidebar-profile.tsx b/src/renderer/src/components/sidebar/sidebar-profile.tsx index c81b24fb..4a89eff1 100644 --- a/src/renderer/src/components/sidebar/sidebar-profile.tsx +++ b/src/renderer/src/components/sidebar/sidebar-profile.tsx @@ -1,6 +1,7 @@ import { useNavigate } from "react-router-dom"; import { PersonIcon } from "@primer/octicons-react"; -import * as styles from "./sidebar.css"; +import * as styles from "./sidebar-profile.css"; + import { useUserDetails } from "@renderer/hooks"; import { useMemo } from "react"; @@ -9,12 +10,13 @@ export function SidebarProfile() { const { userDetails, profileBackground } = useUserDetails(); - const handleClickProfile = () => { - navigate(`/user/${userDetails!.id}`); - }; + const handleButtonClick = () => { + if (userDetails === null) { + window.electron.openExternal("https://auth.hydra.losbroxas.org"); + return; + } - const handleClickLogin = () => { - window.electron.openExternal("https://auth.hydra.losbroxas.org"); + navigate(`/user/${userDetails!.id}`); }; const profileButtonBackground = useMemo(() => { @@ -22,36 +24,16 @@ export function SidebarProfile() { return undefined; }, [profileBackground]); - if (userDetails == null) { - return ( - <> - - - ); - } - return ( - <> - - + + ); } diff --git a/src/renderer/src/components/sidebar/sidebar.css.ts b/src/renderer/src/components/sidebar/sidebar.css.ts index 5a96e87a..75ac2dd5 100644 --- a/src/renderer/src/components/sidebar/sidebar.css.ts +++ b/src/renderer/src/components/sidebar/sidebar.css.ts @@ -125,48 +125,3 @@ export const section = style({ flexDirection: "column", paddingBottom: `${SPACING_UNIT}px`, }); - -export const profileButton = style({ - display: "flex", - cursor: "pointer", - transition: "all ease 0.1s", - gap: `${SPACING_UNIT + SPACING_UNIT / 2}px`, - alignItems: "center", - padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`, - color: vars.color.muted, - borderBottom: `solid 1px ${vars.color.border}`, - boxShadow: "0px 0px 15px 0px #000000", - ":hover": { - backgroundColor: "rgba(255, 255, 255, 0.15)", - }, -}); - -export const profileAvatar = style({ - width: "30px", - height: "30px", - borderRadius: "50%", - display: "flex", - justifyContent: "center", - alignItems: "center", - backgroundColor: vars.color.background, - border: `solid 1px ${vars.color.border}`, - position: "relative", - objectFit: "cover", -}); - -export const profileButtonInformation = style({ - display: "flex", - flexDirection: "column", - alignItems: "flex-start", -}); - -export const statusBadge = style({ - width: "9px", - height: "9px", - borderRadius: "50%", - backgroundColor: vars.color.danger, - position: "absolute", - bottom: "-2px", - right: "-3px", - zIndex: "1", -}); diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 40fc708b..2201a754 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -125,7 +125,7 @@ declare global { updateProfile: ( displayName: string, newProfileImagePath: string | null - ) => Promise; + ) => Promise; } interface Window { diff --git a/src/renderer/src/features/user-details-slice.ts b/src/renderer/src/features/user-details-slice.ts index af14ce56..0cc395b0 100644 --- a/src/renderer/src/features/user-details-slice.ts +++ b/src/renderer/src/features/user-details-slice.ts @@ -15,18 +15,14 @@ export const userDetailsSlice = createSlice({ name: "user-details", initialState, reducers: { - setUserDetails: (state, action: PayloadAction) => { + setUserDetails: (state, action: PayloadAction) => { state.userDetails = action.payload; }, - setProfileBackground: (state, action: PayloadAction) => { + setProfileBackground: (state, action: PayloadAction) => { state.profileBackground = action.payload; }, - clearUserDetails: (state) => { - state.userDetails = null; - state.profileBackground = null; - }, }, }); -export const { setUserDetails, setProfileBackground, clearUserDetails } = +export const { setUserDetails, setProfileBackground } = userDetailsSlice.actions; diff --git a/src/renderer/src/hooks/use-user-details.ts b/src/renderer/src/hooks/use-user-details.ts index 3a5ff515..e36fcd36 100644 --- a/src/renderer/src/hooks/use-user-details.ts +++ b/src/renderer/src/hooks/use-user-details.ts @@ -2,12 +2,9 @@ import { useCallback } from "react"; import { average } from "color.js"; import { useAppDispatch, useAppSelector } from "./redux"; -import { - clearUserDetails, - setProfileBackground, - setUserDetails, -} from "@renderer/features"; +import { setProfileBackground, setUserDetails } from "@renderer/features"; import { darkenColor } from "@renderer/helpers"; +import { UserDetails } from "@types"; export function useUserDetails() { const dispatch = useAppDispatch(); @@ -16,68 +13,64 @@ export function useUserDetails() { (state) => state.userDetails ); - const clearUser = useCallback(async () => { - dispatch(clearUserDetails()); + const clearUserDetails = useCallback(async () => { + dispatch(setUserDetails(null)); + dispatch(setProfileBackground(null)); + + window.localStorage.removeItem("userDetails"); }, [dispatch]); const signOut = useCallback(async () => { - clearUser(); + clearUserDetails(); return window.electron.signOut(); - }, [clearUser]); + }, [clearUserDetails]); - const updateUser = useCallback(async () => { - return window.electron.getMe().then(async (userDetails) => { - if (userDetails) { - dispatch(setUserDetails(userDetails)); + const updateUserDetails = useCallback( + async (userDetails: UserDetails) => { + dispatch(setUserDetails(userDetails)); - if (userDetails.profileImageUrl) { - const output = await average(userDetails.profileImageUrl, { - amount: 1, - format: "hex", - }); - - dispatch( - setProfileBackground( - `linear-gradient(135deg, ${darkenColor(output as string, 0.6)}, ${darkenColor(output as string, 0.7)})` - ) - ); - } - } - }); - }, [dispatch]); - - const patchUser = useCallback( - async (displayName: string, imageProfileUrl: string | null) => { - return window.electron - .updateProfile(displayName, imageProfileUrl) - .then(async (userDetails) => { - if (userDetails) { - dispatch(setUserDetails(userDetails)); - - if (userDetails.profileImageUrl) { - const output = await average(userDetails.profileImageUrl, { - amount: 1, - format: "hex", - }); - - dispatch( - setProfileBackground( - `linear-gradient(135deg, ${darkenColor(output as string, 0.6)}, ${darkenColor(output as string, 0.7)})` - ) - ); - } - } + if (userDetails.profileImageUrl) { + const output = await average(userDetails.profileImageUrl, { + amount: 1, + format: "hex", }); + + const profileBackground = `linear-gradient(135deg, ${darkenColor(output as string, 0.6)}, ${darkenColor(output as string, 0.8)})`; + + dispatch(setProfileBackground(profileBackground)); + + window.localStorage.setItem( + "userDetails", + JSON.stringify({ ...userDetails, profileBackground }) + ); + } }, [dispatch] ); + const fetchUserDetails = useCallback(async () => { + return window.electron.getMe(); + }, []); + + const patchUser = useCallback( + async (displayName: string, imageProfileUrl: string | null) => { + const response = await window.electron.updateProfile( + displayName, + imageProfileUrl + ); + + return updateUserDetails(response); + }, + [updateUserDetails] + ); + return { userDetails, - updateUser, + fetchUserDetails, signOut, - clearUser, + clearUserDetails, + updateUserDetails, patchUser, profileBackground, }; diff --git a/src/renderer/src/pages/user/user-edit-modal.tsx b/src/renderer/src/pages/user/user-edit-modal.tsx index 71ae112f..d70ec510 100644 --- a/src/renderer/src/pages/user/user-edit-modal.tsx +++ b/src/renderer/src/pages/user/user-edit-modal.tsx @@ -71,7 +71,6 @@ export const UserEditProfileModal = ({