From 71b8d6727285146f564c71a6d74b8792240c66c7 Mon Sep 17 00:00:00 2001 From: Steve Henty Date: Wed, 4 Dec 2024 14:16:53 +0100 Subject: [PATCH 1/3] Add CheckoutResponse types --- cypress/pages/common.ts | 5 +- src/demo.ts | 7 ++- src/lib/contracts/CheckoutPopupOptions.ts | 54 ++++++++--------- src/lib/contracts/CheckoutResponse.ts | 59 +++++++++++++++++++ .../services/checkout-popup/CheckoutIFrame.ts | 5 +- 5 files changed, 96 insertions(+), 34 deletions(-) create mode 100644 src/lib/contracts/CheckoutResponse.ts diff --git a/cypress/pages/common.ts b/cypress/pages/common.ts index c103ff5..0159452 100644 --- a/cypress/pages/common.ts +++ b/cypress/pages/common.ts @@ -1,4 +1,5 @@ import { CheckoutOptions, CheckoutPopupEvents } from '../../src'; +import { CheckoutResponse } from '../../src/lib/contracts/CheckoutResponse'; export const initOptions: CheckoutOptions = { product_id: Number.parseInt( @@ -47,7 +48,7 @@ export const eventListeners: CheckoutPopupEvents = { afterClose() { updateEventText(EVENT_LOG.AFTER_CLOSE); }, - success() { + success(data: CheckoutResponse | null) { updateEventText(EVENT_LOG.SUCCESS); }, track(event) { @@ -56,7 +57,7 @@ export const eventListeners: CheckoutPopupEvents = { afterOpen() { updateEventText(EVENT_LOG.AFTER_OPEN); }, - purchaseCompleted() { + purchaseCompleted(data: CheckoutResponse | null) { updateEventText(EVENT_LOG.PURCHASE_COMPLETED); }, onExitIntent() { diff --git a/src/demo.ts b/src/demo.ts index abd2676..9d01732 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -1,4 +1,5 @@ import { Checkout, CheckoutOptions, CheckoutPopupOptions } from '.'; +import { CheckoutResponse } from './lib/contracts/CheckoutResponse'; import './style.css'; @@ -65,13 +66,13 @@ document.addEventListener('DOMContentLoaded', () => { cancel() { log('cancel'); }, - purchaseCompleted(data) { + purchaseCompleted(data: CheckoutResponse | null) { log('purchaseCompleted', data); }, - success(data) { + success(data: CheckoutResponse | null) { log('success', data); }, - track(event, data) { + track(event: string, data: Record | null) { log('track', event, data); }, afterOpen() { diff --git a/src/lib/contracts/CheckoutPopupOptions.ts b/src/lib/contracts/CheckoutPopupOptions.ts index 0a04f3b..9754290 100644 --- a/src/lib/contracts/CheckoutPopupOptions.ts +++ b/src/lib/contracts/CheckoutPopupOptions.ts @@ -1,8 +1,10 @@ +import { CheckoutResponse } from './CheckoutResponse'; + /** * Supported "locale" option for the checkout. * @see https://freemius.com/help/documentation/selling-with-freemius/freemius-checkout-buy-button/ - * 1. `auto` - The system will try to guess the language of your user by looking into the browser and then the geo-location respectively. However, this won’t select languages that are marked as AI-translated or beta for the time being. - * 2. `auto-beta` - Same as above, but will also select a language marked as beta. When a language marked as beta is selected, the UI will also show a “BETA” tag near it. + * 1. `auto` - The system will try to guess the language of your user by looking into the browser and then the geo-location respectively. However, this won't select languages that are marked as AI-translated or beta for the time being. + * 2. `auto-beta` - Same as above, but will also select a language marked as beta. When a language marked as beta is selected, the UI will also show a "BETA" tag near it. * 3. Full locale code (for eg - `en_US`, `de_DE`, `fr_FR`, etc.) */ export type CheckoutLocaleValue = 'auto' | 'auto-beta' | string; @@ -33,7 +35,7 @@ export type CheckoutTrackingEvent = */ export interface CheckoutPopupParams { /** - * Required product ID (whether it’s a plugin, theme, add-on, bundle, or SaaS). + * Required product ID (whether it's a plugin, theme, add-on, bundle, or SaaS). */ plugin_id: number | string; @@ -43,7 +45,7 @@ export interface CheckoutPopupParams { public_key: string; /** - * An optional ID to set the id attribute of the checkout’s HTML element. + * An optional ID to set the id attribute of the checkout's HTML element. * This argument is particularly useful if you have multiple checkout instances * that need to have a slightly different design or visibility of UI components. * You can assign a unique ID for each instance and customize it differently @@ -53,29 +55,29 @@ export interface CheckoutPopupParams { id?: string; /** - * An optional string to override the product’s title. + * An optional string to override the product's title. * - * @default "Defaults to the product’s title set within the Freemius dashboard." + * @default "Defaults to the product's title set within the Freemius dashboard." */ name?: string; /** - * An optional string to override the checkout’s title when buying a new license. + * An optional string to override the checkout's title when buying a new license. * * @default "Great selection, {{ firstName }}!" */ title?: string; /** - * An optional string to override the checkout’s subtitle. + * An optional string to override the checkout's subtitle. * - * @default "You’re one step closer to our {{ planTitle }} features" + * @default "You're one step closer to our {{ planTitle }} features" * @deprecated */ subtitle?: string; /** - * An optional icon that loads at the checkout and will override the product’s + * An optional icon that loads at the checkout and will override the product's * icon uploaded to the Freemius Dashboard. Use a secure path to the image * over HTTPS. While the checkout will remain PCI compliant, * credit-card automatic prefill by the browser will not work. @@ -114,7 +116,7 @@ export interface CheckoutPopupParams { * Use the `licenses` param instead. An optional ID of the exact multi-site * license prices that will load once the checkout opened. * - * @default "plan’s single-site prices ID" + * @default "plan's single-site prices ID" */ pricing_id?: number | string; @@ -172,9 +174,9 @@ export interface CheckoutPopupParams { /** * When set to true, it will open the checkout in a trial mode and the trial - * type (free vs. paid) will be based on the plan’s configuration. This will - * only work if you’ve activated the Free Trial functionality in the plan - * configuration. If you configured the plan to support a trial that doesn’t + * type (free vs. paid) will be based on the plan's configuration. This will + * only work if you've activated the Free Trial functionality in the plan + * configuration. If you configured the plan to support a trial that doesn't * require a payment method, you can also open the checkout in a trial mode * that requires a payment method by setting the value to 'paid'. * @@ -198,17 +200,17 @@ export interface CheckoutPopupParams { is_payment_method_update?: boolean; /** - * An optional string to prefill the buyer’s email address. + * An optional string to prefill the buyer's email address. */ user_email?: string; /** - * An optional string to prefill the buyer’s first name. + * An optional string to prefill the buyer's first name. */ user_firstname?: string; /** - * An optional string to prefill the buyer’s last name. + * An optional string to prefill the buyer's last name. */ user_lastname?: string; @@ -219,19 +221,19 @@ export interface CheckoutPopupParams { affiliate_user_id?: number; /** - * An optional locale to override the checkout’s language. + * An optional locale to override the checkout's language. */ language?: CheckoutLocaleValue; /** - * An optional locale to override the checkout’s language. + * An optional locale to override the checkout's language. * * @see `language` */ locale?: CheckoutLocaleValue; /** - * An optional token which if present, would pre-populate the checkout with user’s personal and billing data (for example, the name, email, country, vat ID etc). + * An optional token which if present, would pre-populate the checkout with user's personal and billing data (for example, the name, email, country, vat ID etc). * * @see https://freemius.com/help/documentation/selling-with-freemius/freemius-checkout-buy-button/#user_token_in_checkout_new */ @@ -377,20 +379,18 @@ export interface CheckoutPopupEvents { * An after successful purchase/subscription completion callback handler. * * Notice: When the user subscribes to a recurring billing plan, this method - * will execute upon a successful subscription creation. It doesn’t guarantee - * that the subscription’s initial payment was processed successfully as well. + * will execute upon a successful subscription creation. It doesn't guarantee + * that the subscription's initial payment was processed successfully as well. */ - purchaseCompleted?: (data: Record | null) => void; + purchaseCompleted?: (data: CheckoutResponse | null) => void; /** * An optional callback handler, similar to purchaseCompleted. The main * difference is that this callback will only execute after the user clicks - * the “Got It”” button that appears in the after purchase screen as a + * the "Got It"" button that appears in the after purchase screen as a * declaration that they successfully received the after purchase email. * This callback is obsolete when the checkout is running in a 'dashboard' mode. */ - success?: ( - data: { purchase: Record } | Record | null - ) => void; + success?: (data: CheckoutResponse | null) => void; /** * An optional callback handler for advanced tracking, which will be called on * multiple checkout events such as updates in the currency, billing cycle, diff --git a/src/lib/contracts/CheckoutResponse.ts b/src/lib/contracts/CheckoutResponse.ts new file mode 100644 index 0000000..b664236 --- /dev/null +++ b/src/lib/contracts/CheckoutResponse.ts @@ -0,0 +1,59 @@ +export interface User { + email: string; + first: string; + last: string; + public_key: string; + id: string; + created: string; + resend_email_endpoint: string; +} + +export interface Purchase { + tax_rate?: number; + total_gross?: number; + amount_per_cycle?: number; + initial_amount?: number; + renewal_amount?: number; + renewals_discount?: number | null; + renewals_discount_type?: string | null; + billing_cycle?: number; + outstanding_balance?: number; + failed_payments?: number; + trial_ends?: string | null; + next_payment?: string; + canceled_at?: string | null; + user_id?: string; + install_id?: string | null; + plan_id?: string; + pricing_id?: string; + license_id?: string; + ip?: string; + country_code?: string; + zip_postal_code?: number; + vat_id?: string | null; + coupon_id?: string | null; + user_card_id?: string; + source?: number; + plugin_id?: string; + external_id?: string; + gateway?: string; + environment?: number; + id?: string; + created?: string; + updated?: string | null; + currency?: string; + license_key?: string; + bound_payment_id?: string | null; + subscription_id?: string | null; + gateway_fee?: number; + gross?: number; + vat?: number; + is_renewal?: boolean; + type?: string; + [key: string]: unknown; +} + +export interface CheckoutResponse { + purchase: Purchase; + user: User; +} diff --git a/src/lib/services/checkout-popup/CheckoutIFrame.ts b/src/lib/services/checkout-popup/CheckoutIFrame.ts index 24a40b2..d695736 100644 --- a/src/lib/services/checkout-popup/CheckoutIFrame.ts +++ b/src/lib/services/checkout-popup/CheckoutIFrame.ts @@ -3,6 +3,7 @@ import { CheckoutPopupEvents } from '../../contracts/CheckoutPopupOptions'; import { buildFreemiusQueryFromOptions } from '../../utils/ops'; import { Logger } from '../logger'; import { IExitIntent } from '../../contracts/IExitIntent'; +import { CheckoutResponse } from '../../contracts/CheckoutResponse'; type EventListener = () => void; @@ -91,7 +92,7 @@ export class CheckoutIFrame { 'upgraded', (data) => { try { - success?.(data as any); + success?.(data as CheckoutResponse); } catch (e) { Logger.Error(e); } @@ -107,7 +108,7 @@ export class CheckoutIFrame { 'purchaseCompleted', (data) => { try { - purchaseCompleted?.(data as any); + purchaseCompleted?.(data as CheckoutResponse); } catch (e) { Logger.Error(e); } From e0d5d249b63c9ec4d05ebd89f42edc90be73a2c6 Mon Sep 17 00:00:00 2001 From: Steve Henty Date: Thu, 5 Dec 2024 14:45:40 +0100 Subject: [PATCH 2/3] Revert changes --- cypress/pages/common.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cypress/pages/common.ts b/cypress/pages/common.ts index 0159452..c103ff5 100644 --- a/cypress/pages/common.ts +++ b/cypress/pages/common.ts @@ -1,5 +1,4 @@ import { CheckoutOptions, CheckoutPopupEvents } from '../../src'; -import { CheckoutResponse } from '../../src/lib/contracts/CheckoutResponse'; export const initOptions: CheckoutOptions = { product_id: Number.parseInt( @@ -48,7 +47,7 @@ export const eventListeners: CheckoutPopupEvents = { afterClose() { updateEventText(EVENT_LOG.AFTER_CLOSE); }, - success(data: CheckoutResponse | null) { + success() { updateEventText(EVENT_LOG.SUCCESS); }, track(event) { @@ -57,7 +56,7 @@ export const eventListeners: CheckoutPopupEvents = { afterOpen() { updateEventText(EVENT_LOG.AFTER_OPEN); }, - purchaseCompleted(data: CheckoutResponse | null) { + purchaseCompleted() { updateEventText(EVENT_LOG.PURCHASE_COMPLETED); }, onExitIntent() { From c862e43cf5cea91573a98d69b594fc80e066c338 Mon Sep 17 00:00:00 2001 From: Steve Henty Date: Thu, 5 Dec 2024 14:48:38 +0100 Subject: [PATCH 3/3] Revert --- src/demo.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/demo.ts b/src/demo.ts index 9d01732..abd2676 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -1,5 +1,4 @@ import { Checkout, CheckoutOptions, CheckoutPopupOptions } from '.'; -import { CheckoutResponse } from './lib/contracts/CheckoutResponse'; import './style.css'; @@ -66,13 +65,13 @@ document.addEventListener('DOMContentLoaded', () => { cancel() { log('cancel'); }, - purchaseCompleted(data: CheckoutResponse | null) { + purchaseCompleted(data) { log('purchaseCompleted', data); }, - success(data: CheckoutResponse | null) { + success(data) { log('success', data); }, - track(event: string, data: Record | null) { + track(event, data) { log('track', event, data); }, afterOpen() {