Conversation
Greptile OverviewGreptile SummaryThis PR adds a Key integration point: Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User as User
participant Page as ChooseYourPlanContent
participant Recoil as Recoil
participant Init as useInitializeQueryParamState
participant URL as URLSearchParams
User->>Page: Navigate to /onboarding (PlanRequired)
Page->>Init: initializeQueryParamState()
Init->>URL: Read window.location.search
URL-->>Init: plan=pro|enterprise (optional)
Init->>Recoil: set(billingCheckoutSessionState.plan)
Recoil-->>Page: billingCheckoutSessionState updated
Page->>Page: Render links based on currentPlanKey
Page-->>User: Shows plan toggle link
|
| import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/BillingCheckoutSessionDefaultValue'; | ||
| import deepEqual from 'deep-equal'; | ||
| import { BillingPlanKey } from '~/generated/graphql'; | ||
|
|
There was a problem hiding this comment.
Mismatched BillingPlanKey enum
This hook sets BillingCheckoutSession.plan using BillingPlanKey from ~/generated/graphql (e.g. BillingPlanKey.PRO), but ChooseYourPlanContent compares currentPlanKey against BillingPlanKey from ~/generated-metadata/graphql. If these are different generated enum objects, strict equality checks like currentPlanKey === BillingPlanKey.PRO will fail, leading to wrong plan-specific UI when the plan is initialized from query params. Align the enum source used across both places (one canonical import).
Additional Comments (1)
|
There was a problem hiding this comment.
Pull request overview
Updates the onboarding “Choose your plan” step to let users switch between Pro and Organization (Enterprise) plans via a ?plan= query parameter, removing the previous external “Change Plan” link.
Changes:
- Remove the “Change Plan” link to the external pricing page from the onboarding plan step.
- Add “Pro plan” / “Organization plan” links that navigate to
/plan-required?plan=.... - Extend query-param hydration to support a
planparameter that updatesbillingCheckoutSessionState.plan.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx | Replaces the external plan-change link with internal links that toggle the plan via ?plan=. |
| packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts | Adds query-param handling for `plan=pro |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <ClickToActionLink href={AppPath.PlanRequired.concat('?plan=enterprise')}> | ||
| <Trans>Organization plan</Trans> | ||
| </ClickToActionLink> | ||
| ) : ( | ||
| <ClickToActionLink href={AppPath.PlanRequired.concat('?plan=pro')}> | ||
| <Trans>Pro plan</Trans> |
There was a problem hiding this comment.
The plan switch links are manually built with AppPath.PlanRequired.concat('?plan=...'). There’s already a buildAppPathWithQueryParams(AppPath.PlanRequired, {...}) helper used elsewhere for this route; using it here would improve readability/consistency and avoid subtle mistakes when more params are added later.
| const updatedBillingCheckoutSession: BillingCheckoutSession = { | ||
| plan: changedPlan, | ||
| interval: billingCheckoutSession.interval, | ||
| requirePaymentMethod: | ||
| billingCheckoutSession.requirePaymentMethod, | ||
| }; | ||
| set(billingCheckoutSessionState, updatedBillingCheckoutSession); |
There was a problem hiding this comment.
The new plan query-param handler always calls set(billingCheckoutSessionState, ...) when the param is valid, even if the current session already has the requested plan. This can trigger unnecessary state updates/rerenders on every navigation where ?plan= is present; consider checking billingCheckoutSession.plan !== changedPlan (similar to the deepEqual guard used in the billingCheckoutSession handler) before calling set.
| const updatedBillingCheckoutSession: BillingCheckoutSession = { | |
| plan: changedPlan, | |
| interval: billingCheckoutSession.interval, | |
| requirePaymentMethod: | |
| billingCheckoutSession.requirePaymentMethod, | |
| }; | |
| set(billingCheckoutSessionState, updatedBillingCheckoutSession); | |
| if (billingCheckoutSession.plan !== changedPlan) { | |
| const updatedBillingCheckoutSession: BillingCheckoutSession = { | |
| plan: changedPlan, | |
| interval: billingCheckoutSession.interval, | |
| requirePaymentMethod: | |
| billingCheckoutSession.requirePaymentMethod, | |
| }; | |
| set( | |
| billingCheckoutSessionState, | |
| updatedBillingCheckoutSession, | |
| ); | |
| } |
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts">
<violation number="1" location="packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts:50">
P2: `plan` builds the new `billingCheckoutSessionState` from a snapshot captured before earlier handlers run, so when both `billingCheckoutSession` and `plan` query params are present, the `plan` handler can overwrite the state set by `billingCheckoutSession` with stale values. Use the functional updater form of `set` to merge with the latest pending state.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts
Outdated
Show resolved
Hide resolved
|
🚀 Preview Environment Ready! Your preview environment is available at: http://bore.pub:38043 This environment will automatically shut down when the PR is closed or after 5 hours. |
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts">
<violation number="1" location="packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts:61">
P2: The `plan` handler compares against a stale Recoil snapshot. If both `billingCheckoutSession` and `plan` query params are present, the earlier handler can queue a plan update but this check uses the old snapshot and may skip the override when the initial state matches the URL plan, preventing the URL plan from taking precedence.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
packages/twenty-front/src/modules/app/hooks/useInitializeQueryParamState.ts
Outdated
Show resolved
Hide resolved
| ); | ||
| } | ||
| }, | ||
| plan: (value: string) => { |
There was a problem hiding this comment.
I'm a bit lost here, why do we need a dedicated entry for plan? I would expect it to be part of billingCheckoutSession handled above?
There was a problem hiding this comment.
According to the issue, new plan parameter should be introduced, I assumed it should be only within planRequired page when user wants to change the plan and billingCheckoutSession should be left as is in pricing page
| <span /> | ||
| {currentPlanKey === BillingPlanKey.PRO ? ( | ||
| <ClickToActionLink | ||
| href={AppPath.PlanRequired.concat('?plan=enterprise')} |
There was a problem hiding this comment.
@charlesBochet just to be clear, said plan parameter shouldn't be used and instead should we use billingCheckoutSession everywhere? If so, I'll quickly add changes
There was a problem hiding this comment.
yes, I think so, that's the purpose of this existing query param, let's use it
charlesBochet
left a comment
There was a problem hiding this comment.
Thanks @BOHEUS, I've left comments
|
@BOHEUS could you fix the conflits and we are good to go :) |
|
Done @charlesBochet |
|
Thanks @BOHEUS for your contribution! |
|
Hey @charlesBochet! After you've done the QA of your Pull Request, you can mark it as done here. Thank you! |


Fixes github.com/twentyhq/core-team-issues/issues/637