fix: update theme logic

This commit is contained in:
Aaryan Khandelwal 2024-04-30 12:09:21 +05:30
parent c389c6b440
commit 9134d704e5
9 changed files with 79 additions and 76 deletions

View File

@ -48,7 +48,7 @@ export type TUserProfile = {
palette: string | undefined; palette: string | undefined;
primary: string | undefined; primary: string | undefined;
background: string | undefined; background: string | undefined;
darkPalette: string | undefined; darkPalette: boolean | undefined;
sidebarText: string | undefined; sidebarText: string | undefined;
sidebarBackground: string | undefined; sidebarBackground: string | undefined;
}; };

View File

@ -1,11 +1,14 @@
import React, { FC, useEffect, useState } from "react"; import { FC, useEffect, useState } from "react";
import { Command } from "cmdk"; import { Command } from "cmdk";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
// icons
import { Settings } from "lucide-react"; import { Settings } from "lucide-react";
// ui
import { TOAST_TYPE, setToast } from "@plane/ui";
// constants // constants
import { THEME_OPTIONS } from "@/constants/themes"; import { THEME_OPTIONS } from "@/constants/themes";
// hooks
import { useUserProfile } from "@/hooks/store";
type Props = { type Props = {
closePalette: () => void; closePalette: () => void;
@ -15,18 +18,20 @@ export const CommandPaletteThemeActions: FC<Props> = observer((props) => {
const { closePalette } = props; const { closePalette } = props;
// states // states
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
// hooks // store hooks
const { updateCurrentUserTheme } = useUserProfile();
// next-themes
const { setTheme } = useTheme(); const { setTheme } = useTheme();
const updateUserTheme = async (newTheme: string) => { const updateUserTheme = async (newTheme: string) => {
setTheme(newTheme); setTheme(newTheme);
// return updateUserProfile({ theme: newTheme }).catch(() => { return updateCurrentUserTheme(newTheme).catch(() => {
// setToast({ setToast({
// type: TOAST_TYPE.ERROR, type: TOAST_TYPE.ERROR,
// title: "Failed to save user theme settings!", title: "Failed to save user theme settings!",
// }); });
// }); });
}; };
// useEffect only runs on the client, so now we can safely show the UI // useEffect only runs on the client, so now we can safely show the UI

View File

@ -26,7 +26,7 @@ const inputRules = {
export const CustomThemeSelector: React.FC = observer(() => { export const CustomThemeSelector: React.FC = observer(() => {
const { const {
profile: { data: userProfile }, profile: { data: userProfile, updateUserProfile },
} = useUser(); } = useUser();
const userTheme: any = userProfile?.theme; const userTheme: any = userProfile?.theme;
@ -64,9 +64,9 @@ export const CustomThemeSelector: React.FC = observer(() => {
setTheme("custom"); setTheme("custom");
console.log(payload); return updateUserProfile({
theme: payload,
// return updateUserProfile({ theme: payload }); });
}; };
const handleValueChange = (val: string | undefined, onChange: any) => { const handleValueChange = (val: string | undefined, onChange: any) => {

View File

@ -33,3 +33,4 @@ export * from "./use-instance";
export * from "./use-app-theme"; export * from "./use-app-theme";
export * from "./use-command-palette"; export * from "./use-command-palette";
export * from "./use-app-router"; export * from "./use-app-router";
export * from "./use-app-theme";

View File

@ -2,7 +2,7 @@ import { FC, ReactNode } from "react";
// layout // layout
import { SidebarHamburgerToggle } from "@/components/core/sidebar/sidebar-menu-hamburger-toggle"; import { SidebarHamburgerToggle } from "@/components/core/sidebar/sidebar-menu-hamburger-toggle";
import { PreferencesMobileHeader } from "@/components/profile/preferences/preferences-mobile-header"; import { PreferencesMobileHeader } from "@/components/profile/preferences/preferences-mobile-header";
import { useApplication } from "@/hooks/store"; import { useAppTheme } from "@/hooks/store";
import { ProfileSettingsLayout } from "@/layouts/settings-layout"; import { ProfileSettingsLayout } from "@/layouts/settings-layout";
// local components // local components
import { ProfilePreferenceSettingsSidebar } from "./sidebar"; import { ProfilePreferenceSettingsSidebar } from "./sidebar";
@ -14,13 +14,14 @@ interface IProfilePreferenceSettingsLayout {
export const ProfilePreferenceSettingsLayout: FC<IProfilePreferenceSettingsLayout> = (props) => { export const ProfilePreferenceSettingsLayout: FC<IProfilePreferenceSettingsLayout> = (props) => {
const { children, header } = props; const { children, header } = props;
const { theme: themeStore } = useApplication(); // store hooks
const { toggleSidebar } = useAppTheme();
return ( return (
<ProfileSettingsLayout <ProfileSettingsLayout
header={ header={
<div className="md:hidden flex flex-shrink-0 gap-4 items-center justify-start border-b border-custom-border-200 p-4"> <div className="md:hidden flex flex-shrink-0 gap-4 items-center justify-start border-b border-custom-border-200 p-4">
<SidebarHamburgerToggle onClick={() => themeStore.toggleSidebar()} /> <SidebarHamburgerToggle onClick={toggleSidebar} />
</div> </div>
} }
> >

View File

@ -43,11 +43,19 @@ const StoreWrapper: FC<TStoreWrapper> = observer((props) => {
if (!userProfile) return; if (!userProfile) return;
if (window) setDom(window.document?.querySelector<HTMLElement>("[data-theme='custom']") || undefined); if (window) setDom(window.document?.querySelector<HTMLElement>("[data-theme='custom']") || undefined);
setTheme(userProfile?.theme?.theme || "system"); const themeData = userProfile.theme;
if (userProfile?.theme?.theme === "custom" && userProfile?.theme?.palette && dom)
applyTheme(userProfile?.theme?.palette, false); console.log("userProfile", userProfile.theme.theme);
else unsetCustomCssVariables();
}, [userProfile, setTheme, dom]); setTheme(themeData?.theme || "system");
if (themeData?.theme === "custom" && themeData?.palette && dom) {
console.log("Setting...");
applyTheme(themeData?.palette, false);
} else {
console.log("Unsetting...");
unsetCustomCssVariables();
}
}, [dom, setTheme, userProfile]);
useEffect(() => { useEffect(() => {
if (!router.query) return; if (!router.query) return;

View File

@ -2,10 +2,7 @@ import { useEffect, useState, ReactElement } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
// ui // ui
import { import { Spinner, setPromiseToast } from "@plane/ui";
Spinner,
// setPromiseToast
} from "@plane/ui";
// components // components
import { CustomThemeSelector, ThemeSwitch, PageHead } from "@/components/core"; import { CustomThemeSelector, ThemeSwitch, PageHead } from "@/components/core";
// constants // constants
@ -23,7 +20,7 @@ const ProfilePreferencesThemePage: NextPageWithLayout = observer(() => {
// store hooks // store hooks
const { const {
data: currentUser, data: currentUser,
profile: { data: userProfile }, profile: { data: userProfile, updateCurrentUserTheme },
} = useUser(); } = useUser();
// computed // computed
const userTheme = userProfile?.theme; const userTheme = userProfile?.theme;
@ -41,24 +38,24 @@ const ProfilePreferencesThemePage: NextPageWithLayout = observer(() => {
const handleThemeChange = (themeOption: I_THEME_OPTION) => { const handleThemeChange = (themeOption: I_THEME_OPTION) => {
setTheme(themeOption.value); setTheme(themeOption.value);
// const updateCurrentUserThemePromise = updateCurrentUserTheme(themeOption.value); const updateCurrentUserThemePromise = updateCurrentUserTheme(themeOption.value);
// setPromiseToast(updateCurrentUserThemePromise, { setPromiseToast(updateCurrentUserThemePromise, {
// loading: "Updating theme...", loading: "Updating theme...",
// success: { success: {
// title: "Success!", title: "Success!",
// message: () => "Theme updated successfully!", message: () => "Theme updated successfully!",
// }, },
// error: { error: {
// title: "Error!", title: "Error!",
// message: () => "Failed to Update the theme", message: () => "Failed to Update the theme",
// }, },
// }); });
}; };
return ( return (
<> <>
<PageHead title="Profile - Theme Prefrence" /> <PageHead title="Profile - Theme Preference" />
{currentUser ? ( {currentUser ? (
<div className="mx-auto mt-10 h-full w-full overflow-y-auto md:px-6 px-4 pb-8 md:mt-14 lg:px-20 vertical-scrollbar scrollbar-md"> <div className="mx-auto mt-10 h-full w-full overflow-y-auto md:px-6 px-4 pb-8 md:mt-14 lg:px-20 vertical-scrollbar scrollbar-md">
<div className="flex items-center border-b border-custom-border-100 pb-3.5"> <div className="flex items-center border-b border-custom-border-100 pb-3.5">

View File

@ -1,18 +1,13 @@
// mobx
import { action, observable, makeObservable } from "mobx"; import { action, observable, makeObservable } from "mobx";
// helper
import { applyTheme, unsetCustomCssVariables } from "@/helpers/theme.helper";
export interface IThemeStore { export interface IThemeStore {
// observables // observables
theme: string | null;
sidebarCollapsed: boolean | undefined; sidebarCollapsed: boolean | undefined;
profileSidebarCollapsed: boolean | undefined; profileSidebarCollapsed: boolean | undefined;
workspaceAnalyticsSidebarCollapsed: boolean | undefined; workspaceAnalyticsSidebarCollapsed: boolean | undefined;
issueDetailSidebarCollapsed: boolean | undefined; issueDetailSidebarCollapsed: boolean | undefined;
// actions // actions
toggleSidebar: (collapsed?: boolean) => void; toggleSidebar: (collapsed?: boolean) => void;
setTheme: (theme: any) => void;
toggleProfileSidebar: (collapsed?: boolean) => void; toggleProfileSidebar: (collapsed?: boolean) => void;
toggleWorkspaceAnalyticsSidebar: (collapsed?: boolean) => void; toggleWorkspaceAnalyticsSidebar: (collapsed?: boolean) => void;
toggleIssueDetailSidebar: (collapsed?: boolean) => void; toggleIssueDetailSidebar: (collapsed?: boolean) => void;
@ -21,7 +16,6 @@ export interface IThemeStore {
export class ThemeStore implements IThemeStore { export class ThemeStore implements IThemeStore {
// observables // observables
sidebarCollapsed: boolean | undefined = undefined; sidebarCollapsed: boolean | undefined = undefined;
theme: string | null = null;
profileSidebarCollapsed: boolean | undefined = undefined; profileSidebarCollapsed: boolean | undefined = undefined;
workspaceAnalyticsSidebarCollapsed: boolean | undefined = undefined; workspaceAnalyticsSidebarCollapsed: boolean | undefined = undefined;
issueDetailSidebarCollapsed: boolean | undefined = undefined; issueDetailSidebarCollapsed: boolean | undefined = undefined;
@ -32,13 +26,11 @@ export class ThemeStore implements IThemeStore {
makeObservable(this, { makeObservable(this, {
// observable // observable
sidebarCollapsed: observable.ref, sidebarCollapsed: observable.ref,
theme: observable.ref,
profileSidebarCollapsed: observable.ref, profileSidebarCollapsed: observable.ref,
workspaceAnalyticsSidebarCollapsed: observable.ref, workspaceAnalyticsSidebarCollapsed: observable.ref,
issueDetailSidebarCollapsed: observable.ref, issueDetailSidebarCollapsed: observable.ref,
// action // action
toggleSidebar: action, toggleSidebar: action,
setTheme: action,
toggleProfileSidebar: action, toggleProfileSidebar: action,
toggleWorkspaceAnalyticsSidebar: action, toggleWorkspaceAnalyticsSidebar: action,
toggleIssueDetailSidebar: action, toggleIssueDetailSidebar: action,
@ -95,30 +87,4 @@ export class ThemeStore implements IThemeStore {
} }
localStorage.setItem("issue_detail_sidebar_collapsed", this.issueDetailSidebarCollapsed.toString()); localStorage.setItem("issue_detail_sidebar_collapsed", this.issueDetailSidebarCollapsed.toString());
}; };
/**
* Sets the user theme and applies it to the platform
* @param _theme
*/
setTheme = async (_theme: { theme: any }) => {
try {
const currentTheme: string = _theme?.theme?.theme?.toString();
// updating the local storage theme value
localStorage.setItem("theme", currentTheme);
// 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(
themeSettings?.theme?.palette !== ",,,,"
? themeSettings?.theme?.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
themeSettings?.theme?.darkPalette
);
} else unsetCustomCssVariables();
} catch (error) {
console.error("setting user theme error", error);
}
};
} }

View File

@ -1,8 +1,9 @@
import set from "lodash/set";
import { action, makeObservable, observable, runInAction } from "mobx"; import { action, makeObservable, observable, runInAction } from "mobx";
// services
import { UserService } from "services/user.service";
// types // types
import { TUserProfile } from "@plane/types"; import { TUserProfile } from "@plane/types";
// services
import { UserService } from "@/services/user.service";
type TError = { type TError = {
status: string; status: string;
@ -19,6 +20,7 @@ export interface IProfileStore {
updateUserProfile: (data: Partial<TUserProfile>) => Promise<void>; updateUserProfile: (data: Partial<TUserProfile>) => Promise<void>;
updateUserOnBoard: () => Promise<void>; updateUserOnBoard: () => Promise<void>;
updateTourCompleted: () => Promise<void>; updateTourCompleted: () => Promise<void>;
updateCurrentUserTheme: (theme: string) => Promise<void>;
} }
export class ProfileStore implements IProfileStore { export class ProfileStore implements IProfileStore {
@ -68,6 +70,7 @@ export class ProfileStore implements IProfileStore {
updateUserProfile: action, updateUserProfile: action,
updateUserOnBoard: action, updateUserOnBoard: action,
updateTourCompleted: action, updateTourCompleted: action,
updateCurrentUserTheme: action,
}); });
// services // services
this.userService = new UserService(); this.userService = new UserService();
@ -164,4 +167,26 @@ export class ProfileStore implements IProfileStore {
throw error; throw error;
} }
}; };
/**
* Updates the current user theme
* @param theme
* @returns Promise<void>
*/
updateCurrentUserTheme = async (theme: string) => {
const originalTheme = this.data?.theme?.theme;
try {
set(this.data, "theme.theme", theme);
const response = await this.updateUserProfile({
theme: {
...this.data?.theme,
theme,
},
});
return response;
} catch (error) {
set(this.data, "theme.theme", originalTheme);
throw error;
}
};
} }