diff --git a/frontend/src/scenes/onboarding/Onboarding.tsx b/frontend/src/scenes/onboarding/Onboarding.tsx index c3520d90bea01..cb1c980f06923 100644 --- a/frontend/src/scenes/onboarding/Onboarding.tsx +++ b/frontend/src/scenes/onboarding/Onboarding.tsx @@ -4,15 +4,13 @@ import { useEffect, useState } from 'react' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { FEATURE_FLAGS } from 'lib/constants' import { urls } from 'scenes/urls' -import { onboardingLogic } from './onboardingLogic' +import { OnboardingStepKey, onboardingLogic } from './onboardingLogic' import { SDKs } from './sdks/SDKs' -import { OnboardingProductIntro } from './OnboardingProductIntro' import { ProductKey } from '~/types' import { ProductAnalyticsSDKInstructions } from './sdks/product-analytics/ProductAnalyticsSDKInstructions' import { SessionReplaySDKInstructions } from './sdks/session-replay/SessionReplaySDKInstructions' import { OnboardingBillingStep } from './OnboardingBillingStep' import { OnboardingOtherProductsStep } from './OnboardingOtherProductsStep' -import { teamLogic } from 'scenes/teamLogic' import { OnboardingVerificationStep } from './OnboardingVerificationStep' import { FeatureFlagsSDKInstructions } from './sdks/feature-flags/FeatureFlagsSDKInstructions' @@ -24,8 +22,8 @@ export const scene: SceneExport = { /** * Wrapper for custom onboarding content. This automatically includes the product intro and billing step. */ -const OnboardingWrapper = ({ children, onStart }: { children: React.ReactNode; onStart?: () => void }): JSX.Element => { - const { currentOnboardingStepNumber, shouldShowBillingStep } = useValues(onboardingLogic) +const OnboardingWrapper = ({ children }: { children: React.ReactNode }): JSX.Element => { + const { currentOnboardingStep, shouldShowBillingStep, shouldShowOtherProductsStep } = useValues(onboardingLogic) const { setAllOnboardingSteps } = useActions(onboardingLogic) const { product } = useValues(onboardingLogic) const [allSteps, setAllSteps] = useState([]) @@ -46,49 +44,50 @@ const OnboardingWrapper = ({ children, onStart }: { children: React.ReactNode; o } const createAllSteps = (): void => { - const ProductIntro = - const OtherProductsStep = let steps = [] if (Array.isArray(children)) { - steps = [ProductIntro, ...children] + steps = [...children] } else { - steps = [ProductIntro, children as JSX.Element] + steps = [children as JSX.Element] } if (shouldShowBillingStep) { - const BillingStep = + const BillingStep = steps = [...steps, BillingStep] } - steps = [...steps, OtherProductsStep] + if (shouldShowOtherProductsStep) { + const OtherProductsStep = + steps = [...steps, OtherProductsStep] + } setAllSteps(steps) } - return (allSteps[currentOnboardingStepNumber - 1] as JSX.Element) || <> + return (currentOnboardingStep as JSX.Element) || <> } const ProductAnalyticsOnboarding = (): JSX.Element => { return ( - - + + ) } const SessionReplayOnboarding = (): JSX.Element => { - const { updateCurrentTeam } = useActions(teamLogic) return ( - { - updateCurrentTeam({ - session_recording_opt_in: true, - capture_console_log_opt_in: true, - capture_performance_opt_in: true, - }) - }} - > + ) @@ -100,6 +99,7 @@ const FeatureFlagsOnboarding = (): JSX.Element => { usersAction="loading flags" sdkInstructionMap={FeatureFlagsSDKInstructions} subtitle="Choose the framework where you want to use feature flags, or use our all-purpose JavaScript library. If you already have the snippet installed, you can skip this step!" + stepKey={OnboardingStepKey.SDKS} /> ) diff --git a/frontend/src/scenes/onboarding/OnboardingBillingStep.tsx b/frontend/src/scenes/onboarding/OnboardingBillingStep.tsx index 6daba12e33fe6..c6901e9d7b829 100644 --- a/frontend/src/scenes/onboarding/OnboardingBillingStep.tsx +++ b/frontend/src/scenes/onboarding/OnboardingBillingStep.tsx @@ -2,7 +2,7 @@ import { OnboardingStep } from './OnboardingStep' import { PlanComparison } from 'scenes/billing/PlanComparison' import { useActions, useValues } from 'kea' import { billingLogic } from 'scenes/billing/billingLogic' -import { onboardingLogic } from './onboardingLogic' +import { OnboardingStepKey, onboardingLogic } from './onboardingLogic' import { BillingProductV2Type } from '~/types' import { Spinner } from 'lib/lemon-ui/Spinner' import { BillingHero } from 'scenes/billing/BillingHero' @@ -13,7 +13,13 @@ import { eventUsageLogic } from 'lib/utils/eventUsageLogic' import { IconCheckCircleOutline } from 'lib/lemon-ui/icons' import { StarHog } from 'lib/components/hedgehogs' -export const OnboardingBillingStep = ({ product }: { product: BillingProductV2Type }): JSX.Element => { +export const OnboardingBillingStep = ({ + product, + stepKey = OnboardingStepKey.BILLING, +}: { + product: BillingProductV2Type + stepKey?: OnboardingStepKey +}): JSX.Element => { const { billing, redirectPath } = useValues(billingLogic) const { productKey } = useValues(onboardingLogic) const { currentAndUpgradePlans } = useValues(billingProductLogic({ product })) @@ -24,6 +30,7 @@ export const OnboardingBillingStep = ({ product }: { product: BillingProductV2Ty { +export const OnboardingOtherProductsStep = ({ + stepKey = OnboardingStepKey.OTHER_PRODUCTS, +}: { + stepKey?: OnboardingStepKey +}): JSX.Element => { const { product, suggestedProducts } = useValues(onboardingLogic) const { completeOnboarding } = useActions(onboardingLogic) - if (suggestedProducts.length === 0) { - completeOnboarding() - } return ( { subtitle="The magic in PostHog is having everyting all in one place. Get started with our other products to unlock your product and data superpowers." showSkip continueOverride={<>} + stepKey={stepKey} >
{suggestedProducts?.map((suggestedProduct) => ( diff --git a/frontend/src/scenes/onboarding/OnboardingProductIntro.tsx b/frontend/src/scenes/onboarding/OnboardingProductIntro.tsx deleted file mode 100644 index 3119e70f76106..0000000000000 --- a/frontend/src/scenes/onboarding/OnboardingProductIntro.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { useActions, useValues } from 'kea' -import { LemonButton, Link } from '@posthog/lemon-ui' -import { onboardingLogic } from './onboardingLogic' -import { billingProductLogic } from 'scenes/billing/billingProductLogic' -import { convertLargeNumberToWords } from 'scenes/billing/billing-utils' -import { BillingProductV2Type } from '~/types' -import { LemonCard } from 'lib/lemon-ui/LemonCard/LemonCard' -import { ProductPricingModal } from 'scenes/billing/ProductPricingModal' -import { IconArrowLeft, IconCheckCircleOutline, IconOpenInNew } from 'lib/lemon-ui/icons' -import { urls } from 'scenes/urls' -import { PlanComparisonModal } from 'scenes/billing/PlanComparison' - -export const OnboardingProductIntro = ({ - product, - onStart, -}: { - product: BillingProductV2Type - onStart?: () => void -}): JSX.Element => { - const { currentAndUpgradePlans, isPricingModalOpen, isPlanComparisonModalOpen } = useValues( - billingProductLogic({ product }) - ) - const { toggleIsPricingModalOpen, toggleIsPlanComparisonModalOpen } = useActions(billingProductLogic({ product })) - const { setCurrentOnboardingStepNumber } = useActions(onboardingLogic) - const { currentOnboardingStepNumber } = useValues(onboardingLogic) - - const pricingBenefits = [ - 'Only pay for what you use', - 'Control spend with billing limits as low as $0/mo', - 'Generous free volume every month, forever', - ] - - const productWebsiteKey = product.type.replace('_', '-') - const communityUrl = 'https://posthog.com/questions/topic/' + productWebsiteKey - const tutorialsUrl = 'https://posthog.com/tutorials/categories/' + productWebsiteKey - const productPageUrl = 'https://posthog.com/' + productWebsiteKey - const productImageUrl = `https://posthog.com/images/product/${productWebsiteKey}-product.png` - - const upgradePlan = currentAndUpgradePlans?.upgradePlan - const plan = upgradePlan ? upgradePlan : currentAndUpgradePlans?.currentPlan - const freePlan = currentAndUpgradePlans?.downgradePlan || currentAndUpgradePlans?.currentPlan - - return ( -
-
-
-
-
- } - type="tertiary" - status="muted" - noPadding - size="small" - > - All products - -
-

{product.name}

-

{product.description}

-
- { - onStart && onStart() - setCurrentOnboardingStepNumber(currentOnboardingStepNumber + 1) - }} - > - Get started - - {product.docs_url && ( - - Learn more - - )} -
-
-
- -
-
-
-
-
-

Features

-
- {plan?.features?.map((feature, i) => ( -
  • -
    - -
    -
    -

    {feature.name}

    -

    {feature.description}

    -
    -
  • - ))} -
    -
    -
    - -

    Pricing

    - {plan?.tiers?.[0].unit_amount_usd && parseInt(plan?.tiers?.[0].unit_amount_usd) === 0 && ( -

    - - First {convertLargeNumberToWords(plan?.tiers?.[0].up_to, null)} {product.unit}s free - - , then ${plan?.tiers?.[1].unit_amount_usd} - /{product.unit}.{' '} - { - toggleIsPricingModalOpen() - }} - > - Volume discounts - {' '} - after {convertLargeNumberToWords(plan?.tiers?.[1].up_to, null)}/mo. -

    - )} -
      - {pricingBenefits.map((benefit, i) => ( -
    • - - {benefit} -
    • - ))} -
    - {!product.subscribed && freePlan.free_allocation && ( -

    - Or stick with our generous free plan and get{' '} - {convertLargeNumberToWords(freePlan.free_allocation, null)} {product.unit}s free every - month, forever.{' '} - { - toggleIsPlanComparisonModalOpen() - }} - > - View plan comparison. - - toggleIsPlanComparisonModalOpen()} - /> -

    - )} -
    - -

    Resources

    - {product.docs_url && ( -

    - - Documentation - -

    - )} -

    - - Community forum - -

    -

    - - Tutorials - -

    -
    -
    -
    - -
    - ) -} diff --git a/frontend/src/scenes/onboarding/OnboardingStep.tsx b/frontend/src/scenes/onboarding/OnboardingStep.tsx index b32c9fdc13a3d..a4bfdd92cbf42 100644 --- a/frontend/src/scenes/onboarding/OnboardingStep.tsx +++ b/frontend/src/scenes/onboarding/OnboardingStep.tsx @@ -1,10 +1,13 @@ import { LemonButton } from '@posthog/lemon-ui' import { BridgePage } from 'lib/components/BridgePage/BridgePage' -import { onboardingLogic } from './onboardingLogic' +import { OnboardingStepKey, onboardingLogic } from './onboardingLogic' import { useActions, useValues } from 'kea' import { IconArrowLeft, IconArrowRight } from 'lib/lemon-ui/icons' +import { router } from 'kea-router' +import { urls } from 'scenes/urls' export const OnboardingStep = ({ + stepKey, title, subtitle, children, @@ -12,6 +15,7 @@ export const OnboardingStep = ({ onSkip, continueOverride, }: { + stepKey: OnboardingStepKey title: string subtitle?: string children: React.ReactNode @@ -19,9 +23,12 @@ export const OnboardingStep = ({ onSkip?: () => void continueOverride?: JSX.Element }): JSX.Element => { - const { currentOnboardingStepNumber, totalOnboardingSteps } = useValues(onboardingLogic) - const { setCurrentOnboardingStepNumber, completeOnboarding } = useActions(onboardingLogic) - const isLastStep = currentOnboardingStepNumber == totalOnboardingSteps + const { hasNextStep, hasPreviousStep } = useValues(onboardingLogic) + const { completeOnboarding, goToNextStep, goToPreviousStep } = useActions(onboardingLogic) + if (!stepKey) { + throw new Error('stepKey is required in any OnboardingStep') + } + return ( 1 && ( -
    - } - onClick={() => setCurrentOnboardingStepNumber(currentOnboardingStepNumber - 1)} - > - Back - -
    - ) +
    + } + onClick={() => (hasPreviousStep ? goToPreviousStep() : router.actions.push(urls.products()))} + > + Back + +
    } >
    @@ -51,13 +56,11 @@ export const OnboardingStep = ({ type="tertiary" onClick={() => { onSkip && onSkip() - isLastStep - ? completeOnboarding() - : setCurrentOnboardingStepNumber(currentOnboardingStepNumber + 1) + !hasNextStep ? completeOnboarding() : goToNextStep() }} status="muted" > - Skip {isLastStep ? 'and finish' : 'for now'} + Skip {!hasNextStep ? 'and finish' : 'for now'} )} {continueOverride ? ( @@ -65,14 +68,10 @@ export const OnboardingStep = ({ ) : ( - currentOnboardingStepNumber == totalOnboardingSteps - ? completeOnboarding() - : setCurrentOnboardingStepNumber(currentOnboardingStepNumber + 1) - } - sideIcon={currentOnboardingStepNumber !== totalOnboardingSteps ? : null} + onClick={() => (!hasNextStep ? completeOnboarding() : goToNextStep())} + sideIcon={hasNextStep ? : null} > - {currentOnboardingStepNumber == totalOnboardingSteps ? 'Finish' : 'Continue'} + {!hasNextStep ? 'Finish' : 'Continue'} )}
    diff --git a/frontend/src/scenes/onboarding/OnboardingVerificationStep.tsx b/frontend/src/scenes/onboarding/OnboardingVerificationStep.tsx index 7b55f2f139bd2..11ba1dc4fd065 100644 --- a/frontend/src/scenes/onboarding/OnboardingVerificationStep.tsx +++ b/frontend/src/scenes/onboarding/OnboardingVerificationStep.tsx @@ -6,13 +6,16 @@ import { eventUsageLogic } from 'lib/utils/eventUsageLogic' import { useInterval } from 'lib/hooks/useInterval' import { BlushingHog } from 'lib/components/hedgehogs' import { capitalizeFirstLetter } from 'lib/utils' +import { OnboardingStepKey } from './onboardingLogic' export const OnboardingVerificationStep = ({ listeningForName, teamPropertyToVerify, + stepKey = OnboardingStepKey.VERIFY, }: { listeningForName: string teamPropertyToVerify: string + stepKey?: OnboardingStepKey }): JSX.Element => { const { loadCurrentTeam } = useActions(teamLogic) const { currentTeam } = useValues(teamLogic) @@ -29,6 +32,7 @@ export const OnboardingVerificationStep = ({ title={`Listening for ${listeningForName}s...`} subtitle={`Once you have integrated the snippet, we will verify the ${listeningForName} was properly received. It can take up to 2 minutes to recieve the ${listeningForName}.`} showSkip={true} + stepKey={stepKey} onSkip={() => { reportIngestionContinueWithoutVerifying() }} @@ -42,6 +46,7 @@ export const OnboardingVerificationStep = ({
    diff --git a/frontend/src/scenes/onboarding/onboardingLogic.tsx b/frontend/src/scenes/onboarding/onboardingLogic.tsx index 2e980cf9f3574..a83f33d5b51fd 100644 --- a/frontend/src/scenes/onboarding/onboardingLogic.tsx +++ b/frontend/src/scenes/onboarding/onboardingLogic.tsx @@ -21,17 +21,9 @@ export enum OnboardingStepKey { VERIFY = 'verify', } -export type OnboardingStepMap = Record - -const onboardingStepMap: OnboardingStepMap = { - [OnboardingStepKey.PRODUCT_INTRO]: 'OnboardingProductIntro', - [OnboardingStepKey.SDKS]: 'SDKs', - [OnboardingStepKey.BILLING]: 'OnboardingBillingStep', - [OnboardingStepKey.OTHER_PRODUCTS]: 'OnboardingOtherProductsStep', - [OnboardingStepKey.VERIFY]: 'OnboardingVerificationStep', -} - -export type AllOnboardingSteps = JSX.Element[] +// These types have to be set like this, so that kea typegen is happy +export type AllOnboardingSteps = OnboardingStep[] +export type OnboardingStep = JSX.Element export const getProductUri = (productKey: ProductKey): string => { switch (productKey) { @@ -56,11 +48,13 @@ export const onboardingLogic = kea({ actions: { setProduct: (product: BillingProductV2Type | null) => ({ product }), setProductKey: (productKey: string | null) => ({ productKey }), - setCurrentOnboardingStepNumber: (currentOnboardingStepNumber: number) => ({ currentOnboardingStepNumber }), completeOnboarding: (nextProductKey?: string) => ({ nextProductKey }), setAllOnboardingSteps: (allOnboardingSteps: AllOnboardingSteps) => ({ allOnboardingSteps }), setStepKey: (stepKey: string) => ({ stepKey }), setSubscribedDuringOnboarding: (subscribedDuringOnboarding: boolean) => ({ subscribedDuringOnboarding }), + goToNextStep: true, + goToPreviousStep: true, + resetStepKey: true, }, reducers: () => ({ productKey: [ @@ -75,12 +69,6 @@ export const onboardingLogic = kea({ setProduct: (_, { product }) => product, }, ], - currentOnboardingStepNumber: [ - 1, - { - setCurrentOnboardingStepNumber: (_, { currentOnboardingStepNumber }) => currentOnboardingStepNumber, - }, - ], allOnboardingSteps: [ [] as AllOnboardingSteps, { @@ -93,7 +81,7 @@ export const onboardingLogic = kea({ setStepKey: (_, { stepKey }) => stepKey, }, ], - onCompleteOnbardingRedirectUrl: [ + onCompleteOnboardingRedirectUrl: [ urls.default() as string, { setProductKey: (_, { productKey }) => { @@ -113,6 +101,25 @@ export const onboardingLogic = kea({ (s) => [s.allOnboardingSteps], (allOnboardingSteps: AllOnboardingSteps) => allOnboardingSteps.length, ], + currentOnboardingStep: [ + (s) => [s.allOnboardingSteps, s.stepKey], + (allOnboardingSteps: AllOnboardingSteps, stepKey: OnboardingStepKey): OnboardingStep | null => + allOnboardingSteps.find((step) => step.props.stepKey === stepKey) || null, + ], + hasNextStep: [ + (s) => [s.allOnboardingSteps, s.stepKey], + (allOnboardingSteps: AllOnboardingSteps, stepKey: OnboardingStepKey) => { + const currentStepIndex = allOnboardingSteps.findIndex((step) => step.props.stepKey === stepKey) + return currentStepIndex < allOnboardingSteps.length - 1 + }, + ], + hasPreviousStep: [ + (s) => [s.allOnboardingSteps, s.stepKey], + (allOnboardingSteps: AllOnboardingSteps, stepKey: OnboardingStepKey) => { + const currentStepIndex = allOnboardingSteps.findIndex((step) => step.props.stepKey === stepKey) + return currentStepIndex > 0 + }, + ], shouldShowBillingStep: [ (s) => [s.product, s.subscribedDuringOnboarding], (product: BillingProductV2Type | null, subscribedDuringOnboarding: boolean) => { @@ -120,6 +127,10 @@ export const onboardingLogic = kea({ return !product?.subscribed || !hasAllAddons || subscribedDuringOnboarding }, ], + shouldShowOtherProductsStep: [ + (s) => [s.suggestedProducts], + (suggestedProducts: BillingProductV2Type[]) => suggestedProducts.length > 0, + ], suggestedProducts: [ (s) => [s.billing, s.product, s.currentTeam], (billing, product, currentTeam) => @@ -131,6 +142,12 @@ export const onboardingLogic = kea({ !currentTeam?.has_completed_onboarding_for?.[p.type] ) || [], ], + isStepKeyInvalid: [ + (s) => [s.stepKey, s.allOnboardingSteps, s.currentOnboardingStep], + (stepKey: string, allOnboardingSteps: AllOnboardingSteps, currentOnboardingStep: React.ReactNode | null) => + (stepKey && allOnboardingSteps.length > 0 && !currentOnboardingStep) || + (!stepKey && allOnboardingSteps.length > 0), + ], }, listeners: ({ actions, values }) => ({ loadBillingSuccess: () => { @@ -175,74 +192,53 @@ export const onboardingLogic = kea({ }) } }, - setAllOnboardingSteps: ({ allOnboardingSteps }) => { - // once we have the onboarding steps we need to make sure the step key is valid, - // and if so use it to set the step number. if not valid, remove it from the state. - // valid step keys are either numbers (used for unnamed steps) or keys from the onboardingStepMap. - // if it's a number, we try to convert it to a named step key using the onboardingStepMap. - let stepKey = values.stepKey - if (values.stepKey) { - if (parseInt(values.stepKey) > 0) { - // try to convert the step number to a step key - const stepName = allOnboardingSteps[parseInt(values.stepKey) - 1]?.type?.name - const newStepKey = Object.keys(onboardingStepMap).find((key) => onboardingStepMap[key] === stepName) - if (stepName && stepKey) { - stepKey = newStepKey || stepKey - actions.setStepKey(stepKey) - } - } - if (stepKey in onboardingStepMap) { - const stepIndex = allOnboardingSteps - .map((step) => step.type.name) - .indexOf(onboardingStepMap[stepKey as OnboardingStepKey]) - if (stepIndex > -1) { - actions.setCurrentOnboardingStepNumber(stepIndex + 1) - } else { - actions.setStepKey('') - actions.setCurrentOnboardingStepNumber(1) - } - } else if ( - // if it's a number, just use that and set the correct onboarding step number - parseInt(stepKey) > 1 && - allOnboardingSteps.length > 0 && - allOnboardingSteps[parseInt(stepKey) - 1] - ) { - actions.setCurrentOnboardingStepNumber(parseInt(stepKey)) - } + setAllOnboardingSteps: () => { + if (values.isStepKeyInvalid) { + actions.resetStepKey() } }, - setStepKey: ({ stepKey }) => { - // if the step key is invalid (doesn't exist in the onboardingStepMap or the allOnboardingSteps array) - // remove it from the state. Numeric step keys are also allowed, as long as they are a valid - // index for the allOnboardingSteps array. - if ( - stepKey && - values.allOnboardingSteps.length > 0 && - (!values.allOnboardingSteps.find( - (step) => step.type.name === onboardingStepMap[stepKey as OnboardingStepKey] - ) || - !values.allOnboardingSteps[parseInt(stepKey) - 1]) - ) { - actions.setStepKey('') + setStepKey: () => { + if (values.isStepKeyInvalid) { + actions.resetStepKey() } }, + resetStepKey: () => { + actions.setStepKey(values.allOnboardingSteps[0].props.stepKey) + }, }), actionToUrl: ({ values }) => ({ - setCurrentOnboardingStepNumber: () => { - // when the current step number changes, update the url to reflect the new step - const stepName = values.allOnboardingSteps[values.currentOnboardingStepNumber - 1]?.type?.name - const stepKey = - Object.keys(onboardingStepMap).find((key) => onboardingStepMap[key] === stepName) || - values.currentOnboardingStepNumber.toString() + setStepKey: ({ stepKey }) => { if (stepKey) { return [`/onboarding/${values.productKey}`, { step: stepKey }] } else { return [`/onboarding/${values.productKey}`] } }, + goToNextStep: () => { + const currentStepIndex = values.allOnboardingSteps.findIndex( + (step) => step.props.stepKey === values.stepKey + ) + const nextStep = values.allOnboardingSteps[currentStepIndex + 1] + if (nextStep) { + return [`/onboarding/${values.productKey}`, { step: nextStep.props.stepKey }] + } else { + return [`/onboarding/${values.productKey}`] + } + }, + goToPreviousStep: () => { + const currentStepIndex = values.allOnboardingSteps.findIndex( + (step) => step.props.stepKey === values.stepKey + ) + const previousStep = values.allOnboardingSteps[currentStepIndex - 1] + if (previousStep) { + return [`/onboarding/${values.productKey}`, { step: previousStep.props.stepKey }] + } else { + return [`/onboarding/${values.productKey}`] + } + }, updateCurrentTeamSuccess(val) { if (values.productKey && val.payload?.has_completed_onboarding_for?.[values.productKey]) { - return [values.onCompleteOnbardingRedirectUrl] + return [values.onCompleteOnboardingRedirectUrl] } }, }), @@ -258,10 +254,10 @@ export const onboardingLogic = kea({ if (productKey !== values.productKey) { actions.setProductKey(productKey) } - if (step && (step in onboardingStepMap || parseInt(step) > 0)) { + if (step) { actions.setStepKey(step) } else { - actions.setCurrentOnboardingStepNumber(1) + actions.resetStepKey() } }, }), diff --git a/frontend/src/scenes/onboarding/sdks/SDKs.tsx b/frontend/src/scenes/onboarding/sdks/SDKs.tsx index 9ac4884dd5d40..fda0e0d52e486 100644 --- a/frontend/src/scenes/onboarding/sdks/SDKs.tsx +++ b/frontend/src/scenes/onboarding/sdks/SDKs.tsx @@ -3,7 +3,7 @@ import { sdksLogic } from './sdksLogic' import { useActions, useValues } from 'kea' import { OnboardingStep } from '../OnboardingStep' import { SDKSnippet } from './SDKSnippet' -import { onboardingLogic } from '../onboardingLogic' +import { OnboardingStepKey, onboardingLogic } from '../onboardingLogic' import { useEffect } from 'react' import React from 'react' import { SDKInstructionsMap } from '~/types' @@ -13,10 +13,12 @@ export function SDKs({ usersAction, sdkInstructionMap, subtitle, + stepKey = OnboardingStepKey.SDKS, }: { usersAction?: string sdkInstructionMap: SDKInstructionsMap subtitle?: string + stepKey?: OnboardingStepKey }): JSX.Element { const { setSourceFilter, setSelectedSDK, setAvailableSDKInstructionsMap } = useActions(sdksLogic) const { sourceFilter, sdks, selectedSDK, sourceOptions, showSourceOptionsSelect } = useValues(sdksLogic) @@ -30,6 +32,7 @@ export function SDKs({
    diff --git a/frontend/src/scenes/products/Products.tsx b/frontend/src/scenes/products/Products.tsx index 922665ecdf730..0ed69a30e48b0 100644 --- a/frontend/src/scenes/products/Products.tsx +++ b/frontend/src/scenes/products/Products.tsx @@ -13,7 +13,7 @@ import { Spinner } from 'lib/lemon-ui/Spinner' import { LemonCard } from 'lib/lemon-ui/LemonCard/LemonCard' import { router } from 'kea-router' import { getProductUri } from 'scenes/onboarding/onboardingLogic' -import { eventUsageLogic } from 'lib/utils/eventUsageLogic' +import { productsLogic } from './productsLogic' export const scene: SceneExport = { component: Products, @@ -29,7 +29,7 @@ function OnboardingCompletedButton({ onboardingUrl: string productKey: ProductKey }): JSX.Element { - const { reportOnboardingProductSelected } = useActions(eventUsageLogic) + const { onSelectProduct } = useActions(productsLogic) return ( <> @@ -39,7 +39,7 @@ function OnboardingCompletedButton({ type="tertiary" status="muted" onClick={() => { - reportOnboardingProductSelected(productKey) + onSelectProduct(productKey) router.actions.push(onboardingUrl) }} > @@ -50,12 +50,12 @@ function OnboardingCompletedButton({ } function OnboardingNotCompletedButton({ url, productKey }: { url: string; productKey: ProductKey }): JSX.Element { - const { reportOnboardingProductSelected } = useActions(eventUsageLogic) + const { onSelectProduct } = useActions(productsLogic) return ( { - reportOnboardingProductSelected(productKey) + onSelectProduct(productKey) router.actions.push(url) }} > diff --git a/frontend/src/scenes/products/productsLogic.tsx b/frontend/src/scenes/products/productsLogic.tsx new file mode 100644 index 0000000000000..5c199fd3f3fc1 --- /dev/null +++ b/frontend/src/scenes/products/productsLogic.tsx @@ -0,0 +1,34 @@ +import { kea } from 'kea' +import { teamLogic } from 'scenes/teamLogic' +import { ProductKey } from '~/types' + +import type { productsLogicType } from './productsLogicType' +import { eventUsageLogic } from 'lib/utils/eventUsageLogic' + +export const productsLogic = kea({ + path: () => ['scenes', 'products', 'productsLogic'], + actions: () => ({ + onSelectProduct: (product: ProductKey) => ({ product }), + }), + listeners: () => ({ + onSelectProduct: ({ product }) => { + eventUsageLogic.actions.reportOnboardingProductSelected(product) + + switch (product) { + case ProductKey.PRODUCT_ANALYTICS: + return + case ProductKey.SESSION_REPLAY: + teamLogic.actions.updateCurrentTeam({ + session_recording_opt_in: true, + capture_console_log_opt_in: true, + capture_performance_opt_in: true, + }) + return + case ProductKey.FEATURE_FLAGS: + return + default: + return + } + }, + }), +})