Chore: mobx setup and app sidebar and theme management (#1798)

* dev: Mobx integration for app sidebar and custom theme

* dev: Handled edge case and conditional rendering for mobx store
This commit is contained in:
guru_sainath 2023-08-08 12:50:27 +05:30 committed by GitHub
parent a164dfd532
commit b6744dcd29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 377 additions and 59 deletions

View File

@ -24,8 +24,12 @@ import issuesService from "services/issues.service";
import inboxService from "services/inbox.service";
// fetch keys
import { INBOX_LIST, ISSUE_DETAILS } from "constants/fetch-keys";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
export const CommandPalette: React.FC = () => {
const store: any = useMobxStore();
const [isPaletteOpen, setIsPaletteOpen] = useState(false);
const [isIssueModalOpen, setIsIssueModalOpen] = useState(false);
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
@ -96,7 +100,8 @@ export const CommandPalette: React.FC = () => {
setIsIssueModalOpen(true);
} else if ((ctrlKey || metaKey) && keyPressed === "b") {
e.preventDefault();
toggleCollapsed();
// toggleCollapsed();
store.theme.setSidebarCollapsed(!store?.theme?.sidebarCollapsed);
} else if (key === "Delete") {
e.preventDefault();
setIsBulkDeleteIssuesModalOpen(true);
@ -120,7 +125,7 @@ export const CommandPalette: React.FC = () => {
}
}
},
[toggleCollapsed, copyIssueUrlToClipboard]
[copyIssueUrlToClipboard]
);
useEffect(() => {

View File

@ -15,6 +15,8 @@ import userService from "services/user.service";
import { applyTheme } from "helpers/theme.helper";
// types
import { ICustomTheme } from "types";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
type Props = {
preLoadedData?: Partial<ICustomTheme> | null;
@ -32,6 +34,8 @@ const defaultValues: ICustomTheme = {
};
export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
const store: any = useMobxStore();
const [darkPalette, setDarkPalette] = useState(false);
const {
@ -60,21 +64,15 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
theme: "custom",
};
await userService
.updateUser({
theme: payload,
})
.then((res) => {
mutateUser((prevData) => {
if (!prevData) return prevData;
return { ...prevData, ...res };
}, false);
store.user
.updateCurrentUserSettings({ theme: payload })
.then((response: any) => {
setTheme("custom");
applyTheme(payload.palette, darkPalette);
})
.catch((err) => console.log(err));
.catch((error: any) => {
console.log("error", error);
});
};
const handleUpdateTheme = async (formData: any) => {

View File

@ -21,8 +21,12 @@ import { NotificationsOutlined } from "@mui/icons-material";
import emptyNotification from "public/empty-state/notification.svg";
// helpers
import { getNumberCount } from "helpers/string.helper";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
export const NotificationPopover = () => {
const store: any = useMobxStore();
const {
notifications,
archived,
@ -77,17 +81,17 @@ export const NotificationPopover = () => {
tooltipContent="Notifications"
position="right"
className="ml-2"
disabled={!sidebarCollapse}
disabled={!store?.theme?.sidebarCollapsed}
>
<Popover.Button
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${
isActive
? "bg-custom-primary-100/10 text-custom-primary-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
} ${sidebarCollapse ? "justify-center" : ""}`}
} ${store?.theme?.sidebarCollapsed ? "justify-center" : ""}`}
>
<NotificationsOutlined fontSize="small" />
{sidebarCollapse ? null : <span>Notifications</span>}
{store?.theme?.sidebarCollapsed ? null : <span>Notifications</span>}
{totalNotificationCount && totalNotificationCount > 0 ? (
<span className="ml-auto bg-custom-primary-300 rounded-full text-xs text-white px-1.5">
{getNumberCount(totalNotificationCount)}

View File

@ -26,8 +26,12 @@ import { orderArrayBy } from "helpers/array.helper";
import { IProject } from "types";
// fetch-keys
import { PROJECTS_LIST } from "constants/fetch-keys";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
export const ProjectSidebarList: FC = () => {
const store: any = useMobxStore();
const [deleteProjectModal, setDeleteProjectModal] = useState(false);
const [projectToDelete, setProjectToDelete] = useState<IProject | null>(null);
@ -139,7 +143,7 @@ export const ProjectSidebarList: FC = () => {
<Disclosure as="div" className="flex flex-col space-y-2" defaultOpen={true}>
{({ open }) => (
<>
{!sidebarCollapse && (
{!store?.theme?.sidebarCollapsed && (
<Disclosure.Button
as="button"
type="button"
@ -165,7 +169,7 @@ export const ProjectSidebarList: FC = () => {
<SingleSidebarProject
key={project.id}
project={project}
sidebarCollapse={sidebarCollapse}
sidebarCollapse={store?.theme?.sidebarCollapsed}
provided={provided}
snapshot={snapshot}
handleDeleteProject={() => handleDeleteProject(project)}
@ -194,7 +198,7 @@ export const ProjectSidebarList: FC = () => {
<Disclosure as="div" className="flex flex-col space-y-2" defaultOpen={true}>
{({ open }) => (
<>
{!sidebarCollapse && (
{!store?.theme?.sidebarCollapsed && (
<Disclosure.Button
as="button"
type="button"
@ -215,7 +219,7 @@ export const ProjectSidebarList: FC = () => {
<SingleSidebarProject
key={project.id}
project={project}
sidebarCollapse={sidebarCollapse}
sidebarCollapse={store?.theme?.sidebarCollapsed}
provided={provided}
snapshot={snapshot}
handleDeleteProject={() => handleDeleteProject(project)}
@ -243,7 +247,7 @@ export const ProjectSidebarList: FC = () => {
>
{({ open }) => (
<>
{!sidebarCollapse && (
{!store?.theme?.sidebarCollapsed && (
<Disclosure.Button
as="button"
type="button"
@ -261,7 +265,7 @@ export const ProjectSidebarList: FC = () => {
<SingleSidebarProject
key={project.id}
project={project}
sidebarCollapse={sidebarCollapse}
sidebarCollapse={store?.theme?.sidebarCollapsed}
handleDeleteProject={() => handleDeleteProject(project)}
handleCopyText={() => handleCopyText(project.id)}
shortContextMenu
@ -284,7 +288,7 @@ export const ProjectSidebarList: FC = () => {
}}
>
<PlusIcon className="h-5 w-5" />
{!sidebarCollapse && "Add Project"}
{!store?.theme?.sidebarCollapsed && "Add Project"}
</button>
)}
</div>

View File

@ -11,6 +11,8 @@ import useOutsideClickDetector from "hooks/use-outside-click-detector";
import { Bolt, HelpOutlineOutlined, WestOutlined } from "@mui/icons-material";
import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline";
import { DocumentIcon, DiscordIcon, GithubIcon } from "components/icons";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
const helpOptions = [
{
@ -41,6 +43,8 @@ export interface WorkspaceHelpSectionProps {
}
export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setSidebarActive }) => {
const store: any = useMobxStore();
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
@ -53,23 +57,23 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
<>
<div
className={`flex w-full items-center justify-between gap-1 self-baseline border-t border-custom-border-200 bg-custom-sidebar-background-100 py-2 px-4 ${
sidebarCollapse ? "flex-col" : ""
store?.theme?.sidebarCollapsed ? "flex-col" : ""
}`}
>
{!sidebarCollapse && (
{!store?.theme?.sidebarCollapsed && (
<div className="w-1/2 text-center cursor-default rounded-md px-2.5 py-1.5 font-medium outline-none text-sm bg-green-500/10 text-green-500">
Free Plan
</div>
)}
<div
className={`flex items-center gap-1 ${
sidebarCollapse ? "flex-col justify-center" : "justify-evenly w-1/2"
store?.theme?.sidebarCollapsed ? "flex-col justify-center" : "justify-evenly w-1/2"
}`}
>
<button
type="button"
className={`grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
sidebarCollapse ? "w-full" : ""
store?.theme?.sidebarCollapsed ? "w-full" : ""
}`}
onClick={() => {
const e = new KeyboardEvent("keydown", {
@ -83,7 +87,7 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
<button
type="button"
className={`grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
sidebarCollapse ? "w-full" : ""
store?.theme?.sidebarCollapsed ? "w-full" : ""
}`}
onClick={() => setIsNeedHelpOpen((prev) => !prev)}
>
@ -99,13 +103,13 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
<button
type="button"
className={`hidden md:grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
sidebarCollapse ? "w-full" : ""
store?.theme?.sidebarCollapsed ? "w-full" : ""
}`}
onClick={() => toggleCollapsed()}
onClick={() => store.theme.setSidebarCollapsed(!store?.theme?.sidebarCollapsed)}
>
<WestOutlined
fontSize="small"
className={`duration-300 ${sidebarCollapse ? "rotate-180" : ""}`}
className={`duration-300 ${store?.theme?.sidebarCollapsed ? "rotate-180" : ""}`}
/>
</button>
</div>
@ -122,7 +126,7 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
>
<div
className={`absolute bottom-2 ${
sidebarCollapse ? "left-full" : "left-[-75px]"
store?.theme?.sidebarCollapsed ? "left-full" : "left-[-75px]"
} space-y-2 rounded-sm bg-custom-background-80 p-1 shadow-md`}
ref={helpOptionsRef}
>

View File

@ -23,6 +23,8 @@ import { CheckIcon, PlusIcon } from "@heroicons/react/24/outline";
import { truncateText } from "helpers/string.helper";
// types
import { IWorkspace } from "types";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// Static Data
const userLinks = (workspaceSlug: string, userId: string) => [
@ -54,6 +56,8 @@ const profileLinks = (workspaceSlug: string, userId: string) => [
];
export const WorkspaceSidebarDropdown = () => {
const store: any = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
@ -108,7 +112,7 @@ export const WorkspaceSidebarDropdown = () => {
<Menu.Button className="text-custom-sidebar-text-200 flex w-full items-center rounded-sm text-sm font-medium focus:outline-none">
<div
className={`flex w-full items-center gap-x-2 rounded-sm bg-custom-sidebar-background-80 p-1 ${
sidebarCollapse ? "justify-center" : ""
store?.theme?.sidebarCollapsed ? "justify-center" : ""
}`}
>
<div className="relative grid h-6 w-6 place-items-center rounded bg-gray-700 uppercase text-white">
@ -123,7 +127,7 @@ export const WorkspaceSidebarDropdown = () => {
)}
</div>
{!sidebarCollapse && (
{!store?.theme?.sidebarCollapsed && (
<h4 className="text-custom-text-100">
{activeWorkspace?.name ? truncateText(activeWorkspace.name, 14) : "Loading..."}
</h4>
@ -243,7 +247,7 @@ export const WorkspaceSidebarDropdown = () => {
</Transition>
</Menu>
{!sidebarCollapse && (
{!store?.theme?.sidebarCollapsed && (
<Menu as="div" className="relative flex-shrink-0">
<Menu.Button className="grid place-items-center outline-none">
<Avatar user={user} height="28px" width="28px" fontSize="14px" />

View File

@ -16,6 +16,8 @@ import {
TaskAltOutlined,
WorkOutlineOutlined,
} from "@mui/icons-material";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
const workspaceLinks = (workspaceSlug: string) => [
{
@ -41,6 +43,8 @@ const workspaceLinks = (workspaceSlug: string) => [
];
export const WorkspaceSidebarMenu = () => {
const store: any = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
@ -61,17 +65,17 @@ export const WorkspaceSidebarMenu = () => {
tooltipContent={link.name}
position="right"
className="ml-2"
disabled={!sidebarCollapse}
disabled={!store?.theme?.sidebarCollapsed}
>
<div
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${
isActive
? "bg-custom-primary-100/10 text-custom-primary-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
} ${sidebarCollapse ? "justify-center" : ""}`}
} ${store?.theme?.sidebarCollapsed ? "justify-center" : ""}`}
>
{<link.Icon fontSize="small" />}
{!sidebarCollapse && link.name}
{!store?.theme?.sidebarCollapsed && link.name}
</div>
</Tooltip>
</a>

View File

@ -7,20 +7,25 @@ import {
WorkspaceSidebarMenu,
} from "components/workspace";
import { ProjectSidebarList } from "components/project";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
export interface SidebarProps {
toggleSidebar: boolean;
setToggleSidebar: React.Dispatch<React.SetStateAction<boolean>>;
}
const Sidebar: React.FC<SidebarProps> = ({ toggleSidebar, setToggleSidebar }) => {
const Sidebar: React.FC<SidebarProps> = observer(({ toggleSidebar, setToggleSidebar }) => {
const store: any = useMobxStore();
// theme
const { collapsed: sidebarCollapse } = useTheme();
return (
<div
className={`fixed md:relative inset-y-0 flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-200 z-20 duration-300 ${
sidebarCollapse ? "" : "md:w-[280px]"
store?.theme?.sidebarCollapsed ? "" : "md:w-[280px]"
} ${toggleSidebar ? "left-0" : "-left-full md:left-0"}`}
>
<div className="flex h-full w-full flex-1 flex-col">
@ -31,6 +36,6 @@ const Sidebar: React.FC<SidebarProps> = ({ toggleSidebar, setToggleSidebar }) =>
</div>
</div>
);
};
});
export default Sidebar;

View File

@ -0,0 +1,33 @@
import { useEffect } from "react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
const MobxStoreInit = () => {
const store: any = useMobxStore();
useEffect(() => {
// sidebar collapsed toggle
if (
localStorage &&
localStorage.getItem("app_sidebar_collapsed") &&
store?.theme?.sidebarCollapsed === null
)
store.theme.setSidebarCollapsed(
localStorage.getItem("app_sidebar_collapsed")
? localStorage.getItem("app_sidebar_collapsed") === "true"
? true
: false
: false
);
// theme
if (localStorage && localStorage.getItem("theme") && store.theme.theme === null)
store.theme.setTheme(
localStorage.getItem("theme") ? localStorage.getItem("theme") : "system"
);
}, [store?.theme]);
return <></>;
};
export default MobxStoreInit;

View File

@ -0,0 +1,30 @@
import { createContext, useContext } from "react";
// mobx store
import { RootStore } from "store/root";
let rootStore: any = null;
export const MobxStoreContext = createContext(null);
const initializeStore = () => {
const _rootStore = rootStore ?? new RootStore();
if (typeof window === "undefined") return _rootStore;
if (!rootStore) rootStore = _rootStore;
return _rootStore;
};
export const MobxStoreProvider = ({ children }: any) => {
const store = initializeStore();
return <MobxStoreContext.Provider value={store}>{children}</MobxStoreContext.Provider>;
};
// hook
export const useMobxStore = () => {
const context = useContext(MobxStoreContext);
if (context === undefined) throw new Error("useMobxStore must be used within MobxStoreProvider");
return context;
};

View File

@ -36,6 +36,8 @@
"dotenv": "^16.0.3",
"js-cookie": "^3.0.1",
"lodash.debounce": "^4.0.8",
"mobx": "^6.10.0",
"mobx-react-lite": "^4.0.3",
"next": "12.3.2",
"next-pwa": "^5.6.0",
"next-themes": "^0.2.1",

View File

@ -33,6 +33,9 @@ import {
SITE_KEYWORDS,
SITE_TITLE,
} from "constants/seo-variables";
// mobx store provider
import { MobxStoreProvider } from "lib/mobx/store-provider";
import MobxStoreInit from "lib/mobx/store-init";
const CrispWithNoSSR = dynamic(() => import("constants/crisp"), { ssr: false });
@ -45,9 +48,10 @@ Router.events.on("routeChangeComplete", NProgress.done);
function MyApp({ Component, pageProps }: AppProps) {
return (
// <UserProvider>
<ThemeProvider themes={THEMES} defaultTheme="system">
<ToastContextProvider>
<ThemeContextProvider>
// mobx root provider
<MobxStoreProvider {...pageProps}>
<ThemeProvider themes={THEMES} defaultTheme="system">
<ToastContextProvider>
<CrispWithNoSSR />
<Head>
<title>{SITE_TITLE}</title>
@ -64,10 +68,11 @@ function MyApp({ Component, pageProps }: AppProps) {
<link rel="manifest" href="/site.webmanifest.json" />
<link rel="shortcut icon" href="/favicon/favicon.ico" />
</Head>
<MobxStoreInit />
<Component {...pageProps} />
</ThemeContextProvider>
</ToastContextProvider>
</ThemeProvider>
</ToastContextProvider>
</ThemeProvider>
</MobxStoreProvider>
// </UserProvider>
);
}

17
apps/app/store/root.ts Normal file
View File

@ -0,0 +1,17 @@
// mobx lite
import { enableStaticRendering } from "mobx-react-lite";
// store imports
import UserStore from "./user";
import ThemeStore from "./theme";
enableStaticRendering(typeof window === "undefined");
export class RootStore {
user;
theme;
constructor() {
this.user = new UserStore(this);
this.theme = new ThemeStore(this);
}
}

66
apps/app/store/theme.ts Normal file
View File

@ -0,0 +1,66 @@
// mobx
import { action, observable, makeObservable } from "mobx";
// helper
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
// interfaces
import { ICurrentUserSettings } from "types";
class ThemeStore {
sidebarCollapsed: boolean | null = null;
theme: string | null = null;
// root store
rootStore;
constructor(_rootStore: any | null = null) {
makeObservable(this, {
// observable
sidebarCollapsed: observable,
theme: observable,
// action
setSidebarCollapsed: action,
setTheme: action,
// computed
});
this.rootStore = _rootStore;
this.initialLoad();
}
setSidebarCollapsed(collapsed: boolean | null = null) {
if (collapsed === null) {
let _sidebarCollapsed: string | boolean | null =
localStorage.getItem("app_sidebar_collapsed");
_sidebarCollapsed = _sidebarCollapsed ? (_sidebarCollapsed === "true" ? true : false) : false;
this.sidebarCollapsed = _sidebarCollapsed;
} else {
this.sidebarCollapsed = collapsed;
localStorage.setItem("app_sidebar_collapsed", collapsed.toString());
}
}
setTheme = async (_theme: ICurrentUserSettings) => {
try {
localStorage.setItem("theme", _theme.theme.toString());
this.theme = _theme.theme.toString();
if (this.theme === "custom") {
let themeSettings = this.rootStore.user.currentUserSettings || null;
if (themeSettings && themeSettings.theme.palette) {
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);
}
};
// init load
initialLoad() {}
}
export default ThemeStore;

106
apps/app/store/user.ts Normal file
View File

@ -0,0 +1,106 @@
// mobx
import { action, observable, computed, makeObservable } from "mobx";
// services
import UserService from "services/user.service";
// interfaces
import { ICurrentUser, ICurrentUserSettings } from "types/users";
class UserStore {
currentUser: ICurrentUser | null = null;
currentUserSettings: ICurrentUserSettings | null = null;
// root store
rootStore;
constructor(_rootStore: any) {
makeObservable(this, {
// observable
currentUser: observable.ref,
currentUserSettings: observable.ref,
// action
setCurrentUser: action,
setCurrentUserSettings: action,
updateCurrentUser: action,
updateCurrentUserSettings: action,
// computed
});
this.rootStore = _rootStore;
this.initialLoad();
}
setCurrentUser = async () => {
try {
let userResponse: ICurrentUser | null = await UserService.currentUser();
userResponse = userResponse || null;
if (userResponse) {
this.currentUser = {
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,
};
}
} catch (error) {
console.error("Fetching current user error", error);
}
};
setCurrentUserSettings = async () => {
try {
let userSettingsResponse: ICurrentUserSettings | null = await UserService.currentUser();
userSettingsResponse = userSettingsResponse || null;
if (userSettingsResponse) {
this.currentUserSettings = {
theme: userSettingsResponse?.theme,
};
this.rootStore.theme.setTheme();
}
} catch (error) {
console.error("Fetching current user error", error);
}
};
updateCurrentUser = async (user: ICurrentUser) => {
try {
let userResponse: ICurrentUser = await UserService.updateUser(user);
userResponse = userResponse || null;
if (userResponse) {
this.currentUser = userResponse;
return userResponse;
}
} catch (error) {
console.error("Updating user error", error);
return error;
}
};
updateCurrentUserSettings = async (userTheme: ICurrentUserSettings) => {
try {
let userSettingsResponse: ICurrentUserSettings = await UserService.updateUser(userTheme);
userSettingsResponse = userSettingsResponse || null;
if (userSettingsResponse) {
this.currentUserSettings = userSettingsResponse;
this.rootStore.theme.setTheme(userTheme);
return userSettingsResponse;
}
} catch (error) {
console.error("Updating user settings error", error);
return error;
}
};
// init load
initialLoad() {
this.setCurrentUser();
this.setCurrentUserSettings();
}
}
export default UserStore;

View File

@ -38,17 +38,6 @@ export interface IUser {
[...rest: string]: any;
}
export interface ICustomTheme {
background: string;
text: string;
primary: string;
sidebarBackground: string;
sidebarText: string;
darkPalette: boolean;
palette: string;
theme: string;
}
export interface ICurrentUserResponse extends IUser {
assigned_issues: number;
last_workspace_id: string | null;
@ -158,3 +147,33 @@ export interface IUserProfileProjectSegregation {
user_timezone: string;
};
}
export interface ICurrentUser {
id: readonly string;
avatar: string;
first_name: string;
last_name: string;
username: string;
email: string;
mobile_number: string;
is_email_verified: boolean;
is_tour_completed: boolean;
onboarding_step: TOnboardingSteps;
is_onboarded: boolean;
role: string;
}
export interface ICustomTheme {
background: string;
text: string;
primary: string;
sidebarBackground: string;
sidebarText: string;
darkPalette: boolean;
palette: string;
theme: string;
}
export interface ICurrentUserSettings {
theme: ICustomTheme;
}

View File

@ -6673,6 +6673,18 @@ mkdirp@^0.5.5:
dependencies:
minimist "^1.2.6"
mobx-react-lite@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-4.0.3.tgz#f7aa5ac3be558ca19a53b2929d9599679769c2a8"
integrity sha512-wEE1oT5zvDdvplG4HnRrFgPwg5GFVVrEtl42Er85k23zeu3om8H8wbDPgdbQP88zAihVsik6xJfw6VnzUl8fQw==
dependencies:
use-sync-external-store "^1.2.0"
mobx@^6.10.0:
version "6.10.0"
resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.10.0.tgz#3537680fe98d45232cc19cc8f76280bd8bb6b0b7"
integrity sha512-WMbVpCMFtolbB8swQ5E2YRrU+Yu8iLozCVx3CdGjbBKlP7dFiCSuiG06uea3JCFN5DnvtAX7+G5Bp82e2xu0ww==
moo@^0.5.1:
version "0.5.2"
resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"