Skip to content

feat(comments): edit & delete your own comments#44

Open
akorman128 wants to merge 2 commits into
mainfrom
worktree-edit-delete-comments
Open

feat(comments): edit & delete your own comments#44
akorman128 wants to merge 2 commits into
mainfrom
worktree-edit-delete-comments

Conversation

@akorman128

Copy link
Copy Markdown
Owner

What

Adds the ability for a user to edit and delete their own comments, and brings the comments screen onto a single source of truth in the process.

Feature

  • Each comment owned by the current user gets a three-dot menu (mirrors PostCard) → Edit / Delete.
  • Edit is inline: the body becomes an editable Input with Cancel/Save (validates non-empty, ≤500). Editing only changes the body; the attached list is untouched. The existing (edited) label surfaces after.
  • Delete confirms first and warns when replies will cascade-delete with it.
  • The menu only shows on the author's own, already-saved comments.

The data layer already existed on main (useUpdateComment / useDeleteComment scoped to author_id, RLS UPDATE/DELETE policies, the edited_at column + label), so this is UI wiring + test coverage — no migrations.

Architecture (from xhigh self-review)

The screen previously mirrored server state into a local comments tree synced via useEffect, hand-maintained with several recursive walkers. This PR drops that mirror: it renders directly from the useGetComments react-query cache and applies optimistic create/like/edit/delete to that single source of truth via queryClient.setQueryData, with getQueryData snapshot rollback on error. Optimistic just-posted comments now carry the real author + a temp- id, and the menu is gated on !id.startsWith("temp-") so an unsaved comment can't be edited/deleted mid-flight.

Files

  • app/(protected)/comments.tsx — render from cache; pure tree helpers; optimistic create/like/edit/delete with rollback.
  • design-system/CommentItem.tsx — author-gated menu, inline editor, delete confirmation (stays presentational; not in the design-sync map).
  • __tests__/hooks/useComments.test.tsx (new) — first coverage for the update/delete mutations: author_id scoping, edited_at stamping, list_id handling, error paths.

Verification

  • tsc --noEmit clean
  • eslint clean on changed files
  • npm run test:hooks79/79 pass (incl. 6 new)
  • Not yet done: a live simulator run; the screen-internal tree helpers are covered by typecheck + reasoning rather than unit tests.

Follow-ups (deferred, not in this PR)

Count triple-source-of-truth reconciliation, renderComment/React.memo perf, and extracting the comment-tree walkers + owner-menu into shared utils.

🤖 Generated with Claude Code

akorman128 and others added 2 commits June 25, 2026 12:46
Add an author-only action menu to each comment: a three-dot menu (mirroring
PostCard) opens an Edit/Delete sheet. Edit swaps the body for an inline editor
(reusing the design-system Input) with Save/Cancel; Delete confirms first and
warns when replies will cascade.

The screen wires the existing useUpdateComment/useDeleteComment mutations with
optimistic local-state patches that revert on failure, and decrements the
post's comment count by the full deleted subtree (cascade-aware).

Also adds the first tests for these mutations (they shipped untested): author_id
scoping on update and delete, edited_at stamping, and list_id handling.

No data-layer changes — the mutations, RLS UPDATE/DELETE policies, edited_at
column, and "(edited)" label already existed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address code-review findings 1, 2, 4, and 10.

#4 (root cause): drop the parallel local `comments` state mirror and its sync
useEffect. The screen now renders directly from the useGetComments react-query
cache, and create/like/edit/delete apply optimistic updates to that single
source of truth via queryClient.setQueryData(comments.byPost). Tree mutations
are extracted to pure module-level helpers.

#2: optimistic updates now use functional setQueryData((old) => ...) reading the
live cache, with a getQueryData snapshot restored on error — no more clobbering
concurrent changes via a stale render-closure snapshot.

#1: the optimistic just-posted comment carries the real profile id/name/avatar
and a temp- id; CommentItem gates the menu on `!id.startsWith("temp-")` so an
unsaved comment exposes no edit/delete until the create round-trip lands.

#10: hoist trimmedDraft/saveDisabled in CommentItem (computed once, not 3x).

tsc + eslint clean; 79/79 hook tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant