diff --git a/cypress/e2e/billing.cy.ts b/cypress/e2e/billing.cy.ts index a21188c0f42d0..a32b416abc39e 100644 --- a/cypress/e2e/billing.cy.ts +++ b/cypress/e2e/billing.cy.ts @@ -39,6 +39,7 @@ describe('Billing', () => { cy.get('[data-attr=more-button]').first().click() cy.contains('.LemonButton', 'Unsubscribe').click() cy.get('.LemonModal h3').should('contain', 'Unsubscribe from Product analytics') + cy.get('[data-attr=unsubscribe-reason-too-expensive]').click() cy.get('[data-attr=unsubscribe-reason-survey-textarea]').type('Product analytics') cy.contains('.LemonModal .LemonButton', 'Cancel').click() @@ -46,6 +47,7 @@ describe('Billing', () => { cy.get('[data-attr=more-button]').eq(1).click() cy.contains('.LemonButton', 'Unsubscribe').click() cy.get('.LemonModal h3').should('contain', 'Unsubscribe from Session replay') + cy.get('[data-attr=unsubscribe-reason-too-expensive]').click() cy.get('[data-attr=unsubscribe-reason-survey-textarea]').type('Session replay') cy.contains('.LemonModal .LemonButton', 'Cancel').click() diff --git a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--dark.png b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--dark.png index 83009eedca75c..e1b89aae6cea2 100644 Binary files a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--dark.png and b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--dark.png differ diff --git a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--light.png b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--light.png index 1ef92fbabedfa..37bfc40833416 100644 Binary files a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--light.png and b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal--light.png differ diff --git a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--dark.png b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--dark.png index 163316bc42a7e..b725bdd5c50ce 100644 Binary files a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--dark.png and b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--dark.png differ diff --git a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--light.png b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--light.png index 2407ed95965c3..c0d570ba527f9 100644 Binary files a/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--light.png and b/frontend/__snapshots__/scenes-other-billing--billing-unsubscribe-modal-data-pipelines--light.png differ diff --git a/frontend/src/scenes/billing/UnsubscribeSurveyModal.tsx b/frontend/src/scenes/billing/UnsubscribeSurveyModal.tsx index 79d2447260270..18502d80581ec 100644 --- a/frontend/src/scenes/billing/UnsubscribeSurveyModal.tsx +++ b/frontend/src/scenes/billing/UnsubscribeSurveyModal.tsx @@ -9,29 +9,20 @@ import { LemonModal, LemonTextArea, Link, + Tooltip, } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { HeartHog } from 'lib/components/hedgehogs' import { useHogfetti } from 'lib/components/Hogfetti/Hogfetti' import { supportLogic } from 'lib/components/Support/supportLogic' +import { useState } from 'react' import { BillingProductV2AddonType, BillingProductV2Type } from '~/types' import { billingLogic } from './billingLogic' -import { billingProductLogic } from './billingProductLogic' +import { billingProductLogic, randomizeReasons, UNSUBSCRIBE_REASONS } from './billingProductLogic' import { ExportsUnsubscribeTable, exportsUnsubscribeTableLogic } from './ExportsUnsubscribeTable' -const UNSUBSCRIBE_REASONS = [ - 'Too expensive', - 'Not getting enough value', - 'Not using the product', - 'Found a better alternative', - 'Poor customer support', - 'Too difficult to use', - 'Not enough hedgehogs', - 'Other (let us know below!)', -] - export const UnsubscribeSurveyModal = ({ product, }: { @@ -39,7 +30,7 @@ export const UnsubscribeSurveyModal = ({ }): JSX.Element | null => { const { trigger, HogfettiComponent } = useHogfetti() - const { surveyID, surveyResponse, isAddonProduct, unsubscribeModalStep } = useValues( + const { surveyID, surveyResponse, isAddonProduct, unsubscribeModalStep, unsubscribeReasonQuestions } = useValues( billingProductLogic({ product, hogfettiTrigger: trigger }) ) const { @@ -55,6 +46,7 @@ export const UnsubscribeSurveyModal = ({ const { unsubscribeError, billingLoading, billing } = useValues(billingLogic) const { unsubscribeDisabledReason, itemsToDisable } = useValues(exportsUnsubscribeTableLogic) const { openSupportForm } = useActions(supportLogic) + const [randomizedReasons] = useState(randomizeReasons(UNSUBSCRIBE_REASONS)) const textAreaNotEmpty = surveyResponse['$survey_response']?.length > 0 const includesPipelinesAddon = @@ -152,7 +144,15 @@ export const UnsubscribeSurveyModal = ({ @@ -192,30 +192,35 @@ export const UnsubscribeSurveyModal = ({ ? `Why are you ${actionVerb}?` : `Why are you ${actionVerb} from ${product.name}?`}{' '} (you can select multiple) + + * +
- {UNSUBSCRIBE_REASONS.map((reason) => ( + {randomizedReasons.map((reason) => ( toggleSurveyReason(reason)} + key={reason.reason} + label={reason.reason} + dataAttr={`unsubscribe-reason-${reason.reason.toLowerCase().replace(' ', '-')}`} + checked={surveyResponse['$survey_response_2'].includes(reason.reason)} + onChange={() => toggleSurveyReason(reason.reason)} className="w-full" labelClassName="w-full" /> ))}
- { - setSurveyResponse('$survey_response', value) - }} - /> + {surveyResponse['$survey_response_2'].length > 0 && ( + { + setSurveyResponse('$survey_response', value) + }} + /> + )}

diff --git a/frontend/src/scenes/billing/billingProductLogic.ts b/frontend/src/scenes/billing/billingProductLogic.ts index 3d6a3bed351fa..a36bde1a388ec 100644 --- a/frontend/src/scenes/billing/billingProductLogic.ts +++ b/frontend/src/scenes/billing/billingProductLogic.ts @@ -15,6 +15,28 @@ import { BillingGaugeItemKind, BillingGaugeItemType } from './types' const DEFAULT_BILLING_LIMIT: number = 500 +type UnsubscribeReason = { + reason: string + question: string +} + +export const UNSUBSCRIBE_REASONS: UnsubscribeReason[] = [ + { reason: 'Too expensive', question: 'What will you be using instead?' }, + { reason: 'Not getting enough value', question: 'What prevented you from getting more value out of PostHog?' }, + { reason: 'Not using the product', question: 'Why are you not using the product?' }, + { reason: 'Found a better alternative', question: 'What service will you be moving to?' }, + { reason: 'Poor customer support', question: 'Please provide details on your support experience.' }, + { reason: 'Too difficult to use', question: 'What was difficult to use?' }, + { reason: 'Not enough hedgehogs', question: 'How many hedgehogs do you need? (but really why are you leaving)' }, + { reason: 'Other (let us know below!)', question: 'Why are you leaving?' }, +] + +export const randomizeReasons = (reasons: UnsubscribeReason[]): UnsubscribeReason[] => { + const shuffledReasons = reasons.slice(0, -1).sort(() => Math.random() - 0.5) + shuffledReasons.push(reasons[reasons.length - 1]) + return shuffledReasons +} + export interface BillingProductLogicProps { product: BillingProductV2Type | BillingProductV2AddonType productRef?: React.MutableRefObject @@ -298,6 +320,18 @@ export const billingProductLogic = kea([ (billing, product): boolean => !!billing?.products?.some((p) => p.addons?.some((addon) => addon.type === product?.type)), ], + unsubscribeReasonQuestions: [ + (s) => [s.surveyResponse], + (surveyResponse): string => { + return surveyResponse['$survey_response_2'] + .map((reason) => { + const reasonObject = UNSUBSCRIBE_REASONS.find((r) => r.reason === reason) + return reasonObject?.question + }) + .join(' ') + .concat(' (required)') + }, + ], })), listeners(({ actions, values, props }) => ({ updateBillingLimitsSuccess: () => {