diff --git a/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx b/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx index 7711158ce..3690a1136 100644 --- a/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx +++ b/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx @@ -1,7 +1,8 @@ +import { observer } from "mobx-react-lite"; import { useEffect } from "react"; import MemoResourceListView from "@/components/MemoResourceListView"; import useLoading from "@/hooks/useLoading"; -import { useResourceStore } from "@/store/v1"; +import { resourceStore } from "@/store/v2"; import { cn } from "@/utils"; import Error from "./Error"; @@ -35,9 +36,8 @@ const getAdditionalClassNameWithParams = (params: URLSearchParams) => { return additionalClassNames.join(" "); }; -const EmbeddedResource = ({ resourceId: uid, params: paramsStr }: Props) => { +const EmbeddedResource = observer(({ resourceId: uid, params: paramsStr }: Props) => { const loadingState = useLoading(); - const resourceStore = useResourceStore(); const resource = resourceStore.getResourceByName(uid); const params = new URLSearchParams(paramsStr); @@ -57,6 +57,6 @@ const EmbeddedResource = ({ resourceId: uid, params: paramsStr }: Props) => { ); -}; +}); export default EmbeddedResource; diff --git a/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx b/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx index 074fa24a7..e63a5c924 100644 --- a/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx +++ b/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx @@ -1,8 +1,9 @@ import { Button } from "@usememos/mui"; import { LoaderIcon, PaperclipIcon } from "lucide-react"; +import { observer } from "mobx-react-lite"; import { useContext, useRef, useState } from "react"; import toast from "react-hot-toast"; -import { useResourceStore } from "@/store/v1"; +import { resourceStore } from "@/store/v2"; import { Resource } from "@/types/proto/api/v1/resource_service"; import { MemoEditorContext } from "../types"; @@ -14,9 +15,8 @@ interface State { uploadingFlag: boolean; } -const UploadResourceButton = (props: Props) => { +const UploadResourceButton = observer((props: Props) => { const context = useContext(MemoEditorContext); - const resourceStore = useResourceStore(); const [state, setState] = useState({ uploadingFlag: false, }); @@ -86,6 +86,6 @@ const UploadResourceButton = (props: Props) => { /> ); -}; +}); export default UploadResourceButton; diff --git a/web/src/components/MemoEditor/index.tsx b/web/src/components/MemoEditor/index.tsx index 0b71b0640..724ffeaa8 100644 --- a/web/src/components/MemoEditor/index.tsx +++ b/web/src/components/MemoEditor/index.tsx @@ -13,8 +13,8 @@ import { TAB_SPACE_WIDTH } from "@/helpers/consts"; import { isValidUrl } from "@/helpers/utils"; import useAsyncEffect from "@/hooks/useAsyncEffect"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { useMemoStore, useResourceStore } from "@/store/v1"; -import { userStore, workspaceStore } from "@/store/v2"; +import { useMemoStore } from "@/store/v1"; +import { resourceStore, userStore, workspaceStore } from "@/store/v2"; import { Location, Memo, MemoRelation, MemoRelation_Type, Visibility } from "@/types/proto/api/v1/memo_service"; import { Resource } from "@/types/proto/api/v1/resource_service"; import { UserSetting } from "@/types/proto/api/v1/user_service"; @@ -62,7 +62,6 @@ const MemoEditor = observer((props: Props) => { const t = useTranslate(); const { i18n } = useTranslation(); const memoStore = useMemoStore(); - const resourceStore = useResourceStore(); const currentUser = useCurrentUser(); const [state, setState] = useState({ memoVisibility: Visibility.PRIVATE, diff --git a/web/src/store/v1/index.ts b/web/src/store/v1/index.ts index 65cd971de..b090b900a 100644 --- a/web/src/store/v1/index.ts +++ b/web/src/store/v1/index.ts @@ -1,3 +1,2 @@ export * from "./memo"; -export * from "./resource"; export * from "./memoFilter"; diff --git a/web/src/store/v1/resource.ts b/web/src/store/v1/resource.ts deleted file mode 100644 index c95752227..000000000 --- a/web/src/store/v1/resource.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { create } from "zustand"; -import { combine } from "zustand/middleware"; -import { resourceServiceClient } from "@/grpcweb"; -import { CreateResourceRequest, Resource, UpdateResourceRequest } from "@/types/proto/api/v1/resource_service"; - -interface State { - resourceMapByName: Record; -} - -const getDefaultState = (): State => ({ - resourceMapByName: {}, -}); - -export const useResourceStore = create( - combine(getDefaultState(), (set, get) => ({ - setState: (state: State) => set(state), - getState: () => get(), - fetchResourceByName: async (name: string) => { - const resource = await resourceServiceClient.getResource({ - name, - }); - const resourceMap = get().resourceMapByName; - resourceMap[resource.name] = resource; - set({ resourceMapByName: resourceMap }); - return resource; - }, - getResourceByName: (name: string) => { - const resourceMap = get().resourceMapByName; - return Object.values(resourceMap).find((r) => r.name === name); - }, - async createResource(create: CreateResourceRequest): Promise { - const resource = await resourceServiceClient.createResource(create); - const resourceMap = get().resourceMapByName; - resourceMap[resource.name] = resource; - return resource; - }, - async updateResource(update: UpdateResourceRequest): Promise { - const resource = await resourceServiceClient.updateResource(update); - const resourceMap = get().resourceMapByName; - resourceMap[resource.name] = resource; - return resource; - }, - })), -); diff --git a/web/src/store/v2/index.ts b/web/src/store/v2/index.ts index 94307e441..4747e2bbf 100644 --- a/web/src/store/v2/index.ts +++ b/web/src/store/v2/index.ts @@ -1,5 +1,6 @@ +import resourceStore from "./resource"; import userStore from "./user"; import viewStore from "./view"; import workspaceStore from "./workspace"; -export { workspaceStore, userStore, viewStore }; +export { resourceStore, workspaceStore, userStore, viewStore }; diff --git a/web/src/store/v2/resource.ts b/web/src/store/v2/resource.ts new file mode 100644 index 000000000..09164c687 --- /dev/null +++ b/web/src/store/v2/resource.ts @@ -0,0 +1,59 @@ +import { makeAutoObservable } from "mobx"; +import { resourceServiceClient } from "@/grpcweb"; +import { CreateResourceRequest, Resource, UpdateResourceRequest } from "@/types/proto/api/v1/resource_service"; + +class LocalState { + resourceMapByName: Record = {}; + + constructor() { + makeAutoObservable(this); + } + + setPartial(partial: Partial) { + Object.assign(this, partial); + } +} + +const resourceStore = (() => { + const state = new LocalState(); + + const fetchResourceByName = async (name: string) => { + const resource = await resourceServiceClient.getResource({ + name, + }); + const resourceMap = { ...state.resourceMapByName }; + resourceMap[resource.name] = resource; + state.setPartial({ resourceMapByName: resourceMap }); + return resource; + }; + + const getResourceByName = (name: string) => { + return Object.values(state.resourceMapByName).find((r) => r.name === name); + }; + + const createResource = async (create: CreateResourceRequest): Promise => { + const resource = await resourceServiceClient.createResource(create); + const resourceMap = { ...state.resourceMapByName }; + resourceMap[resource.name] = resource; + state.setPartial({ resourceMapByName: resourceMap }); + return resource; + }; + + const updateResource = async (update: UpdateResourceRequest): Promise => { + const resource = await resourceServiceClient.updateResource(update); + const resourceMap = { ...state.resourceMapByName }; + resourceMap[resource.name] = resource; + state.setPartial({ resourceMapByName: resourceMap }); + return resource; + }; + + return { + state, + fetchResourceByName, + getResourceByName, + createResource, + updateResource, + }; +})(); + +export default resourceStore;