Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 17 additions & 32 deletions apps/app/components/core/theme/custom-theme-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ import { useTheme } from "next-themes";

import { useForm } from "react-hook-form";

// hooks
import useUser from "hooks/use-user";
// ui
import { PrimaryButton } from "components/ui";
import { ColorPickerInput } from "components/core";
// services
import userService from "services/user.service";
// helper
import { applyTheme } from "helpers/theme.helper";
// types
import { ICustomTheme } from "types";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";

Expand All @@ -33,11 +29,11 @@ const defaultValues: ICustomTheme = {
theme: "custom",
};

export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
export const CustomThemeSelector: React.FC<Props> = observer(({ preLoadedData }) => {
const store: any = useMobxStore();
const { setTheme } = useTheme();

const [darkPalette, setDarkPalette] = useState(false);

const {
register,
formState: { errors, isSubmitting },
Expand All @@ -48,11 +44,14 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
} = useForm<ICustomTheme>({
defaultValues,
});
useEffect(() => {
reset({
...defaultValues,
...preLoadedData,
});
}, [preLoadedData, reset]);

const { setTheme } = useTheme();
const { mutateUser } = useUser();

const handleFormSubmit = async (formData: ICustomTheme) => {
const handleUpdateTheme = async (formData: any) => {
const payload: ICustomTheme = {
background: formData.background,
text: formData.text,
Expand All @@ -64,28 +63,14 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
theme: "custom",
};

store.user
.updateCurrentUserSettings({ theme: payload })
.then((response: any) => {
setTheme("custom");
applyTheme(payload.palette, darkPalette);
})
.catch((error: any) => {
console.log("error", error);
});
};
setTheme("custom");

const handleUpdateTheme = async (formData: any) => {
await handleFormSubmit({ ...formData, darkPalette });
return store.user
.updateCurrentUserSettings({ theme: payload })
.then((response: any) => response)
.catch((error: any) => error);
};

useEffect(() => {
reset({
...defaultValues,
...preLoadedData,
});
}, [preLoadedData, reset]);

return (
<form onSubmit={handleSubmit(handleUpdateTheme)}>
<div className="space-y-5">
Expand Down Expand Up @@ -164,4 +149,4 @@ export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
</div>
</form>
);
};
});
240 changes: 107 additions & 133 deletions apps/app/components/core/theme/theme-switch.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { useState, useEffect } from "react";

// next-themes
import { useTheme } from "next-themes";
// services
import userService from "services/user.service";
// hooks
import useUser from "hooks/use-user";
// constants
Expand All @@ -13,149 +9,127 @@ import { CustomSelect } from "components/ui";
// types
import { ICustomTheme } from "types";
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 = {
setPreLoadedData: React.Dispatch<React.SetStateAction<ICustomTheme | null>>;
customThemeSelectorOptions: boolean;
setCustomThemeSelectorOptions: React.Dispatch<React.SetStateAction<boolean>>;
};

export const ThemeSwitch: React.FC<Props> = ({
setPreLoadedData,
customThemeSelectorOptions,
setCustomThemeSelectorOptions,
}) => {
const [mounted, setMounted] = useState(false);

const { theme, setTheme } = useTheme();

const { user, mutateUser } = useUser();

const updateUserTheme = (newTheme: string) => {
if (!user) return;

setTheme(newTheme);

mutateUser((prevData) => {
if (!prevData) return prevData;

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);

return (
<CustomSelect
value={theme}
label={
currentThemeObj ? (
<div className="flex items-center gap-2">
<div
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
style={{
borderColor: currentThemeObj.icon.border,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: currentThemeObj.icon.color1,
}}
/>
export const ThemeSwitch: React.FC<Props> = observer(
({ setPreLoadedData, customThemeSelectorOptions, setCustomThemeSelectorOptions }) => {
const store: any = useMobxStore();

const { user, mutateUser } = useUser();
const { theme, setTheme } = useTheme();

const updateUserTheme = (newTheme: string) => {
if (!user) return;
setTheme(newTheme);
return store.user
.updateCurrentUserSettings({ theme: { ...user.theme, theme: newTheme } })
.then((response: any) => response)
.catch((error: any) => error);
};

const currentThemeObj = THEMES_OBJ.find((t) => t.value === theme);

return (
<CustomSelect
value={theme}
label={
currentThemeObj ? (
<div className="flex items-center gap-2">
<div
className="h-full w-1/2 rounded-r-full border-l"
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
style={{
borderLeftColor: currentThemeObj.icon.border,
background: currentThemeObj.icon.color2,
borderColor: currentThemeObj.icon.border,
}}
/>
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: currentThemeObj.icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: currentThemeObj.icon.border,
background: currentThemeObj.icon.color2,
}}
/>
</div>
{currentThemeObj.label}
</div>
{currentThemeObj.label}
</div>
) : (
"Select your theme"
)
}
onChange={({ value, type }: { value: string; type: string }) => {
if (value === "custom") {
if (user?.theme.palette) {
setPreLoadedData({
background: user.theme.background !== "" ? user.theme.background : "#0d101b",
text: user.theme.text !== "" ? user.theme.text : "#c5c5c5",
primary: user.theme.primary !== "" ? user.theme.primary : "#3f76ff",
sidebarBackground:
user.theme.sidebarBackground !== "" ? user.theme.sidebarBackground : "#0d101b",
sidebarText: user.theme.sidebarText !== "" ? user.theme.sidebarText : "#c5c5c5",
darkPalette: false,
palette:
user.theme.palette !== ",,,,"
? user.theme.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
theme: "custom",
});
}

if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
} else {
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
unsetCustomCssVariables();
) : (
"Select your theme"
)
}
onChange={({ value, type }: { value: string; type: string }) => {
if (value === "custom") {
if (user?.theme.palette) {
setPreLoadedData({
background: user.theme.background !== "" ? user.theme.background : "#0d101b",
text: user.theme.text !== "" ? user.theme.text : "#c5c5c5",
primary: user.theme.primary !== "" ? user.theme.primary : "#3f76ff",
sidebarBackground:
user.theme.sidebarBackground !== "" ? user.theme.sidebarBackground : "#0d101b",
sidebarText: user.theme.sidebarText !== "" ? user.theme.sidebarText : "#c5c5c5",
darkPalette: false,
palette:
user.theme.palette !== ",,,,"
? user.theme.palette
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
theme: "custom",
});
}

if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
} else {
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
unsetCustomCssVariables();
}

updateUserTheme(value);
document.documentElement.style.setProperty("--color-scheme", type);
}}
input
width="w-full"
position="right"
>
{THEMES_OBJ.map(({ value, label, type, icon }) => (
<CustomSelect.Option key={value} value={{ value, type }}>
<div className="flex items-center gap-2">
<div
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
style={{
borderColor: icon.border,
}}
>
updateUserTheme(value);
document.documentElement.style.setProperty("--color-scheme", type);
}}
input
width="w-full"
position="right"
>
{THEMES_OBJ.map(({ value, label, type, icon }) => (
<CustomSelect.Option key={value} value={{ value, type }}>
<div className="flex items-center gap-2">
<div
className="h-full w-1/2 rounded-l-full"
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
style={{
background: icon.color1,
borderColor: icon.border,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: icon.border,
background: icon.color2,
}}
/>
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: icon.border,
background: icon.color2,
}}
/>
</div>
{label}
</div>
{label}
</div>
</CustomSelect.Option>
))}
</CustomSelect>
);
};
</CustomSelect.Option>
))}
</CustomSelect>
);
}
);
Loading