Skip to content

feat: Login on web#7360

Open
yash-rajpal wants to merge 1 commit into
developfrom
login-on-web
Open

feat: Login on web#7360
yash-rajpal wants to merge 1 commit into
developfrom
login-on-web

Conversation

@yash-rajpal
Copy link
Copy Markdown
Member

@yash-rajpal yash-rajpal commented May 29, 2026

Proposed changes

Hides the required login services buttons and shows new login on web button based on server response.

Requires - Rocket.Chat/Rocket.Chat#40733

Issue(s)

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

PRM-48

Summary by CodeRabbit

  • New Features

    • Mobile users now have a "Login on web" option to access login via the web interface.
  • Updates

    • Mobile login interface now selectively displays login services.
    • Layout calculations updated to support new mobile interface elements.

Review Change Stack

@yash-rajpal yash-rajpal requested a deployment to approve_e2e_testing May 29, 2026 12:33 — with GitHub Actions Waiting
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Walkthrough

The PR adds a "Login on web" button to the LoginServices mobile view. Services can now opt out of showing buttons on mobile via hideButtonOnMobile, and a conditional button appears when such services exist, navigating users to the server's mobile login page via deep linking.

Changes

Mobile Login on Web Feature

Layer / File(s) Summary
Service interface contract
app/containers/LoginServices/interfaces.ts
IItemService gains an optional hideButtonOnMobile boolean property to control whether a service button displays on mobile.
Mobile login button and filtering logic
app/containers/LoginServices/index.tsx
React Native imports added for Linking and Button. Services are filtered by hideButtonOnMobile, triggering showLoginOnWeb detection. A new Button is conditionally rendered, calling Linking.openURL to ${server}/home?loginClient=mobile. Animated height calculation adjusts for the extra button row, and both render branches pass filtered services and the showLoginOnWeb prop to child components.
English translation for login button
app/i18n/locales/en.json
Adds the Login_on_web localization key with the value "Login on web".

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

type: feature

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature being added—a 'Login on web' button capability on mobile.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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)
  • PRM-48: 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.

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: 1

🧹 Nitpick comments (1)
app/containers/LoginServices/index.tsx (1)

63-63: ⚡ Quick win

Simplify the boolean check.

The === true comparison is redundant when the result is already wrapped in Boolean(). The find() method returns either a truthy value (the service object) or undefined, so the explicit comparison adds no value.

♻️ Proposed simplification
-const showLoginOnWeb = Boolean(Object.values(services).find((service: IItemService) => service.hideButtonOnMobile === true));
+const showLoginOnWeb = Boolean(Object.values(services).find((service: IItemService) => service.hideButtonOnMobile));
🤖 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/containers/LoginServices/index.tsx` at line 63, The boolean expression
for showLoginOnWeb is overcomplicated: remove the redundant "=== true" and
simplify the check by using the truthiness of the found service (e.g., use
Object.values(services).find(...) directly wrapped with Boolean or use
.some(...)) so that the expression references services, IItemService, and
hideButtonOnMobile and relies on find()/some() returning a truthy value instead
of comparing to true.
🤖 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/containers/LoginServices/index.tsx`:
- Around line 39-46: The call to Linking.openURL inside the conditional render
(when showLoginOnWeb is true) is unhandled and may reject; update the Button
onPress handler in LoginServices so
Linking.openURL(`${server}/home?loginClient=mobile`) is explicitly handled with
a Promise rejection handler (e.g., .catch(err => /* log or show error */)) to
satisfy ESLint's no-void rule and avoid unhandled rejections; keep the same
URL/template and ensure the catch logs or surfaces the error (using the app
logger or console) rather than leaving the promise unhandled.

---

Nitpick comments:
In `@app/containers/LoginServices/index.tsx`:
- Line 63: The boolean expression for showLoginOnWeb is overcomplicated: remove
the redundant "=== true" and simplify the check by using the truthiness of the
found service (e.g., use Object.values(services).find(...) directly wrapped with
Boolean or use .some(...)) so that the expression references services,
IItemService, and hideButtonOnMobile and relies on find()/some() returning a
truthy value instead of comparing to true.
🪄 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: c0aeed82-c575-4ea4-992d-1366f08eb79f

📥 Commits

Reviewing files that changed from the base of the PR and between 815ff6c and 3487134.

📒 Files selected for processing (3)
  • app/containers/LoginServices/index.tsx
  • app/containers/LoginServices/interfaces.ts
  • app/i18n/locales/en.json
📜 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). (1)
  • GitHub Check: ESLint and Test / run-eslint-and-test
