mirror of
https://github.com/usememos/memos.git
synced 2025-11-20 17:45:17 +08:00
feat(inbox): handles errors while fetching and adds possibility to delete items (#4908)
This commit is contained in:
parent
db63b1949a
commit
2c7eb23343
5 changed files with 86 additions and 31 deletions
|
|
@ -108,6 +108,9 @@ func (s *APIV1Service) convertActivityPayloadFromStore(ctx context.Context, payl
|
|||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get memo: %v", err)
|
||||
}
|
||||
if memo == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "memo does not exist")
|
||||
}
|
||||
relatedMemo, err := s.Store.GetMemo(ctx, &store.FindMemo{
|
||||
ID: &payload.MemoComment.RelatedMemoId,
|
||||
ExcludeContent: true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { InboxIcon, LoaderIcon, MessageCircleIcon } from "lucide-react";
|
||||
import { InboxIcon, LoaderIcon, MessageCircleIcon, TrashIcon } from "lucide-react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
|
|
@ -24,24 +24,32 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
const [relatedMemo, setRelatedMemo] = useState<Memo | undefined>(undefined);
|
||||
const [sender, setSender] = useState<User | undefined>(undefined);
|
||||
const [initialized, setInitialized] = useState<boolean>(false);
|
||||
const [hasError, setHasError] = useState<boolean>(false);
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if (!inbox.activityId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activity = await activityServiceClient.getActivity({
|
||||
name: `${activityNamePrefix}${inbox.activityId}`,
|
||||
});
|
||||
if (activity.payload?.memoComment) {
|
||||
const memoCommentPayload = activity.payload.memoComment;
|
||||
const memo = await memoStore.getOrFetchMemoByName(memoCommentPayload.relatedMemo, {
|
||||
skipStore: true,
|
||||
try {
|
||||
const activity = await activityServiceClient.getActivity({
|
||||
name: `${activityNamePrefix}${inbox.activityId}`,
|
||||
});
|
||||
setRelatedMemo(memo);
|
||||
const sender = await userStore.getOrFetchUserByName(inbox.sender);
|
||||
setSender(sender);
|
||||
setInitialized(true);
|
||||
|
||||
if (activity.payload?.memoComment) {
|
||||
const memoCommentPayload = activity.payload.memoComment;
|
||||
const memo = await memoStore.getOrFetchMemoByName(memoCommentPayload.relatedMemo, {
|
||||
skipStore: true,
|
||||
});
|
||||
setRelatedMemo(memo);
|
||||
const sender = await userStore.getOrFetchUserByName(inbox.sender);
|
||||
setSender(sender);
|
||||
setInitialized(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch activity:", error);
|
||||
setHasError(true);
|
||||
return;
|
||||
}
|
||||
}, [inbox.activityId]);
|
||||
|
||||
|
|
@ -69,6 +77,51 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleDeleteMessage = async () => {
|
||||
await userStore.deleteInbox(inbox.name);
|
||||
toast.success(t("message.deleted-successfully"));
|
||||
};
|
||||
|
||||
const deleteButton = () => (
|
||||
<>
|
||||
<div>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<TrashIcon
|
||||
className="w-4 h-auto cursor-pointer text-muted-foreground hover:text-primary"
|
||||
onClick={() => handleDeleteMessage()}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common.delete")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
const archiveButton = () => (
|
||||
<>
|
||||
<div>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InboxIcon
|
||||
className="w-4 h-auto cursor-pointer text-muted-foreground hover:text-primary"
|
||||
onClick={() => handleArchiveMessage()}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common.archive")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-row justify-start items-start gap-3">
|
||||
<div
|
||||
|
|
@ -100,23 +153,7 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
<>
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<span className="text-sm text-muted-foreground">{inbox.createTime?.toLocaleString()}</span>
|
||||
<div>
|
||||
{inbox.status === Inbox_Status.UNREAD && (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InboxIcon
|
||||
className="w-4 h-auto cursor-pointer text-muted-foreground hover:text-primary"
|
||||
onClick={() => handleArchiveMessage()}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common.archive")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
)}
|
||||
</div>
|
||||
{inbox.status === Inbox_Status.UNREAD ? archiveButton() : deleteButton()}
|
||||
</div>
|
||||
<p
|
||||
className="text-base leading-tight cursor-pointer text-muted-foreground hover:underline hover:text-primary"
|
||||
|
|
@ -129,6 +166,11 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
})}
|
||||
</p>
|
||||
</>
|
||||
) : hasError ? (
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<span className="text-sm text-muted-foreground">{t("inbox.failed-to-load")}</span>
|
||||
{deleteButton()}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full flex flex-row justify-center items-center my-2">
|
||||
<LoaderIcon className="animate-spin text-muted-foreground" />
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@
|
|||
},
|
||||
"inbox": {
|
||||
"memo-comment": "{{user}} hat einen Kommentar zu {{memo}} hinterlassen.",
|
||||
"version-update": "Die neue Version {{version}} ist jetzt verfügbar!"
|
||||
"version-update": "Die neue Version {{version}} ist jetzt verfügbar!",
|
||||
"failed-to-load": "Fehler beim Laden des Eintrags"
|
||||
},
|
||||
"markdown": {
|
||||
"checkbox": "Checkbox",
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@
|
|||
},
|
||||
"inbox": {
|
||||
"memo-comment": "{{user}} has a comment on your {{memo}}.",
|
||||
"version-update": "New version {{version}} is available now!"
|
||||
"version-update": "New version {{version}} is available now!",
|
||||
"failed-to-load": "Failed to load inbox item"
|
||||
},
|
||||
"markdown": {
|
||||
"checkbox": "Checkbox",
|
||||
|
|
|
|||
|
|
@ -189,6 +189,13 @@ const userStore = (() => {
|
|||
return updatedInbox;
|
||||
};
|
||||
|
||||
const deleteInbox = async (name: string) => {
|
||||
await inboxServiceClient.deleteInbox({ name });
|
||||
state.setPartial({
|
||||
inboxes: state.inboxes.filter((i) => i.name !== name),
|
||||
});
|
||||
};
|
||||
|
||||
const fetchUserStats = async (user?: string) => {
|
||||
const userStatsByName: Record<string, UserStats> = {};
|
||||
if (!user) {
|
||||
|
|
@ -224,6 +231,7 @@ const userStore = (() => {
|
|||
fetchShortcuts,
|
||||
fetchInboxes,
|
||||
updateInbox,
|
||||
deleteInbox,
|
||||
fetchUserStats,
|
||||
setStatsStateId,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue