Skip to content

Frontend/licensee change email #922

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

jsandoval81
Copy link
Collaborator

@jsandoval81 jsandoval81 commented Jul 10, 2025

Requirements List

  • None

Description List

  • Updated the UserAccount component with the ability for licensees to change their email, including verification
    • Staff users should continue to not be able to update their email, only licensees
  • Updated the network layer with the new licensee endpoints
  • Updated the form mixin to trim string values

Testing List

  • yarn test:unit:all should run without errors or warnings
  • yarn serve should run without errors or warnings
  • yarn build should run without errors or warnings
  • Code review
  • Testing
    • Login as a licensee / provider
    • Navigate to the Account page
    • Change your email address and click Save Changes
      • Licensee users should only be able to change their email, not their first / last name
      • Tip: changing to a ...+ variation of your current address will make this easier, since you won't need a separate inbox account
    • You should receive a code at your new email address
    • Enter the code in the expected popup and submit
    • Should receive a success modal
    • Closing modal should return to the Account form with your updated email
    • You should receive an email at your old email address confirming there was a change
    • Login as staff user
    • Navigate to the Account page
    • Staff users should not be able to update their email (same as before)

Closes #532

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced an email verification process for licensee users when updating their email address, including a modal dialog for entering a verification code.
    • Added keyboard accessibility and focus management to the email verification modal.
    • Enhanced localization with new English and Spanish strings for the email verification flow.
  • Bug Fixes

    • Improved form handling by trimming whitespace from string inputs.
  • Style

    • Added new styles for the email verification modal to improve layout, responsiveness, and visual feedback.
  • Chores

    • Updated mock data and API endpoints to support the new email verification process.

Copy link
Contributor

coderabbitai bot commented Jul 10, 2025

Walkthrough

The changes implement a multi-step email update and verification flow for licensee (practitioner) users. Licensees updating their email now trigger a modal to enter a verification code sent to the new address. The update includes new API methods, UI modal logic, localization strings, and supporting CSS and mocks, with staff and licensee flows separated.

Changes

File(s) Change Summary
webroot/src/components/Forms/_mixins/form.mixin.ts Trimmed whitespace from string values in form field values before submission.
webroot/src/components/UserAccount/UserAccount.ts, UserAccount.vue, UserAccount.less Added email verification modal, separated staff/licensee update flows, modal UI logic, accessibility, and styles.
webroot/src/locales/en.json, webroot/src/locales/es.json Added new localization strings for email verification and related messages.
webroot/src/network/data.api.ts, webroot/src/network/userApi/data.api.ts Added methods for updating and verifying licensee user email via API.
webroot/src/network/mocks/mock.data.api.ts Replaced generic licensee update with explicit email update and verification mocks.
webroot/src/network/mocks/mock.data.ts Updated mock licensee email addresses and added a new field.
webroot/src/network/userApi/interceptors.ts Registered new email update/verify endpoints for licensee authorization.

Sequence Diagram(s)

sequenceDiagram
    participant LicenseeUser
    participant UserAccountComponent
    participant DataApi
    participant UserDataApi
    participant Modal

    LicenseeUser->>UserAccountComponent: Submit new email
    UserAccountComponent->>DataApi: updateAuthenticatedLicenseeUserEmail(newEmail)
    DataApi->>UserDataApi: PATCH /v1/provider-users/me/email
    UserDataApi-->>DataApi: Response
    DataApi-->>UserAccountComponent: Response
    UserAccountComponent->>Modal: Show verification modal
    LicenseeUser->>Modal: Enter verification code
    Modal->>UserAccountComponent: Submit code
    UserAccountComponent->>DataApi: verifyAuthenticatedLicenseeUserEmail(code)
    DataApi->>UserDataApi: POST /v1/provider-users/me/email/verify
    UserDataApi-->>DataApi: Response
    DataApi-->>UserAccountComponent: Response
    UserAccountComponent->>Modal: Show success or error
Loading

Assessment against linked issues