🧰 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/containers/LoginServices/interfaces.ts
  • app/containers/LoginServices/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/containers/LoginServices/interfaces.ts
  • app/containers/LoginServices/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/containers/LoginServices/interfaces.ts
  • app/containers/LoginServices/index.tsx
app/containers/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Reusable UI components should be placed in app/containers/ directory

Files:

  • app/containers/LoginServices/interfaces.ts
  • app/containers/LoginServices/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/containers/LoginServices/interfaces.ts
  • app/containers/LoginServices/index.tsx
🔇 Additional comments (6)
app/containers/LoginServices/interfaces.ts (1)

27-27: LGTM!

app/containers/LoginServices/index.tsx (4)

64-67: LGTM!


77-77: LGTM!


86-92: LGTM!


107-113: LGTM!

app/i18n/locales/en.json (1)

517-517: LGTM!

Comment on lines +39 to +46
{showLoginOnWeb && (
<Button
title={I18n.t('Login_on_web')}
onPress={() => {
Linking.openURL(`${server}/home?loginClient=mobile`);
}}
/>
)}
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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add error handling for Linking.openURL.

Linking.openURL returns a Promise that can reject if the URL cannot be opened. The unhandled rejection could cause runtime errors. Based on learnings, you must handle the promise explicitly with .catch(...) to satisfy ESLint's no-void: error rule.

🛡️ Proposed fix to add error handling
 {showLoginOnWeb && (
 	<Button
 		title={I18n.t('Login_on_web')}
 		onPress={() => {
-			Linking.openURL(`${server}/home?loginClient=mobile`);
+			Linking.openURL(`${server}/home?loginClient=mobile`).catch(err => {
+				// Handle error - could log or show user feedback
+				console.error('Failed to open login URL:', err);
+			});
 		}}
 	/>
 )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{showLoginOnWeb && (
<Button
title={I18n.t('Login_on_web')}
onPress={() => {
Linking.openURL(`${server}/home?loginClient=mobile`);
}}
/>
)}
{showLoginOnWeb && (
<Button
title={I18n.t('Login_on_web')}
onPress={() => {
Linking.openURL(`${server}/home?loginClient=mobile`).catch(err => {
// Handle error - could log or show user feedback
console.error('Failed to open login URL:', 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/containers/LoginServices/index.tsx` around lines 39 - 46, The call to
Linking.openURL inside the conditional render (when showLoginOnWeb is true) is
unhandled and may reject; update the Button onPress handler in LoginServices so
Linking.openURL(`${server}/home?loginClient=mobile`) is explicitly handled with
a Promise rejection handler (e.g., .catch(err => /* log or show error */)) to
satisfy ESLint's no-void rule and avoid unhandled rejections; keep the same
URL/template and ensure the catch logs or surfaces the error (using the app
logger or console) rather than leaving the promise unhandled.

const server = useAppSelector(state => state.server.server);
const services = useAppSelector(state => state.login.services as IServices, shallowEqual);
const { length } = Object.values(services);
const showLoginOnWeb = Boolean(Object.values(services).find((service: IItemService) => service.hideButtonOnMobile === true));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the service has hideButtonOnMobile we show login on web?
It looks wrong and can generate confusion for the user and for maintainability.
Not sure if it's a new prop or not, but if it's new and we ever want to hide login services on mobile, it's going to be very weird.

Comment on lines +63 to +65
const showLoginOnWeb = Boolean(Object.values(services).find((service: IItemService) => service.hideButtonOnMobile === true));
const filteredServices = Object.fromEntries(
Object.entries(services).filter(([, service]) => !service.hideButtonOnMobile)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we really need to map the array twice, one with service.hideButtonOnMobile === true and another with !service.hideButtonOnMobile?


const onPressButtonSeparator = () => {
heightButtons.value = collapsed ? SERVICE_HEIGHT * length : SERVICES_COLLAPSED_HEIGHT;
heightButtons.value = collapsed ? SERVICE_HEIGHT * (length + (showLoginOnWeb ? 1 : 0)) : SERVICES_COLLAPSED_HEIGHT;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The new login should belong to the same filteredServices, so length would have the correct value.
Shouldn't this new login service be returned on settings.oauth endpoint?

Comment thread app/i18n/locales/en.json
"Login_error": "Your credentials were rejected! Please try again.",
"Login_has_been_temporarily_blocked_for_this_IP": "Login has been temporarily blocked for this IP",
"Login_has_been_temporarily_blocked_for_this_User": "Login has been temporarily blocked for this user",
"Login_on_web": "Login on web",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use AI to write translations for all supported languages

export const LANGUAGES: ILanguage[] = [

Copy link
Copy Markdown
Member

@diegolmello diegolmello left a comment

Choose a reason for hiding this comment

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

Also missing stories and tests

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.

2 participants