diff --git a/web/src/components/AuthFooter.tsx b/web/src/components/AuthFooter.tsx index f5015e40c..8431aaa99 100644 --- a/web/src/components/AuthFooter.tsx +++ b/web/src/components/AuthFooter.tsx @@ -1,7 +1,7 @@ import { useTranslation } from "react-i18next"; -import i18n from "@/i18n"; import { cn } from "@/lib/utils"; import { getInitialTheme, loadTheme } from "@/utils/theme"; +import { loadLocale } from "@/utils/i18n"; import LocaleSelect from "./LocaleSelect"; import ThemeSelect from "./ThemeSelect"; @@ -15,7 +15,7 @@ const AuthFooter = ({ className }: Props) => { const currentTheme = getInitialTheme(); const handleLocaleChange = (locale: Locale) => { - i18n.changeLanguage(locale); + loadLocale(locale); }; const handleThemeChange = (theme: string) => { diff --git a/web/src/components/UserMenu.tsx b/web/src/components/UserMenu.tsx index 3bb9b56f3..9d90b79a4 100644 --- a/web/src/components/UserMenu.tsx +++ b/web/src/components/UserMenu.tsx @@ -1,16 +1,13 @@ -import { create } from "@bufbuild/protobuf"; -import { FieldMaskSchema } from "@bufbuild/protobuf/wkt"; import { ArchiveIcon, CheckIcon, GlobeIcon, LogOutIcon, PaletteIcon, SettingsIcon, SquareUserIcon, User2Icon } from "lucide-react"; -import { userServiceClient } from "@/connect"; import { useAuth } from "@/contexts/AuthContext"; import useCurrentUser from "@/hooks/useCurrentUser"; import useNavigateTo from "@/hooks/useNavigateTo"; -import i18n, { locales } from "@/i18n"; +import { useUpdateUserGeneralSetting } from "@/hooks/useUserQueries"; +import { locales } from "@/i18n"; import { cn } from "@/lib/utils"; import { Routes } from "@/router"; -import { UserSetting_GeneralSettingSchema, UserSettingSchema } from "@/types/proto/api/v1/user_service_pb"; -import { getLocaleDisplayName, useTranslate } from "@/utils/i18n"; -import { loadTheme, THEME_OPTIONS } from "@/utils/theme"; +import { getLocaleDisplayName, getLocaleWithFallback, loadLocale, useTranslate } from "@/utils/i18n"; +import { getThemeWithFallback, loadTheme, THEME_OPTIONS } from "@/utils/theme"; import UserAvatar from "./UserAvatar"; import { DropdownMenu, @@ -32,31 +29,23 @@ const UserMenu = (props: Props) => { const navigateTo = useNavigateTo(); const currentUser = useCurrentUser(); const { userGeneralSetting, refetchSettings, logout } = useAuth(); - const currentLocale = userGeneralSetting?.locale || "en"; - const currentTheme = userGeneralSetting?.theme || "default"; + const { mutate: updateUserGeneralSetting } = useUpdateUserGeneralSetting(currentUser?.name); + const currentLocale = getLocaleWithFallback(userGeneralSetting?.locale); + const currentTheme = getThemeWithFallback(userGeneralSetting?.theme); const handleLocaleChange = async (locale: Locale) => { if (!currentUser) return; - // Apply locale immediately for instant UI feedback - i18n.changeLanguage(locale); + // Apply locale immediately for instant UI feedback and persist to localStorage + loadLocale(locale); // Persist to user settings - const settingName = `${currentUser.name}/setting`; - const updatedGeneralSetting = create(UserSetting_GeneralSettingSchema, { - locale, - theme: userGeneralSetting?.theme, - memoVisibility: userGeneralSetting?.memoVisibility, - }); - await userServiceClient.updateUserSetting({ - setting: create(UserSettingSchema, { - name: settingName, - value: { - case: "generalSetting", - value: updatedGeneralSetting, + updateUserGeneralSetting( + { generalSetting: { locale }, updateMask: ["locale"] }, + { + onSuccess: () => { + refetchSettings(); }, - }), - updateMask: create(FieldMaskSchema, { paths: ["general_setting.locale"] }), - }); - await refetchSettings(); + }, + ); }; const handleThemeChange = async (theme: string) => { @@ -64,23 +53,14 @@ const UserMenu = (props: Props) => { // Apply theme immediately for instant UI feedback loadTheme(theme); // Persist to user settings - const settingName = `${currentUser.name}/setting`; - const updatedGeneralSetting = create(UserSetting_GeneralSettingSchema, { - locale: userGeneralSetting?.locale, - theme, - memoVisibility: userGeneralSetting?.memoVisibility, - }); - await userServiceClient.updateUserSetting({ - setting: create(UserSettingSchema, { - name: settingName, - value: { - case: "generalSetting", - value: updatedGeneralSetting, + updateUserGeneralSetting( + { generalSetting: { theme }, updateMask: ["theme"] }, + { + onSuccess: () => { + refetchSettings(); }, - }), - updateMask: create(FieldMaskSchema, { paths: ["general_setting.theme"] }), - }); - await refetchSettings(); + }, + ); }; const handleSignOut = async () => {