Objective Addressed Explanation
Allow practitioner (licensee) to change login email, including frontend flow (#532)
Implement email verification step for changed email (#532)
Add frontend design/UI for email update and verification (#532)
Separate backend/frontend logic for staff vs. licensee email updates (#532)

Suggested reviewers

  • carlsims
  • jlkravitz
  • isabeleliassen

Poem

In the warren where emails hop anew,
A modal appears with a code just for you.
Practitioners rejoice, your address can now change,
With a trim and a check, in a flow not so strange.
Success is a carrot, verification the key—
The rabbits of code have set your inbox free!
🥕✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92a834e and 1679c8b.

📒 Files selected for processing (2)
  • webroot/src/components/UserAccount/UserAccount.ts (6 hunks)
  • webroot/src/components/UserAccount/UserAccount.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • webroot/src/components/UserAccount/UserAccount.vue
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: jsandoval81
PR: csg-org/CompactConnect#922
File: webroot/src/components/UserAccount/UserAccount.ts:0-0
Timestamp: 2025-07-10T19:50:56.706Z
Learning: In the UserAccount component (webroot/src/components/UserAccount/UserAccount.ts), the email field should be disabled for staff users (`isDisabled: this.isStaff`) to maintain existing restrictions, while licensees should be able to change their email address through the new verification process. This is the intended behavior per PR #922 requirements.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/provider-data-v1/handlers/registration.py:111-117
Timestamp: 2025-06-17T19:05:36.255Z
Learning: In CompactConnect PR #848, the user landonshumway-ia decided to leave timezone handling code in _should_allow_reregistration function as-is after testing in sandbox environment confirmed it works correctly. The user's reasoning was that reregistration is an edge case, the code has been tested and verified, and AWS is unlikely to change behavior that would break many clients. This represents a pragmatic engineering decision based on testing and risk assessment.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/migration/provider_user_pool_migration_551/main.py:35-39
Timestamp: 2025-06-10T03:16:16.896Z
Learning: In the provider user pool migration (provider_user_pool_migration_551), the FilterExpression intentionally only checks for the existence of compactConnectRegisteredEmailAddress. The migration should only remove currentHomeJurisdiction if compactConnectRegisteredEmailAddress is also present, targeting records that went through the old registration process. Records with only currentHomeJurisdiction but no compactConnectRegisteredEmailAddress should be left untouched.
webroot/src/components/UserAccount/UserAccount.ts (15)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#922
File: webroot/src/components/UserAccount/UserAccount.ts:0-0
Timestamp: 2025-07-10T19:50:56.706Z
Learning: In the UserAccount component (webroot/src/components/UserAccount/UserAccount.ts), the email field should be disabled for staff users (`isDisabled: this.isStaff`) to maintain existing restrictions, while licensees should be able to change their email address through the new verification process. This is the intended behavior per PR #922 requirements.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/LicenseCard/LicenseCard.ts:414-443
Timestamp: 2025-06-24T00:02:39.944Z
Learning: In LicenseCard component's clickUnencumberItem method (webroot/src/components/LicenseCard/LicenseCard.ts), complex event handling for checkbox interactions is intentionally designed to ensure consistent behavior across checkbox input, wrapper label, and outer selection parent elements for custom UI requirements. This complexity should be preserved rather than simplified.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.vue:26-30
Timestamp: 2025-05-28T16:13:19.506Z
Learning: In the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.vue), the formInput.labelSubtext property rendered with v-html contains only developer-controlled content, not user-controlled content, so XSS concerns do not apply.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.less:17-26
Timestamp: 2025-05-28T16:10:55.628Z
Learning: The `.add-email-help` element in the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.less) is display-only and not meant to handle interaction states like hover or focus. It should not have cursor: pointer or interactive styling.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/migration/provider_user_pool_migration_551/main.py:35-39
Timestamp: 2025-06-10T03:16:16.896Z
Learning: In the provider user pool migration (provider_user_pool_migration_551), the FilterExpression intentionally only checks for the existence of compactConnectRegisteredEmailAddress. The migration should only remove currentHomeJurisdiction if compactConnectRegisteredEmailAddress is also present, targeting records that went through the old registration process. Records with only currentHomeJurisdiction but no compactConnectRegisteredEmailAddress should be left untouched.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#922
File: webroot/src/components/UserAccount/UserAccount.ts:250-267
Timestamp: 2025-07-10T19:52:40.275Z
Learning: In focus trap implementations for modals, when there's only one focusable element (like in a success state), it's correct for both firstTabIndex and lastTabIndex to reference the same element. This keeps focus appropriately trapped on that single element. Optional chaining operators (?.focus()) provide adequate null safety for DOM element access in focus management code.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/LicenseCard/LicenseCard.ts:509-528
Timestamp: 2025-06-24T00:07:10.463Z
Learning: In the CompactConnect frontend codebase, the project prefers to avoid early returns in frontend code when possible, as mentioned by jsandoval81 in webroot/src/components/LicenseCard/LicenseCard.ts.
Learnt from: rmolinares
PR: csg-org/CompactConnect#843
File: webroot/src/components/Forms/InputDate/InputDate.ts:0-0
Timestamp: 2025-06-04T22:04:14.373Z
Learning: In the InputDate component (webroot/src/components/Forms/InputDate/InputDate.ts), immediate validation on every keystroke is intentional design behavior. The team prefers to alert users to encourage expected date format completion rather than deferring validation until the date is complete. This provides immediate feedback to guide users toward proper MM/dd/yyyy format completion.
Learnt from: rmolinares
PR: csg-org/CompactConnect#905
File: webroot/src/components/UpdateHomeJurisdiction/UpdateHomeJurisdiction.vue:32-41
Timestamp: 2025-07-03T15:35:57.893Z
Learning: In the CompactConnect frontend codebase, the team prefers to keep non-dynamic text directly in Vue templates rather than moving it to computed properties in TypeScript modules, as this approach prevents cluttering the TS files with template labels.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/PrivilegeCard/PrivilegeCard.ts:0-0
Timestamp: 2025-06-19T23:43:25.512Z
Learning: In Vue form components, when programmatically setting form input values, it's more efficient to validate just the specific form element being updated (e.g., `formInput.validate()`) rather than calling `validateAll()` on the entire form.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/styles.common/_inputs.less:115-118
Timestamp: 2025-06-24T00:17:31.188Z
Learning: The team intentionally uses broad CSS selectors like `.dp__input_wrap div { position: static; }` to fix styling issues with the Vue Date-Picker library. They have experience with these styles working well, keep the library version pinned in yarn.lock, and have established processes to re-test everything when updating the library version. This approach is acceptable given their testing discipline and version control.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/provider-data-v1/handlers/registration.py:111-117
Timestamp: 2025-06-17T19:05:36.255Z
Learning: In CompactConnect PR #848, the user landonshumway-ia decided to leave timezone handling code in _should_allow_reregistration function as-is after testing in sandbox environment confirmed it works correctly. The user's reasoning was that reregistration is an edge case, the code has been tested and verified, and AWS is unlikely to change behavior that would break many clients. This represents a pragmatic engineering decision based on testing and risk assessment.
Learnt from: rmolinares
PR: csg-org/CompactConnect#851
File: webroot/src/pages/RegisterLicensee/RegisterLicensee.ts:0-0
Timestamp: 2025-06-09T19:57:51.519Z
Learning: In the RegisterLicensee component, when handling DOM element availability issues, the developer prefers using Vue Watchers over retry mechanisms with requestAnimationFrame to avoid infinite recursion risks and maintain Vue's reactive patterns.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#882
File: backend/compact-connect/lambdas/python/common/cc_common/data_model/compact_configuration_client.py:287-359
Timestamp: 2025-07-08T18:40:24.408Z
Learning: In the CompactConnect codebase, landonshumway-ia prefers to avoid extraneous unit tests when existing test coverage is already sufficient to catch bugs. For the get_privilege_purchase_options method's live-jurisdiction filtering logic, the existing tests in the purchases test suite provide adequate coverage without needing additional edge case tests.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/StateSettingsConfig/StateSettingsConfig.ts:273-321
Timestamp: 2025-05-28T16:28:48.898Z
Learning: The development team has established length & complexity bounds for different types of methods, including submit-handler methods. Methods that fall within these bounds are considered acceptable even if they handle multiple responsibilities. Refactoring is considered when methods grow beyond these established bounds in the future.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CheckWebroot
🔇 Additional comments (10)
webroot/src/components/UserAccount/UserAccount.ts (10)

14-14: LGTM: Imports are appropriate for the new functionality.

The new imports (nextTick, Modal, CheckCircleIcon, MockPopulate) are all necessary for implementing the email verification modal flow.

Also applies to: 22-24


48-54: LGTM: Data properties are well-defined and purposeful.

The new data properties clearly support the email verification flow:

  • initialUserEmail enables change detection
  • Modal state booleans control UI flow appropriately
  • emailVerificationErrorMessage provides specific error handling for verification

94-96: LGTM: Email getter implementation is robust.

The getter safely accesses compactConnectEmail with optional chaining and provides an appropriate empty string fallback.


98-100: LGTM: Submit label handles loading states appropriately.

The computed property correctly shows loading text during form submission and uses proper translation keys.


105-111: Excellent refactoring implementation.

The conditional form initialization cleanly separates concerns between the main account form and email verification modal, making the code more maintainable and easier to understand.


113-152: LGTM: Account form initialization is well-structured.

The method properly sets up form inputs with validation, correctly disables the email field for staff users, and maintains clean separation of concerns.


154-170: LGTM: Email verification form initialization is properly configured.

The method sets up the verification code input with appropriate validation, security considerations (autocomplete off), and UX enhancements (enforceMax).


172-185: LGTM: Handle submit method properly separates user type flows.

The method correctly validates the form, uses nextTick for DOM updates, and cleanly routes to appropriate update methods based on user type.


187-232: LGTM: Update methods are well-structured with proper user type separation.

Both methods handle their respective user types appropriately:

  • Staff method updates attributes directly with store dispatch
  • Licensee method specifically handles email changes with verification flow
  • Both include proper loading states and error handling

234-298: LGTM: Modal management and email verification are well-implemented.

The implementation includes:

  • Proper state management for modal visibility
  • Comprehensive focus management for accessibility
  • Robust error handling in verification flow
  • Appropriate store updates on successful verification
  • Good use of nextTick for DOM timing
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba6647 and cb8b9b6.

📒 Files selected for processing (11)
  • webroot/src/components/Forms/_mixins/form.mixin.ts (1 hunks)
  • webroot/src/components/UserAccount/UserAccount.less (1 hunks)
  • webroot/src/components/UserAccount/UserAccount.ts (5 hunks)
  • webroot/src/components/UserAccount/UserAccount.vue (1 hunks)
  • webroot/src/locales/en.json (1 hunks)
  • webroot/src/locales/es.json (1 hunks)
  • webroot/src/network/data.api.ts (1 hunks)
  • webroot/src/network/mocks/mock.data.api.ts (1 hunks)
  • webroot/src/network/mocks/mock.data.ts (4 hunks)
  • webroot/src/network/userApi/data.api.ts (1 hunks)
  • webroot/src/network/userApi/interceptors.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/provider-data-v1/handlers/registration.py:111-117
Timestamp: 2025-06-17T19:05:36.255Z
Learning: In CompactConnect PR #848, the user landonshumway-ia decided to leave timezone handling code in _should_allow_reregistration function as-is after testing in sandbox environment confirmed it works correctly. The user's reasoning was that reregistration is an edge case, the code has been tested and verified, and AWS is unlikely to change behavior that would break many clients. This represents a pragmatic engineering decision based on testing and risk assessment.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/migration/provider_user_pool_migration_551/main.py:35-39
Timestamp: 2025-06-10T03:16:16.896Z
Learning: In the provider user pool migration (provider_user_pool_migration_551), the FilterExpression intentionally only checks for the existence of compactConnectRegisteredEmailAddress. The migration should only remove currentHomeJurisdiction if compactConnectRegisteredEmailAddress is also present, targeting records that went through the old registration process. Records with only currentHomeJurisdiction but no compactConnectRegisteredEmailAddress should be left untouched.
webroot/src/components/Forms/_mixins/form.mixin.ts (2)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.ts:77-89
Timestamp: 2025-05-28T19:57:53.185Z
Learning: In TypeScript, when dealing with union types that include arrays, direct assignment after filtering can cause compilation errors. The pattern `(formInput.value as Array<string>) = ...` is valid syntax for type assertion on the left-hand side of assignments and can be used as a workaround when TypeScript struggles with type inference on complex nested properties.
Learnt from: rmolinares
PR: csg-org/CompactConnect#843
File: webroot/src/components/Forms/InputDate/InputDate.ts:0-0
Timestamp: 2025-06-04T22:04:14.373Z
Learning: In the InputDate component (webroot/src/components/Forms/InputDate/InputDate.ts), immediate validation on every keystroke is intentional design behavior. The team prefers to alert users to encourage expected date format completion rather than deferring validation until the date is complete. This provides immediate feedback to guide users toward proper MM/dd/yyyy format completion.
webroot/src/network/mocks/mock.data.ts (3)
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#769
File: backend/compact-connect/lambdas/python/common/tests/resources/dynamo/provider.json:5-5
Timestamp: 2025-04-29T01:57:43.684Z
Learning: The provider.json test data contains both "providerDateOfUpdate" and "dateOfUpdate" fields which serve different purposes, and both should be maintained in the test files.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#769
File: backend/compact-connect/lambdas/python/provider-data-v1/tests/function/test_handlers/test_encumbrance.py:138-147
Timestamp: 2025-04-29T02:52:40.532Z
Learning: In CompactConnect tests, hardcoded values (like license type abbreviations 'slp') in test queries are sometimes used intentionally rather than using dynamic lookups. This is a deliberate design decision to make tests fail if default test data changes, requiring developers to consciously update related tests.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/migration/provider_user_pool_migration_551/main.py:35-39
Timestamp: 2025-06-10T03:16:16.896Z
Learning: In the provider user pool migration (provider_user_pool_migration_551), the FilterExpression intentionally only checks for the existence of compactConnectRegisteredEmailAddress. The migration should only remove currentHomeJurisdiction if compactConnectRegisteredEmailAddress is also present, targeting records that went through the old registration process. Records with only currentHomeJurisdiction but no compactConnectRegisteredEmailAddress should be left untouched.
webroot/src/components/UserAccount/UserAccount.vue (4)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.vue:26-30
Timestamp: 2025-05-28T16:13:19.506Z
Learning: In the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.vue), the formInput.labelSubtext property rendered with v-html contains only developer-controlled content, not user-controlled content, so XSS concerns do not apply.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/LicenseCard/LicenseCard.ts:414-443
Timestamp: 2025-06-24T00:02:39.944Z
Learning: In LicenseCard component's clickUnencumberItem method (webroot/src/components/LicenseCard/LicenseCard.ts), complex event handling for checkbox interactions is intentionally designed to ensure consistent behavior across checkbox input, wrapper label, and outer selection parent elements for custom UI requirements. This complexity should be preserved rather than simplified.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.less:17-26
Timestamp: 2025-05-28T16:10:55.628Z
Learning: The `.add-email-help` element in the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.less) is display-only and not meant to handle interaction states like hover or focus. It should not have cursor: pointer or interactive styling.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/PrivilegeCard/PrivilegeCard.ts:0-0
Timestamp: 2025-06-19T23:43:25.512Z
Learning: In Vue form components, when programmatically setting form input values, it's more efficient to validate just the specific form element being updated (e.g., `formInput.validate()`) rather than calling `validateAll()` on the entire form.
webroot/src/components/UserAccount/UserAccount.less (2)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.less:17-26
Timestamp: 2025-05-28T16:10:55.628Z
Learning: The `.add-email-help` element in the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.less) is display-only and not meant to handle interaction states like hover or focus. It should not have cursor: pointer or interactive styling.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/styles.common/_inputs.less:115-118
Timestamp: 2025-06-24T00:17:31.188Z
Learning: The team intentionally uses broad CSS selectors like `.dp__input_wrap div { position: static; }` to fix styling issues with the Vue Date-Picker library. They have experience with these styles working well, keep the library version pinned in yarn.lock, and have established processes to re-test everything when updating the library version. This approach is acceptable given their testing discipline and version control.
webroot/src/components/UserAccount/UserAccount.ts (7)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/LicenseCard/LicenseCard.ts:414-443
Timestamp: 2025-06-24T00:02:39.944Z
Learning: In LicenseCard component's clickUnencumberItem method (webroot/src/components/LicenseCard/LicenseCard.ts), complex event handling for checkbox interactions is intentionally designed to ensure consistent behavior across checkbox input, wrapper label, and outer selection parent elements for custom UI requirements. This complexity should be preserved rather than simplified.
Learnt from: rmolinares
PR: csg-org/CompactConnect#851
File: webroot/src/pages/RegisterLicensee/RegisterLicensee.ts:0-0
Timestamp: 2025-06-09T19:57:51.519Z
Learning: In the RegisterLicensee component, when handling DOM element availability issues, the developer prefers using Vue Watchers over retry mechanisms with requestAnimationFrame to avoid infinite recursion risks and maintain Vue's reactive patterns.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.vue:26-30
Timestamp: 2025-05-28T16:13:19.506Z
Learning: In the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.vue), the formInput.labelSubtext property rendered with v-html contains only developer-controlled content, not user-controlled content, so XSS concerns do not apply.
Learnt from: rmolinares
PR: csg-org/CompactConnect#905
File: webroot/src/components/UpdateHomeJurisdiction/UpdateHomeJurisdiction.vue:32-41
Timestamp: 2025-07-03T15:35:57.893Z
Learning: In the CompactConnect frontend codebase, the team prefers to keep non-dynamic text directly in Vue templates rather than moving it to computed properties in TypeScript modules, as this approach prevents cluttering the TS files with template labels.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/styles.common/_inputs.less:115-118
Timestamp: 2025-06-24T00:17:31.188Z
Learning: The team intentionally uses broad CSS selectors like `.dp__input_wrap div { position: static; }` to fix styling issues with the Vue Date-Picker library. They have experience with these styles working well, keep the library version pinned in yarn.lock, and have established processes to re-test everything when updating the library version. This approach is acceptable given their testing discipline and version control.
Learnt from: rmolinares
PR: csg-org/CompactConnect#843
File: webroot/src/components/Forms/InputDate/InputDate.ts:0-0
Timestamp: 2025-06-04T22:04:14.373Z
Learning: In the InputDate component (webroot/src/components/Forms/InputDate/InputDate.ts), immediate validation on every keystroke is intentional design behavior. The team prefers to alert users to encourage expected date format completion rather than deferring validation until the date is complete. This provides immediate feedback to guide users toward proper MM/dd/yyyy format completion.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/PrivilegeCard/PrivilegeCard.ts:0-0
Timestamp: 2025-06-19T23:43:25.512Z
Learning: In Vue form components, when programmatically setting form input values, it's more efficient to validate just the specific form element being updated (e.g., `formInput.validate()`) rather than calling `validateAll()` on the entire form.
🧬 Code Graph Analysis (1)
webroot/src/network/data.api.ts (1)
webroot/src/network/userApi/data.api.ts (1)
  • userDataApi (391-391)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CheckWebroot
