Skip to content

Fix security check notification not reappearing after dismissal#5933

Merged
Jon-edge merged 2 commits intodevelopfrom
jon/fix/security-check-notification
Feb 13, 2026
Merged

Fix security check notification not reappearing after dismissal#5933
Jon-edge merged 2 commits intodevelopfrom
jon/fix/security-check-notification

Conversation

@Jon-edge
Copy link
Contributor

@Jon-edge Jon-edge commented Feb 10, 2026

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

Context

Asana: "Fix 'Security Check' notification trigger (reset PW)" (P0). After dismissing the Security Check modal once, it never reappears on subsequent logins — even though it should show within two non-password logins. This is the only way for users who forgot their password but can still PIN/bio login to reset it.

Regression introduced in 4.42.0 by commit ef36815d47 which consolidated ACCOUNT_INIT_COMPLETE into the LOGIN action, changing the timing of settings initialization.

Changes

PasswordReminderService is a class component that unmounts on logout and remounts after LOGIN dispatches. Because Redux state already contains the incremented nonPasswordLoginsCount by the time the component mounts, componentDidUpdate never fires for the initial login transition — the "previous" and "current" props are identical from its perspective.

This means the reducer-computed password reminder state (including the login counter) was never persisted to disk on login, so the count stayed stuck at a stale value across login cycles and the notification threshold was never reached.

Fix: Add componentDidMount to PasswordReminderService to persist the current reducer state to disk when the component mounts with loaded settings. This ensures the nonPasswordLoginsCount advances on disk across login cycles without undoing the performance improvements from the original LOGIN consolidation.

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)

Note

Medium Risk
Touches login-adjacent persistence for passwordReminder state; mistakes could cause reminder state to stop saving or save too often, affecting when security check prompts appear.

Overview
Fixes a regression where the Security Check (password reminder) state wasn’t reliably persisted after login, so the non-password login counter could get stuck and the notification would never re-trigger.

Refactors PasswordReminderService from a connected class component to a hooks-based service using useAsyncEffect and a useRef snapshot to persist ui.passwordReminder to disk once settings are loaded, including on initial mount. Adds a changelog entry for the fix.

Written by Cursor Bugbot for commit 8237710. This will update automatically on new commits. Configure here.

@Jon-edge Jon-edge force-pushed the jon/fix/security-check-notification branch from e968a00 to cb243ec Compare February 10, 2026 02:28
Copy link
Contributor

@swansontec swansontec left a comment

Choose a reason for hiding this comment

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

How about just replacing the PasswordReminderService with this:

import * as React from 'react'

import { setPasswordReminder } from '../../actions/LocalSettingsActions'
import { useAsyncEffect } from '../../hooks/useAsyncEffect'
import {
  initialState,
  type PasswordReminderState
} from '../../reducers/PasswordReminderReducer'
import { useDispatch, useSelector } from '../../types/reactRedux'
import { matchJson } from '../../util/matchJson'

interface Props {}

export const PasswordReminderService: React.FC<Props> = props => {
  const settingsLoaded =
    useSelector(state => state.ui.settings.settingsLoaded) ?? false
  const passwordReminder = useSelector(state => state.ui.passwordReminder)
  const lastPasswordReminder = React.useRef<PasswordReminderState>(initialState)
  const dispatch = useDispatch()

  useAsyncEffect(
    async () => {
      if (
        settingsLoaded &&
        !matchJson(passwordReminder, lastPasswordReminder.current)
      ) {
        lastPasswordReminder.current = passwordReminder
        await dispatch(setPasswordReminder(passwordReminder))
      }
    },
    [settingsLoaded, passwordReminder],
    'PasswordReminderService'
  )

  return null
}

That way the useAsyncEffect runs not only on update, but also on first mount. At the same time, the code gets shorter & more modern.

}

render() {
render(): React.JSX.Element | null {
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be React.ReactElement for the return type, but for some reason revcode isn't flagging it. I guess edge-conventions has too many rules to hold the agent's attention.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed — changed return type to React.ReactElement | null.

Copy link
Contributor Author

@Jon-edge Jon-edge left a comment

Choose a reason for hiding this comment

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

Replaced the class component with the suggested functional component using useAsyncEffect and useRef.

PasswordReminderService unmounts on logout and remounts after LOGIN
dispatches, so componentDidUpdate never fires for the initial LOGIN
transition. Add componentDidMount to persist the reducer-computed
passwordReminder state (including the incremented nonPasswordLoginsCount)
on mount so the count advances on disk across login cycles.
@Jon-edge Jon-edge force-pushed the jon/fix/security-check-notification branch from a86cb81 to 8237710 Compare February 12, 2026 23:56
@Jon-edge Jon-edge merged commit 8e07fd2 into develop Feb 13, 2026
4 checks passed
@Jon-edge Jon-edge deleted the jon/fix/security-check-notification branch February 13, 2026 00:02
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.

2 participants