From 41405bc3faa0a9ba55e398399e2ce188771cb844 Mon Sep 17 00:00:00 2001 From: Ahmed-Elgendy25 Date: Tue, 24 Mar 2026 00:44:55 +0200 Subject: [PATCH] feat: enhance MemoCompleteList with task clearing functionality and integrate task extraction utility --- .../MemoView/components/MemoCompleteList.tsx | 128 ++++++++++++++++-- .../MemoView/components/MemoFooter.tsx | 6 + 2 files changed, 122 insertions(+), 12 deletions(-) diff --git a/web/src/components/MemoView/components/MemoCompleteList.tsx b/web/src/components/MemoView/components/MemoCompleteList.tsx index 07509df47..d089ebd18 100644 --- a/web/src/components/MemoView/components/MemoCompleteList.tsx +++ b/web/src/components/MemoView/components/MemoCompleteList.tsx @@ -1,19 +1,123 @@ import { Button } from "@/components/ui/button"; -import { Switch } from "@/components/ui/switch"; +import { useMemoViewContext } from "../MemoViewContext"; +import { useCreateMemo, useDeleteMemo, useUpdateMemo } from "@/hooks/useMemoQueries"; +import { extractTasks } from "@/utils/markdown-manipulation"; +import { toast } from "react-hot-toast"; function MemoCompleteList() { + const { memo } = useMemoViewContext(); + const { mutate: updateMemo } = useUpdateMemo(); + const { mutate: deleteMemo } = useDeleteMemo(); + const { mutate: createMemo } = useCreateMemo(); + + // Parse tasks once per render for both counting and clearing + const tasks = extractTasks(memo.content); + const completedTasks = tasks.filter((task) => task.checked); + const completedCount = completedTasks.length; + const hasCompletedTasks = completedCount > 0; + + const handleClearCompleted = () => { + if (!hasCompletedTasks) { + return; + } + + const previousContent = memo.content; + + // Remove completed task lines based on the precomputed task list + const lines = previousContent.split("\n"); + const completedLines = completedTasks + .map((task) => task.lineNumber) + .sort((a, b) => b - a); + + for (const lineNumber of completedLines) { + if (lineNumber >= 0 && lineNumber < lines.length) { + lines.splice(lineNumber, 1); + } + } + + const newContent = lines.join("\n"); + if (newContent === previousContent) { + return; + } + + const isNowEmpty = newContent.trim().length === 0; + + if (isNowEmpty) { + // Delete memo when clearing completed tasks leaves it empty + deleteMemo(memo.name); + + toast.custom( + (t) => ( +
+ {completedCount} completed items cleared and memo deleted. Undo? + +
+ ), + { position: "bottom-center" }, + ); + } else { + // Just update content when there is still other content + updateMemo({ + update: { + name: memo.name, + content: newContent, + }, + updateMask: ["content"], + }); + + toast.custom( + (t) => ( +
+ {completedCount} completed items cleared. Undo? + +
+ ), + { position: "bottom-center" }, + ); + } + }; + return ( -
-
- Completed Task - -
- +
+
- ) + ); } -export default MemoCompleteList \ No newline at end of file +export default MemoCompleteList; \ No newline at end of file diff --git a/web/src/components/MemoView/components/MemoFooter.tsx b/web/src/components/MemoView/components/MemoFooter.tsx index b42b3e079..d3728ebb8 100644 --- a/web/src/components/MemoView/components/MemoFooter.tsx +++ b/web/src/components/MemoView/components/MemoFooter.tsx @@ -1,6 +1,12 @@ +import { useMemoViewContext } from "../MemoViewContext"; import MemoCompleteList from "./MemoCompleteList"; function MemoFooter() { + const { memo } = useMemoViewContext(); + const hasTaskList = memo.property?.hasTaskList; + if (!hasTaskList) { + return null; + } return (