🔇 Additional comments (11)
webroot/src/network/userApi/interceptors.ts (1)

22-23: LGTM! Proper endpoint authorization configuration.

The new email-related endpoints are correctly added to the licenseeUserEndPoints array, ensuring they use licensee authentication tokens as expected for user-specific operations.

webroot/src/network/mocks/mock.data.ts (1)

1499-1500: LGTM! Well-structured mock data updates.

The changes properly update the test email addresses to use the RFC 2606 reserved domain "example.com" and consistently add the compactConnectRegisteredEmailAddress field across all licensee entries, supporting the new email verification workflow.

Also applies to: 1749-1750, 1816-1817, 1905-1906

webroot/src/components/Forms/_mixins/form.mixin.ts (1)

38-42: LGTM! Excellent form data quality improvement.

The type-safe string trimming logic ensures cleaner form submissions by removing leading/trailing whitespace from string values while preserving non-string values unchanged. This is a solid defensive programming practice.

webroot/src/locales/en.json (1)

843-848: LGTM - Well-structured localization strings for email verification

The new email verification strings are clear, informative, and follow the existing naming conventions. The subtext appropriately informs users about the 15-minute code expiration.

webroot/src/network/data.api.ts (1)

392-408: LGTM - Consistent API delegation for email update and verification

