@churnkey/react 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,624 +0,0 @@
1
- import { ReactNode, ReactElement, ComponentType } from 'react';
2
-
3
- interface DirectAddress {
4
- line1?: string;
5
- line2?: string;
6
- city?: string;
7
- state?: string;
8
- postalCode?: string;
9
- /** ISO 3166-1 alpha-2 */
10
- country?: string;
11
- }
12
- interface DirectCustomer {
13
- id: string;
14
- email?: string;
15
- name?: string;
16
- lastName?: string;
17
- phone?: string;
18
- /** ISO 4217 */
19
- currency?: string;
20
- addresses?: DirectAddress[];
21
- metadata?: Record<string, unknown>;
22
- }
23
- interface DirectPrice {
24
- id: string;
25
- type?: 'standalone' | 'product';
26
- active?: boolean;
27
- productId?: string;
28
- name?: string;
29
- description?: string;
30
- duration?: {
31
- interval: 'day' | 'week' | 'month' | 'year';
32
- intervalCount?: number;
33
- };
34
- amount: {
35
- model?: 'fixed' | 'tiered';
36
- /** Smallest currency unit (cents for USD). */
37
- value: number;
38
- currency?: string;
39
- };
40
- metadata?: Record<string, unknown>;
41
- }
42
- interface DirectCoupon {
43
- id?: string;
44
- name?: string;
45
- percentOff?: number;
46
- /** Smallest currency unit (cents for USD). */
47
- amountOff?: number;
48
- currency?: string;
49
- duration?: 'once' | 'repeating' | 'forever';
50
- durationInMonths?: number;
51
- metadata?: Record<string, unknown>;
52
- }
53
- type SubscriptionStatus = {
54
- name: 'active';
55
- currentPeriod: {
56
- start: Date | string;
57
- end: Date | string;
58
- };
59
- } | {
60
- name: 'trial';
61
- trial: {
62
- start: Date | string;
63
- end: Date | string;
64
- };
65
- currentPeriod?: {
66
- start: Date | string;
67
- end: Date | string;
68
- };
69
- } | {
70
- name: 'paused';
71
- pause: {
72
- start: Date | string;
73
- end?: Date | string;
74
- };
75
- currentPeriod?: {
76
- start: Date | string;
77
- end: Date | string;
78
- };
79
- } | {
80
- name: 'canceled';
81
- canceledAt: Date | string;
82
- } | {
83
- name: 'unpaid';
84
- currentPeriod?: {
85
- start: Date | string;
86
- end: Date | string;
87
- };
88
- } | {
89
- name: 'future';
90
- currentPeriod?: {
91
- start: Date | string;
92
- end: Date | string;
93
- };
94
- };
95
- interface DirectSubscriptionItem {
96
- id?: string;
97
- price: DirectPrice;
98
- quantity?: number;
99
- }
100
- interface DirectSubscription {
101
- id: string;
102
- customerId?: string;
103
- start: Date | string;
104
- status: SubscriptionStatus;
105
- items: DirectSubscriptionItem[];
106
- duration?: {
107
- interval: 'day' | 'week' | 'month' | 'year';
108
- intervalCount?: number;
109
- };
110
- end?: Date | string;
111
- discounts?: Array<{
112
- id?: string;
113
- coupon?: DirectCoupon;
114
- start?: Date | string;
115
- end?: Date | string;
116
- }>;
117
- metadata?: Record<string, unknown>;
118
- }
119
- interface DiscountOffer {
120
- type: 'discount';
121
- couponId?: string;
122
- percentOff?: number;
123
- /** Smallest currency unit (cents for USD). */
124
- amountOff?: number;
125
- currency?: string;
126
- durationInMonths?: number;
127
- }
128
- interface PauseOffer {
129
- type: 'pause';
130
- months: number;
131
- interval?: 'month' | 'week';
132
- }
133
- interface PlanChangeOffer {
134
- type: 'plan_change';
135
- plans: PlanOption[];
136
- }
137
- /**
138
- * Plan option in a `plan_change` offer — `DirectPrice` plus optional
139
- * cancel-flow merchandising fields. Marketing fields are presentation-only
140
- * and live on `PlanOption` rather than `DirectPrice` so `Direct` stays a
141
- * clean billing-data shape reusable outside the cancel-flow context.
142
- */
143
- interface PlanOption extends DirectPrice {
144
- /** Short marketing line (e.g. "Most popular"). */
145
- tagline?: string;
146
- /** Bullet list of plan features shown on the card. */
147
- features?: string[];
148
- /** Pre-formatted "before" price rendered struck-through (e.g. "$49/mo"). */
149
- msrp?: string;
150
- }
151
- interface TrialExtensionOffer {
152
- type: 'trial_extension';
153
- days: number;
154
- }
155
- interface ContactOffer {
156
- type: 'contact';
157
- url?: string;
158
- label?: string;
159
- }
160
- interface RedirectOffer {
161
- type: 'redirect';
162
- url: string;
163
- label: string;
164
- }
165
- interface RebateOffer {
166
- type: 'rebate';
167
- /** The rebate amount (pre-tax), smallest currency unit. The card is refunded this plus any tax charged on it. */
168
- amountMinor: number;
169
- currency: string;
170
- /** Gross paid on the target invoice. Server-resolved in token mode. */
171
- amountPaidMinor?: number;
172
- /** amountPaidMinor minus the full refund (the rebate plus its tax). Server-resolved in token mode. */
173
- netAfterRebateMinor?: number;
174
- paymentMethodBrand?: string;
175
- paymentMethodLast4?: string;
176
- }
177
- interface CustomOfferConfig {
178
- type: string;
179
- data?: Record<string, unknown>;
180
- }
181
- type BuiltInOfferConfig = DiscountOffer | PauseOffer | PlanChangeOffer | TrialExtensionOffer | ContactOffer | RedirectOffer | RebateOffer;
182
- type OfferConfig = BuiltInOfferConfig | CustomOfferConfig;
183
- type OfferDecision = OfferConfig & {
184
- copy: OfferCopy;
185
- decisionId?: string;
186
- };
187
- interface OfferCopy {
188
- headline: string;
189
- body: string;
190
- cta: string;
191
- declineCta: string;
192
- }
193
- type AcceptedOffer = OfferConfig & {
194
- /** Survey reason that routed to this offer. Absent when the offer was
195
- * declared as a standalone `OfferStep`. */
196
- reasonId?: string;
197
- /** Payload from custom offers — whatever your component passed to
198
- * `onAccept(result)`. Built-in offer types do not populate this. */
199
- result?: Record<string, unknown>;
200
- };
201
- interface ReasonConfig {
202
- id: string;
203
- label: string;
204
- /**
205
- * When true, picking this reason reveals a text input below the reason list.
206
- * The typed text lands on the session as `followupResponse`. `surveyChoiceId`
207
- * still carries the reason's `id` and `surveyChoiceValue` still carries the
208
- * static `label`, so analytics groupings stay stable.
209
- */
210
- freeform?: boolean;
211
- offer?: OfferConfig;
212
- }
213
- interface SurveyStep {
214
- type: 'survey';
215
- guid?: string;
216
- title?: string;
217
- description?: string;
218
- reasons: ReasonConfig[];
219
- classNames?: SurveyClassNames;
220
- }
221
- interface OfferStep {
222
- type: 'offer';
223
- guid?: string;
224
- title?: string;
225
- description?: string;
226
- /**
227
- * Offer attached to this step. Set this to declare a standalone offer
228
- * step (one that isn't routed from a survey reason). `copy` is optional —
229
- * the SDK synthesizes default copy from the offer config when none is
230
- * provided, the same way it does for survey-attached offers.
231
- */
232
- offer?: OfferConfig | OfferDecision;
233
- classNames?: OfferClassNames;
234
- }
235
- interface FeedbackStep {
236
- type: 'feedback';
237
- guid?: string;
238
- title?: string;
239
- description?: string;
240
- placeholder?: string;
241
- required?: boolean;
242
- minLength?: number;
243
- classNames?: FeedbackClassNames;
244
- }
245
- interface ConfirmStep {
246
- type: 'confirm';
247
- guid?: string;
248
- title?: string;
249
- description?: string;
250
- /** Optional bullet list of what the customer is giving up. Rendered between the description and the period-end notice. */
251
- losses?: string[];
252
- /** Heading above the loss list. Defaults to "You'll lose access to:". */
253
- lossesLabel?: string;
254
- confirmLabel?: string;
255
- goBackLabel?: string;
256
- classNames?: ConfirmClassNames;
257
- }
258
- interface SuccessStep {
259
- type: 'success';
260
- guid?: string;
261
- savedTitle?: string;
262
- savedDescription?: string;
263
- cancelledTitle?: string;
264
- cancelledDescription?: string;
265
- classNames?: SuccessClassNames;
266
- }
267
- interface CustomStepConfig {
268
- type: string;
269
- guid?: string;
270
- title?: string;
271
- description?: string;
272
- data?: Record<string, unknown>;
273
- }
274
- type BuiltInStep = SurveyStep | OfferStep | FeedbackStep | ConfirmStep | SuccessStep;
275
- type Step = BuiltInStep | CustomStepConfig;
276
- type BuiltInStepType = 'survey' | 'offer' | 'feedback' | 'confirm' | 'success';
277
- interface SurveyClassNames {
278
- root?: string;
279
- title?: string;
280
- description?: string;
281
- reasonList?: string;
282
- reasonButton?: string;
283
- reasonButtonSelected?: string;
284
- reasonLabel?: string;
285
- followupInput?: string;
286
- continueButton?: string;
287
- }
288
- interface OfferClassNames {
289
- root?: string;
290
- title?: string;
291
- description?: string;
292
- card?: string;
293
- headline?: string;
294
- body?: string;
295
- acceptButton?: string;
296
- declineButton?: string;
297
- discountBadge?: string;
298
- priceComparison?: string;
299
- pauseSlider?: string;
300
- planGrid?: string;
301
- planCard?: string;
302
- planCardSelected?: string;
303
- }
304
- interface FeedbackClassNames {
305
- root?: string;
306
- title?: string;
307
- description?: string;
308
- textarea?: string;
309
- characterCount?: string;
310
- submitButton?: string;
311
- }
312
- interface ConfirmClassNames {
313
- root?: string;
314
- title?: string;
315
- description?: string;
316
- lossList?: string;
317
- lossLabel?: string;
318
- lossItem?: string;
319
- lossBullet?: string;
320
- confirmButton?: string;
321
- goBackButton?: string;
322
- periodEndNotice?: string;
323
- }
324
- interface SuccessClassNames {
325
- root?: string;
326
- icon?: string;
327
- title?: string;
328
- description?: string;
329
- closeButton?: string;
330
- }
331
- interface StructuralClassNames {
332
- overlay?: string;
333
- modal?: string;
334
- closeButton?: string;
335
- backButton?: string;
336
- }
337
- /**
338
- * Typed surface for `appearance.variables`. Every key maps to a `--ck-*`
339
- * CSS custom property. Consumers who need a token not in this list can
340
- * still set the underlying CSS variable directly — these are the ones
341
- * exposed through the typed JS API.
342
- */
343
- interface AppearanceVariables {
344
- colorBackground: string;
345
- colorSurface: string;
346
- colorSurfaceMuted: string;
347
- colorBorder: string;
348
- colorBorderStrong: string;
349
- colorText: string;
350
- colorTextSecondary: string;
351
- colorTextMuted: string;
352
- colorPrimary: string;
353
- colorPrimaryHover: string;
354
- colorPrimarySoft: string;
355
- colorSuccess: string;
356
- colorSuccessSoft: string;
357
- colorDanger: string;
358
- colorDangerHover: string;
359
- colorDangerSoft: string;
360
- fontFamily: string;
361
- fontFamilyMono: string;
362
- /**
363
- * Display face used by step titles and other visual headlines. Defaults
364
- * to `fontFamily`. Set this when your brand uses a separate display face
365
- * (Tiempos, Canela, etc.) for headings.
366
- */
367
- fontFamilyDisplay: string;
368
- fontSize: string;
369
- /** Weight applied to the step title. Default `'600'`. */
370
- fontWeightDisplay: string;
371
- /** Letter spacing applied to the step title. Default `'-0.015em'`. */
372
- letterSpacingDisplay: string;
373
- borderRadius: string;
374
- radiusSm: string;
375
- radiusMd: string;
376
- radiusLg: string;
377
- radiusXl: string;
378
- shadowModal: string;
379
- shadowCard: string;
380
- /**
381
- * Color of the dim behind the modal. Defaults to a neutral translucent
382
- * ink. Set to `color-mix(in srgb, var(--ck-color-primary) 40%, transparent)`
383
- * to derive the overlay from your primary color, or any CSS color value.
384
- */
385
- overlayColor: string;
386
- }
387
- interface Appearance {
388
- /**
389
- * `'auto'` follows the user's OS preference (`prefers-color-scheme`) and
390
- * watches for changes. Default: `'light'`.
391
- */
392
- colorScheme?: 'auto' | 'light' | 'dark';
393
- variables?: Partial<AppearanceVariables>;
394
- }
395
- interface CustomStepProps {
396
- step: CustomStepConfig;
397
- customer: DirectCustomer | null;
398
- subscriptions: DirectSubscription[];
399
- onNext: (result?: Record<string, unknown>) => void;
400
- onBack: () => void;
401
- }
402
- interface CustomOfferProps {
403
- offer: OfferDecision;
404
- customer: DirectCustomer | null;
405
- subscriptions: DirectSubscription[];
406
- onAccept: (result?: Record<string, unknown>) => Promise<void>;
407
- onDecline: () => void;
408
- isProcessing: boolean;
409
- }
410
- interface ComponentOverrides {
411
- Modal?: (props: ModalProps) => ReactElement;
412
- CloseButton?: (props: CloseButtonProps) => ReactElement;
413
- BackButton?: (props: BackButtonProps) => ReactElement;
414
- Survey?: (props: SurveyStepProps) => ReactElement;
415
- Offer?: (props: OfferStepProps) => ReactElement;
416
- Feedback?: (props: FeedbackStepProps) => ReactElement;
417
- Confirm?: (props: ConfirmStepProps) => ReactElement;
418
- Success?: (props: SuccessStepProps) => ReactElement;
419
- ReasonButton?: (props: ReasonButtonProps) => ReactElement;
420
- DiscountOffer?: (props: OfferStepProps) => ReactElement;
421
- PauseOffer?: (props: OfferStepProps) => ReactElement;
422
- PlanChangeOffer?: (props: OfferStepProps) => ReactElement;
423
- TrialExtensionOffer?: (props: OfferStepProps) => ReactElement;
424
- ContactOffer?: (props: OfferStepProps) => ReactElement;
425
- RedirectOffer?: (props: OfferStepProps) => ReactElement;
426
- RebateOffer?: (props: OfferStepProps) => ReactElement;
427
- }
428
- type CustomComponents = Record<string, ComponentType<CustomStepProps> | ComponentType<CustomOfferProps>>;
429
- interface ModalProps {
430
- open: boolean;
431
- onClose: () => void;
432
- children: ReactNode;
433
- className?: string;
434
- overlayClassName?: string;
435
- }
436
- interface CloseButtonProps {
437
- onClose: () => void;
438
- className?: string;
439
- }
440
- interface BackButtonProps {
441
- onBack: () => void;
442
- className?: string;
443
- }
444
- interface SurveyStepProps {
445
- title: string;
446
- description?: string;
447
- customer: DirectCustomer | null;
448
- subscriptions: DirectSubscription[];
449
- reasons: ReasonConfig[];
450
- selectedReason: string | null;
451
- onSelectReason: (id: string) => void;
452
- /** Free-text value when the selected reason has `freeform: true`. Lands on the session as `followupResponse`. */
453
- followupResponse: string;
454
- /** Set the follow-up response. The SDK forwards the value to the session. */
455
- onFollowupResponseChange: (text: string) => void;
456
- onNext: () => void;
457
- classNames?: SurveyClassNames;
458
- components?: Partial<ComponentOverrides>;
459
- }
460
- interface OfferStepProps {
461
- title?: string;
462
- description?: string;
463
- customer: DirectCustomer | null;
464
- subscriptions: DirectSubscription[];
465
- offer: OfferDecision;
466
- /**
467
- * Accept the offer. The optional `result` is included on the resulting
468
- * `AcceptedOffer` payload — used by offers that need a user choice (e.g.
469
- * `plan_change` passes `{ planId }`).
470
- */
471
- onAccept: (result?: Record<string, unknown>) => Promise<void>;
472
- onDecline: () => void;
473
- isProcessing: boolean;
474
- classNames?: OfferClassNames;
475
- /**
476
- * Forwarded to the default `Offer` switcher so it can dispatch to per-type
477
- * overrides (`DiscountOffer`, `PauseOffer`, etc). Custom `Offer`
478
- * implementations can ignore this.
479
- */
480
- components?: Partial<ComponentOverrides>;
481
- }
482
- interface FeedbackStepProps {
483
- title: string;
484
- description?: string;
485
- customer: DirectCustomer | null;
486
- subscriptions: DirectSubscription[];
487
- placeholder?: string;
488
- required: boolean;
489
- minLength: number;
490
- value: string;
491
- onChange: (text: string) => void;
492
- onSubmit: () => void;
493
- classNames?: FeedbackClassNames;
494
- }
495
- interface ConfirmStepProps {
496
- title: string;
497
- description?: string;
498
- customer: DirectCustomer | null;
499
- subscriptions: DirectSubscription[];
500
- losses?: string[];
501
- lossesLabel?: string;
502
- confirmLabel: string;
503
- goBackLabel: string;
504
- onConfirm: () => Promise<void>;
505
- onGoBack: () => void;
506
- isProcessing: boolean;
507
- classNames?: ConfirmClassNames;
508
- }
509
- interface SuccessStepProps {
510
- outcome: 'saved' | 'cancelled';
511
- offer?: OfferDecision;
512
- title: string;
513
- description?: string;
514
- customer: DirectCustomer | null;
515
- subscriptions: DirectSubscription[];
516
- onClose: () => void;
517
- classNames?: SuccessClassNames;
518
- }
519
- interface ReasonButtonProps {
520
- reason: ReasonConfig;
521
- index: number;
522
- isSelected: boolean;
523
- onSelect: (id: string) => void;
524
- }
525
- interface FlowState {
526
- step: string;
527
- currentStepId: string;
528
- selectedReason: string | null;
529
- followupResponse: string;
530
- feedback: string;
531
- outcome: 'saved' | 'cancelled' | null;
532
- isProcessing: boolean;
533
- error: Error | null;
534
- customer: DirectCustomer | null;
535
- subscriptions: DirectSubscription[];
536
- }
537
- interface FlowConfig extends FlowCallbacks {
538
- appId?: string;
539
- customer?: DirectCustomer;
540
- subscriptions?: DirectSubscription[];
541
- session?: string;
542
- apiBaseUrl?: string;
543
- steps?: Step[];
544
- /**
545
- * Tags the session as live or test. Use `'test'` from staging so your
546
- * dashboard can filter out non-production traffic. Defaults to `'live'`.
547
- * In token mode the mode is encoded in the signed token and overrides
548
- * this field.
549
- */
550
- mode?: 'live' | 'test';
551
- }
552
- type OfferCallback = (offer: AcceptedOffer, customer: DirectCustomer | null) => Promise<void> | void;
553
- type CancelCallback = (customer: DirectCustomer | null) => Promise<void> | void;
554
- /**
555
- * Two kinds of callbacks, distinguished by name:
556
- *
557
- * - `handle<Type>` runs the action. When defined, it replaces whatever
558
- * Churnkey would do on the server — the consumer takes responsibility.
559
- * In local mode (no token), handlers are the only path that does anything.
560
- * - `on<Type>` is a listener that fires after the action. Side effects only —
561
- * refetch state, log analytics, show a toast. Errors thrown here are
562
- * swallowed; listeners can't flip the flow into an error state.
563
- *
564
- * `onAccept` is a catch-all that fires alongside the per-type listener.
565
- */
566
- interface FlowCallbacks {
567
- handleDiscount?: OfferCallback;
568
- handlePause?: OfferCallback;
569
- handlePlanChange?: OfferCallback;
570
- handleTrialExtension?: OfferCallback;
571
- handleRebate?: OfferCallback;
572
- handleCancel?: CancelCallback;
573
- onAccept?: OfferCallback;
574
- onDiscount?: OfferCallback;
575
- onPause?: OfferCallback;
576
- onPlanChange?: OfferCallback;
577
- onTrialExtension?: OfferCallback;
578
- onRebate?: OfferCallback;
579
- onCancel?: CancelCallback;
580
- onClose?: () => void;
581
- onStepChange?: (step: string, prevStep: string) => void;
582
- }
583
- interface CancelFlowProps extends FlowCallbacks {
584
- appId?: string;
585
- customer?: DirectCustomer;
586
- subscriptions?: DirectSubscription[];
587
- session?: string;
588
- steps?: Step[];
589
- apiBaseUrl?: string;
590
- /** See FlowConfig.mode. Ignored in token mode (the token is authoritative). */
591
- mode?: 'live' | 'test';
592
- appearance?: Appearance;
593
- classNames?: StructuralClassNames;
594
- components?: Partial<ComponentOverrides>;
595
- customComponents?: CustomComponents;
596
- }
597
-
598
- interface ResolvedStep {
599
- guid: string;
600
- type: string;
601
- defaultNextStep?: string;
602
- defaultPreviousStep?: string;
603
- title?: string;
604
- description?: string;
605
- reasons?: ReasonConfig[];
606
- offersAttached?: Record<string, string>;
607
- numChoices?: number;
608
- offer?: OfferDecision;
609
- /** True if this step was synthesized from a survey choice. Used by stepIndex so synthetic offers share the survey's progress slot. */
610
- surveyOffer?: boolean;
611
- placeholder?: string;
612
- required?: boolean;
613
- minLength?: number;
614
- losses?: string[];
615
- lossesLabel?: string;
616
- savedTitle?: string;
617
- savedDescription?: string;
618
- cancelledTitle?: string;
619
- cancelledDescription?: string;
620
- data?: Record<string, unknown>;
621
- classNames?: unknown;
622
- }
623
-
624
- export type { SurveyClassNames as $, AcceptedOffer as A, BackButtonProps as B, CancelFlowProps as C, DirectAddress as D, FlowState as E, FeedbackStepProps as F, OfferClassNames as G, OfferConfig as H, OfferCopy as I, OfferDecision as J, OfferStep as K, PlanChangeOffer as L, ModalProps as M, PlanOption as N, OfferStepProps as O, PauseOffer as P, ReasonConfig as Q, ReasonButtonProps as R, SuccessStepProps as S, RebateOffer as T, RedirectOffer as U, ResolvedStep as V, Step as W, StructuralClassNames as X, SubscriptionStatus as Y, SuccessClassNames as Z, SuccessStep as _, ConfirmStepProps as a, SurveyStep as a0, TrialExtensionOffer as a1, SurveyStepProps as b, CloseButtonProps as c, Appearance as d, AppearanceVariables as e, BuiltInOfferConfig as f, BuiltInStep as g, BuiltInStepType as h, ComponentOverrides as i, ConfirmClassNames as j, ConfirmStep as k, ContactOffer as l, CustomComponents as m, CustomOfferConfig as n, CustomOfferProps as o, CustomStepConfig as p, CustomStepProps as q, DirectCoupon as r, DirectCustomer as s, DirectPrice as t, DirectSubscription as u, DirectSubscriptionItem as v, DiscountOffer as w, FeedbackClassNames as x, FeedbackStep as y, FlowConfig as z };
@@ -1 +0,0 @@
1
- export {}