feat: skip license page for cloud billing users (#41102)

## Description

This PR enhances the signup success flow to automatically skip the
license page when cloud billing is enabled, providing a smoother
onboarding experience for cloud users.

## Key Changes

### 🚀 New Features
- Added cloud billing detection using `useIsCloudBillingEnabled()` hook
- Implemented automatic license page skipping for cloud billing users
- Enhanced redirect logic with proper async/await handling

### 🔧 Improvements
- Added redirect state management to prevent race conditions
- Improved error handling in redirect flow with try-catch blocks
- Extracted redirect conditions into `shouldAutoRedirect` variable for
better readability
- Added redirect protection to prevent multiple simultaneous redirects

### 🛠️ Technical Details
- Added `isMultiOrgEnabled` flag to signup redirect parameters
- Made `redirectUsingQueryParam` and `onGetStarted` functions async
- Implemented `isRedirecting` state to track redirect status
- Added proper dependency management in useEffect and useCallback hooks

## Impact

- **Cloud billing users** will now bypass the license page automatically
- **Improved UX** with more robust redirect handling and loading states
- **Better performance** by preventing unnecessary redirect attempts
- **Enhanced reliability** with proper error handling and state
management

## Automation

/ok-to-test tags="@tag.Sanity, @tag.Authentication,
@tag.LicenseAndBilling"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/16167808138>
> Commit: ab4247c9e01d23159f07451f3014f76fa313134e
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=16167808138&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Sanity, @tag.Authentication, @tag.LicenseAndBilling`
> Spec:
> <hr>Wed, 09 Jul 2025 12:00:44 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Improved signup success experience with smarter automatic redirection
based on user status and organization settings.
  * Added a loading spinner during redirection for better user feedback.

* **Bug Fixes**
  * Prevented multiple redirects from occurring at the same time.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Jacques Ikot 2025-07-10 21:42:42 +01:00 committed by GitHub
parent 3981590006
commit 7282f64dcf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,7 +1,7 @@
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
import { requiresAuth } from "pages/UserAuth/requiresAuthHOC";
import React from "react";
import { useCallback } from "react";
import { useCallback, useState } from "react";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getCurrentUser } from "selectors/usersSelectors";
@ -16,6 +16,7 @@ import { redirectUserAfterSignup } from "ee/utils/signupHelpers";
import { setUserSignedUpFlag } from "utils/storage";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors";
import { useIsCloudBillingEnabled } from "hooks/useIsCloudBillingEnabled";
export function SignupSuccess() {
const dispatch = useDispatch();
@ -25,50 +26,78 @@ export function SignupSuccess() {
"enableFirstTimeUserExperience",
);
const isAiAgentInstanceEnabled = useSelector(getIsAiAgentInstanceEnabled);
const isMultiOrgEnabled = useIsCloudBillingEnabled();
const validLicense = useSelector(isValidLicense);
const user = useSelector(getCurrentUser);
const isOnLoginPage = !useSelector(isWithinAnOrganization);
const [isRedirecting, setIsRedirecting] = useState(false);
useEffect(() => {
user?.email && setUserSignedUpFlag(user?.email);
}, []);
const isNonInvitedUser = shouldEnableFirstTimeUserOnboarding === "true";
const redirectUsingQueryParam = useCallback(
() =>
redirectUserAfterSignup({
const redirectUsingQueryParam = useCallback(async () => {
if (isRedirecting) return;
setIsRedirecting(true);
try {
await redirectUserAfterSignup({
redirectUrl,
shouldEnableFirstTimeUserOnboarding,
validLicense,
dispatch,
isAiAgentInstanceEnabled,
isMultiOrgEnabled,
isOnLoginPage,
}),
[
dispatch,
isNonInvitedUser,
isOnLoginPage,
redirectUrl,
shouldEnableFirstTimeUserOnboarding,
validLicense,
],
});
} catch (err) {
setIsRedirecting(false);
}
}, [
dispatch,
isNonInvitedUser,
isOnLoginPage,
redirectUrl,
shouldEnableFirstTimeUserOnboarding,
validLicense,
isAiAgentInstanceEnabled,
isMultiOrgEnabled,
]);
const onGetStarted = useCallback(
async (proficiency?: string, useCase?: string) => {
dispatch({
type: ReduxActionTypes.UPDATE_USER_DETAILS_INIT,
payload: {
proficiency,
useCase,
},
});
AnalyticsUtil.logEvent("GET_STARTED_CLICKED", {
proficiency,
goal: useCase,
});
await redirectUsingQueryParam();
},
[redirectUsingQueryParam],
);
const onGetStarted = useCallback((proficiency?: string, useCase?: string) => {
dispatch({
type: ReduxActionTypes.UPDATE_USER_DETAILS_INIT,
payload: {
proficiency,
useCase,
},
});
AnalyticsUtil.logEvent("GET_STARTED_CLICKED", {
proficiency,
goal: useCase,
});
redirectUsingQueryParam();
}, []);
const shouldAutoRedirect =
user?.isSuperUser ||
((user?.role || user?.proficiency) && user?.useCase) ||
shouldEnableFirstTimeUserOnboarding !== "true" ||
isAiAgentInstanceEnabled ||
isMultiOrgEnabled;
useEffect(() => {
if (shouldAutoRedirect && !isRedirecting) {
redirectUsingQueryParam();
}
}, [shouldAutoRedirect, redirectUsingQueryParam, isRedirecting]);
/*
* Proceed with redirection,
@ -78,15 +107,7 @@ export function SignupSuccess() {
* We identify an invited user based on `enableFirstTimeUserExperience` flag in url.
*/
//TODO(Balaji): Factor in case, where user had closed the tab, while filling the form.And logs back in again.
if (
user?.isSuperUser ||
((user?.role || user?.proficiency) && user?.useCase) ||
shouldEnableFirstTimeUserOnboarding !== "true" ||
isAiAgentInstanceEnabled
) {
redirectUsingQueryParam();
// Showing a loader until the redirect
if (shouldAutoRedirect) {
return (
<Center>
<Spinner size="lg" />