The new methods follow the established delegation pattern and are properly documented. The separation of email update and verification into distinct methods provides good security separation.

webroot/src/locales/es.json (1)

842-847: LGTM - Accurate Spanish translations maintain consistency

The Spanish translations are accurate and maintain the same informative tone as the English versions. The key consistency ensures proper internationalization support.

webroot/src/network/userApi/data.api.ts (1)

256-276: LGTM - Well-designed email update and verification API methods

The implementation follows proper REST conventions with PATCH for email updates and POST for verification. The endpoints are appropriately scoped to the authenticated user and follow established patterns in the codebase.

webroot/src/network/mocks/mock.data.api.ts (1)

362-374: LGTM! Mock implementation aligns with the email verification flow.

The mock methods correctly simulate the email update and verification process, with appropriate error handling when the verification code is missing.

webroot/src/components/UserAccount/UserAccount.vue (1)

12-76: Well-implemented email verification modal with good accessibility features.

The modal implementation includes proper keyboard navigation with tab trap and escape key handling. The conditional content based on verification success state provides a good user experience.

webroot/src/components/UserAccount/UserAccount.less (1)

35-145: Clean and responsive modal styles.

The styles are well-structured with appropriate responsive breakpoints. The verification code input styling and success state presentation enhance the user experience.

