chore: adjust initial states

This commit is contained in:
Steven 2023-09-10 23:44:06 +08:00
parent 3ad0832516
commit b6d1ded668
12 changed files with 143 additions and 222 deletions

View File

@ -8,6 +8,7 @@
}, },
"packageManager": "pnpm@8.7.0", "packageManager": "pnpm@8.7.0",
"dependencies": { "dependencies": {
"@bufbuild/protobuf": "^1.3.1",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@mui/joy": "5.0.0-beta.2", "@mui/joy": "5.0.0-beta.2",

View File

@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
dependencies: dependencies:
'@bufbuild/protobuf':
specifier: ^1.3.1
version: 1.3.1
'@emotion/react': '@emotion/react':
specifier: ^11.11.1 specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.21)(react@18.2.0) version: 11.11.1(@types/react@18.2.21)(react@18.2.0)
@ -407,6 +410,10 @@ packages:
'@babel/helper-validator-identifier': 7.22.5 '@babel/helper-validator-identifier': 7.22.5
to-fast-properties: 2.0.0 to-fast-properties: 2.0.0
/@bufbuild/protobuf@1.3.1:
resolution: {integrity: sha512-BUyJWutgP2S8K/1NphOJokuwDckXS4qI2T1pGZAlkFdZchWae3jm6fCdkcGbLlM1QLOcNFFePd+7Feo4BYGrJQ==}
dev: false
/@emotion/babel-plugin@11.11.0: /@emotion/babel-plugin@11.11.0:
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
dependencies: dependencies:

View File

@ -1,20 +1,44 @@
import { useColorScheme } from "@mui/joy"; import { useColorScheme } from "@mui/joy";
import { Suspense, useEffect } from "react"; import { Suspense, useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { RouterProvider } from "react-router-dom"; import { Outlet } from "react-router-dom";
import storage from "./helpers/storage"; import storage from "./helpers/storage";
import { getSystemColorScheme } from "./helpers/utils"; import { getSystemColorScheme } from "./helpers/utils";
import Loading from "./pages/Loading"; import Loading from "./pages/Loading";
import router from "./router"; import { initialGlobalState, initialUserState, useGlobalStore } from "./store/module";
import { useGlobalStore } from "./store/module"; import { useUserV1Store } from "./store/v1";
const App = () => { const App = () => {
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const { mode, setMode } = useColorScheme(); const { mode, setMode } = useColorScheme();
const userV1Store = useUserV1Store();
const [loading, setLoading] = useState(true);
const { appearance, locale, systemStatus } = globalStore.state; const { appearance, locale, systemStatus } = globalStore.state;
useEffect(() => {
const initialState = async () => {
try {
await initialGlobalState();
} catch (error) {
// do nothing
}
try {
const user = await initialUserState();
if (user) {
await userV1Store.getOrFetchUserByUsername(user.username);
}
} catch (error) {
// do nothing.
}
setLoading(false);
};
initialState();
}, []);
useEffect(() => { useEffect(() => {
const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleColorSchemeChange = (e: MediaQueryListEvent) => { const handleColorSchemeChange = (e: MediaQueryListEvent) => {
@ -85,10 +109,11 @@ const App = () => {
} }
}, [mode]); }, [mode]);
return ( return loading ? (
<Loading />
) : (
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
<RouterProvider router={router} /> <Outlet />
<Toaster position="top-right" />
</Suspense> </Suspense>
); );
}; };

View File

@ -1,12 +1,14 @@
import { CssVarsProvider } from "@mui/joy"; import { CssVarsProvider } from "@mui/joy";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { Toaster } from "react-hot-toast";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import App from "./App"; import { RouterProvider } from "react-router-dom";
import "./css/global.css"; import "./css/global.css";
import "./css/tailwind.css"; import "./css/tailwind.css";
import "./helpers/polyfill"; import "./helpers/polyfill";
import "./i18n"; import "./i18n";
import "./less/code-highlight.less"; import "./less/code-highlight.less";
import router from "./router";
import store from "./store"; import store from "./store";
import theme from "./theme"; import theme from "./theme";
@ -15,7 +17,8 @@ const root = createRoot(container as HTMLElement);
root.render( root.render(
<Provider store={store}> <Provider store={store}>
<CssVarsProvider theme={theme}> <CssVarsProvider theme={theme}>
<App /> <RouterProvider router={router} />
<Toaster position="top-right" />
</CssVarsProvider> </CssVarsProvider>
</Provider> </Provider>
); );

View File

@ -4,6 +4,7 @@ import ArchivedMemo from "@/components/ArchivedMemo";
import Empty from "@/components/Empty"; import Empty from "@/components/Empty";
import MemoFilter from "@/components/MemoFilter"; import MemoFilter from "@/components/MemoFilter";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
import useCurrentUser from "@/hooks/useCurrentUser";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useFilterStore, useMemoStore } from "@/store/module"; import { useFilterStore, useMemoStore } from "@/store/module";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
@ -11,6 +12,7 @@ import "@/less/archived.less";
const Archived = () => { const Archived = () => {
const t = useTranslate(); const t = useTranslate();
const user = useCurrentUser();
const memoStore = useMemoStore(); const memoStore = useMemoStore();
const loadingState = useLoading(); const loadingState = useLoading();
const [archivedMemos, setArchivedMemos] = useState<Memo[]>([]); const [archivedMemos, setArchivedMemos] = useState<Memo[]>([]);
@ -19,6 +21,12 @@ const Archived = () => {
const filter = filterStore.state; const filter = filterStore.state;
const { text: textQuery } = filter; const { text: textQuery } = filter;
useEffect(() => {
if (!user) {
window.location.href = "/auth";
}
}, []);
useEffect(() => { useEffect(() => {
memoStore memoStore
.fetchArchivedMemos() .fetchArchivedMemos()

View File

@ -11,6 +11,7 @@ import showPreviewImageDialog from "@/components/PreviewImageDialog";
import DatePicker from "@/components/kit/DatePicker"; import DatePicker from "@/components/kit/DatePicker";
import { DAILY_TIMESTAMP, DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; import { DAILY_TIMESTAMP, DEFAULT_MEMO_LIMIT } from "@/helpers/consts";
import { convertToMillis, getDateStampByDate, getNormalizedDateString, getTimeStampByDate, isFutureDate } from "@/helpers/datetime"; import { convertToMillis, getDateStampByDate, getNormalizedDateString, getTimeStampByDate, isFutureDate } from "@/helpers/datetime";
import useCurrentUser from "@/hooks/useCurrentUser";
import i18n from "@/i18n"; import i18n from "@/i18n";
import toImage from "@/labs/html2image"; import toImage from "@/labs/html2image";
import { useMemoStore, useUserStore } from "@/store/module"; import { useMemoStore, useUserStore } from "@/store/module";
@ -20,6 +21,7 @@ const DailyReview = () => {
const t = useTranslate(); const t = useTranslate();
const memoStore = useMemoStore(); const memoStore = useMemoStore();
const userStore = useUserStore(); const userStore = useUserStore();
const user = useCurrentUser();
const { localSetting } = userStore.state.user as User; const { localSetting } = userStore.state.user as User;
const [currentDateStamp, setCurrentDateStamp] = useState(getDateStampByDate(getNormalizedDateString())); const [currentDateStamp, setCurrentDateStamp] = useState(getDateStampByDate(getNormalizedDateString()));
const [showDatePicker, toggleShowDatePicker] = useToggle(false); const [showDatePicker, toggleShowDatePicker] = useToggle(false);
@ -37,6 +39,12 @@ const DailyReview = () => {
}) })
.sort((a, b) => getTimeStampByDate(a.displayTs) - getTimeStampByDate(b.displayTs)); .sort((a, b) => getTimeStampByDate(a.displayTs) - getTimeStampByDate(b.displayTs));
useEffect(() => {
if (!user) {
window.location.href = "/auth";
}
}, []);
useEffect(() => { useEffect(() => {
let offset = 0; let offset = 0;
const fetchMoreMemos = async () => { const fetchMoreMemos = async () => {

View File

@ -1,34 +1,29 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { toast } from "react-hot-toast";
import HomeSidebar from "@/components/HomeSidebar"; import HomeSidebar from "@/components/HomeSidebar";
import MemoEditor from "@/components/MemoEditor"; import MemoEditor from "@/components/MemoEditor";
import MemoFilter from "@/components/MemoFilter"; import MemoFilter from "@/components/MemoFilter";
import MemoList from "@/components/MemoList"; import MemoList from "@/components/MemoList";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useGlobalStore, useUserStore } from "@/store/module"; import { useGlobalStore, useUserStore } from "@/store/module";
import { useUserV1Store } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
const Home = () => { const Home = () => {
const t = useTranslate();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const userStore = useUserStore(); const userStore = useUserStore();
const userV1Store = useUserV1Store(); const user = useCurrentUser();
const user = userStore.state.user;
useEffect(() => { useEffect(() => {
const currentUsername = userStore.getCurrentUsername(); if (user) {
userV1Store.getOrFetchUserByUsername(currentUsername).catch((error) => { return;
console.error(error);
toast.error(t("message.user-not-found"));
});
}, [userStore.getCurrentUsername()]);
useEffect(() => {
if (user?.setting.locale) {
globalStore.setLocale(user.setting.locale);
} }
}, [user?.setting.locale]);
const systemStatus = globalStore.state.systemStatus;
if (systemStatus.disablePublicMemos) {
window.location.href = "/auth";
} else {
window.location.href = "/explore";
}
}, []);
return ( return (
<div className="w-full flex flex-row justify-start items-start"> <div className="w-full flex flex-row justify-start items-start">

View File

@ -11,6 +11,7 @@ import ResourceItem from "@/components/ResourceItem";
import ResourceSearchBar from "@/components/ResourceSearchBar"; import ResourceSearchBar from "@/components/ResourceSearchBar";
import Dropdown from "@/components/kit/Dropdown"; import Dropdown from "@/components/kit/Dropdown";
import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts";
import useCurrentUser from "@/hooks/useCurrentUser";
import useEvent from "@/hooks/useEvent"; import useEvent from "@/hooks/useEvent";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import { useResourceStore } from "@/store/module"; import { useResourceStore } from "@/store/module";
@ -19,6 +20,7 @@ import { useTranslate } from "@/utils/i18n";
const ResourcesDashboard = () => { const ResourcesDashboard = () => {
const t = useTranslate(); const t = useTranslate();
const loadingState = useLoading(); const loadingState = useLoading();
const user = useCurrentUser();
const resourceStore = useResourceStore(); const resourceStore = useResourceStore();
const resources = resourceStore.state.resources; const resources = resourceStore.state.resources;
const [selectedList, setSelectedList] = useState<Array<ResourceId>>([]); const [selectedList, setSelectedList] = useState<Array<ResourceId>>([]);
@ -27,6 +29,12 @@ const ResourcesDashboard = () => {
const [dragActive, setDragActive] = useState(false); const [dragActive, setDragActive] = useState(false);
const [isComplete, setIsComplete] = useState<boolean>(false); const [isComplete, setIsComplete] = useState<boolean>(false);
useEffect(() => {
if (!user) {
window.location.href = "/auth";
}
}, []);
useEffect(() => { useEffect(() => {
resourceStore resourceStore
.fetchResourceListWithLimit(DEFAULT_MEMO_LIMIT) .fetchResourceListWithLimit(DEFAULT_MEMO_LIMIT)

View File

@ -1,5 +1,6 @@
import { Option, Select } from "@mui/joy"; import { Option, Select } from "@mui/joy";
import { useState } from "react"; import { isEqual } from "lodash-es";
import { useEffect, useState } from "react";
import BetaBadge from "@/components/BetaBadge"; import BetaBadge from "@/components/BetaBadge";
import Icon from "@/components/Icon"; import Icon from "@/components/Icon";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
@ -9,7 +10,7 @@ import PreferencesSection from "@/components/Settings/PreferencesSection";
import SSOSection from "@/components/Settings/SSOSection"; import SSOSection from "@/components/Settings/SSOSection";
import StorageSection from "@/components/Settings/StorageSection"; import StorageSection from "@/components/Settings/StorageSection";
import SystemSection from "@/components/Settings/SystemSection"; import SystemSection from "@/components/Settings/SystemSection";
import { useUserStore } from "@/store/module"; import useCurrentUser from "@/hooks/useCurrentUser";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import "@/less/setting.less"; import "@/less/setting.less";
@ -21,12 +22,17 @@ interface State {
const Setting = () => { const Setting = () => {
const t = useTranslate(); const t = useTranslate();
const userStore = useUserStore(); const user = useCurrentUser();
const user = userStore.state.user;
const [state, setState] = useState<State>({ const [state, setState] = useState<State>({
selectedSection: "my-account", selectedSection: "my-account",
}); });
const isHost = user?.role === "HOST"; const isHost = isEqual(user.role, "HOST");
useEffect(() => {
if (!user) {
window.location.href = "/auth";
}
}, []);
const handleSectionSelectorItemClick = (settingSection: SettingSection) => { const handleSectionSelectorItemClick = (settingSection: SettingSection) => {
setState({ setState({

View File

@ -1,12 +1,11 @@
import { lazy } from "react"; import { lazy } from "react";
import { createBrowserRouter, redirect } from "react-router-dom"; import { createBrowserRouter } from "react-router-dom";
import { isNullorUndefined } from "@/helpers/utils"; import App from "@/App";
import Archived from "@/pages/Archived"; import Archived from "@/pages/Archived";
import DailyReview from "@/pages/DailyReview"; import DailyReview from "@/pages/DailyReview";
import ResourcesDashboard from "@/pages/ResourcesDashboard"; import ResourcesDashboard from "@/pages/ResourcesDashboard";
import Setting from "@/pages/Setting"; import Setting from "@/pages/Setting";
import store from "@/store"; import { initialGlobalState } from "@/store/module";
import { initialGlobalState, initialUserState } from "@/store/module";
const Root = lazy(() => import("@/layouts/Root")); const Root = lazy(() => import("@/layouts/Root"));
const Auth = lazy(() => import("@/pages/Auth")); const Auth = lazy(() => import("@/pages/Auth"));
@ -35,210 +34,70 @@ const initialGlobalStateLoader = (() => {
})(); })();
const router = createBrowserRouter([ const router = createBrowserRouter([
{
path: "/auth",
element: <Auth />,
loader: async () => {
await initialGlobalStateLoader();
return null;
},
},
{
path: "/auth/callback",
element: <AuthCallback />,
},
{ {
path: "/", path: "/",
element: <Root />, element: <App />,
children: [ children: [
{ {
path: "", path: "/auth",
element: <Home />, element: <Auth />,
loader: async () => { loader: async () => {
await initialGlobalStateLoader(); await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
const { user } = store.getState().user;
const { systemStatus } = store.getState().global;
// if user is authenticated, then show home
if (!isNullorUndefined(user)) {
return null;
}
// if user is anonymous, then redirect to auth if disabled public memos, else redirect to explore
if (systemStatus.disablePublicMemos) {
return redirect("/auth");
}
return redirect("/explore");
},
},
{
path: "explore",
element: <Explore />,
loader: async () => {
await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
const { user } = store.getState().user;
const { systemStatus } = store.getState().global;
if (isNullorUndefined(user) && systemStatus.disablePublicMemos) {
return redirect("/auth");
}
return null; return null;
}, },
}, },
{ {
path: "review", path: "/auth/callback",
element: <DailyReview />, element: <AuthCallback />,
loader: async () => {
await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
const { user } = store.getState().user;
if (isNullorUndefined(user)) {
return redirect("/auth");
}
return null;
},
}, },
{ {
path: "resources", path: "/",
element: <ResourcesDashboard />, element: <Root />,
loader: async () => { children: [
await initialGlobalStateLoader(); {
path: "",
try { element: <Home />,
await initialUserState(); },
} catch (error) { {
// do nth path: "explore",
} element: <Explore />,
},
const { user } = store.getState().user; {
path: "review",
if (isNullorUndefined(user)) { element: <DailyReview />,
return redirect("/auth"); },
} {
return null; path: "resources",
}, element: <ResourcesDashboard />,
},
{
path: "archived",
element: <Archived />,
},
{
path: "setting",
element: <Setting />,
},
],
}, },
{ {
path: "archived", path: "/m/:memoId",
element: <Archived />, element: <MemoDetail />,
loader: async () => {
await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
const { user } = store.getState().user;
if (isNullorUndefined(user)) {
return redirect("/auth");
}
return null;
},
}, },
{ {
path: "setting", path: "/m/:memoId/embed",
element: <Setting />, element: <EmbedMemo />,
loader: async () => { },
await initialGlobalStateLoader(); {
path: "/u/:username",
try { element: <UserProfile />,
await initialUserState(); },
} catch (error) { {
// do nth path: "*",
} element: <NotFound />,
const { user } = store.getState().user;
if (isNullorUndefined(user)) {
return redirect("/auth");
}
return null;
},
}, },
], ],
}, },
{
path: "/m/:memoId",
element: <MemoDetail />,
loader: async () => {
await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
const { user } = store.getState().user;
const { systemStatus } = store.getState().global;
if (isNullorUndefined(user) && systemStatus.disablePublicMemos) {
return redirect("/auth");
}
return null;
},
},
{
path: "/m/:memoId/embed",
element: <EmbedMemo />,
loader: async () => {
await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
return null;
},
},
{
path: "/u/:username",
element: <UserProfile />,
loader: async () => {
await initialGlobalStateLoader();
try {
await initialUserState();
} catch (error) {
// do nth
}
return null;
},
},
{
path: "*",
element: <NotFound />,
loader: async () => {
await initialGlobalStateLoader();
return null;
},
},
]); ]);
export default router; export default router;

View File

@ -68,6 +68,7 @@ export const initialUserState = async () => {
if (user.setting.appearance) { if (user.setting.appearance) {
store.dispatch(setAppearance(user.setting.appearance)); store.dispatch(setAppearance(user.setting.appearance));
} }
return user;
} }
}; };

View File

@ -39,7 +39,7 @@ const useUserV1Store = create<UserV1Store>()((set, get) => ({
}, },
getUserByUsername: (username: string) => { getUserByUsername: (username: string) => {
const userMap = get().userMapByUsername; const userMap = get().userMapByUsername;
return userMap[username] as User; return userMap[username];
}, },
updateUser: async (user: Partial<User>, updateMask: string[]) => { updateUser: async (user: Partial<User>, updateMask: string[]) => {
const { const {