dev: Updating themening worfkflow (#1827)

This commit is contained in:
guru_sainath 2023-08-10 13:03:42 +05:30 committed by GitHub
parent be062ccd34
commit 005b42cb8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 251 additions and 231 deletions

View File

@ -4,17 +4,13 @@ import { useTheme } from "next-themes";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// hooks
import useUser from "hooks/use-user";
// ui // ui
import { PrimaryButton } from "components/ui"; import { PrimaryButton } from "components/ui";
import { ColorPickerInput } from "components/core"; import { ColorPickerInput } from "components/core";
// services
import userService from "services/user.service";
// helper
import { applyTheme } from "helpers/theme.helper";
// types // types
import { ICustomTheme } from "types"; import { ICustomTheme } from "types";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
@ -33,11 +29,11 @@ const defaultValues: ICustomTheme = {
theme: "custom", theme: "custom",
}; };
export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => { export const CustomThemeSelector: React.FC<Props> = observer(({ preLoadedData }) => {
const store: any = useMobxStore(); const store: any = useMobxStore();
const { setTheme } = useTheme();
const [darkPalette, setDarkPalette] = useState(false); const [darkPalette, setDarkPalette] = useState(false);
const { const {
register, register,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
@ -48,11 +44,14 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
} = useForm<ICustomTheme>({ } = useForm<ICustomTheme>({
defaultValues, defaultValues,
}); });
useEffect(() => {
reset({
...defaultValues,
...preLoadedData,
});
}, [preLoadedData, reset]);
const { setTheme } = useTheme(); const handleUpdateTheme = async (formData: any) => {
const { mutateUser } = useUser();
const handleFormSubmit = async (formData: ICustomTheme) => {
const payload: ICustomTheme = { const payload: ICustomTheme = {
background: formData.background, background: formData.background,
text: formData.text, text: formData.text,
@ -64,28 +63,14 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
theme: "custom", theme: "custom",
}; };
store.user
.updateCurrentUserSettings({ theme: payload })
.then((response: any) => {
setTheme("custom"); setTheme("custom");
applyTheme(payload.palette, darkPalette);
})
.catch((error: any) => {
console.log("error", error);
});
};
const handleUpdateTheme = async (formData: any) => { return store.user
await handleFormSubmit({ ...formData, darkPalette }); .updateCurrentUserSettings({ theme: payload })
.then((response: any) => response)
.catch((error: any) => error);
}; };
useEffect(() => {
reset({
...defaultValues,
...preLoadedData,
});
}, [preLoadedData, reset]);
return ( return (
<form onSubmit={handleSubmit(handleUpdateTheme)}> <form onSubmit={handleSubmit(handleUpdateTheme)}>
<div className="space-y-5"> <div className="space-y-5">
@ -164,4 +149,4 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
</div> </div>
</form> </form>
); );
}; });

View File

@ -1,9 +1,5 @@
import { useState, useEffect } from "react";
// next-themes // next-themes
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
// services
import userService from "services/user.service";
// hooks // hooks
import useUser from "hooks/use-user"; import useUser from "hooks/use-user";
// constants // constants
@ -13,6 +9,10 @@ import { CustomSelect } from "components/ui";
// types // types
import { ICustomTheme } from "types"; import { ICustomTheme } from "types";
import { unsetCustomCssVariables } from "helpers/theme.helper"; import { unsetCustomCssVariables } from "helpers/theme.helper";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
type Props = { type Props = {
setPreLoadedData: React.Dispatch<React.SetStateAction<ICustomTheme | null>>; setPreLoadedData: React.Dispatch<React.SetStateAction<ICustomTheme | null>>;
@ -20,48 +20,21 @@ type Props = {
setCustomThemeSelectorOptions: React.Dispatch<React.SetStateAction<boolean>>; setCustomThemeSelectorOptions: React.Dispatch<React.SetStateAction<boolean>>;
}; };
export const ThemeSwitch: React.FC<Props> = ({ export const ThemeSwitch: React.FC<Props> = observer(
setPreLoadedData, ({ setPreLoadedData, customThemeSelectorOptions, setCustomThemeSelectorOptions }) => {
customThemeSelectorOptions, const store: any = useMobxStore();
setCustomThemeSelectorOptions,
}) => {
const [mounted, setMounted] = useState(false);
const { theme, setTheme } = useTheme();
const { user, mutateUser } = useUser(); const { user, mutateUser } = useUser();
const { theme, setTheme } = useTheme();
const updateUserTheme = (newTheme: string) => { const updateUserTheme = (newTheme: string) => {
if (!user) return; if (!user) return;
setTheme(newTheme); setTheme(newTheme);
return store.user
mutateUser((prevData) => { .updateCurrentUserSettings({ theme: { ...user.theme, theme: newTheme } })
if (!prevData) return prevData; .then((response: any) => response)
.catch((error: any) => error);
return {
...prevData,
theme: {
...prevData.theme,
theme: newTheme,
},
}; };
}, false);
userService.updateUser({
theme: {
...user.theme,
theme: newTheme,
},
});
};
// useEffect only runs on the client, so now we can safely show the UI
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return null;
const currentThemeObj = THEMES_OBJ.find((t) => t.value === theme); const currentThemeObj = THEMES_OBJ.find((t) => t.value === theme);
@ -158,4 +131,5 @@ export const ThemeSwitch: React.FC<Props> = ({
))} ))}
</CustomSelect> </CustomSelect>
); );
}; }
);

