Skip to content

Commit

Permalink
[options] [update] Add new product_id and make plugin_id as alias wit…
Browse files Browse the repository at this point in the history
…h supported type intellisense.
  • Loading branch information
swashata committed Nov 24, 2024
1 parent 7e082e1 commit a85f2c0
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 41 deletions.
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- [Instantiate the class](#instantiate-the-class)
- [Calling the method](#calling-the-method)
- [Use with React](#use-with-react)
- [Testing with Sandbox](#testing-with-sandbox)
- [Testing with Sandbox](#testing-with-the-sandbox)
- [Migration guide](#migration-guide)
- [Contributing](#contributing)

Expand Down Expand Up @@ -50,7 +50,7 @@ function getSelectedLicenses() {
}

const handler = new Checkout({
plugin_id: '311',
product_id: '311',
public_key: 'pk_a42d2ee6de0b31c389d5d11e36211',
});

Expand Down Expand Up @@ -104,7 +104,7 @@ need to hook into the `load` event of `window` or use `window.onload`.
<script type="text/javascript">
window.addEventListener('load', () => {
const handler = new FS.Checkout({
plugin_id: '1234',
product_id: '1234',
public_key: 'pk_xxxx',
});
Expand Down Expand Up @@ -179,7 +179,7 @@ available under the global `FS` namespace.

```js
const handler = new FS.Checkout({
plugin_id: '1234',
product_id: '1234',
public_key: 'pk_xxxx',
});
```
Expand All @@ -191,12 +191,12 @@ import { Checkout } from 'freemius-checkout-js';

// instantiate
const handler = new Checkout({
plugin_id: '0001',
product_id: '0001',
public_key: 'pk_xxxx',
});
```

Note that the `plugin_id` and `public_key` are required parameters and must be
Note that the `product_id` and `public_key` are required parameters and must be
supplied during instantiation.

### Calling the method
Expand Down Expand Up @@ -233,8 +233,8 @@ handle.close();

## Use with React

We will make a small react hook. Here we assume the `plugin_id` and `public_key`
are available in
We will make a small react hook. Here we assume the `product_id` and
`public_key` are available in
[some environment variable](https://vite.dev/guide/env-and-mode).

**checkout.ts**
Expand All @@ -244,7 +244,7 @@ import { Checkout, CheckoutOptions } from '@freemius/checkout';
import { useState, useEffect } from 'react';

export const checkoutConfig: CheckoutOptions = {
plugin_id: import.meta.env.VITE_FS_PLUGIN_ID as string,
product_id: import.meta.env.VITE_FS_PLUGIN_ID as string,
public_key: import.meta.env.VITE_FS_PUBLIC_KEY as string,
};

Expand Down Expand Up @@ -347,6 +347,10 @@ context. In this repository we use the `.env` file for storing sandbox data.

The rest of the code will continue to work exactly as it is with no changes.

Optionally you can also change `plugin_id` to `product_id`, but we support both
(giving preference to `product_id` if both are set) and we don't plan to remove
it the near future.

```js
document.querySelector('#purchase').addEventListener('click', (e) => {
handler.open({
Expand All @@ -372,7 +376,7 @@ page, just create a new checkout:

```js
const anotherHandler = new FS.Checkout({
plugin_id: '4321',
product_id: '4321',
plan_id: '9876',
public_key: 'pk_....nnn',
image: 'https://your-plugin-site.com/logo-100x100.png',
Expand Down
4 changes: 2 additions & 2 deletions src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Backward compatible adapter for the checkout service.
*/
import './global';
import { CheckoutOptions, Checkout } from '.';
import { Checkout, CheckoutOptions } from '.';
import { IFSOldCheckout } from './lib/contracts/IFSOldCheckout';

class FSOldCheckout implements IFSOldCheckout {
Expand Down Expand Up @@ -38,7 +38,7 @@ class FSOldCheckout implements IFSOldCheckout {

checkout.open({
...(this.options ?? {}),
...options,
...(options as Omit<CheckoutOptions, 'plugin_id' | 'product_id'>),
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/demo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Checkout, CheckoutOptions } from '.';
import { Checkout, CheckoutOptions, CheckoutPopupOptions } from '.';

import './style.css';

Expand Down Expand Up @@ -39,7 +39,7 @@ document.addEventListener('DOMContentLoaded', () => {
}

function getEventLoggers(): Pick<
CheckoutOptions,
CheckoutPopupOptions,
| 'cancel'
| 'purchaseCompleted'
| 'success'
Expand Down
28 changes: 22 additions & 6 deletions src/lib/checkout.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { screen } from '@testing-library/dom';
import { Checkout } from './checkout';
import { Checkout, CheckoutOptions } from './checkout';
import { sendMockedCanceledEvent } from '../../tests/utils';
import { createHydratedMock } from 'ts-auto-mock';
import {
CheckoutPopupOptions,
CheckoutPopupParams,
} from './contracts/CheckoutPopupOptions';
import { CheckoutPopupParams } from './contracts/CheckoutPopupOptions';
import { getQueryValueFromItem } from './utils/ops';

describe('CheckoutPopup', () => {
Expand Down Expand Up @@ -145,7 +142,7 @@ describe('CheckoutPopup', () => {
});

test('passes all undocumented query parameters', () => {
const option: CheckoutPopupOptions = {
const option: CheckoutOptions = {
plugin_id: 1,
public_key: 'pk_123456',
foo: 'bar',
Expand Down Expand Up @@ -207,4 +204,23 @@ describe('CheckoutPopup', () => {
new URL(iFrame.src).searchParams.get('license_key')
).toMatchInlineSnapshot(`"sk_R-5E2+%20BD:.kp*(Oq2aodhzZ1Jw"`);
});

test('supports product_id instead of plugin_id', () => {
const checkout = new Checkout({
product_id: 1,
public_key: 'pk_123456',
license_key: 'sk_R-5E2+%20BD:.kp*(Oq2aodhzZ1Jw',
});
checkout.open();

const guid = checkout.getGuid();

const iFrame = screen.queryByTestId(
`fs-checkout-page-${guid}`
) as HTMLIFrameElement;

expect(iFrame).toBeInTheDocument();

expect(new URL(iFrame.src).searchParams.get('plugin_id')).toBe('1');
});
});
31 changes: 21 additions & 10 deletions src/lib/checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import type { CheckoutOptions } from './types';
import { Style } from './services/style';
import { Loader } from './services/loader';
import { CheckoutPopup } from './services/checkout-popup';
import { CheckoutPopupOptions } from './contracts/CheckoutPopupOptions';
import {
CheckoutPopupArbitraryParams,
CheckoutPopupOptions,
} from './contracts/CheckoutPopupOptions';
import { ExitIntent } from './services/exit-intent';
import { ILoader } from './contracts/ILoader';
import { IExitIntent } from './contracts/IExitIntent';
Expand All @@ -14,7 +17,8 @@ import { Cart } from './services/cart';
export type { PostmanEvents, CheckoutOptions };

export class Checkout {
private readonly options: CheckoutOptions = {
private readonly options: CheckoutPopupOptions &
CheckoutPopupArbitraryParams = {
plugin_id: 0,
public_key: '',
};
Expand All @@ -36,14 +40,22 @@ export class Checkout {
recoverCart: boolean = true,
private readonly baseUrl: string = 'https://checkout.freemius.com'
) {
if (!options.plugin_id) {
throw new Error('Must provide a plugin_id to options.');
const { plugin_id, product_id, public_key, ...popupOptions } = options;

if (!plugin_id && !product_id) {
throw new Error('Must provide a product_id to options.');
}
if (!options.public_key) {

if (!public_key) {
throw new Error('Must provide the public_key to options.');
}

this.options = options;
this.options = {
...popupOptions,
public_key,
plugin_id: plugin_id ?? product_id,
};

this.guid = generateGuid();

if (isSsr()) {
Expand All @@ -54,9 +66,8 @@ export class Checkout {

this.loader = new Loader(
this.style,
this.options.loadingImageUrl ??
`${this.baseUrl}/assets/img/spinner.svg`,
this.options.loadingImageAlt
options.loadingImageUrl ?? `${this.baseUrl}/assets/img/spinner.svg`,
options.loadingImageAlt
);

this.exitIntent = new ExitIntent(this.style);
Expand Down Expand Up @@ -84,7 +95,7 @@ export class Checkout {
*/
public open(
options?: Partial<
Omit<CheckoutPopupOptions, 'plugin_id' | 'public_key'>
Omit<CheckoutOptions, 'plugin_id' | 'public_key' | 'product_id'>
>
) {
if (isSsr()) {
Expand Down
25 changes: 20 additions & 5 deletions src/lib/contracts/CheckoutPopupOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export type CheckoutTrackingEvent =
| 'load'
| 'review-order';

/**
* All known parameters for the Checkout iFrame.
*
* @internal
*/
export interface CheckoutPopupParams {
/**
* Required product ID (whether it’s a plugin, theme, add-on, bundle, or SaaS).
Expand Down Expand Up @@ -356,6 +361,11 @@ export interface CheckoutPopupParams {
default_currency?: 'usd' | 'eur' | 'gbp';
}

/**
* All known events for the Checkout iFrame.
*
* @internal
*/
export interface CheckoutPopupEvents {
/**
* A callback handler that will execute once a user closes the checkout by
Expand Down Expand Up @@ -405,11 +415,16 @@ export interface CheckoutPopupEvents {
onExitIntent?: () => void;
}

/**
* All options (parameters and events) required and supported by the Freemius Checkout.
*/
export interface CheckoutPopupOptions
extends CheckoutPopupParams,
CheckoutPopupEvents {
/**
* Accept any arbitrary key-value pair to be passed to the checkout.
*/
[key: string]: any;
CheckoutPopupEvents {}

/**
* Accept any arbitrary key-value pair to be passed to the checkout.
*/
export interface CheckoutPopupArbitraryParams {
[key: Exclude<string, keyof CheckoutPopupOptions>]: any;
}
9 changes: 6 additions & 3 deletions src/lib/services/cart/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { CheckoutPopupOptions } from '../../contracts/CheckoutPopupOptions';
import {
CheckoutPopupArbitraryParams,
CheckoutPopupOptions,
} from '../../contracts/CheckoutPopupOptions';
import { assertNotNull } from '../../utils/ops';

/**
Expand Down Expand Up @@ -40,10 +43,10 @@ export class Cart {
);
}

getCheckoutOptions(): CheckoutPopupOptions {
getCheckoutOptions(): CheckoutPopupOptions & CheckoutPopupArbitraryParams {
assertNotNull(this.queryParams, Cart.NO_CART_FOUND_MESSAGE);

const params: CheckoutPopupOptions = {
const params: CheckoutPopupOptions & CheckoutPopupArbitraryParams = {
plugin_id: '',
public_key: '',
};
Expand Down
34 changes: 31 additions & 3 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { CheckoutPopupOptions } from './contracts/CheckoutPopupOptions';
import {
CheckoutPopupArbitraryParams,
CheckoutPopupOptions,
} from './contracts/CheckoutPopupOptions';

export interface CheckoutOptions extends CheckoutPopupOptions {
/**
* All options required and supported by the Freemius Checkout.
*
* @see https://freemius.com/help/documentation/selling-with-freemius/freemius-checkout-buy-button/
*
* @note The `public_key` and either of `plugin_id` or `product_id` are required.
*/
export type CheckoutOptions = Omit<CheckoutPopupOptions, 'plugin_id'> & {
/**
* The URL of the image to display while the checkout is loading. By default a loading indicator from Freemius will be used.
*/
Expand All @@ -9,4 +19,22 @@ export interface CheckoutOptions extends CheckoutPopupOptions {
* The alt text for the loading image. By default 'Loading Freemius Checkout' will be used.
*/
loadingImageAlt?: string;
}
} & CheckoutPopupArbitraryParams &
(
| {
/**
* Required product ID (whether it’s a plugin, theme, add-on, bundle, or SaaS).
*/
product_id: number | string;
plugin_id?: never;
}
| {
/**
* Required product ID (whether it’s a plugin, theme, add-on, bundle, or SaaS).
*
* @deprecated Use `product_id` instead.
*/
plugin_id: number | string;
product_id?: never;
}
);

0 comments on commit a85f2c0

Please sign in to comment.