diff --git a/libs/domains/organization/src/index.ts b/libs/domains/organization/src/index.ts index 4d72946464..cd6864f90e 100644 --- a/libs/domains/organization/src/index.ts +++ b/libs/domains/organization/src/index.ts @@ -9,6 +9,3 @@ export * from './lib/mocks/organizations-handler.mock' export * from './lib/mocks/cluster-factory.mock' export * from './lib/mocks/cluster-log-factory.mock' export * from './lib/mocks/auth-provider.mock' -export * from './lib/interfaces/organization-plan.interface' -export * from './lib/interfaces/organization-price.interface' -export * from './lib/enums/organization-plan-type.enum' diff --git a/libs/domains/organization/src/lib/interfaces/organization-plan.interface.ts b/libs/domains/organization/src/lib/interfaces/organization-plan.interface.ts deleted file mode 100644 index 66ff0fa20d..0000000000 --- a/libs/domains/organization/src/lib/interfaces/organization-plan.interface.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { OrganizationPrice } from './organization-price.interface' -import { PlanEnum } from 'qovery-typescript-axios' - -export interface OrganizationPlan { - name: PlanEnum - title: string - text: string - price: number - listPrice: OrganizationPrice[] -} diff --git a/libs/domains/organization/src/lib/interfaces/organization-price.interface.ts b/libs/domains/organization/src/lib/interfaces/organization-price.interface.ts deleted file mode 100644 index b37c2a7d60..0000000000 --- a/libs/domains/organization/src/lib/interfaces/organization-price.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface OrganizationPrice { - number: string - price: string -} diff --git a/libs/domains/organization/src/lib/slices/organization.slice.ts b/libs/domains/organization/src/lib/slices/organization.slice.ts index 4ea738eb0b..e7a780e6b2 100644 --- a/libs/domains/organization/src/lib/slices/organization.slice.ts +++ b/libs/domains/organization/src/lib/slices/organization.slice.ts @@ -53,13 +53,9 @@ export const fetchOrganizationById = createAsyncThunk( export const postOrganization = createAsyncThunk( 'organization/post', - async (data: OrganizationRequest, { rejectWithValue }) => { - try { - const result = await organizationMainCalls.createOrganization(data) - return result.data - } catch (err) { - return rejectWithValue(err) - } + async (data: OrganizationRequest) => { + const result = await organizationMainCalls.createOrganization(data) + return result.data } ) @@ -259,12 +255,14 @@ export const organizationSlice = createSlice({ state.loadingStatus = 'loading' }) .addCase(postOrganization.fulfilled, (state: OrganizationState, action: PayloadAction) => { - organizationAdapter.setOne(state, action.payload) + organizationAdapter.addOne(state, action.payload) state.loadingStatus = 'loaded' + toast(ToastEnum.SUCCESS, 'Your organization has been created') }) .addCase(postOrganization.rejected, (state: OrganizationState, action) => { state.loadingStatus = 'error' state.error = action.error.message + toastError(action.error) }) // delete organization .addCase(deleteOrganization.pending, (state: OrganizationState) => { diff --git a/libs/pages/onboarding/src/lib/feature/container/container.tsx b/libs/pages/onboarding/src/lib/feature/container/container.tsx index b2fc1f85cf..7141f09be7 100644 --- a/libs/pages/onboarding/src/lib/feature/container/container.tsx +++ b/libs/pages/onboarding/src/lib/feature/container/container.tsx @@ -1,14 +1,9 @@ import { createContext, useEffect, useState } from 'react' import { Params, useNavigate } from 'react-router-dom' -import { - ONBOARDING_PRICING_FREE_URL, - ONBOARDING_PRICING_URL, - ONBOARDING_PROJECT_URL, - ONBOARDING_URL, - Route, -} from '@qovery/shared/router' +import { ONBOARDING_PRICING_URL, ONBOARDING_PROJECT_URL, Route } from '@qovery/shared/router' +import { FunnelFlow, FunnelFlowBody } from '@qovery/shared/ui' import { ROUTER_ONBOARDING_STEP_1, ROUTER_ONBOARDING_STEP_2 } from '../../router/router' -import { LayoutOnboarding } from '../../ui/layout-onboarding/layout-onboarding' +import OnboardingRightContent from '../../ui/onboarding-right-content/onboarding-right-content' interface DefaultContextProps { organization_name: string @@ -40,20 +35,12 @@ export function Container(props: ContainerProps) { useEffect(() => { setStep(params['*']) - - if (step === ONBOARDING_PRICING_URL.replace('/', '')) { - navigate(`${ONBOARDING_URL}${ONBOARDING_PRICING_FREE_URL}`) - } }, [params, setStep, step, navigate]) - const stepsNumber: number = firstStep ? ROUTER_ONBOARDING_STEP_1.length : ROUTER_ONBOARDING_STEP_2.length - const currentStepPosition = (routes: Route[]) => routes.findIndex((route: Route) => route.path.replace('/:plan', '') === `/${step?.split('/')[0]}`) + 1 - function getProgressPercentValue(): number { - return (100 * currentStepPosition(currentRoutes)) / stepsNumber - } + const isNotStepPricing = `/${step}` !== ONBOARDING_PRICING_URL return ( - - {children} - + } + customContentWidth={!isNotStepPricing ? 'max-w-[1096px]' : undefined} + > + {children} + + ) } diff --git a/libs/pages/onboarding/src/lib/feature/onboarding-pricing/onboarding-pricing.tsx b/libs/pages/onboarding/src/lib/feature/onboarding-pricing/onboarding-pricing.tsx index 4c74359929..55cdb85504 100644 --- a/libs/pages/onboarding/src/lib/feature/onboarding-pricing/onboarding-pricing.tsx +++ b/libs/pages/onboarding/src/lib/feature/onboarding-pricing/onboarding-pricing.tsx @@ -1,86 +1,69 @@ import { Organization, PlanEnum, Project } from 'qovery-typescript-axios' -import { useContext, useEffect, useState } from 'react' +import { useContext, useState } from 'react' import { useDispatch } from 'react-redux' import { useNavigate } from 'react-router-dom' import { useIntercom } from 'react-use-intercom' -import { - OrganizationPlan, - OrganizationPlanType, - OrganizationPrice, - postOrganization, -} from '@qovery/domains/organization' +import { postOrganization } from '@qovery/domains/organization' import { postProject } from '@qovery/domains/projects' import { useAuth } from '@qovery/shared/auth' -import { ONBOARDING_PRICING_URL, ONBOARDING_PROJECT_URL, ONBOARDING_URL } from '@qovery/shared/router' +import { ENVIRONMENTS_GENERAL_URL, ENVIRONMENTS_URL } from '@qovery/shared/router' import { useDocumentTitle } from '@qovery/shared/utils' import { AppDispatch } from '@qovery/store' import { StepPricing } from '../../ui/step-pricing/step-pricing' import { ContextOnboarding } from '../container/container' -function listPrice(base: number, isBusinessPlan?: boolean) { - const results: OrganizationPrice[] = [] - let multiple = 0 - - for (let i = 100; i <= 4000; i = i + 100) { - const nbDeploy = isBusinessPlan ? 1000 : 300 - - if (i > nbDeploy) multiple += 1 - const price = i > nbDeploy ? base + 50 * multiple : base - results.push({ - number: i.toString(), - price: price.toString(), - }) - } - return results +export interface OrganizationPlan { + name: PlanEnum + title: string + text: string + price: number + list: string[] } const PLANS: OrganizationPlan[] = [ { name: PlanEnum.FREE, - title: 'Free', - text: 'Adapted for personnal project', + title: 'Free plan', + text: 'Adapted for start', price: 0, - listPrice: [], + list: [ + 'Deploy on your AWS account', + 'Unlimited Developers', + 'Up to 1 cluster', + 'Up to 5 Environments', + 'Preview Environment in one-click', + 'Community support (forum)', + ], }, { name: PlanEnum.TEAM, - title: 'Professional', - text: 'For 5-20 members', + title: 'Team plan', + text: 'Adapted to scale', price: 49, - listPrice: listPrice(49, false), + list: [ + 'All FREE features', + 'Up to 3 clusters', + 'Unlimited Deployments', + 'Unlimited Environments', + '24/5 support (email and chat)', + ], }, { name: PlanEnum.ENTERPRISE, - title: 'Business', - text: 'For medium company', - price: 599, - listPrice: listPrice(599, true), - }, - { - name: PlanEnum.ENTERPRISE, - title: 'Enterprise', - text: 'For large company', - price: 0, - listPrice: [], + title: 'Enterprise plan', + text: 'Adapted for 100+ team', + price: 899, + list: [ + 'All TEAM features', + 'Unlimited Clusters', + 'Role-Based Access Control', + 'Extended security and compliance', + 'Usage Report', + 'Custom support', + ], }, ] -const PLAN_DEFAULT: PlanEnum = PlanEnum.FREE -const DEPLOY_DEFAULT = 100 - -const DEFAULT_PRICE = { - [OrganizationPlanType.FREE]: { disable: false }, - [OrganizationPlanType.PROFESSIONAL]: { - number: PLANS.find((p) => p.name === PlanEnum.TEAM)?.listPrice[0].number, - disable: false, - }, - [OrganizationPlanType.BUSINESS]: { - number: PLANS.find((p) => p.name === PlanEnum.ENTERPRISE)?.listPrice[0].number, - disable: false, - }, - [OrganizationPlanType.ENTERPRISE]: { disable: false }, -} - export function OnboardingPricing() { useDocumentTitle('Onboarding Pricing - Qovery') @@ -89,89 +72,43 @@ export function OnboardingPricing() { const { showNewMessages } = useIntercom() const { organization_name, project_name } = useContext(ContextOnboarding) const { createAuthCookies, getAccessTokenSilently } = useAuth() - const [selectPlan, setSelectPlan] = useState(PLAN_DEFAULT) - const [currentValue, setCurrentValue] = useState(DEFAULT_PRICE) - const [currentDeploy, setCurrentDeploy] = useState(DEPLOY_DEFAULT) - const [loading, setLoading] = useState(false) - - useEffect(() => { - if (organization_name === '' && project_name === '') { - navigate(`${ONBOARDING_URL}${ONBOARDING_PROJECT_URL}`) - } else { - navigate(`${ONBOARDING_URL}${ONBOARDING_PRICING_URL}/${selectPlan.toLowerCase()}`) - } - }, [selectPlan, navigate, organization_name, project_name]) - - const chooseDeploy = (value: number | null) => { - if (value) { - setCurrentDeploy(value) - - if (value > 100) { - if (selectPlan === PlanEnum.FREE) setSelectPlan(PlanEnum.TEAM) - - setCurrentValue({ - [OrganizationPlanType.FREE]: { disable: true }, - [OrganizationPlanType.PROFESSIONAL]: { number: value.toString(), disable: false }, - [OrganizationPlanType.BUSINESS]: { number: value.toString(), disable: false }, - [OrganizationPlanType.ENTERPRISE]: { disable: false }, - }) - } else { - setCurrentValue({ - [OrganizationPlanType.FREE]: { disable: false }, - [OrganizationPlanType.PROFESSIONAL]: { number: value.toString(), disable: false }, - [OrganizationPlanType.BUSINESS]: { number: value.toString(), disable: false }, - [OrganizationPlanType.ENTERPRISE]: { disable: false }, - }) - } - } - } + const [loading, setLoading] = useState('') - const onSubmit = async () => { - setLoading(true) + const onSubmit = async (plan: PlanEnum) => { + setLoading(plan) - const organization: Organization = await dispatch( + await dispatch( postOrganization({ name: organization_name, - plan: selectPlan, + plan: plan, }) - ).unwrap() - // refresh token needed after created an organization - await getAccessTokenSilently({ ignoreCache: true }) - - if (organization) { - const project: Project = await dispatch( - postProject({ organizationId: organization.id, name: project_name }) - ).unwrap() - - if (project) { - await createAuthCookies() - setLoading(false) - - setTimeout(() => { - const url = `${process.env['NX_URL'] || 'https://console.qovery.com'}?redirectLoginV3` - window.location.replace(url) - }, 500) - } - } else { - setLoading(false) - } + ) + .then(async (result) => { + // refresh token needed after created an organization + await getAccessTokenSilently({ ignoreCache: true }) + + const organization = result.payload as Organization + + if (result.payload) { + const project: Project = await dispatch( + postProject({ organizationId: organization.id, name: project_name }) + ).unwrap() + if (project) { + await createAuthCookies() + setLoading('') + // redirect on the project page + navigate(ENVIRONMENTS_URL(organization.id, project.id) + ENVIRONMENTS_GENERAL_URL) + } + } else { + setLoading('') + } + }) + .catch(() => setLoading('')) } const onClickContact = () => showNewMessages() - return ( - - ) + return } export default OnboardingPricing diff --git a/libs/pages/onboarding/src/lib/feature/onboarding-thanks/onboarding-thanks.tsx b/libs/pages/onboarding/src/lib/feature/onboarding-thanks/onboarding-thanks.tsx index 11ef84e042..206b7471da 100644 --- a/libs/pages/onboarding/src/lib/feature/onboarding-thanks/onboarding-thanks.tsx +++ b/libs/pages/onboarding/src/lib/feature/onboarding-thanks/onboarding-thanks.tsx @@ -10,14 +10,12 @@ export function OnboardingThanks() { const { update } = useIntercom() useEffect(() => { - // if (process.env['NODE_ENV'] === 'production') { // update user intercom update({ email: userSignUp?.user_email, name: `${userSignUp?.first_name} ${userSignUp?.last_name}`, userId: user.sub, }) - // } }, [user, userSignUp, update]) return ( diff --git a/libs/pages/onboarding/src/lib/router/router.tsx b/libs/pages/onboarding/src/lib/router/router.tsx index 6e9f52a71a..d877b236b5 100644 --- a/libs/pages/onboarding/src/lib/router/router.tsx +++ b/libs/pages/onboarding/src/lib/router/router.tsx @@ -33,7 +33,7 @@ export const ROUTER_ONBOARDING_STEP_2: Route[] = [ component: , }, { - path: `${ONBOARDING_PRICING_URL}/:plan`, + path: ONBOARDING_PRICING_URL, component: , }, ] diff --git a/libs/pages/onboarding/src/lib/ui/layout-onboarding/layout-onboarding.spec.tsx b/libs/pages/onboarding/src/lib/ui/layout-onboarding/layout-onboarding.spec.tsx deleted file mode 100644 index c33634b079..0000000000 --- a/libs/pages/onboarding/src/lib/ui/layout-onboarding/layout-onboarding.spec.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' -import { render } from '__tests__/utils/setup-jest' - -import LayoutOnboarding, { LayoutOnboardingProps } from './layout-onboarding' - -describe('LayoutOnboarding', () => { - let props: LayoutOnboardingProps - - beforeEach(() => { - props = { - children: React.createElement('div'), - currentStepPosition: 1, - stepsNumber: 5, - getProgressPercentValue: 20, - step: '1', - routes: [], - } - }) - it('should render successfully', () => { - const { baseElement } = render() - expect(baseElement).toBeTruthy() - }) -}) diff --git a/libs/pages/onboarding/src/lib/ui/layout-onboarding/layout-onboarding.tsx b/libs/pages/onboarding/src/lib/ui/layout-onboarding/layout-onboarding.tsx deleted file mode 100644 index ca65aa0b6a..0000000000 --- a/libs/pages/onboarding/src/lib/ui/layout-onboarding/layout-onboarding.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Route } from '@qovery/shared/router' -import { Navbar } from '@qovery/shared/ui' -import OnboardingRightContent from '../onboarding-right-content/onboarding-right-content' - -export interface LayoutOnboardingProps { - children: React.ReactElement - currentStepPosition: number - stepsNumber: number - getProgressPercentValue: number - step: string | undefined - catchline: string - routes: Route[] -} - -export function LayoutOnboarding(props: LayoutOnboardingProps) { - const { children, currentStepPosition, stepsNumber, getProgressPercentValue, step, catchline } = props - - return ( -
- -
- {currentStepPosition}/{stepsNumber} -
-

{catchline}

- - } - /> -
-
-
{children}
-
-
- -
-
-
- ) -} - -export default LayoutOnboarding diff --git a/libs/pages/onboarding/src/lib/ui/onboarding-right-content/onboarding-right-content.tsx b/libs/pages/onboarding/src/lib/ui/onboarding-right-content/onboarding-right-content.tsx index 2127ffd88c..4337064f22 100644 --- a/libs/pages/onboarding/src/lib/ui/onboarding-right-content/onboarding-right-content.tsx +++ b/libs/pages/onboarding/src/lib/ui/onboarding-right-content/onboarding-right-content.tsx @@ -1,45 +1,5 @@ -import { - ONBOARDING_PRICING_BUSINESS_URL, - ONBOARDING_PRICING_ENTERPRISE_URL, - ONBOARDING_PRICING_FREE_URL, - ONBOARDING_PRICING_PRO_URL, - ONBOARDING_PROJECT_URL, -} from '@qovery/shared/router' +import { ONBOARDING_PROJECT_URL } from '@qovery/shared/router' import BenefitsCard from '../benefits-card/benefits-card' -import PlanList from '../plan-list/plan-list' - -const FreeList = [ - Deploy on your AWS account, - 3 users, - Up to 10 applications, - Github, and Gitlab auto-deploy, - Managed infrastructure, - Community support (forum), -] - -const ProList = [ - All FREE features, - 15 users included, - Unlimited applications, - Application auto-scaling, - Preview environment (optional), - 24/5 support (email and chat), -] - -const BusinessList = [ - All PROFESSIONAL features, - 30 users included, - Multi clusters, - Single Sign-On (SSO), - Cloud cost optimization, - Priority support, -] - -const EnterpriseList = [ - Extended security and compliance, - Hybrid cloud, - 24/7 support, -] export interface OnboardingRightContentProps { step: string | undefined @@ -51,29 +11,9 @@ export function OnboardingRightContent(props: OnboardingRightContentProps) { const detectCurrentStep = (path: string) => step === path.replace('/', '') return ( -
+
{detectCurrentStep(ONBOARDING_PROJECT_URL) ? ( - ) : detectCurrentStep(ONBOARDING_PRICING_FREE_URL) ? ( - - ) : detectCurrentStep(ONBOARDING_PRICING_PRO_URL) ? ( - - ) : detectCurrentStep(ONBOARDING_PRICING_BUSINESS_URL) ? ( - - ) : detectCurrentStep(ONBOARDING_PRICING_ENTERPRISE_URL) ? ( - ) : ( { @@ -7,11 +7,13 @@ describe('PlanCard', () => { beforeEach(() => { props = { - name: OrganizationPlanType.FREE, - selected: OrganizationPlanType.FREE, + name: PlanEnum.FREE, title: 'Free', text: 'Adapted for personnal project', onClick: jest.fn(), + loading: '', + price: 200, + list: ['test'], } }) @@ -19,4 +21,21 @@ describe('PlanCard', () => { const { baseElement } = render() expect(baseElement).toBeTruthy() }) + + it('should have text content', () => { + const { baseElement } = render() + + expect(baseElement.textContent).toContain(props.title) + expect(baseElement.textContent).toContain(props.text) + expect(baseElement.textContent).toContain(`$${props.price}`) + expect(baseElement.textContent).toContain(props.list[0]) + }) + + it('should Custom text for Enterprise plan', () => { + props.name = PlanEnum.ENTERPRISE + + const { baseElement } = render() + + expect(baseElement.textContent).toContain('Custom') + }) }) diff --git a/libs/pages/onboarding/src/lib/ui/plan-card/plan-card.tsx b/libs/pages/onboarding/src/lib/ui/plan-card/plan-card.tsx index 853eca4a13..7ca5e00058 100644 --- a/libs/pages/onboarding/src/lib/ui/plan-card/plan-card.tsx +++ b/libs/pages/onboarding/src/lib/ui/plan-card/plan-card.tsx @@ -1,52 +1,49 @@ -import { OrganizationPlanType, OrganizationPrice } from '@qovery/domains/organization' -import { InputRadio } from '@qovery/shared/ui' +import { PlanEnum } from 'qovery-typescript-axios' +import { Button, ButtonSize, ButtonStyle, Icon, IconAwesomeEnum } from '@qovery/shared/ui' export interface PlanCardProps { - name: string - selected: string title: string + name: string text: string - price?: number - listPrice?: OrganizationPrice[] - currentValue?: { [name: string]: { number?: string | undefined } } - onClick: (plan: string) => void - disable?: boolean | undefined + onClick: () => void + loading: string + price: number + list: string[] } export function PlanCard(props: PlanCardProps) { - const { name, selected, title, text, price, listPrice = [], currentValue = {}, onClick, disable = false } = props + const { name, title, text, price, loading, onClick, list } = props return ( -
(!disable ? onClick(name) : null)} - > -
- -
-

- {title} plan -

-

{text}

-
-
- {name !== OrganizationPlanType.ENTERPRISE && ( -

- {'$'} - {name === OrganizationPlanType.PROFESSIONAL} - {name === OrganizationPlanType.FREE && price} - {name === OrganizationPlanType.BUSINESS && - listPrice.find((p) => p.number === currentValue[OrganizationPlanType.BUSINESS].number)?.price} - {name === OrganizationPlanType.PROFESSIONAL && - listPrice.find((p) => p.number === currentValue[OrganizationPlanType.PROFESSIONAL].number)?.price} - / Month -

- )} - {name === OrganizationPlanType.ENTERPRISE &&

Contact us

} +
+

{title}

+

{text}

+

+ {name !== PlanEnum.ENTERPRISE ? ( + <> + ${price} per user/month + + ) : ( + Custom + )} +

+ +
    + {list.map((line: string, index: number) => ( +
  • + + {line} +
  • + ))} +
) } diff --git a/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.spec.tsx b/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.spec.tsx index e8c362570e..4b9aef5f3f 100644 --- a/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.spec.tsx +++ b/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.spec.tsx @@ -1,4 +1,3 @@ -import { ResizeObserver } from '__tests__/utils/resize-observer' import { render } from '__tests__/utils/setup-jest' import { PlanEnum } from 'qovery-typescript-axios' import StepPricing from './step-pricing' @@ -6,26 +5,20 @@ import { StepPricingProps } from './step-pricing' describe('StepPricing', () => { let props: StepPricingProps - window.ResizeObserver = ResizeObserver beforeEach(() => { props = { - selectPlan: PlanEnum.ENTERPRISE, - setSelectPlan: jest.fn(), plans: [ { name: PlanEnum.ENTERPRISE, title: 'some-title', text: 'bla bla', price: 49, - listPrice: [{ number: '1', price: '100' }], + list: ['hello'], }, ], - chooseDeploy: jest.fn(), - currentValue: { [PlanEnum.ENTERPRISE]: { disable: false, number: '1' } }, - currentDeploy: 100, onSubmit: jest.fn(), - loading: false, + loading: '', onClickContact: jest.fn(), } }) diff --git a/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.tsx b/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.tsx index 03dde2a76e..a1ff0cce3c 100644 --- a/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.tsx +++ b/libs/pages/onboarding/src/lib/ui/step-pricing/step-pricing.tsx @@ -1,61 +1,23 @@ import { PlanEnum } from 'qovery-typescript-axios' -import { OrganizationPlan } from '@qovery/domains/organization' import { ONBOARDING_PROJECT_URL, ONBOARDING_URL } from '@qovery/shared/router' -import { Button, ButtonSize, ButtonStyle, Icon, Slider } from '@qovery/shared/ui' -import { PlanCard } from '../plan-card/plan-card' +import { Button, ButtonSize, ButtonStyle, Icon } from '@qovery/shared/ui' +import { OrganizationPlan } from '../../feature/onboarding-pricing/onboarding-pricing' +import PlanCard from '../plan-card/plan-card' export interface StepPricingProps { - selectPlan: PlanEnum - setSelectPlan: (value: PlanEnum) => void plans: OrganizationPlan[] - chooseDeploy: (value: number | null) => void - currentValue: { [name: string]: { number?: string | undefined; disable: boolean | undefined } } - currentDeploy: number - onSubmit: () => void - loading: boolean + onSubmit: (plan: PlanEnum) => void + loading: string onClickContact: () => void } export function StepPricing(props: StepPricingProps) { - const { - selectPlan, - setSelectPlan, - plans, - chooseDeploy, - currentValue, - currentDeploy, - onSubmit, - loading, - onClickContact, - } = props - - const priceParagraph = () => { - const currentPlans = plans.find((plan) => plan.name === selectPlan) - - if (currentPlans && currentPlans.price > 0) { - const nbDeploy = selectPlan === PlanEnum.TEAM ? 1000 : 300 - let deploymentPrice = 0 - - if (currentDeploy > nbDeploy) { - deploymentPrice = ((currentDeploy - nbDeploy) / 100) * 50 - } - - return ( -

- {`Price computed as: Base Plan (${ - currentPlans?.price - }$) + ${currentDeploy} Deployments (${deploymentPrice}$) = ${currentPlans?.price + deploymentPrice}$`} -

- ) - } else { - return null - } - } + const { onSubmit, plans, loading } = props return (
-

Simple, transparent pricing

-

+

Simple, transparent pricing

+

14 days trial with no credit card required for all paid plans - .

-
- chooseDeploy(value[0])} - /> +
+ {plans.map((plan: OrganizationPlan) => ( + onSubmit(plan.name)} loading={loading} {...plan} /> + ))}
- - {plans.map((plan: OrganizationPlan) => ( - setSelectPlan(plan.name)} - disable={currentValue[plan.name] && currentValue[plan.name].disable} - /> - ))} - {priceParagraph()} -

Price plan does not include your AWS costs

- {selectPlan === PlanEnum.ENTERPRISE && ( - - )} - {selectPlan !== PlanEnum.ENTERPRISE && ( - - )}
diff --git a/libs/shared/router/src/lib/sub-router/onboarding.router.ts b/libs/shared/router/src/lib/sub-router/onboarding.router.ts index 6cf82af78b..62374298ab 100644 --- a/libs/shared/router/src/lib/sub-router/onboarding.router.ts +++ b/libs/shared/router/src/lib/sub-router/onboarding.router.ts @@ -2,9 +2,5 @@ export const ONBOARDING_URL = '/onboarding' export const ONBOARDING_PERSONALIZE_URL = '/personalize' export const ONBOARDING_MORE_URL = '/more' export const ONBOARDING_PRICING_URL = '/pricing' -export const ONBOARDING_PRICING_FREE_URL = `${ONBOARDING_PRICING_URL}/free` -export const ONBOARDING_PRICING_PRO_URL = `${ONBOARDING_PRICING_URL}/professional` -export const ONBOARDING_PRICING_BUSINESS_URL = `${ONBOARDING_PRICING_URL}/business` -export const ONBOARDING_PRICING_ENTERPRISE_URL = `${ONBOARDING_PRICING_URL}/enterprise` export const ONBOARDING_PROJECT_URL = '/project' export const ONBOARDING_THANKS_URL = '/thanks' diff --git a/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.spec.tsx b/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.spec.tsx index 4c4708349e..679827a7da 100644 --- a/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.spec.tsx +++ b/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.spec.tsx @@ -1,4 +1,4 @@ -import { getByTestId, getByText } from '@testing-library/react' +import { getByTestId, getByText, queryByTestId } from '@testing-library/react' import { render } from '__tests__/utils/setup-jest' import { ReactNode } from 'react' import FunnelFlowBody from './funnel-flow-body' @@ -29,4 +29,10 @@ describe('FunnelFlowBody', () => { getByText(getByTestId(baseElement, 'funnel-body-content'), 'Content') }) + + it('should not render help section on the side', () => { + const { baseElement } = render({children}) + + expect(queryByTestId(baseElement, 'funnel-body-help')).toBeNull() + }) }) diff --git a/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.tsx b/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.tsx index 45b0fccd8b..89e60824c2 100644 --- a/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.tsx +++ b/libs/shared/ui/src/lib/components/funnel-flow-body/funnel-flow-body.tsx @@ -1,17 +1,23 @@ export interface FunnelFlowBodyProps { children: React.ReactNode + helpSectionClassName?: string helpSection?: React.ReactNode + customContentWidth?: string } export function FunnelFlowBody(props: FunnelFlowBodyProps) { return ( <> -
+ {props.helpSection && ( +
+ )}
-
+
{props.children}
@@ -20,7 +26,9 @@ export function FunnelFlowBody(props: FunnelFlowBodyProps) {
-
- -
+ {props.onExit && ( +
+ +
+ )}
+ />
{props.children}