@ churnkey/ 反应
React 的取消流量组件 。 调查、提议、反馈和确认。 准备用出盒子,在需要的时候可以完全定制.
开源. 可选连接到 Rn克 分析学和人工智能能力保留.
安装
npm install @churnkey/react
创建取消流量
导入组件和样式表,定义您的步骤,并处理结果.
import { CancelFlow } from '@churnkey/react'
import '@churnkey/react/styles.css'
<CancelFlow
steps={[
{
type: 'survey',
title: 'Why are you leaving?',
reasons: [
{
id: 'expensive',
label: 'Too expensive',
offer: {
type: 'discount',
couponId: 'STRIPE_SAVE20', // your coupon ID
percentOff: 20, // for the UI
durationInMonths: 3, // for the UI
},
},
{
id: 'not-using',
label: 'Not using it enough',
offer: { type: 'pause', months: 2 },
},
{ id: 'missing', label: 'Missing features' },
],
},
{ type: 'feedback', title: 'Anything else?' },
{ type: 'confirm' },
]}
handleDiscount={async (offer) => myBilling.applyCoupon(offer.couponId)}
handlePause={async (offer) => myBilling.pause({ months: offer.result?.months ?? offer.months })}
handleCancel={async () => myBilling.cancel()}
onClose={() => setOpen(false)}
/>
当客户选择"太贵"时,SDK会显示折扣报价. 如果他们接受了, handleDiscount 运行。 如果他们拒绝所有的报价和确认, handleCancel 运行.
改变外观
SDK飞船的轻而易举和黑暗计划. 'auto' 跟踪用户的OS偏好,并对变化作出反应.
<CancelFlow
appearance={{ colorScheme: 'auto' }}
steps={steps}
onAccept={handleOffer}
onCancel={handleCancel}
/>
覆盖通过 appearance.variables同样的价值在两种方案中都适用——一次设定出你的品牌颜色,然后随处可见.
appearance={{
variables: { colorPrimary: '#7c3aed', borderRadius: '12px' },
}}
基于类的样式( Tailwind, CSS 模块), 使用 classNames数字 :
classNames={{
modal: 'max-w-lg shadow-2xl',
overlay: 'bg-black/60 backdrop-blur-sm',
}}
替换组件
换掉任何UI的一部分。 SDK处理导航和状态;你处理渲染.
<CancelFlow
steps={steps}
components={{
ReasonButton: ({ reason, isSelected, onSelect }) => (
<button
onClick={() => onSelect(reason.id)}
className={isSelected ? 'border-blue-500 bg-blue-50' : 'border-gray-200'}
>
{reason.label}
</button>
),
}}
onAccept={handleOffer}
onCancel={handleCancel}
/>
您可以替换 Modal, (中文(简体) ), CloseButton, (中文(简体) ), BackButton,步骤组件Survey, (中文(简体) ), Offer, (中文(简体) ), Feedback, (中文(简体) ), Confirm, (中文(简体) ), Success, (中文(简体) ), ReasonButton每发价类型的组件(DiscountOffer, (中文(简体) ), PauseOffer, (中文(简体) ), PlanChangeOffer, (中文(简体) ), TrialExtensionOffer, (中文(简体) ), ContactOffer, (中文(简体) ), RedirectOffer),以及 StackedOffer 为一对报价.
添加自定义步骤
台阶系统开放. 使用任意字符串作为步骤类型,然后为它注册一个组件.
<CancelFlow
steps={[
{ type: 'survey', reasons: [
{ id: 'seats', label: 'Too many seats',
offer: { type: 'change-seats', data: { minSeats: 1 } } },
]},
{ type: 'nps', title: 'One quick question', data: { scale: 10 } },
{ type: 'feedback' },
{ type: 'confirm' },
]}
customComponents={{
'nps': ({ step, onNext }) => (
<NpsRating scale={step.data.scale} onSubmit={(score) => onNext({ score })} />
),
'change-seats': ({ offer, onAccept }) => (
<SeatAdjuster onConfirm={(seats) => onAccept({ seats })} />
),
}}
onAccept={handleOffer}
onCancel={handleCancel}
/>
自定义步骤像内置步骤一样导航 。 自定义要约在选择匹配原因时出现 。 无论你传递给什么 onNext(result) 或者说 onAccept(result) 现身 offer.result 在你身边 onAccept 处理器,并记录在分析会话中(如: customStepResults[stepType] 步骤, acceptedOffer.customOfferResult (关于要约).
预建定制出价组件
如果你不想自己建定制的UI, 导入一个预建的 @churnkey/react/recipes它们采用与内置报价相同的造型系统,并将结果通过 onAccept,所以你只执行计费部分.
import { TermExtensionOffer, PassthroughOffer } from '@churnkey/react/recipes'
<CancelFlow
customComponents={{
// "Delay your next charge by N days". Reads offer.data.days, shows the
// new renewal date, passes { days } through onAccept.
annual_term_extension: TermExtensionOffer,
// Copy + accept/decline, nothing else. Register it for any offer type
// whose substance lives entirely in the flow-authored copy; offer.data
// passes through as the result.
scheduled_transfer: PassthroughOffer,
immediate_transfer: PassthroughOffer,
}}
onAccept={handleOffer}
onCancel={handleCancel}
/>
组件位于子路径导出后, 因此除非导入, 否则不会添加到您的捆绑中 。 要进行完整的演示文稿控制,请从 packages/react/examples/ 转而进入你的密码库 从那里拥有它.
无头去
如果要完全控制UI,直接使用钩子.
import { useCancelFlow } from '@churnkey/react/headless'
function MyCancelPage() {
const flow = useCancelFlow({ steps, onAccept: handleOffer, onCancel: handleCancel })
if (flow.step === 'survey') {
return (
<div>
{flow.reasons.map((r) => (
<button key={r.id} onClick={() => flow.selectReason(r.id)}>{r.label}</button>
))}
<button onClick={flow.next} disabled={!flow.selectedReason}>Continue</button>
</div>
)
}
if (flow.step === 'offer' && flow.currentOffer) {
return (
<div>
<h2>{flow.currentOffer.copy.headline}</h2>
<button onClick={flow.accept}>Accept</button>
<button onClick={flow.decline}>No thanks</button>
</div>
)
}
// ... feedback, confirm, success
}
钩子返回当前状态( T)step, (中文(简体) ), reasons, (中文(简体) ), currentOffer, (中文(简体) ), feedback, (中文(简体) ), outcome, (中文(简体) ), isProcessing和行动selectReason, (中文(简体) ), next, (中文(简体) ), back, (中文(简体) ), accept, (中文(简体) ), decline, (中文(简体) ), cancel, (中文(简体) ), close) (中文(简体) ).
在象征性模式中,钩子会留下一对报价,除非你通过 stackedOffers: true; 见 报价对等。 。 。 .
添加分析
创建一个 免费 Churnkey 账户 并通过你的 appId。SDK记录每个会话,这样你就可以知道为什么客户取消,提供工作,以及你的储蓄率是什么样子.
<CancelFlow
appId="app_xxx"
customer={{ id: 'cus_123' }}
steps={steps}
onAccept={handleOffer}
onCancel={handleCancel}
/>
仅 customer.id 需要时间。 关于收入衡量标准,也通过订阅数据:
<CancelFlow
appId="app_xxx"
customer={{ id: 'cus_123', email: '[email protected]' }}
subscriptions={[{
id: 'sub_456',
start: '2024-06-01',
status: { name: 'active', currentPeriod: { start: '2025-04-01', end: '2025-05-01' } },
items: [{ price: { id: 'price_pro', amount: { value: 2999 } } }],
}]}
steps={steps}
onAccept={handleOffer}
onCancel={handleCancel}
/>
你的步骤和召回不会改变。 不需要后端工作 .
当客户接受要约、确认取消或完成(放弃)之前关闭模式时,会话记录。 从自定义步骤通过的数据 onNext(result) 与会议同时进行.
为了保持交通 出你的生产分析,通过 mode="test"数字 :
<CancelFlow
appId="app_xxx"
customer={{ id: 'cus_123' }}
mode={process.env.NODE_ENV === 'production' ? 'live' : 'test'}
steps={steps}
onAccept={handleOffer}
onCancel={handleCancel}
/>
默认为 'live'。如果您的矿石连接到一个 花边沙盒 而不是经典测试模式,通过 mode="sandbox" 而不是服务器侧的帐单操作 使用您的沙盒证书。 在指使模式中,指使模式优先——它是服务器签名的,不能被压倒客户端侧面.
让Churnkey处理账单
在Churnkey仪表板上连接您的计费供应商(Stripe,Chargebee等),Churnkey可以应用折扣,暂停订阅,并代表您取消. 在您的服务器上生成一个令牌以认证会话 .
// Server
import { Churnkey } from '@churnkey/node'
const ck = new Churnkey({ appId: 'app_xxx', apiKey: 'sk_xxx' })
const token = ck.createToken({ customerId: 'cus_123' })
// Client
<CancelFlow
appId="app_xxx"
customer={{ id: 'cus_123', email: '[email protected]' }}
subscriptions={[...]}
session={token}
onAccept={async (offer) => console.log('Applied:', offer)}
onCancel={async () => router.push('/goodbye')}
/>
在此模式下,取消流由Churnkey仪表板配置. 您的自定义组件和外观设置继续 .
处理器对听众
两种回叫,用名来区分:
handle<Type>- 运行动作。 替换 Churnkey 在服务器上所做的 。 在本地模式( 无令牌 ) 中, 这是唯一运行动作 .on<Type>——行动后起火,无论是谁指挥. 副作用只有——分析,回放,土司.
<CancelFlow
session={token}
// Handler: defining handlePause tells the SDK NOT to call its own
// server-side pause; you run the action instead. Skip handle* and
// Churnkey takes the action automatically in token mode.
handlePause={async (offer, customer) => {
await myBilling.pause({ months: offer.result?.months ?? offer.months })
}}
// Listener: fires after the pause completes (whoever ran it).
onPause={(offer, customer) => analytics.track('paused', { months: offer.result?.months ?? offer.months })}
onAccept={(offer) => analytics.track('offer_accepted', { type: offer.type })}
onCancel={() => router.push('/goodbye')}
/>
可用的处理器 : handleDiscount, (中文(简体) ), handlePause, (中文(简体) ), handlePlanChange, (中文(简体) ), handleTrialExtension, (中文(简体) ), handleCancel。可用的听众 : onDiscount, (中文(简体) ), onPause, (中文(简体) ), onPlanChange, (中文(简体) ), onTrialExtension, (中文(简体) ), onCancel,加上包罗万象 onAccept 任何被接受的报价.
单位 本地模式 (没有标志),没有服务器动作——处理者做活. 单位 符号模式定义一个操作员选择退出运行动作的Churnkey,并将工作还给你.
报价对等
报价可携带第二个报价(offer.stackedOffer),设置在仪表板上. SDK显示每张出价一张卡和一个单个"接受两个出价"按钮;通过: StackedOffer 组件槽.
Churnkey只向一个显示两种报价的UI发送一对. 和你自己一样 Offer 组件,或 a customComponents 输入内置要约类型,对子不包含在流量中,除非您也通过 StackedOffer与 useCancelFlow,通过 stackedOffers: true 一旦你的UI让 offer.stackedOffer。 。 。 .
- 没有处理器,令牌模式在一项请求中同时适用两种要约. 在暂停或延长审判后,第二次提议在暂停或审判结束后开始.
- 与处理者,每出价通过自己的处理者,先出价,但退价最后出价. 如果第二顺位的报价失败了, 流量仍然完成,
acceptedOffer.stackedOffer.stackStatus实值'failed'财务报告和审定财务报表failedOfferType列出不适用的报价。 只有Churnkey在暂停或试运行时可以持有第二个报价,因此在本地模式中,当一个处理者覆盖任一报价时,一对其第二个报价等待被忽略出流量. 在象征性模式中,当处理者只覆盖其一项要约时,一对也会被排除在外,因为Churnkey只将一对要约与另一对一起应用. - 听众和
onAccept得到每个报价 自己, 一旦适用报价. - A 类
StackedOffer组件接受配对并有一个结果:months用于暂停和planId计划改变。 每个报价result只有自己的选择,加上你通过的任何其他钥匙.
传递客户/订阅数据并附带一个令牌
你可以通过 customer 财务报告和审定财务报表 subscriptions 合并 session 用客户端数据来丰富会话记录的Churnkey还没有(海关元数据,当前计划价格等). 指使牌上签名的客户ID保持权威;直接数据填补了空白.
<CancelFlow
appId="app_xxx"
customer={{ id: 'cus_123', email: '[email protected]', metadata: { plan: 'pro' } }}
subscriptions={[...]}
session={token}
onAccept={handleOffer}
onCancel={handleCancel}
/>
混合本地和服务器步骤
你可以通过两个 session 财务报告和审定财务报表 steps 以覆盖特定的服务器配置 :
<CancelFlow
session={token}
steps={[
{ type: 'confirm', title: 'We hate to see you go' },
{ type: 'nps', title: 'Quick question', data: { scale: 10 } },
]}
customComponents={{ 'nps': NpsStep }}
onAccept={handleOffer}
onCancel={handleCancel}
/>
本地步骤按类型覆盖 。 未在服务器配置中的步骤会被附加 .
进口
import { CancelFlow } from '@churnkey/react' // drop-in component
import { useCancelFlow } from '@churnkey/react/headless' // headless hook
import { CancelFlowMachine } from '@churnkey/react/core' // state machine, no React
import { TermExtensionOffer } from '@churnkey/react/recipes' // prebuilt custom-offer components
许可证
麻省理工学院