View File

@ -1,9 +1,14 @@
import { useEffect } from "react"; import { useEffect } from "react";
// next themes
import { useTheme } from "next-themes";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
// theme helpers
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
const MobxStoreInit = () => { const MobxStoreInit = () => {
const store: any = useMobxStore(); const store: any = useMobxStore();
const { setTheme } = useTheme();
useEffect(() => { useEffect(() => {
// sidebar collapsed toggle // sidebar collapsed toggle
@ -21,11 +26,25 @@ const MobxStoreInit = () => {
); );
// theme // theme
if (localStorage && localStorage.getItem("theme") && store.theme.theme === null) if (store.theme.theme === null && store?.user?.currentUserSettings) {
store.theme.setTheme( let currentTheme = localStorage.getItem("theme");
localStorage.getItem("theme") ? localStorage.getItem("theme") : "system" currentTheme = currentTheme ? currentTheme : "system";
);
}, [store?.theme]); // validating the theme and applying for initial state
if (currentTheme) {
setTheme(currentTheme);
store.theme.setTheme({ theme: { theme: currentTheme } });
}
}
}, [store?.theme, store?.user, setTheme]);
useEffect(() => {
// current user
if (store?.user?.currentUser === null) store.user.setCurrentUser();
// current user settings
if (store?.user?.currentUserSettings === null) store.user.setCurrentUserSettings();
}, [store?.user]);
return <></>; return <></>;
}; };

View File

@ -1,7 +1,4 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
// next-themes
import { useTheme } from "next-themes";
// hooks // hooks
import useUserAuth from "hooks/use-user-auth"; import useUserAuth from "hooks/use-user-auth";
// layouts // layouts
@ -14,37 +11,47 @@ import { Spinner } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types // types
import { ICustomTheme } from "types"; import { ICustomTheme } from "types";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// next themes
import { useTheme } from "next-themes";
const ProfilePreferences = () => { const ProfilePreferences = observer(() => {
const [customThemeSelectorOptions, setCustomThemeSelectorOptions] = useState(false);
const [preLoadedData, setPreLoadedData] = useState<ICustomTheme | null>(null);
const { theme } = useTheme();
const { user: myProfile } = useUserAuth(); const { user: myProfile } = useUserAuth();
const store: any = useMobxStore();
const { theme } = useTheme();
console.log("store", store?.theme?.theme);
console.log("theme", theme);
const [customThemeSelectorOptions, setCustomThemeSelectorOptions] = useState(false);
const [preLoadedData, setPreLoadedData] = useState<ICustomTheme | null>(null);
useEffect(() => { useEffect(() => {
if (theme === "custom") { if (store?.user && store?.theme?.theme === "custom") {
if (myProfile?.theme.palette) const currentTheme = store?.user?.currentUserSettings?.theme;
if (currentTheme.palette)
setPreLoadedData({ setPreLoadedData({
background: myProfile.theme.background !== "" ? myProfile.theme.background : "#0d101b", background: currentTheme.background !== "" ? currentTheme.background : "#0d101b",
text: myProfile.theme.text !== "" ? myProfile.theme.text : "#c5c5c5", text: currentTheme.text !== "" ? currentTheme.text : "#c5c5c5",
primary: myProfile.theme.primary !== "" ? myProfile.theme.primary : "#3f76ff", primary: currentTheme.primary !== "" ? currentTheme.primary : "#3f76ff",
sidebarBackground: sidebarBackground:
myProfile.theme.sidebarBackground !== "" currentTheme.sidebarBackground !== "" ? currentTheme.sidebarBackground : "#0d101b",
? myProfile.theme.sidebarBackground sidebarText: currentTheme.sidebarText !== "" ? currentTheme.sidebarText : "#c5c5c5",
: "#0d101b",
sidebarText: myProfile.theme.sidebarText !== "" ? myProfile.theme.sidebarText : "#c5c5c5",
darkPalette: false, darkPalette: false,
palette: palette:
myProfile.theme.palette !== ",,,," currentTheme.palette !== ",,,,"
? myProfile.theme.palette ? currentTheme.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
theme: "custom", theme: "custom",
}); });
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true); setCustomThemeSelectorOptions((prevData) => true);
} }
}, [myProfile, theme, customThemeSelectorOptions]); }, [store, store?.theme?.theme]);
return ( return (
<WorkspaceAuthorizationLayout <WorkspaceAuthorizationLayout
@ -91,6 +98,6 @@ const ProfilePreferences = () => {
)} )}
</WorkspaceAuthorizationLayout> </WorkspaceAuthorizationLayout>
); );
}; });
export default ProfilePreferences; export default ProfilePreferences;

