mirror of
https://github.com/usememos/memos.git
synced 2025-03-04 01:04:38 +08:00
chore: migrate memo route
This commit is contained in:
parent
a2aea3747c
commit
288527914b
8 changed files with 60 additions and 23 deletions
|
@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
|
|||
import toast from "react-hot-toast";
|
||||
import { activityServiceClient } from "@/grpcweb";
|
||||
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||
import { useInboxStore, extractUsernameFromName } from "@/store/v1";
|
||||
import { useInboxStore, extractUsernameFromName, useMemoStore } from "@/store/v1";
|
||||
import { Activity } from "@/types/proto/api/v2/activity_service";
|
||||
import { Inbox, Inbox_Status } from "@/types/proto/api/v2/inbox_service";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
|
@ -18,6 +18,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
|
|||
const t = useTranslate();
|
||||
const navigateTo = useNavigateTo();
|
||||
const inboxStore = useInboxStore();
|
||||
const memoStore = useMemoStore();
|
||||
const [activity, setActivity] = useState<Activity | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -34,11 +35,19 @@ const MemoCommentMessage = ({ inbox }: Props) => {
|
|||
});
|
||||
}, [inbox.activityId]);
|
||||
|
||||
const handleNavigateToMemo = () => {
|
||||
if (!activity?.payload?.memoComment?.relatedMemoId) {
|
||||
const handleNavigateToMemo = async () => {
|
||||
const relatedMemoId = activity?.payload?.memoComment?.relatedMemoId;
|
||||
if (!relatedMemoId) {
|
||||
return;
|
||||
}
|
||||
navigateTo(`/m/${activity?.payload?.memoComment?.relatedMemoId}`);
|
||||
|
||||
const memo = await memoStore.getOrFetchMemoById(relatedMemoId);
|
||||
if (!memo) {
|
||||
toast.error("Memo not found");
|
||||
return;
|
||||
}
|
||||
|
||||
navigateTo(`/m/${memo.name}`);
|
||||
if (inbox.status === Inbox_Status.UNREAD) {
|
||||
handleArchiveMessage(true);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ const MemoRelationListView = (props: Props) => {
|
|||
<div key={memo.id} className="block w-auto max-w-[50%]">
|
||||
<Link
|
||||
className="px-2 border rounded-md w-auto text-sm leading-6 flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-400 dark:border-zinc-700 dark:bg-zinc-900 hover:shadow hover:opacity-80"
|
||||
to={`/m/${memo.id}`}
|
||||
to={`/m/${memo.name}`}
|
||||
unstable_viewTransition
|
||||
>
|
||||
<Tooltip title="Reference" placement="top">
|
||||
|
@ -64,7 +64,7 @@ const MemoRelationListView = (props: Props) => {
|
|||
<div key={memo.id} className="block w-auto max-w-[50%]">
|
||||
<Link
|
||||
className="px-2 border rounded-md w-auto text-sm leading-6 flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-300 dark:border-gray-600 hover:shadow hover:opacity-80"
|
||||
to={`/m/${memo.id}`}
|
||||
to={`/m/${memo.name}`}
|
||||
unstable_viewTransition
|
||||
>
|
||||
<Tooltip title="Backlink" placement="top">
|
||||
|
|
|
@ -75,7 +75,7 @@ const MemoView: React.FC<Props> = (props: Props) => {
|
|||
if (event.altKey) {
|
||||
showChangeMemoCreatedTsDialog(memo.id);
|
||||
} else {
|
||||
navigateTo(`/m/${memo.id}`);
|
||||
navigateTo(`/m/${memo.name}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ const ShareMemoDialog: React.FC<Props> = (props: Props) => {
|
|||
};
|
||||
|
||||
const handleCopyLinkBtnClick = () => {
|
||||
copy(`${window.location.origin}/m/${memo.id}`);
|
||||
copy(`${window.location.origin}/m/${memo.name}`);
|
||||
toast.success(t("message.succeed-copy-link"));
|
||||
};
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@ const MemoDetail = () => {
|
|||
const memoStore = useMemoStore();
|
||||
const userStore = useUserStore();
|
||||
const [creator, setCreator] = useState<User>();
|
||||
const memoId = Number(params.memoId);
|
||||
const memo = memoStore.getMemoById(memoId);
|
||||
const memoName = params.memoName;
|
||||
const memo = memoStore.getMemoByName(memoName || "");
|
||||
const [parentMemo, setParentMemo] = useState<Memo | undefined>(undefined);
|
||||
const referenceRelations = memo?.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE) || [];
|
||||
const commentRelations =
|
||||
|
@ -44,9 +44,9 @@ const MemoDetail = () => {
|
|||
|
||||
// Prepare memo.
|
||||
useEffect(() => {
|
||||
if (memoId && !isNaN(memoId)) {
|
||||
if (memoName) {
|
||||
memoStore
|
||||
.getOrFetchMemoById(memoId)
|
||||
.getOrFetchMemoByName(memoName)
|
||||
.then(async (memo) => {
|
||||
const user = await userStore.getOrFetchUserByUsername(extractUsernameFromName(memo.creator));
|
||||
setCreator(user);
|
||||
|
@ -58,7 +58,7 @@ const MemoDetail = () => {
|
|||
} else {
|
||||
navigateTo("/404");
|
||||
}
|
||||
}, [memoId]);
|
||||
}, [memoName]);
|
||||
|
||||
// Prepare memo comments.
|
||||
useEffect(() => {
|
||||
|
@ -100,7 +100,7 @@ const MemoDetail = () => {
|
|||
};
|
||||
|
||||
const handleCopyLinkBtnClick = () => {
|
||||
copy(`${window.location.origin}/m/${memo.id}`);
|
||||
copy(`${window.location.origin}/m/${memo.name}`);
|
||||
toast.success(t("message.succeed-copy-link"));
|
||||
};
|
||||
|
||||
|
@ -129,7 +129,7 @@ const MemoDetail = () => {
|
|||
<div className="w-auto mb-2">
|
||||
<Link
|
||||
className="px-3 py-1 border rounded-lg max-w-xs w-auto text-sm flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-400 dark:border-gray-500 hover:shadow hover:opacity-80"
|
||||
to={`/m/${parentMemo.id}`}
|
||||
to={`/m/${parentMemo.name}`}
|
||||
unstable_viewTransition
|
||||
>
|
||||
<Icon.ArrowUpLeftFromCircle className="w-4 h-auto shrink-0 opacity-60 mr-2" />
|
||||
|
|
|
@ -10,6 +10,7 @@ import ResourceIcon from "@/components/ResourceIcon";
|
|||
import { resourceServiceClient } from "@/grpcweb";
|
||||
import useLoading from "@/hooks/useLoading";
|
||||
import i18n from "@/i18n";
|
||||
import { useMemoStore } from "@/store/v1";
|
||||
import { Resource } from "@/types/proto/api/v2/resource_service";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
|
||||
|
@ -38,6 +39,7 @@ const Resources = () => {
|
|||
const [state, setState] = useState<State>({
|
||||
searchQuery: "",
|
||||
});
|
||||
const memoStore = useMemoStore();
|
||||
const [resources, setResources] = useState<Resource[]>([]);
|
||||
const filteredResources = resources.filter((resource) => includes(resource.filename, state.searchQuery));
|
||||
const groupedResources = groupResourcesByDate(filteredResources.filter((resoure) => resoure.memoId));
|
||||
|
@ -47,6 +49,7 @@ const Resources = () => {
|
|||
resourceServiceClient.listResources({}).then(({ resources }) => {
|
||||
setResources(resources);
|
||||
loadingState.setFinish();
|
||||
Promise.all(resources.map((resource) => (resource.memoId ? memoStore.getOrFetchMemoById(resource.memoId) : null)));
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
@ -109,6 +112,7 @@ const Resources = () => {
|
|||
</div>
|
||||
<div className="w-full max-w-[calc(100%-4rem)] sm:max-w-[calc(100%-6rem)] flex flex-row justify-start items-start gap-4 flex-wrap">
|
||||
{resources.map((resource) => {
|
||||
const relatedMemo = resource.memoId ? memoStore.getMemoById(resource.memoId) : null;
|
||||
return (
|
||||
<div key={resource.id} className="w-24 sm:w-32 h-auto flex flex-col justify-start items-start">
|
||||
<div className="w-24 h-24 flex justify-center items-center sm:w-32 sm:h-32 border dark:border-zinc-900 overflow-clip rounded-xl cursor-pointer hover:shadow hover:opacity-80">
|
||||
|
@ -116,13 +120,15 @@ const Resources = () => {
|
|||
</div>
|
||||
<div className="w-full max-w-full flex flex-row justify-between items-center mt-1 px-1">
|
||||
<p className="text-xs shrink text-gray-400 truncate">{resource.filename}</p>
|
||||
<Link
|
||||
className="shrink-0 text-xs ml-1 text-gray-400 hover:underline hover:text-blue-600"
|
||||
to={`/m/${resource.memoId}`}
|
||||
target="_blank"
|
||||
>
|
||||
#{resource.memoId}
|
||||
</Link>
|
||||
{relatedMemo && (
|
||||
<Link
|
||||
className="shrink-0 text-xs ml-1 text-gray-400 hover:underline hover:text-blue-600"
|
||||
to={`/m/${relatedMemo.name}`}
|
||||
target="_blank"
|
||||
>
|
||||
#{relatedMemo.id}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -112,7 +112,7 @@ const router = createBrowserRouter([
|
|||
element: <Explore />,
|
||||
},
|
||||
{
|
||||
path: "m/:memoId",
|
||||
path: "m/:memoName",
|
||||
element: <MemoDetail />,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -47,6 +47,28 @@ export const useMemoStore = create(
|
|||
getMemoById: (id: number) => {
|
||||
return get().memoMapById[id];
|
||||
},
|
||||
getOrFetchMemoByName: async (name: string) => {
|
||||
const memoMap = get().memoMapById;
|
||||
const memo = Object.values(memoMap).find((memo) => memo.name === name);
|
||||
if (memo) {
|
||||
return memo;
|
||||
}
|
||||
|
||||
const res = await memoServiceClient.getMemoByName({
|
||||
name,
|
||||
});
|
||||
if (!res.memo) {
|
||||
throw new Error("Memo not found");
|
||||
}
|
||||
|
||||
memoMap[res.memo.id] = res.memo;
|
||||
set({ memoMapById: memoMap });
|
||||
return res.memo;
|
||||
},
|
||||
getMemoByName: (name: string) => {
|
||||
const memoMap = get().memoMapById;
|
||||
return Object.values(memoMap).find((memo) => memo.name === name);
|
||||
},
|
||||
createMemo: async (request: CreateMemoRequest) => {
|
||||
const { memo } = await memoServiceClient.createMemo(request);
|
||||
if (!memo) {
|
||||
|
|
Loading…
Reference in a new issue