webroot/src/components/UserAccount/UserAccount.ts (1)

204-222: Good implementation of email change validation.

The method correctly checks if the email has changed before making the API call, preventing unnecessary requests.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
webroot/src/components/UserAccount/UserAccount.ts (1)

144-153: Email field disability logic is correctly implemented.

The email field is properly disabled for staff users (isDisabled: this.isStaff) and enabled for licensees, which aligns with the PR objectives. Licensees can update their email through the verification flow, while staff users cannot modify their email through this interface.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb8b9b6 and b410f78.

📒 Files selected for processing (3)
  • webroot/src/components/Forms/_mixins/mixins.spec.ts (1 hunks)
  • webroot/src/components/UserAccount/UserAccount.ts (5 hunks)
  • webroot/src/components/UserAccount/UserAccount.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • webroot/src/components/UserAccount/UserAccount.vue
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/provider-data-v1/handlers/registration.py:111-117
Timestamp: 2025-06-17T19:05:36.255Z
Learning: In CompactConnect PR #848, the user landonshumway-ia decided to leave timezone handling code in _should_allow_reregistration function as-is after testing in sandbox environment confirmed it works correctly. The user's reasoning was that reregistration is an edge case, the code has been tested and verified, and AWS is unlikely to change behavior that would break many clients. This represents a pragmatic engineering decision based on testing and risk assessment.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/migration/provider_user_pool_migration_551/main.py:35-39
Timestamp: 2025-06-10T03:16:16.896Z
Learning: In the provider user pool migration (provider_user_pool_migration_551), the FilterExpression intentionally only checks for the existence of compactConnectRegisteredEmailAddress. The migration should only remove currentHomeJurisdiction if compactConnectRegisteredEmailAddress is also present, targeting records that went through the old registration process. Records with only currentHomeJurisdiction but no compactConnectRegisteredEmailAddress should be left untouched.
webroot/src/components/UserAccount/UserAccount.ts (9)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/LicenseCard/LicenseCard.ts:414-443
Timestamp: 2025-06-24T00:02:39.944Z
Learning: In LicenseCard component's clickUnencumberItem method (webroot/src/components/LicenseCard/LicenseCard.ts), complex event handling for checkbox interactions is intentionally designed to ensure consistent behavior across checkbox input, wrapper label, and outer selection parent elements for custom UI requirements. This complexity should be preserved rather than simplified.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.vue:26-30
Timestamp: 2025-05-28T16:13:19.506Z
Learning: In the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.vue), the formInput.labelSubtext property rendered with v-html contains only developer-controlled content, not user-controlled content, so XSS concerns do not apply.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.less:17-26
Timestamp: 2025-05-28T16:10:55.628Z
Learning: The `.add-email-help` element in the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.less) is display-only and not meant to handle interaction states like hover or focus. It should not have cursor: pointer or interactive styling.
Learnt from: landonshumway-ia
PR: csg-org/CompactConnect#848
File: backend/compact-connect/lambdas/python/migration/provider_user_pool_migration_551/main.py:35-39
Timestamp: 2025-06-10T03:16:16.896Z
Learning: In the provider user pool migration (provider_user_pool_migration_551), the FilterExpression intentionally only checks for the existence of compactConnectRegisteredEmailAddress. The migration should only remove currentHomeJurisdiction if compactConnectRegisteredEmailAddress is also present, targeting records that went through the old registration process. Records with only currentHomeJurisdiction but no compactConnectRegisteredEmailAddress should be left untouched.
Learnt from: rmolinares
PR: csg-org/CompactConnect#851
File: webroot/src/pages/RegisterLicensee/RegisterLicensee.ts:0-0
Timestamp: 2025-06-09T19:57:51.519Z
Learning: In the RegisterLicensee component, when handling DOM element availability issues, the developer prefers using Vue Watchers over retry mechanisms with requestAnimationFrame to avoid infinite recursion risks and maintain Vue's reactive patterns.
Learnt from: rmolinares
PR: csg-org/CompactConnect#905
File: webroot/src/components/UpdateHomeJurisdiction/UpdateHomeJurisdiction.vue:32-41
Timestamp: 2025-07-03T15:35:57.893Z
Learning: In the CompactConnect frontend codebase, the team prefers to keep non-dynamic text directly in Vue templates rather than moving it to computed properties in TypeScript modules, as this approach prevents cluttering the TS files with template labels.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/styles.common/_inputs.less:115-118
Timestamp: 2025-06-24T00:17:31.188Z
Learning: The team intentionally uses broad CSS selectors like `.dp__input_wrap div { position: static; }` to fix styling issues with the Vue Date-Picker library. They have experience with these styles working well, keep the library version pinned in yarn.lock, and have established processes to re-test everything when updating the library version. This approach is acceptable given their testing discipline and version control.
Learnt from: rmolinares
PR: csg-org/CompactConnect#843
File: webroot/src/components/Forms/InputDate/InputDate.ts:0-0
Timestamp: 2025-06-04T22:04:14.373Z
Learning: In the InputDate component (webroot/src/components/Forms/InputDate/InputDate.ts), immediate validation on every keystroke is intentional design behavior. The team prefers to alert users to encourage expected date format completion rather than deferring validation until the date is complete. This provides immediate feedback to guide users toward proper MM/dd/yyyy format completion.
Learnt from: jsandoval81
PR: csg-org/CompactConnect#873
File: webroot/src/components/PrivilegeCard/PrivilegeCard.ts:0-0
Timestamp: 2025-06-19T23:43:25.512Z
Learning: In Vue form components, when programmatically setting form input values, it's more efficient to validate just the specific form element being updated (e.g., `formInput.validate()`) rather than calling `validateAll()` on the entire form.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CheckWebroot
🔇 Additional comments (5)
webroot/src/components/Forms/_mixins/mixins.spec.ts (1)

