From 703b8831653fd06e893431c3ebaa4cb3e0eb3b3d Mon Sep 17 00:00:00 2001 From: agent_coder Date: Thu, 2 Jul 2026 01:20:01 +0300 Subject: [PATCH] feat(temp-notes): add 'Move to trash' button to the temporary-note banner (closes #273) The banner only offered 'Make permanent'. Add a secondary destructive 'Move to trash' button that soft-deletes the note now instead of waiting for TTL expiry, reusing the tree/header soft-delete path (useTreeMutation.handleDelete): optimistic tree removal, the undo-toast, the deletedAt cache stamp, and the redirect to space home. No confirm modal (project convention = undo-toast). Gated on the existing Edit permission. Client-only, no server/i18n changes (both labels already exist). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../page/components/temporary-note-banner.tsx | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/apps/client/src/features/page/components/temporary-note-banner.tsx b/apps/client/src/features/page/components/temporary-note-banner.tsx index 0c004abf..f5bef76a 100644 --- a/apps/client/src/features/page/components/temporary-note-banner.tsx +++ b/apps/client/src/features/page/components/temporary-note-banner.tsx @@ -1,8 +1,10 @@ import { Button, Group, Paper, Text } from "@mantine/core"; -import { IconClockHour4 } from "@tabler/icons-react"; +import { IconClockHour4, IconTrash } from "@tabler/icons-react"; +import { useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { useTimeAgo } from "@/hooks/use-time-ago.tsx"; import { usePageQuery } from "@/features/page/queries/page-query.ts"; +import { useTreeMutation } from "@/features/page/tree/hooks/use-tree-mutation.ts"; import { useToggleTemporaryMutation, syncTemporaryExpiresInCache, @@ -31,6 +33,11 @@ export function TemporaryNoteBanner({ slugId }: TemporaryNoteBannerProps) { const spaceAbility = useSpaceAbility(space?.membership?.permissions); const expiresTimeAgo = useTimeAgo(page?.temporaryExpiresAt); const toggleTemporary = useToggleTemporaryMutation(); + // Reuse the exact soft-delete path the tree/header menus use: optimistic + // tree removal, the "Page moved to trash" undo-toast, the deletedAt cache + // stamp, and the redirect to space home (which unmounts this banner). + const { handleDelete: trashPage } = useTreeMutation(page?.spaceId ?? ""); + const [isDeleting, setIsDeleting] = useState(false); // Don't show on a note that is already in trash; the deleted-page banner // owns that state. @@ -38,6 +45,16 @@ export function TemporaryNoteBanner({ slugId }: TemporaryNoteBannerProps) { const canEdit = spaceAbility.can(SpaceCaslAction.Edit, SpaceCaslSubject.Page); + const handleTrashNow = async () => { + // No confirm modal by convention — the undo-toast is the safety net. + setIsDeleting(true); + try { + await trashPage(page.id); + } finally { + setIsDeleting(false); + } + }; + const handleMakePermanent = async () => { try { const res = await toggleTemporary.mutateAsync({ @@ -70,16 +87,28 @@ export function TemporaryNoteBanner({ slugId }: TemporaryNoteBannerProps) { {canEdit && ( - + + + + )}