Skip to content

feat(procurement): enable saving and editing notes on procurement tracker steps#5885

Open
Santi-3rd wants to merge 8 commits into
mainfrom
OPS-5435/edit-existing-pt-notes
Open

feat(procurement): enable saving and editing notes on procurement tracker steps#5885
Santi-3rd wants to merge 8 commits into
mainfrom
OPS-5435/edit-existing-pt-notes

Conversation

@Santi-3rd

@Santi-3rd Santi-3rd commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

What changed

Enables users to save notes on procurement tracker steps independently of completing the step, and to edit notes on steps that are already completed.

Frontend — frontend/src/components/Agreements/ProcurementTracker/ProcurementTrackerStep{One..Six}/

  • The notes TextArea is now enabled independently of the step's completion / pre-solicitation state, with a dedicated Save Notes button (data-cy="save-notes-button") that PATCHes only the notes field and surfaces a success/error alert.
  • Notes state hydrates from stepXData?.notes and stays in sync via a useEffect, so previously saved notes are shown.
  • Completed steps render an inline Edit Notes / Cancel flow, allowing notes to be edited and re-saved without reopening the whole step.
  • Added handleSaveNotes to each step's hook and wired it through the component.

Backend — backend/ops_api/ops/validation/rules/procurement_tracker_step.py

  • NoUpdatingCompletedProcurementStepRule now allows a notes-only update on a completed step (via EDITABLE_AFTER_COMPLETION = {"notes"}) while still blocking any other field change.
  • AcquisitionPlanningRequiredFieldsRule only enforces task_completed_by / date_completed when the step is actually being moved to complete, and treats fields already persisted on the step as satisfied — so notes-only edits and partial updates aren't wrongly rejected.

Tests

  • Updated BDD feature + step definitions to cover "notes-only update on a completed step succeeds" and "cannot complete acquisition planning step without required fields".
  • Updated the API event test to send the now-required completion fields.
  • Extensive unit tests added/updated across all six step components and their hooks.

Issue

#5435

How to test

Backend:

cd backend/ops_api
pipenv run pytest tests/ops/features/test_validate_procurement_tracker_steps.py
pipenv run pytest tests/ops/procurement_tracker/test_procurement_tracker_steps_api.py

Frontend:

cd frontend
bun run test --watch=false src/components/Agreements/ProcurementTracker

Manual:

  1. Open an agreement's Procurement Tracker.
  2. On an incomplete step, type in the Notes field and click Save Notes — confirm a success alert and that the note persists after reload.
  3. Complete a step, then click Edit Notes, change the text, and Save Notes — confirm the note updates and the step stays completed.
  4. Click Edit Notes then Cancel — confirm edits are discarded.
  5. Confirm you still cannot change non-notes fields on a completed step.

A11y impact

  • No accessibility-impacting changes in this PR
  • Accessibility changes included and validated against WCAG 2.1 AA intent
  • Any temporary suppression includes A11Y-SUPPRESSION metadata (owner, expires, rationale)

Storybook

  • No UI component changes in this PR
  • Story added for new component in src/components/UI/
  • Story updated to reflect changed props/states
  • N/A — change is page-specific or non-visual

Screenshots

image

Definition of Done Checklist

  • OESA: Code refactored for clarity
  • OESA: Dependency rules followed
  • Automated unit tests updated and passed
  • Automated integration tests updated and passed
  • Automated quality tests updated and passed
  • Automated load tests updated and passed
  • Automated a11y tests updated and passed
  • Automated security tests updated and passed
  • 90%+ Code coverage achieved
  • Form validations updated

Links

N/A

@Santi-3rd Santi-3rd changed the title feat: proc tracker step one text area is enabled and able to save feat(procurement): enable saving and editing notes on procurement tracker steps Jul 8, 2026
@rajohnson90 rajohnson90 marked this pull request as ready for review July 8, 2026 21:21

@rajohnson90 rajohnson90 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI PR review identified at least one problem that needs to be fixed:

frontend/.../ProcurementTrackerStepOne.hooks.js:24 — useEffect overwrites in-progress draft on RTK Query
refetch (CONFIRMED, same in all 6 hooks)
handleSaveNotes invalidates the "ProcurementTrackers" cache tag, triggering an immediate refetch. When
the new stepOneData.notes prop arrives, the useEffect fires setStep1Notes(stepOneData?.notes ?? "") —
overwriting keystrokes typed since the last save. Race: user clicks Save → types more text → refetch
resolves → effect resets the field to the older saved value. Fix: skip the effect when the field is dirty
(track with a isDirty ref, reset after a successful save).

* @param {string} value - The new notes value.
*/
const setNotes = React.useCallback((value) => {
isDirtyRef.current = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setNotes marks the field dirty unconditionally, so Cancel (and completion) leave it permanently dirty.

setNotes always sets isDirtyRef.current = true, even when the caller is restoring the server value rather than typing a fresh edit. StepNotesEditor’s Cancel handler calls setNotes(savedNotes ?? ""), which brings the field value back in line with the server but leaves the dirty flag true.

Per this hook’s own docstring, the sync-from-server effect is supposed to resume once the field is clean again. After a Cancel it never will (the flag is only cleared on a successful save), so a later external server update — another user editing the note, or a refetch delivering a newer value — won’t flow into the field. The completion handlers (handleStep1Complete, etc.) have the same issue: they send notes but never clear the flag.

Suggestion: expose a resetNotes(value) (or clearDirty) from useSaveNotes that sets the value and clears isDirtyRef, and use it in the Cancel path (and after completion). Edge-case severity, but it contradicts the documented intent and none of the current tests cover it.

@Santi-3rd

Copy link
Copy Markdown
Contributor Author

Duplicated inline "Save Notes" block across all 6 step files — Medium

The active-step editing markup (

+ TextArea with textAreaStyle={{ height: "8.5rem", minWidth: "30rem" }} + maxLength={750} + the faCheck "Save Notes" button) is copy-pasted verbatim into all six
ProcurementTrackerStep*.jsx files, and is nearly identical to the editing branch already inside StepNotesEditor.jsx. This is the exact repetition the branch set out to remove (refactor: removed repeated code). Extract a shared
SaveNotesButton (or let StepNotesEditor cover the active-step form too) so the style constants and button live in one place.

@rajohnson90 rajohnson90 self-requested a review July 10, 2026 16:14
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.

3 participants