Skip to content

chore: refactor the submit function on ProfileView#7353

Open
OtavioStasiak wants to merge 3 commits into
developfrom
chore.refactor-submit-function-profileview
Open

chore: refactor the submit function on ProfileView#7353
OtavioStasiak wants to merge 3 commits into
developfrom
chore.refactor-submit-function-profileview

Conversation

@OtavioStasiak
Copy link
Copy Markdown
Contributor

@OtavioStasiak OtavioStasiak commented May 27, 2026

Proposed changes

Break the submit function into smaller functions to improve the readability of the code.

Issue(s)

https://rocketchat.atlassian.net/browse/NATIVE-1037

How to test or reproduce

Screenshots

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Summary by CodeRabbit

  • Bug Fixes

    • Require password confirmation when changing email.
    • Improved two-factor authentication handling and retry during profile updates.
    • Better validation messages for unavailable usernames or emails.
  • Refactor

    • Streamlined profile save flow for more consistent save success feedback (form reset and success toast).

Review Change Stack

@OtavioStasiak OtavioStasiak temporarily deployed to approve_e2e_testing May 27, 2026 19:28 — with GitHub Actions Inactive
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c6e2daf6-66ff-46fe-ac6b-dcf7ea43d577

📥 Commits

Reviewing files that changed from the base of the PR and between fbabd85 and 44cd95a.

📒 Files selected for processing (1)
  • app/views/ProfileView/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/views/ProfileView/index.tsx
📜 Recent review details
⏰ 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). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format

Walkthrough

ProfileView extracts payload construction to buildProfileParams, removes inline sha256, and refactors submit into helpers that handle confirm-email-change, success application, field-error mapping, two-factor challenge/retry, and centralized state resets.

Changes

Profile save flow refactor

Layer / File(s) Summary
buildProfileParams helper
app/views/ProfileView/methods/buildProfileParams.ts
New module exports buildProfileParams(formValues, user), which builds IProfileParams by comparing form fields against existing user state and conditionally hashing currentPassword.
ProfileView submit refactor
app/views/ProfileView/index.tsx
Removes inline sha256 import, adds buildProfileParams import, introduces helpers for confirm-email-change sheet, resetting save/password/2FA state, applying save success (Redux update, form reset, events), mapping server validation errors to form fields, handling totp-invalid via twoFactor and retry, and reworks submit to use these helpers and the new params builder.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

type: chore

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the changeset: refactoring the submit function on ProfileView into smaller, more focused functions to improve code readability.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • NATIVE-1037: Request failed with status code 401

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@OtavioStasiak OtavioStasiak temporarily deployed to approve_e2e_testing May 28, 2026 00:28 — with GitHub Actions Inactive
@OtavioStasiak OtavioStasiak marked this pull request as ready for review May 28, 2026 00:28
Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (2)
app/views/ProfileView/index.tsx (2)

164-164: ⚡ Quick win

Replace as any cast with proper typing.

Using as any bypasses TypeScript's type safety. The parameter p should have an explicit type based on ConfirmEmailChangeActionSheetContent's onSubmit prop signature.

♻️ Suggested improvement
-					onSubmit={p => {
+					onSubmit={(password: string) => {
 						hideActionSheet();
-						setValue('currentPassword', p as any);
+						setValue('currentPassword', password);
 						submit().catch(err => {
 							console.error('Profile submit failed:', err);
 						});
 					}}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/views/ProfileView/index.tsx` at line 164, The line uses a loose cast
setValue('currentPassword', p as any) which bypasses TypeScript safety; change
the handler so parameter p is explicitly typed to match the
ConfirmEmailChangeActionSheetContent onSubmit signature (e.g. declare the
callback param as the exact type from
ConfirmEmailChangeActionSheetContent['onSubmit'] or extract/define a named type
for the submitted payload) and pass that typed value to setValue without using
any, ensuring setValue('currentPassword', p) uses the correctly typed property
(currentPassword) from that payload.

216-229: 💤 Low value

Consider adding a comment to clarify the recursive retry logic.

The function recursively calls submit() at line 223, which will invoke handleTwoFactorChallenge again if needed. While this is protected by the twoFactorCode state and modal cancellation, a brief comment would help future maintainers understand the retry flow.

📝 Suggested comment
 		try {
 			const code = await twoFactor({ method: e.details.method, invalid: e?.error === 'totp-invalid' && !!twoFactorCode });
 			setTwoFactorCode(code as any);
+			// Recursively retry submit with the 2FA code
 			await submit();
 			return true;
 		} catch {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/views/ProfileView/index.tsx` around lines 216 - 229, Add a short
clarifying comment explaining the recursive retry flow in
handleTwoFactorChallenge: note that handleTwoFactorChallenge can trigger
twoFactor(...) to set twoFactorCode and then calls submit(), which may re-enter
handleTwoFactorChallenge if the server still requires TOTP; also mention the
protections (the twoFactorCode state prevents infinite loops and modal
cancellation is handled in the catch) so future maintainers understand why this
recursion is intentional. Place the comment above the handleTwoFactorChallenge
function or immediately before the await submit() call and reference the
twoFactorCode state and twoFactor(...) modal behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/views/ProfileView/index.tsx`:
- Line 165: The call to the async function submit() is currently a floating
promise; update the invocation to handle errors explicitly (e.g.,
submit().catch(err => processLogger?.error?.('Profile submit failed', err) or
set component error state) so the promise cannot fail silently; ensure you call
submit() with .catch(...) rather than using void or await in this location and
reference the submit() function in ProfileView to implement the error handler.
- Around line 210-212: The guard currently calls e?.message.startsWith(email)
which will throw when email is null; modify the conditional in the error
handling (the branch that calls setError) to ensure email is a non-null string
first (e.g. check typeof email === 'string' or email != null) before calling
startsWith, keeping the existing e?.error === 'error-field-unavailable' check
and leaving setError('email', ...) unchanged.
- Around line 178-203: The applySaveSuccess handler is dispatching setUser twice
and uses setValue/getValues to update form fields right before reset, causing
redundant Redux updates and wasted work; modify applySaveSuccess to compute the
merged updatedUser once, call dispatch(setUser(updatedUser)) a single time
(include customFields on the merged object if present), remove the earlier
conditional dispatch and the manual setValue loop, and then call reset(...) with
values derived from that same updatedUser so the form and store are consistent
without duplicate dispatches.

---

Nitpick comments:
In `@app/views/ProfileView/index.tsx`:
- Line 164: The line uses a loose cast setValue('currentPassword', p as any)
which bypasses TypeScript safety; change the handler so parameter p is
explicitly typed to match the ConfirmEmailChangeActionSheetContent onSubmit
signature (e.g. declare the callback param as the exact type from
ConfirmEmailChangeActionSheetContent['onSubmit'] or extract/define a named type
for the submitted payload) and pass that typed value to setValue without using
any, ensuring setValue('currentPassword', p) uses the correctly typed property
(currentPassword) from that payload.
- Around line 216-229: Add a short clarifying comment explaining the recursive
retry flow in handleTwoFactorChallenge: note that handleTwoFactorChallenge can
trigger twoFactor(...) to set twoFactorCode and then calls submit(), which may
re-enter handleTwoFactorChallenge if the server still requires TOTP; also
mention the protections (the twoFactorCode state prevents infinite loops and
modal cancellation is handled in the catch) so future maintainers understand why
this recursion is intentional. Place the comment above the
handleTwoFactorChallenge function or immediately before the await submit() call
and reference the twoFactorCode state and twoFactor(...) modal behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ebd9570f-b68b-443c-8e25-8d6398332b80

📥 Commits

Reviewing files that changed from the base of the PR and between 3961d4d and fbabd85.

📒 Files selected for processing (2)
  • app/views/ProfileView/index.tsx
  • app/views/ProfileView/methods/buildProfileParams.ts
📜 Review details
⏰ 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). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • app/views/ProfileView/methods/buildProfileParams.ts
  • app/views/ProfileView/index.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbers

Use TypeScript with strict mode and baseUrl set to app/ for import resolution

Files:

  • app/views/ProfileView/methods/buildProfileParams.ts
  • app/views/ProfileView/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use Prettier with tabs, single quotes, 130 char width, no trailing commas, arrow parens avoid, bracket same line
Use @rocket.chat/eslint-config base with React, React Native, TypeScript, Jest plugins

Files:

  • app/views/ProfileView/methods/buildProfileParams.ts
  • app/views/ProfileView/index.tsx
app/views/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

View components (70+ screen components) should be placed in app/views/ directory

Files:

  • app/views/ProfileView/methods/buildProfileParams.ts
  • app/views/ProfileView/index.tsx
🧠 Learnings (1)
📚 Learning: 2026-04-30T17:07:51.020Z
Learnt from: diegolmello
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7274
File: app/lib/services/voip/MediaCallEvents.ts:0-0
Timestamp: 2026-04-30T17:07:51.020Z
Learning: In this Rocket.Chat React Native codebase, the ESLint rule `no-void: error` is enforced. When you see a promise returned from an async call that is not awaited (a “floating promise”), do not silence it with the `void somePromise()` pattern. Instead, handle the promise explicitly by attaching `.catch(...)` (or otherwise awaiting/handling the error) so unhandled-rejection risks are addressed in a way that satisfies the existing ESLint configuration.

Applied to files:

  • app/views/ProfileView/methods/buildProfileParams.ts
  • app/views/ProfileView/index.tsx
🔇 Additional comments (3)
app/views/ProfileView/index.tsx (2)

172-176: LGTM!


231-266: LGTM!

app/views/ProfileView/methods/buildProfileParams.ts (1)

20-20: ⚡ Quick win

Prevent params.email = null from reaching the API

  • ProfileView validates email with yup.string().email(...).required(...), and submit returns early when validation fails, so the UI shouldn’t submit with email: null (i.e., clearing the email field isn’t supported via this flow).
  • While buildProfileParams would set params.email = null and skip the password confirmation (requirePassword = !!params.email), that path shouldn’t be reachable through the normal submit button.

Comment thread app/views/ProfileView/index.tsx Outdated
Comment thread app/views/ProfileView/index.tsx
Comment thread app/views/ProfileView/index.tsx Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@github-actions
Copy link
Copy Markdown

iOS Build Available

Rocket.Chat 4.73.0.108990

@github-actions
Copy link
Copy Markdown

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.

1 participant