fix: store reactive

pull/4394/head
Johnny 9 months ago
parent 01a9bb2d49
commit 9027430646

@ -70,6 +70,7 @@ const App = observer(() => {
useEffect(() => { useEffect(() => {
const currentLocale = workspaceStore.state.locale; const currentLocale = workspaceStore.state.locale;
// This will trigger re-rendering of the whole app.
i18n.changeLanguage(currentLocale); i18n.changeLanguage(currentLocale);
document.documentElement.setAttribute("lang", currentLocale); document.documentElement.setAttribute("lang", currentLocale);
if (["ar", "fa"].includes(currentLocale)) { if (["ar", "fa"].includes(currentLocale)) {
@ -101,7 +102,7 @@ const App = observer(() => {
return; return;
} }
workspaceStore.setPartial({ workspaceStore.state.setPartial({
locale: userSetting.locale || workspaceStore.state.locale, locale: userSetting.locale || workspaceStore.state.locale,
appearance: userSetting.appearance || workspaceStore.state.appearance, appearance: userSetting.appearance || workspaceStore.state.appearance,
}); });

@ -1,6 +1,6 @@
import { Divider, Option, Select } from "@mui/joy"; import { Divider, Option, Select } from "@mui/joy";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { userStore, workspaceStore } from "@/store/v2"; import { userStore } from "@/store/v2";
import { Visibility } from "@/types/proto/api/v1/memo_service"; import { Visibility } from "@/types/proto/api/v1/memo_service";
import { UserSetting } from "@/types/proto/api/v1/user_service"; import { UserSetting } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
@ -15,7 +15,6 @@ const PreferencesSection = observer(() => {
const setting = userStore.state.userSetting as UserSetting; const setting = userStore.state.userSetting as UserSetting;
const handleLocaleSelectChange = async (locale: Locale) => { const handleLocaleSelectChange = async (locale: Locale) => {
workspaceStore.setPartial({ locale });
await userStore.updateUserSetting( await userStore.updateUserSetting(
{ {
locale, locale,
@ -25,7 +24,6 @@ const PreferencesSection = observer(() => {
}; };
const handleAppearanceSelectChange = async (appearance: Appearance) => { const handleAppearanceSelectChange = async (appearance: Appearance) => {
workspaceStore.setPartial({ appearance });
await userStore.updateUserSetting( await userStore.updateUserSetting(
{ {
appearance, appearance,

@ -13,11 +13,11 @@ const AdminSignIn = observer(() => {
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL).generalSetting || WorkspaceGeneralSetting.fromPartial({}); workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL).generalSetting || WorkspaceGeneralSetting.fromPartial({});
const handleLocaleSelectChange = (locale: Locale) => { const handleLocaleSelectChange = (locale: Locale) => {
workspaceStore.setPartial({ locale }); workspaceStore.state.setPartial({ locale });
}; };
const handleAppearanceSelectChange = (appearance: Appearance) => { const handleAppearanceSelectChange = (appearance: Appearance) => {
workspaceStore.setPartial({ appearance }); workspaceStore.state.setPartial({ appearance });
}; };
return ( return (

@ -43,11 +43,11 @@ const SignIn = observer(() => {
}, []); }, []);
const handleLocaleSelectChange = (locale: Locale) => { const handleLocaleSelectChange = (locale: Locale) => {
workspaceStore.setPartial({ locale }); workspaceStore.state.setPartial({ locale });
}; };
const handleAppearanceSelectChange = (appearance: Appearance) => { const handleAppearanceSelectChange = (appearance: Appearance) => {
workspaceStore.setPartial({ appearance }); workspaceStore.state.setPartial({ appearance });
}; };
const handleSignInWithIdentityProvider = async (identityProvider: IdentityProvider) => { const handleSignInWithIdentityProvider = async (identityProvider: IdentityProvider) => {

@ -38,11 +38,11 @@ const SignUp = observer(() => {
}; };
const handleLocaleSelectChange = (locale: Locale) => { const handleLocaleSelectChange = (locale: Locale) => {
workspaceStore.setPartial({ locale }); workspaceStore.state.setPartial({ locale });
}; };
const handleAppearanceSelectChange = (appearance: Appearance) => { const handleAppearanceSelectChange = (appearance: Appearance) => {
workspaceStore.setPartial({ appearance }); workspaceStore.state.setPartial({ appearance });
}; };
const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => { const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {

@ -1,21 +1,29 @@
import { last } from "lodash-es"; import { last } from "lodash-es";
import { makeAutoObservable } from "mobx"; import { makeAutoObservable, runInAction } from "mobx";
class LocalState {
stack: string[] = [];
constructor() {
makeAutoObservable(this);
}
setPartial(partial: Partial<LocalState>) {
Object.assign(this, partial);
}
}
const dialogStore = (() => { const dialogStore = (() => {
const state = makeAutoObservable<{ const state = new LocalState();
stack: string[];
}>({
stack: [],
});
const pushDialog = (name: string) => { const pushDialog = (name: string) => {
state.stack.push(name); runInAction(() => state.stack.push(name));
}; };
const popDialog = () => state.stack.pop(); const popDialog = () => runInAction(() => state.stack.pop());
const removeDialog = (name: string) => { const removeDialog = (name: string) => {
state.stack = state.stack.filter((n) => n !== name); runInAction(() => (state.stack = state.stack.filter((n) => n !== name)));
}; };
const topDialog = last(state.stack); const topDialog = last(state.stack);

@ -2,27 +2,26 @@ import { makeAutoObservable } from "mobx";
import { authServiceClient, inboxServiceClient, userServiceClient } from "@/grpcweb"; import { authServiceClient, inboxServiceClient, userServiceClient } from "@/grpcweb";
import { Inbox } from "@/types/proto/api/v1/inbox_service"; import { Inbox } from "@/types/proto/api/v1/inbox_service";
import { Shortcut, User, UserSetting } from "@/types/proto/api/v1/user_service"; import { Shortcut, User, UserSetting } from "@/types/proto/api/v1/user_service";
import workspaceStore from "./workspace";
interface LocalState { class LocalState {
// The name of current user. Format: `users/${uid}`
currentUser?: string; currentUser?: string;
// userSetting is the setting of the current user.
userSetting?: UserSetting; userSetting?: UserSetting;
// shortcuts is the list of shortcuts of the current user. shortcuts: Shortcut[] = [];
shortcuts: Shortcut[]; inboxes: Inbox[] = [];
// inboxes is the list of inboxes of the current user. userMapByName: Record<string, User> = {};
inboxes: Inbox[];
// userMapByName is used to cache user information. constructor() {
// Key is the `user.name` and value is the `User` object. makeAutoObservable(this);
userMapByName: Record<string, User>; }
setPartial(partial: Partial<LocalState>) {
Object.assign(this, partial);
}
} }
const userStore = (() => { const userStore = (() => {
const state = makeAutoObservable<LocalState>({ const state = new LocalState();
shortcuts: [],
inboxes: [],
userMapByName: {},
});
const getOrFetchUserByName = async (name: string) => { const getOrFetchUserByName = async (name: string) => {
const userMap = state.userMapByName; const userMap = state.userMapByName;
@ -32,8 +31,12 @@ const userStore = (() => {
const user = await userServiceClient.getUser({ const user = await userServiceClient.getUser({
name: name, name: name,
}); });
userMap[name] = user; state.setPartial({
state.userMapByName = userMap; userMapByName: {
...userMap,
[name]: user,
},
});
return user; return user;
}; };
@ -42,10 +45,12 @@ const userStore = (() => {
user, user,
updateMask, updateMask,
}); });
state.userMapByName = { state.setPartial({
...state.userMapByName, userMapByName: {
[updatedUser.name]: updatedUser, ...state.userMapByName,
}; [updatedUser.name]: updatedUser,
},
});
}; };
const updateUserSetting = async (userSetting: Partial<UserSetting>, updateMask: string[]) => { const updateUserSetting = async (userSetting: Partial<UserSetting>, updateMask: string[]) => {
@ -53,7 +58,12 @@ const userStore = (() => {
setting: userSetting, setting: userSetting,
updateMask: updateMask, updateMask: updateMask,
}); });
state.userSetting = UserSetting.fromPartial(updatedUserSetting); state.setPartial({
userSetting: UserSetting.fromPartial({
...state.userSetting,
...updatedUserSetting,
}),
});
}; };
const fetchShortcuts = async () => { const fetchShortcuts = async () => {
@ -62,12 +72,16 @@ const userStore = (() => {
} }
const { shortcuts } = await userServiceClient.listShortcuts({ parent: state.currentUser }); const { shortcuts } = await userServiceClient.listShortcuts({ parent: state.currentUser });
state.shortcuts = shortcuts; state.setPartial({
shortcuts,
});
}; };
const fetchInboxes = async () => { const fetchInboxes = async () => {
const { inboxes } = await inboxServiceClient.listInboxes({}); const { inboxes } = await inboxServiceClient.listInboxes({});
state.inboxes = inboxes; state.setPartial({
inboxes,
});
}; };
const updateInbox = async (inbox: Partial<Inbox>, updateMask: string[]) => { const updateInbox = async (inbox: Partial<Inbox>, updateMask: string[]) => {
@ -75,7 +89,14 @@ const userStore = (() => {
inbox, inbox,
updateMask, updateMask,
}); });
state.inboxes = state.inboxes.map((i) => (i.name === updatedInbox.name ? updatedInbox : i)); state.setPartial({
inboxes: state.inboxes.map((i) => {
if (i.name === updatedInbox.name) {
return updatedInbox;
}
return i;
}),
});
return updatedInbox; return updatedInbox;
}; };
@ -94,7 +115,7 @@ export const initialUserStore = async () => {
try { try {
const currentUser = await authServiceClient.getAuthStatus({}); const currentUser = await authServiceClient.getAuthStatus({});
const userSetting = await userServiceClient.getUserSetting({}); const userSetting = await userServiceClient.getUserSetting({});
Object.assign(userStore.state, { userStore.state.setPartial({
currentUser: currentUser.name, currentUser: currentUser.name,
userSetting: UserSetting.fromPartial({ userSetting: UserSetting.fromPartial({
...userSetting, ...userSetting,
@ -103,6 +124,10 @@ export const initialUserStore = async () => {
[currentUser.name]: currentUser, [currentUser.name]: currentUser,
}, },
}); });
workspaceStore.state.setPartial({
locale: userSetting.locale,
appearance: userSetting.appearance,
});
} catch { } catch {
// Do nothing. // Do nothing.
} }

@ -1,3 +1,4 @@
import { uniqBy } from "lodash-es";
import { makeAutoObservable } from "mobx"; import { makeAutoObservable } from "mobx";
import { workspaceServiceClient, workspaceSettingServiceClient } from "@/grpcweb"; import { workspaceServiceClient, workspaceSettingServiceClient } from "@/grpcweb";
import { WorkspaceProfile } from "@/types/proto/api/v1/workspace_service"; import { WorkspaceProfile } from "@/types/proto/api/v1/workspace_service";
@ -6,38 +7,48 @@ import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { isValidateLocale } from "@/utils/i18n"; import { isValidateLocale } from "@/utils/i18n";
import { workspaceSettingNamePrefix } from "../v1"; import { workspaceSettingNamePrefix } from "../v1";
interface LocalState { class LocalState {
locale: string; locale: string = "en";
appearance: string; appearance: string = "system";
profile: WorkspaceProfile; profile: WorkspaceProfile = WorkspaceProfile.fromPartial({});
settings: WorkspaceSetting[]; settings: WorkspaceSetting[] = [];
constructor() {
makeAutoObservable(this);
}
setPartial(partial: Partial<LocalState>) {
const finalState = {
...this,
...partial,
};
if (!isValidateLocale(finalState.locale)) {
finalState.locale = "en";
}
if (!["system", "light", "dark"].includes(finalState.appearance)) {
finalState.appearance = "system";
}
Object.assign(this, finalState);
}
} }
const workspaceStore = (() => { const workspaceStore = (() => {
const state = makeAutoObservable<LocalState>({ const state = new LocalState();
locale: "en",
appearance: "system",
profile: WorkspaceProfile.fromPartial({}),
settings: [],
});
const generalSetting = const generalSetting =
state.settings.find((setting) => setting.name === `${workspaceSettingNamePrefix}${WorkspaceSettingKey.GENERAL}`)?.generalSetting || state.settings.find((setting) => setting.name === `${workspaceSettingNamePrefix}${WorkspaceSettingKey.GENERAL}`)?.generalSetting ||
WorkspaceGeneralSetting.fromPartial({}); WorkspaceGeneralSetting.fromPartial({});
const setPartial = (partial: Partial<LocalState>) => {
Object.assign(state, partial);
};
const fetchWorkspaceSetting = async (settingKey: WorkspaceSettingKey) => { const fetchWorkspaceSetting = async (settingKey: WorkspaceSettingKey) => {
const setting = await workspaceSettingServiceClient.getWorkspaceSetting({ name: `${workspaceSettingNamePrefix}${settingKey}` }); const setting = await workspaceSettingServiceClient.getWorkspaceSetting({ name: `${workspaceSettingNamePrefix}${settingKey}` });
state.settings.push(setting); state.setPartial({
settings: uniqBy([setting, ...state.settings], "name"),
});
}; };
return { return {
state, state,
generalSetting, generalSetting,
setPartial,
fetchWorkspaceSetting, fetchWorkspaceSetting,
}; };
})(); })();
@ -50,17 +61,9 @@ export const initialWorkspaceStore = async () => {
} }
const workspaceGeneralSetting = workspaceStore.generalSetting; const workspaceGeneralSetting = workspaceStore.generalSetting;
let locale = workspaceGeneralSetting.customProfile?.locale; workspaceStore.state.setPartial({
if (!isValidateLocale(locale)) { locale: workspaceGeneralSetting.customProfile?.locale,
locale = "en"; appearance: workspaceGeneralSetting.customProfile?.appearance,
}
let appearance = workspaceGeneralSetting.customProfile?.appearance;
if (!appearance || !["system", "light", "dark"].includes(appearance)) {
appearance = "system";
}
workspaceStore.setPartial({
locale: locale,
appearance: appearance,
profile: workspaceProfile, profile: workspaceProfile,
}); });
}; };

Loading…
Cancel
Save