Skip to content

PO-8902-Route-guard-does-not-trigger - #2852

Merged
TimGonella merged 29 commits into
masterfrom
PO-8902-Route-guard-does-not-trigger
Jul 23, 2026
Merged

PO-8902-Route-guard-does-not-trigger#2852
TimGonella merged 29 commits into
masterfrom
PO-8902-Route-guard-does-not-trigger

Conversation

@marcmollins

Copy link
Copy Markdown
Contributor

Jira link

https://tools.hmcts.net/jira/browse/PO-8902

Change description

make sure route guard shows when cancelling and changes have been made to the form in question

Testing done

Unit tested, tested locally.

Security Vulnerability Assessment

CVE Suppression: Are there any CVEs present in the codebase (either newly introduced or pre-existing) that are being intentionally suppressed or ignored by this commit?

  • Yes
  • No

Checklist

  • commit messages are meaningful and follow good commit message guidelines
  • README and other documentation has been updated / added (if needed)
  • tests have been updated / new tests has been added (if needed)
  • Does this PR introduce a breaking change

make sure route guard shows when cancelling and changes have been made to the form

@iamfrankiemoran iamfrankiemoran 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.

The change needs to be made where the unsaved state is lost, rather than in the route guard.

  1. Revert the guard change
    In fines-mac-offence-details.component.ts, restore canDeactivate() so it only uses the existing shared unsavedChanges state:
canDeactivate(): CanDeactivateTypes {
  return !this.finesMacStore.unsavedChanges();
}

Please remove this check:

const hasDraftOffenceChanges = this.finesMacOffenceDetailsStore.offenceDetailsDraft().length > 0;

offenceDetailsDraft is temporary navigation state, not a dirty-state indicator. It remains populated after the offence is copied into the main MAC store, so using it here can show a warning after a successful save.

  1. Restore the unsaved state after saving the minor creditor
    In fines-mac-offence-details-minor-creditor.component.ts, update handleMinorCreditorFormSubmit() immediately after the creditor is written to the draft:
this.finesMacOffenceDetailsStore.setOffenceDetailsDraft(offenceDetailsDraft);
this.finesMacOffenceDetailsStore.setMinorCreditorAdded(true);
this.finesMacStore.setUnsavedChanges(true);

this.routerNavigate(FINES_MAC_OFFENCE_DETAILS_ROUTING_PATHS.children.addOffence);

The important new line is:

this.finesMacStore.setUnsavedChanges(true);

Please set the store directly here. Do not call:

this.handleUnsavedChanges(true);

That would also set stateUnsavedChanges on the minor-creditor component itself. Because that child route has its own canDeactivate guard, it could cause the warning to appear while navigating away after pressing Save.

The expected state lifecycle should be:
Minor-creditor form submitted
    → creditor stored in offence draft
    → finesMacStore.unsavedChanges = true

User clicks Cancel on Add an offence
    → outer route guard sees true
    → warning displayed

User saves/reviews the complete offence
    → the offence form’s normal submission emits false
    → finesMacStore.unsavedChanges = false
    → leaving Offence details does not warn
  1. Move the regression test
    Remove the new test from fines-mac-offence-details.component.spec.ts:
it('should block deactivation when offence draft data exists', ...)

Also remove its now-unused FINES_MAC_OFFENCE_DETAILS_DRAFT_STATE_MOCK import.
Instead, update fines-mac-offence-details-minor-creditor.component.spec.ts. In the existing submission test, after:

component.handleMinorCreditorFormSubmit(formSubmit);

add:

expect(finesMacStore.unsavedChanges()).toBe(true);

We should also have journey coverage for both outcomes:

Save minor-creditor details → return to Add an offence → Cancel → warning appears.
Save minor-creditor details → save/review the complete offence → leave Offence details → no warning appears.

This fixes the point where the state becomes incorrect and keeps the route guard concerned only with actual unsaved state.

@iamfrankiemoran iamfrankiemoran 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.

Minor comment

@iamfrankiemoran
iamfrankiemoran requested a review from a team July 15, 2026 16:07
removing file from diff

@iamfrankiemoran iamfrankiemoran 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.

LGTM ✅
@marcmollins just run:
yarn install
then yarn audit:save

@louisbriggs louisbriggs 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.

LGTM

@louisbriggs louisbriggs 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.

Minor change

@louisbriggs louisbriggs 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.

P2 – Rehydrated dirty drafts do not sync the route guard state

fines-mac-offence-details-add-an-offence-form.component.ts (line 233) marks the form as dirty when offenceDetailsDraftDirty() is true, but it does not also update finesMacStore.unsavedChanges(true).

The top-level route guard reads this value from the store (fines-mac-offence-details.component.ts, line 22), so a restored dirty form can still leave the guard state as false if navigation doesn't go through the form's cancel handler.

Suggested fix:

Synchronise the global unsavedChanges state when hasSavedDraftChanges is applied.
Add a unit test to verify the store value is updated correctly.

P2 – Removal flows update the draft without marking it dirty

fines-mac-offence-details-remove-minor-creditor.component.ts (line 70) and fines-mac-offence-details-remove-imposition.component.ts (line 215) both update offenceDetailsDraft before navigating back, but neither sets offenceDetailsDraftDirty nor updates finesMacStore.unsavedChanges.

If the offence form was pristine before entering the removal confirmation flow, the removal creates an unsaved draft change that the route guard will not detect.

Suggested fix:

Set both offenceDetailsDraftDirty and finesMacStore.unsavedChanges(true) after a successful removal.
Add unit tests covering both the minor creditor and imposition removal flows to verify the route guard state is updated correctly.

@louisbriggs louisbriggs 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.

LGTM

@TimGonella
TimGonella self-requested a review July 23, 2026 13:39
@TimGonella
TimGonella enabled auto-merge (squash) July 23, 2026 14:15
@TimGonella

Copy link
Copy Markdown
Contributor

QA Review - LGTM

@TimGonella
TimGonella merged commit de0c7ce into master Jul 23, 2026
5 checks passed
@TimGonella
TimGonella deleted the PO-8902-Route-guard-does-not-trigger branch July 23, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants