Skip to content

Commit

Permalink
enough hogs logic
Browse files Browse the repository at this point in the history
  • Loading branch information
zlwaterfield committed Oct 29, 2024
1 parent 447a189 commit 813ea5b
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 136 deletions.
346 changes: 213 additions & 133 deletions frontend/src/scenes/billing/UnsubscribeSurveyModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import './UnsubscribeSurveyModal.scss'

import { LemonBanner, LemonButton, LemonCheckbox, LemonLabel, LemonModal, LemonTextArea, Link } from '@posthog/lemon-ui'
import {
LemonBanner,
LemonButton,
LemonCheckbox,
LemonDivider,
LemonLabel,
LemonModal,
LemonTextArea,
Link,
} 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 { BillingProductV2AddonType, BillingProductV2Type } from '~/types'
Expand All @@ -26,10 +37,20 @@ export const UnsubscribeSurveyModal = ({
}: {
product: BillingProductV2Type | BillingProductV2AddonType
}): JSX.Element | null => {
const { surveyID, surveyResponse, isAddonProduct } = useValues(billingProductLogic({ product }))
const { setSurveyResponse, toggleSurveyReason, reportSurveyDismissed } = useActions(
billingProductLogic({ product })
const { trigger, HogfettiComponent } = useHogfetti()

const { surveyID, surveyResponse, isAddonProduct, surveyStep } = useValues(
billingProductLogic({ product, hogfettiTrigger: trigger })
)
const {
setSurveyResponse,
toggleSurveyReason,
reportSurveyDismissed,
setStepTwo,
resetStep,
setHedgehogSatisfied,
triggerMoreHedgehogs,
} = useActions(billingProductLogic({ product }))
const { deactivateProduct, resetUnsubscribeError } = useActions(billingLogic)
const { unsubscribeError, billingLoading, billing } = useValues(billingLogic)
const { unsubscribeDisabledReason, itemsToDisable } = useValues(exportsUnsubscribeTableLogic)
Expand All @@ -50,146 +71,205 @@ export const UnsubscribeSurveyModal = ({
actionVerb = isAddonProduct ? 'removing this addon' : 'downgrading'
}

return (
<LemonModal
onClose={() => {
reportSurveyDismissed(surveyID)
resetUnsubscribeError()
}}
width="max(44vw)"
title={isAddonProduct ? action : `${action} from ${product.name}`}
footer={
<>
<LemonButton
type="secondary"
onClick={() => {
reportSurveyDismissed(surveyID)
}}
>
Cancel
</LemonButton>
<LemonButton
type={textAreaNotEmpty ? 'primary' : 'secondary'}
disabledReason={includesPipelinesAddon && unsubscribeDisabledReason}
onClick={() => {
deactivateProduct(
billing?.subscription_level === 'paid' && !isAddonProduct
? 'all_products'
: product.type
)
}}
loading={billingLoading}
>
{action}
</LemonButton>
</>
}
>
<div className="flex flex-col gap-3.5">
{unsubscribeError && (
<LemonBanner type="error">
<p>
{unsubscribeError.detail} {unsubscribeError.link}
</p>
</LemonBanner>
)}
{isAddonProduct ? (
<p className="mb-0">
We're sorry to see you go! Please note, you'll lose access to the addon features immediately.
</p>
) : (
<p className="mb-0">
We're sorry to see you go! Please note, you'll lose access to platform features and usage limits
will apply immediately. And if you have any outstanding invoices, they will be billed
immediately.{' '}
<Link to={billing?.stripe_portal_url} target="_blank">
View invoices
</Link>
</p>
)}
const handleUnsubscribe = (): void => {
if (surveyResponse['$survey_response_2'].includes('Not enough hedgehogs')) {
setStepTwo()
triggerMoreHedgehogs()
} else {
deactivateProduct(billing?.subscription_level === 'paid' && !isAddonProduct ? 'all_products' : product.type)
}
}

<LemonLabel>
{billing?.subscription_level === 'paid'
? `Why are you ${actionVerb}?`
: `Why are you ${actionVerb} from ${product.name}?`}{' '}
<i className="text-muted">(you can select multiple)</i>
</LemonLabel>
<div className="grid grid-cols-2 gap-2">
{UNSUBSCRIBE_REASONS.map((reason) => (
<LemonCheckbox
bordered
key={reason}
label={reason}
dataAttr={`unsubscribe-reason-${reason.toLowerCase().replace(' ', '-')}`}
checked={surveyResponse['$survey_response_2'].includes(reason)}
onChange={() => toggleSurveyReason(reason)}
className="w-full"
labelClassName="w-full"
/>
))}
const renderStep2 = (): JSX.Element => (
<div className="flex flex-col gap-4">
<div className="text-center">
<h3 className="text-lg mb-2">How about now? Was that enough hedgehogs?</h3>
<p className="text-muted mb-4">Look at all these adorable hedgehogs dancing just for you! 🦔✨</p>
<div className="flex justify-center items-center">
<HeartHog width="100" height="100" />
</div>

<LemonTextArea
data-attr="unsubscribe-reason-survey-textarea"
placeholder="Share your feedback here so we can improve PostHog!"
value={surveyResponse['$survey_response']}
onChange={(value) => {
setSurveyResponse('$survey_response', value)
</div>
<div className="flex gap-2 justify-center">
<Link onClick={triggerMoreHedgehogs} disabled={billingLoading}>
Still not enough! More hedgehogs! 🦔
</Link>
</div>
<LemonDivider />
<div className="space-y-2 flex flex-col items-center justify-center">
<LemonButton
type="primary"
loading={billingLoading}
onClick={() => {
setHedgehogSatisfied(true)
deactivateProduct(
billing?.subscription_level === 'paid' && !isAddonProduct ? 'all_products' : product.type
)
}}
>
Never enough, proceed with {action}
</LemonButton>
<LemonButton
type="tertiary"
loading={billingLoading}
onClick={() => {
resetStep()
setSurveyResponse(
'$survey_response_2',
surveyResponse['$survey_response_2'].filter((r) => r !== 'Not enough hedgehogs')
)
}}
/>
>
You convinced me to stay! 💕
</LemonButton>
</div>
</div>
)

<LemonBanner type="info">
<p>
{'Are you looking to control your costs? Learn about ways to '}
<Link
to="https://posthog.com/docs/billing/estimating-usage-costs#how-to-reduce-your-posthog-costs"
target="_blank"
onClick={() => {
reportSurveyDismissed(surveyID)
}}
>
reduce your bill
</Link>
{`${product.type !== 'session_replay' ? ' or ' : ', '}`}
<Link
to=""
target="_blank"
onClick={() => {
reportSurveyDismissed(surveyID)
openSupportForm({ target_area: 'billing', isEmailFormOpen: true })
return (
<>
<HogfettiComponent />
<LemonModal
onClose={() => {
reportSurveyDismissed(surveyID)
resetUnsubscribeError()
resetStep()
}}
width="max(44vw)"
title={isAddonProduct ? action : `${action} from ${product.name}`}
footer={
surveyStep === 1 ? (
<>
<LemonButton
type="secondary"
onClick={() => {
reportSurveyDismissed(surveyID)
}}
>
Cancel
</LemonButton>
<LemonButton
type={textAreaNotEmpty ? 'primary' : 'secondary'}
disabledReason={includesPipelinesAddon && unsubscribeDisabledReason}
onClick={handleUnsubscribe}
loading={billingLoading}
>
{action}
</LemonButton>
</>
) : null
}
>
{surveyStep === 1 ? (
<div className="flex flex-col gap-3.5">
{unsubscribeError && (
<LemonBanner type="error">
<p>
{unsubscribeError.detail} {unsubscribeError.link}
</p>
</LemonBanner>
)}
{isAddonProduct ? (
<p className="mb-0">
We're sorry to see you go! Please note, you'll lose access to the addon features
immediately.
</p>
) : (
<p className="mb-0">
We're sorry to see you go! Please note, you'll lose access to platform features and
usage limits will apply immediately. And if you have any outstanding invoices, they will
be billed immediately.{' '}
<Link to={billing?.stripe_portal_url} target="_blank">
View invoices
</Link>
</p>
)}

<LemonLabel>
{billing?.subscription_level === 'paid'
? `Why are you ${actionVerb}?`
: `Why are you ${actionVerb} from ${product.name}?`}{' '}
<i className="text-muted">(you can select multiple)</i>
</LemonLabel>
<div className="grid grid-cols-2 gap-2">
{UNSUBSCRIBE_REASONS.map((reason) => (
<LemonCheckbox
bordered
key={reason}
label={reason}
dataAttr={`unsubscribe-reason-${reason.toLowerCase().replace(' ', '-')}`}
checked={surveyResponse['$survey_response_2'].includes(reason)}
onChange={() => toggleSurveyReason(reason)}
className="w-full"
labelClassName="w-full"
/>
))}
</div>

<LemonTextArea
data-attr="unsubscribe-reason-survey-textarea"
placeholder="Share your feedback here so we can improve PostHog!"
value={surveyResponse['$survey_response']}
onChange={(value) => {
setSurveyResponse('$survey_response', value)
}}
>
chat with support
</Link>
{product.type === 'session_replay' && (
<>
{', or '}
/>

<LemonBanner type="info">
<p>
{'Are you looking to control your costs? Learn about ways to '}
<Link
to="mailto:sales@posthog.com?subject=Joining%session%replay%controls%20beta"
to="https://posthog.com/docs/billing/estimating-usage-costs#how-to-reduce-your-posthog-costs"
target="_blank"
onClick={() => {
reportSurveyDismissed(surveyID)
}}
>
join our beta
reduce your bill
</Link>
{' for tuning recording volume with sampling and minimum duration.'}
</>
)}
.
</p>
</LemonBanner>
</div>
{includesPipelinesAddon && itemsToDisable.length > 0 ? (
<div className="mt-6">
<h3 className="mt-2 mb-2 mr-8">Important: Disable remaining export apps</h3>
<p>
To avoid unexpected impact on your data, you must explicitly disable the following apps and
exports before unsubscribing:
</p>
<ExportsUnsubscribeTable />
</div>
) : null}
</LemonModal>
{`${product.type !== 'session_replay' ? ' or ' : ', '}`}
<Link
to=""
target="_blank"
onClick={() => {
reportSurveyDismissed(surveyID)
openSupportForm({ target_area: 'billing', isEmailFormOpen: true })
}}
>
chat with support
</Link>
{product.type === 'session_replay' && (
<>
{', or '}
<Link
to="mailto:[email protected]?subject=Joining%session%replay%controls%20beta"
target="_blank"
onClick={() => {
reportSurveyDismissed(surveyID)
}}
>
join our beta
</Link>
{' for tuning recording volume with sampling and minimum duration.'}
</>
)}
.
</p>
</LemonBanner>
{includesPipelinesAddon && itemsToDisable.length > 0 ? (
<div className="mt-6">
<h3 className="mt-2 mb-2 mr-8">Important: Disable remaining export apps</h3>
<p>
To avoid unexpected impact on your data, you must explicitly disable the following
apps and exports before unsubscribing:
</p>
<ExportsUnsubscribeTable />
</div>
) : null}
</div>
) : (
renderStep2()
)}
</LemonModal>
</>
)
}
1 change: 0 additions & 1 deletion frontend/src/scenes/billing/billingLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ export const billingLogic = kea<billingLogicType>([
try {
const response = await api.getResponse('api/billing/deactivate?products=' + key)
const jsonRes = await getJSONOrNull(response)
lemonToast.success('You have been unsubscribed')
actions.reportProductUnsubscribed(key)
return parseBillingResponse(jsonRes)
} catch (error: any) {
Expand Down
Loading

0 comments on commit 813ea5b

Please sign in to comment.