View File

@ -22,8 +22,14 @@ import {
import { Spinner } from "components/ui"; import { Spinner } from "components/ui";
// images // images
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png"; import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// next themes
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { ICurrentUserResponse, IUser } from "types"; import { IUser } from "types";
// types // types
type EmailPasswordFormValues = { type EmailPasswordFormValues = {
email: string; email: string;
@ -31,15 +37,18 @@ type EmailPasswordFormValues = {
medium?: string; medium?: string;
}; };
const HomePage: NextPage = () => { const HomePage: NextPage = observer(() => {
const store: any = useMobxStore();
const { setTheme } = useTheme();
const { isLoading, mutateUser } = useUserAuth("sign-in"); const { isLoading, mutateUser } = useUserAuth("sign-in");
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { setTheme } = useTheme(); const handleTheme = (user: IUser) => {
const currentTheme = user.theme.theme ?? "system";
const changeTheme = (user: IUser) => { setTheme(currentTheme);
setTheme(user.theme.theme ?? "system"); store?.user?.setCurrentUserSettings();
}; };
const handleGoogleSignIn = async ({ clientId, credential }: any) => { const handleGoogleSignIn = async ({ clientId, credential }: any) => {
@ -53,7 +62,7 @@ const HomePage: NextPage = () => {
const response = await authenticationService.socialAuth(socialAuthPayload); const response = await authenticationService.socialAuth(socialAuthPayload);
if (response && response?.user) { if (response && response?.user) {
mutateUser(); mutateUser();
changeTheme(response.user); handleTheme(response?.user);
} }
} else { } else {
throw Error("Cant find credentials"); throw Error("Cant find credentials");
@ -79,7 +88,7 @@ const HomePage: NextPage = () => {
const response = await authenticationService.socialAuth(socialAuthPayload); const response = await authenticationService.socialAuth(socialAuthPayload);
if (response && response?.user) { if (response && response?.user) {
mutateUser(); mutateUser();
changeTheme(response.user); handleTheme(response?.user);
} }
} else { } else {
throw Error("Cant find credentials"); throw Error("Cant find credentials");
@ -101,7 +110,7 @@ const HomePage: NextPage = () => {
try { try {
if (response) { if (response) {
mutateUser(); mutateUser();
changeTheme(response.user); handleTheme(response?.user);
} }
} catch (err: any) { } catch (err: any) {
setToastAlert({ setToastAlert({
@ -128,7 +137,7 @@ const HomePage: NextPage = () => {
try { try {
if (response) { if (response) {
mutateUser(); mutateUser();
changeTheme(response.user); handleTheme(response?.user);
} }
} catch (err: any) { } catch (err: any) {
setToastAlert({ setToastAlert({
@ -140,10 +149,6 @@ const HomePage: NextPage = () => {
} }
}; };
useEffect(() => {
setTheme("system");
}, [setTheme]);
return ( return (
<DefaultLayout> <DefaultLayout>
{isLoading ? ( {isLoading ? (
@ -202,6 +207,6 @@ const HomePage: NextPage = () => {
)} )}
</DefaultLayout> </DefaultLayout>
); );
}; });
export default HomePage; export default HomePage;

View File

@ -38,21 +38,24 @@ class ThemeStore {
} }
} }
setTheme = async (_theme: ICurrentUserSettings) => { setTheme = async (_theme: { theme: ICurrentUserSettings }) => {
try { try {
localStorage.setItem("theme", _theme.theme.toString()); const currentTheme: string = _theme.theme.theme.toString();
this.theme = _theme.theme.toString();
if (this.theme === "custom") { // updating the local storage theme value
let themeSettings = this.rootStore.user.currentUserSettings || null; localStorage.setItem("theme", currentTheme);
if (themeSettings && themeSettings.theme.palette) { // updating the mobx theme value
this.theme = currentTheme;
// applying the theme to platform if the selected theme is custom
if (currentTheme === "custom") {
const themeSettings = this.rootStore.user.currentUserSettings || null;
applyTheme( applyTheme(
themeSettings.theme.palette !== ",,,," themeSettings?.theme?.palette !== ",,,,"
? themeSettings.theme.palette ? themeSettings?.theme?.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5", : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
themeSettings.theme.darkPalette themeSettings?.theme?.darkPalette
); );
}
} else unsetCustomCssVariables(); } else unsetCustomCssVariables();
} catch (error) { } catch (error) {
console.error("setting user theme error", error); console.error("setting user theme error", error);

View File

@ -1,5 +1,5 @@
// mobx // mobx
import { action, observable, computed, makeObservable } from "mobx"; import { action, observable, computed, runInAction, makeObservable } from "mobx";
// services // services
import UserService from "services/user.service"; import UserService from "services/user.service";
// interfaces // interfaces
@ -31,8 +31,9 @@ class UserStore {
try { try {
let userResponse: ICurrentUser | null = await UserService.currentUser(); let userResponse: ICurrentUser | null = await UserService.currentUser();
userResponse = userResponse || null; userResponse = userResponse || null;
if (userResponse) { if (userResponse) {
this.currentUser = { const userPayload: ICurrentUser = {
id: userResponse?.id, id: userResponse?.id,
avatar: userResponse?.avatar, avatar: userResponse?.avatar,
first_name: userResponse?.first_name, first_name: userResponse?.first_name,
@ -46,6 +47,9 @@ class UserStore {
is_onboarded: userResponse?.is_onboarded, is_onboarded: userResponse?.is_onboarded,
role: userResponse?.role, role: userResponse?.role,
}; };
runInAction(() => {
this.currentUser = userPayload;
});
} }
} catch (error) { } catch (error) {
console.error("Fetching current user error", error); console.error("Fetching current user error", error);
@ -56,11 +60,15 @@ class UserStore {
try { try {
let userSettingsResponse: ICurrentUserSettings | null = await UserService.currentUser(); let userSettingsResponse: ICurrentUserSettings | null = await UserService.currentUser();
userSettingsResponse = userSettingsResponse || null; userSettingsResponse = userSettingsResponse || null;
if (userSettingsResponse) { if (userSettingsResponse) {
this.currentUserSettings = { const themePayload = {
theme: userSettingsResponse?.theme, theme: { ...userSettingsResponse?.theme },
}; };
this.rootStore.theme.setTheme(); runInAction(() => {
this.currentUserSettings = themePayload;
this.rootStore.theme.setTheme(themePayload);
});
} }
} catch (error) { } catch (error) {
console.error("Fetching current user error", error); console.error("Fetching current user error", error);
@ -71,9 +79,26 @@ class UserStore {
try { try {
let userResponse: ICurrentUser = await UserService.updateUser(user); let userResponse: ICurrentUser = await UserService.updateUser(user);
userResponse = userResponse || null; userResponse = userResponse || null;
if (userResponse) { if (userResponse) {
this.currentUser = userResponse; const userPayload: ICurrentUser = {
return userResponse; id: userResponse?.id,
avatar: userResponse?.avatar,
first_name: userResponse?.first_name,
last_name: userResponse?.last_name,
username: userResponse?.username,
email: userResponse?.email,
mobile_number: userResponse?.mobile_number,
is_email_verified: userResponse?.is_email_verified,
is_tour_completed: userResponse?.is_tour_completed,
onboarding_step: userResponse?.onboarding_step,
is_onboarded: userResponse?.is_onboarded,
role: userResponse?.role,
};
runInAction(() => {
this.currentUser = userPayload;
});
return userPayload;
} }
} catch (error) { } catch (error) {
console.error("Updating user error", error); console.error("Updating user error", error);
@ -86,9 +111,14 @@ class UserStore {
let userSettingsResponse: ICurrentUserSettings = await UserService.updateUser(userTheme); let userSettingsResponse: ICurrentUserSettings = await UserService.updateUser(userTheme);
userSettingsResponse = userSettingsResponse || null; userSettingsResponse = userSettingsResponse || null;
if (userSettingsResponse) { if (userSettingsResponse) {
this.currentUserSettings = userSettingsResponse; const themePayload = {
this.rootStore.theme.setTheme(userTheme); theme: { ...userSettingsResponse?.theme },
return userSettingsResponse; };
runInAction(() => {
this.currentUserSettings = themePayload;
this.rootStore.theme.setTheme(themePayload);
});
return themePayload;
} }
} catch (error) { } catch (error) {
console.error("Updating user settings error", error); console.error("Updating user settings error", error);
@ -97,10 +127,7 @@ class UserStore {
}; };
// init load // init load
initialLoad() { initialLoad() {}
this.setCurrentUser();
this.setCurrentUserSettings();
}
} }
export default UserStore; export default UserStore;