Message edit save button#75
Conversation
Co-authored-by: me <me@kentcdodds.com>
|
Cursor Agent can help with this pull request. Just |
Co-authored-by: me <me@kentcdodds.com>
Co-authored-by: me <me@kentcdodds.com>
| const [confirmDelete, setConfirmDelete] = useState(false) | ||
| const [canDelete, setCanDelete] = useState(false) | ||
| const [savedContent, setSavedContent] = useState(message.content) | ||
| const [hasEdits, setHasEdits] = useState(false) |
There was a problem hiding this comment.
@cursor, I think this can be derived and we don't need state for it.
There was a problem hiding this comment.
Review response: Agreed — hasEdits is now derived from currentContent !== savedContent, so no extra state is needed for save visibility.【F:app/routes/_app+/recipients+/$recipientId.index.tsx†L384-L461】
Walkthrough
Save checkmark appears only after edits and hides after save.
Summary
- Derive save-check visibility from current vs saved content instead of separate state in
app/routes/_app+/recipients+/$recipientId.index.tsx.【F:app/routes/_app+/recipients+/$recipientId.index.tsx†L384-L461】
Testing
- ✅
npm run format— full-gate formatting check.【F:/tmp/format.log†L1-L4】 - ✅
npm run typecheck— full-gate type safety check.【F:/tmp/typecheck.log†L1-L3】 ⚠️ npm run lint— full-gate linting; existing warnings in scripts directory.【F:/tmp/lint.log†L1-L14】- ✅
npm run test -- --run --project node --pool=threads --maxWorkers=1 --no-file-parallelism— full-gate node tests, serialized to avoid SQLite locking.【F:/tmp/test-node.log†L1-L30】 - ✅
npm run test -- --run --project browser --pool=threads --maxWorkers=1 --no-file-parallelism— full-gate browser tests.【F:/tmp/test-browser.log†L1-L15】 - ❌
DATABASE_URL="file:/workspace/tests/prisma/base.db" CACHE_DATABASE_PATH="/workspace/tests/prisma/cache.db" PORT=3001 npm run test:e2e:run— 7 e2e failures in onboarding/send/settings profile flows.【F:/home/ubuntu/.cursor/projects/workspace/terminals/779679.txt†L2674-L2717】 - ✅ Manual UI test (no command) — required for UI change; verified save checkmark behavior (see walkthrough).
Co-authored-by: me <me@kentcdodds.com>
| const deleteSafeDelayMs = 150 | ||
| const [confirmDelete, setConfirmDelete] = useState(false) | ||
| const [canDelete, setCanDelete] = useState(false) | ||
| const [savedContent, setSavedContent] = useState(message.content) |
There was a problem hiding this comment.
@cursor, message.content will always be the saved content (react router revalidates on changes), so we don't need state for this.
| useEffect(() => { | ||
| setSavedContent(message.content) | ||
| setCurrentContent(message.content) | ||
| }, [message.content]) |
There was a problem hiding this comment.
@cursor, ditch this useEffect in favor of just setting the current content in the event handler
There was a problem hiding this comment.
Walkthrough
Save checkmark appears only after edits, hides after save.
Summary
- Review response: removed the sync
useEffectand rely on the input handler to updatecurrentContentagainstmessage.contentfor save visibility inapp/routes/_app+/recipients+/$recipientId.index.tsx.【F:app/routes/_app+/recipients+/$recipientId.index.tsx†L380-L458】
Testing
- ✅
npm run format— full-gate formatting check.【F:/tmp/format-3.log†L1-L4】 - ✅
npm run typecheck— full-gate type safety check.【F:/tmp/typecheck-3.log†L1-L3】 ⚠️ npm run lint— full-gate linting; existing warnings in scripts directory.【F:/tmp/lint-3.log†L1-L14】- ✅
npm run test -- --run --project node --pool=threads --maxWorkers=1 --no-file-parallelism— full-gate node tests, serialized to avoid SQLite locking.【F:/tmp/test-node-3.log†L1-L77】 - ✅
npm run test -- --run --project browser --pool=threads --maxWorkers=1 --no-file-parallelism— full-gate browser tests.【F:/tmp/test-browser-3.log†L1-L15】 - ❌
DATABASE_URL="file:/workspace/tests/prisma/base.db" CACHE_DATABASE_PATH="/workspace/tests/prisma/cache.db" PORT=3001 npm run test:e2e:run— 7 e2e failures in onboarding/send/settings profile flows.【F:/home/ubuntu/.cursor/projects/workspace/terminals/19483.txt†L2671-L2714】 - ✅ Manual UI test (no command) — required for UI change; verified checkmark appears after edits and hides after save (see walkthrough).
Co-authored-by: me <me@kentcdodds.com>
Co-authored-by: me <me@kentcdodds.com>
| const handleContentInput: React.FormEventHandler<HTMLTextAreaElement> = ( | ||
| event, | ||
| ) => { | ||
| setCurrentContent(event.currentTarget.value) |
There was a problem hiding this comment.
Summary
- Inlined the message edit
onInputhandler inapp/routes/_app+/recipients+/$recipientId.index.tsxas requested.【F:app/routes/_app+/recipients+/$recipientId.index.tsx†L540-L551】
Testing
- Manual UI testing not rerun because this is a handler refactor with no behavior change.
- ✅
npm run format— full-gate formatting check.【F:/tmp/format-4.log†L1-L4】 - ✅
npm run typecheck— full-gate type safety check.【F:/tmp/typecheck-4.log†L1-L3】 - ✅
npm run lint— full-gate linting; existing warnings in scripts directory.【F:/tmp/lint-4.log†L1-L14】 - ✅
npm run test -- --run --project node --pool=threads --maxWorkers=1 --no-file-parallelism— full-gate node tests, serialized to avoid SQLite locking.【F:/tmp/test-node-4.log†L1-L77】 - ✅
npm run test -- --run --project browser --pool=threads --maxWorkers=1 --no-file-parallelism— full-gate browser tests.【F:/tmp/test-browser-4.log†L1-L15】 ⚠️ E2E not rerun for this refactor; last run failed in onboarding/send/settings flows.【F:/home/ubuntu/.cursor/projects/workspace/terminals/19483.txt†L2671-L2714】
Co-authored-by: me <me@kentcdodds.com>
| const sendIsPending = sendNowFetcher.state !== 'idle' | ||
| const deleteIsPending = deleteFetcher.state !== 'idle' | ||
| const textareaProps = getTextareaProps(updateContentFields.content) | ||
| const hasEdits = currentContent !== message.content |
There was a problem hiding this comment.
State not reset when save succeeds with modified content
Low Severity
The currentContent state is initialized once via useState(message.content) and only updates through onInput. After a successful save, if message.content from the server differs from what the user typed (e.g., server-side trimming or normalization), hasEdits remains true and the save button incorrectly stays visible. Additionally, if external updates change message.content while the form is open, the save button may appear even though the user hasn't made any edits, potentially leading to unintentional data overwrites.






Test Plan
Checklist
Screenshots
Note
Low Risk
UI-only change limited to client-side state/conditional rendering; no changes to server actions or data validation.
Overview
Updates the recipient message edit UI to make saving explicit and less noisy by only showing the save
StatusButtonwhen the textarea content has changed (or while a save is in progress).Adds local
currentContentstate wired to the textareaonInputto detect edits and drive the conditional render of the save control.Written by Cursor Bugbot for commit 8078cfe. This will update automatically on new commits. Configure here.