37-47: LGTM! Test properly verifies string trimming functionality.

The test correctly validates that the formValues getter trims whitespace from string values, ensuring the form mixin's new trimming behavior is working as expected.

webroot/src/components/UserAccount/UserAccount.ts (4)

48-54: LGTM! Well-structured data properties for email verification state.

The new data properties properly track the email verification modal state and provide clear separation of concerns for the multi-step verification process.


163-176: LGTM! Clean separation of staff and licensee update flows.

The refactored handleSubmit method properly delegates to specific update methods based on user type, improving code organization and maintainability.


260-287: LGTM! Well-implemented email verification with proper error handling.

The email verification method properly handles validation, API calls, error states, and success flows. The focus management and store updates are appropriately handled.


225-239: Add null safety for DOM element access.

The modal open/close methods access DOM elements without null checking, which could cause runtime errors if elements don't exist.

Apply this diff to add null safety:

 async openEmailVerificationModal(): Promise<void> {
     this.isEmailVerificationModalDisplayed = true;
     this.initFormInputs();
     await nextTick();
-    document.getElementById(this.formData.emailVerificationCode.id)?.focus();
+    const emailInput = document.getElementById(this.formData.emailVerificationCode.id);
+    if (emailInput) emailInput.focus();
 }

 async closeEmailVerificationModal(): Promise<void> {
     this.isEmailVerificationModalDisplayed = false;
     this.isEmailVerificationModalSuccess = false;
     this.emailVerificationErrorMessage = '';
     this.initFormInputs();
     await nextTick();
-    document.getElementById(this.formData.submitUserUpdate.id)?.focus();
+    const submitButton = document.getElementById(this.formData.submitUserUpdate.id);
+    if (submitButton) submitButton.focus();
 }
⛔ Skipped due to learnings
Learnt from: jsandoval81
PR: csg-org/CompactConnect#822
File: webroot/src/components/Forms/InputEmailList/InputEmailList.less:17-26
Timestamp: 2025-05-28T16:10:55.628Z
Learning: The `.add-email-help` element in the InputEmailList component (webroot/src/components/Forms/InputEmailList/InputEmailList.less) is display-only and not meant to handle interaction states like hover or focus. It should not have cursor: pointer or interactive styling.

@jsandoval81 jsandoval81 requested a review from rmolinares July 11, 2025 16:11
@jsandoval81
Copy link
Collaborator Author

@jlkravitz This is ready for your review.

Copy link
Collaborator

@jlkravitz jlkravitz left a comment

Choose a reason for hiding this comment

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

looks good! just one accessibility issue i found

@jsandoval81 jsandoval81 requested a review from jlkravitz July 15, 2025 19:48
Copy link
Collaborator

@jlkravitz jlkravitz left a comment

Choose a reason for hiding this comment

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

@isabeleliassen good to merge!

@carlsims carlsims merged commit bff9cec into csg-org:development Jul 16, 2025
2 checks passed
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.

practitioner can change account email FE
4 participants