From 2c7eb2334351a9223420959d123bfe17d7cf85d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Krau=C3=9F?= Date: Wed, 23 Jul 2025 16:21:26 +0200 Subject: [PATCH] feat(inbox): handles errors while fetching and adds possibility to delete items (#4908) --- server/router/api/v1/activity_service.go | 3 + .../components/Inbox/MemoCommentMessage.tsx | 100 +++++++++++++----- web/src/locales/de.json | 3 +- web/src/locales/en.json | 3 +- web/src/store/user.ts | 8 ++ 5 files changed, 86 insertions(+), 31 deletions(-) diff --git a/server/router/api/v1/activity_service.go b/server/router/api/v1/activity_service.go index 1731cf272..ae016905f 100644 --- a/server/router/api/v1/activity_service.go +++ b/server/router/api/v1/activity_service.go @@ -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, diff --git a/web/src/components/Inbox/MemoCommentMessage.tsx b/web/src/components/Inbox/MemoCommentMessage.tsx index 05662269f..f73ff944f 100644 --- a/web/src/components/Inbox/MemoCommentMessage.tsx +++ b/web/src/components/Inbox/MemoCommentMessage.tsx @@ -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(undefined); const [sender, setSender] = useState(undefined); const [initialized, setInitialized] = useState(false); + const [hasError, setHasError] = useState(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 = () => ( + <> +
+ + + + handleDeleteMessage()} + /> + + +

{t("common.delete")}

+
+
+
+
+ + ); + + const archiveButton = () => ( + <> +
+ + + + handleArchiveMessage()} + /> + + +

{t("common.archive")}

+
+
+
+
+ + ); + return (
{ <>
{inbox.createTime?.toLocaleString()} -
- {inbox.status === Inbox_Status.UNREAD && ( - - - - handleArchiveMessage()} - /> - - -

{t("common.archive")}

-
-
-
- )} -
+ {inbox.status === Inbox_Status.UNREAD ? archiveButton() : deleteButton()}

{ })}

+ ) : hasError ? ( +
+ {t("inbox.failed-to-load")} + {deleteButton()} +
) : (
diff --git a/web/src/locales/de.json b/web/src/locales/de.json index b36079feb..4b9d15dff 100644 --- a/web/src/locales/de.json +++ b/web/src/locales/de.json @@ -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", diff --git a/web/src/locales/en.json b/web/src/locales/en.json index e904e46e6..7dfde32f9 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -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", diff --git a/web/src/store/user.ts b/web/src/store/user.ts index 3e2b70809..4892ea164 100644 --- a/web/src/store/user.ts +++ b/web/src/store/user.ts @@ -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 = {}; if (!user) { @@ -224,6 +231,7 @@ const userStore = (() => { fetchShortcuts, fetchInboxes, updateInbox, + deleteInbox, fetchUserStats, setStatsStateId, };