fix: store reactive
This commit is contained in:
parent
01a9bb2d49
commit
9027430646
8 changed files with 108 additions and 73 deletions
|
|
@ -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({
|
||||||
|
userMapByName: {
|
||||||
...state.userMapByName,
|
...state.userMapByName,
|
||||||
[updatedUser.name]: updatedUser,
|
[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…
Reference in a new issue