Skip to content

Commit

Permalink
One-click payment flow for external developers (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
SamborGornicz authored Oct 31, 2024
1 parent 86d6634 commit 1f78de6
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 69 deletions.
7 changes: 7 additions & 0 deletions .changeset/brown-planes-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@livechat/agent-app-sdk": minor
"@livechat/helpdesk-sdk": minor
"@livechat/widget-core-sdk": minor
---

Added `startTransaction` for all widget types to support One-click Payment flow
79 changes: 79 additions & 0 deletions packages/agent-app-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,85 @@ createDetailsWidget().then(widget => {

Each widget type offers a different set of events that you can listen to. Check them out in the descriptions below.

## Payments

All widgets allow you to pass a registered charge and display a summary of it to the customer within the payment modal in the Agent App application, enabling them to complete or decline the transaction.

### Events

#### `transaction_accepted`

Emitted when a payment transaction is approved by the customer and successfully processed by the Billing API.

```ts
interface ITransactionAccepted {
chargeId: string;
}
```

#### `transaction_declined`

Emitted when a payment transaction is declined by the customer (e.g., the user closes the payment modal or clicks the cancel button), and the charge is subsequently marked as declined in the Billing API.

```ts
interface ITransactionDeclined {
chargeId: string;
}
```
#### `transaction_failed`

Emitted when a payment transaction fails and cannot be processed by the billing API.

```ts
interface ITransactionAccepted {
error: unknown;
}
```

#### `update_billing_cycle`

This event is triggered when a customer selects a different billing cycle for a transaction. It only emits if the `showBillingCyclePicker` flag is set to `true` in the `metadata` object at the start of the transaction. The event includes the new billing cycle number and key charge details, allowing you to register the updated charge with the provided information.

```ts
interface ITransactionAccepted {
billingCycle: number,
paymentIntent: {
name: string,
price: number,
per_account: boolean,
test: boolean,
return_url: string | null,
months?: number,
trial_days?: number,
quantity?: number,
metadata: {
type: string,
isExternalTransaction: boolean,
showBillingCyclePicker: boolean,
icon: string,
description?: string,
}
}
}
```

### Methods

#### `startTransaction(charge: Charge, metadata: Metadata): Promise<void>`

This method allows you to pass a registered charge and accompanying metadata to the Agent App. The payment modal will then be displayed to the customer, enabling them to complete the transaction. For more information on registering a charge, refer to the [Billing API documentation](https://platform.text.com/docs/monetization/billing-api).

```ts
const charge = {...} // Billing API charge object
const metadata = {
icon: "https://icon.url";
description: "This is a description of the transaction.";
showBillingCyclePicker: true; // optional, use if you want to display the billing cycle picker to the customer
}

widget.startTransaction(charge, metadata);
```

## Details widget (`IDetailsWidget`)

A type of widget that has access to the Chat Details context.
Expand Down
4 changes: 3 additions & 1 deletion packages/agent-app-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { Charge, IDirectCharge, IRecurrentCharge, Metadata, TransactionError, TransactionEvent, UpdateBillingCycleEvent } from '@livechat/widget-core-sdk';
export * from './widgets/details';
export * from './widgets/messagebox';
export * from './widgets/fullscreen';
export * from './widgets/messagebox';
export * from './widgets/settings';
export * from './widgets/shared/customer-profile';

16 changes: 4 additions & 12 deletions packages/agent-app-sdk/src/widgets/details/details-widget.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import {
createWidget,
withAmplitude,
createConnection,
IConnection
} from '@livechat/widget-core-sdk';
import { createConnection, createWidget, IConnection, withAmplitude, withPayments } from '@livechat/widget-core-sdk';
import { withCustomerProfile } from '../shared/customer-profile';
import { withRichMessages } from '../shared/rich-messages';
import assertSection from './custom-sections';
import {
IDetailsWidgetEvents,
IDetailsWidgetApi,
ISection
} from './interfaces';
import { IDetailsWidgetApi, IDetailsWidgetEvents, ISection } from './interfaces';


export function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
const base = createWidget<IDetailsWidgetApi, IDetailsWidgetEvents>(
Expand All @@ -33,7 +25,7 @@ export function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
}
);

const widget = withAmplitude(withRichMessages(withCustomerProfile(base)));
const widget = withAmplitude(withRichMessages(withCustomerProfile(withPayments(base))));

return widget;
}
Expand Down
16 changes: 4 additions & 12 deletions packages/agent-app-sdk/src/widgets/fullscreen/fullscreen-widget.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import {
createWidget,
withAmplitude,
createConnection,
IConnection
} from '@livechat/widget-core-sdk';
import {
IFullscreenWidgetApi,
IFullscreenWidgetEvents,
ReportsFilters
} from './interfaces';
import { createConnection, createWidget, IConnection, withAmplitude, withPayments } from '@livechat/widget-core-sdk';
import { withPageData } from '../shared/page-data';
import { IFullscreenWidgetApi, IFullscreenWidgetEvents, ReportsFilters } from './interfaces';

export { ReportsFilters } from './interfaces';

Expand All @@ -36,7 +27,8 @@ export function FullscreenWidget(
}
}
);
return withAmplitude(withPageData(base));

return withAmplitude(withPageData(withPayments(base)));
}

export type IFullscreenWidget = ReturnType<typeof FullscreenWidget>;
Expand Down
15 changes: 3 additions & 12 deletions packages/agent-app-sdk/src/widgets/messagebox/messagebox-widget.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import {
createWidget,
withAmplitude,
createConnection,
IConnection
} from '@livechat/widget-core-sdk';
import { createConnection, createWidget, IConnection, withAmplitude, withPayments } from '@livechat/widget-core-sdk';
import { withCustomerProfile } from '../shared/customer-profile';
import { withRichMessages } from '../shared/rich-messages';
import {
IMessageBoxWidgetApi,
IMessageBoxWidgetEvents,
IRichMessage
} from './interfaces';
import { IMessageBoxWidgetApi, IMessageBoxWidgetEvents, IRichMessage } from './interfaces';

export function MessageBoxWidget(
connection: IConnection<IMessageBoxWidgetEvents>
Expand All @@ -30,7 +21,7 @@ export function MessageBoxWidget(
}
);

const widget = withAmplitude(withRichMessages(withCustomerProfile(base)));
const widget = withAmplitude(withRichMessages(withCustomerProfile(withPayments(base))));

return widget;
}
Expand Down
11 changes: 3 additions & 8 deletions packages/agent-app-sdk/src/widgets/settings/settings-widget.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import {
createWidget,
withAmplitude,
createConnection,
IConnection
} from '@livechat/widget-core-sdk';
import { ISettingsWidgetApi, ISettingsWidgetEvents } from './interfaces';
import { createConnection, createWidget, IConnection, withAmplitude, withPayments } from '@livechat/widget-core-sdk';
import { withPageData } from '../shared/page-data';
import { ISettingsWidgetApi, ISettingsWidgetEvents } from './interfaces';

export function SettingsWidget(connection: IConnection<ISettingsWidgetEvents>) {
const base = createWidget<ISettingsWidgetApi, ISettingsWidgetEvents>(
Expand All @@ -16,7 +11,7 @@ export function SettingsWidget(connection: IConnection<ISettingsWidgetEvents>) {
}
}
);
return withAmplitude(withPageData(base));
return withAmplitude(withPageData(withPayments(base)));
}

export type ISettingsWidget = ReturnType<typeof SettingsWidget>;
Expand Down
79 changes: 79 additions & 0 deletions packages/helpdesk-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,85 @@ createDetailsWidget().then(widget => {

Each widget type offers a different set of events that you can listen to. Check them out in the descriptions below.

## Payments

All widgets allow you to pass a registered charge and display a summary of it to the customer within the payment modal in the helpdesk application, enabling them to complete or decline the transaction.

### Events

#### `transaction_accepted`

Emitted when a payment transaction is approved by the customer and successfully processed by the Billing API.

```ts
interface ITransactionAccepted {
chargeId: string;
}
```

#### `transaction_declined`

Emitted when a payment transaction is declined by the customer (e.g., the user closes the payment modal or clicks the cancel button), and the charge is subsequently marked as declined in the Billing API.

```ts
interface ITransactionDeclined {
chargeId: string;
}
```
#### `transaction_failed`

Emitted when a payment transaction fails and cannot be processed by the billing API.

```ts
interface ITransactionAccepted {
error: unknown;
}
```

#### `update_billing_cycle`

This event is triggered when a customer selects a different billing cycle for a transaction. It only emits if the `showBillingCyclePicker` flag is set to `true` in the `metadata` object at the start of the transaction. The event includes the new billing cycle number and key charge details, allowing you to register the updated charge with the provided information.

```ts
interface ITransactionAccepted {
billingCycle: number,
paymentIntent: {
name: string,
price: number,
per_account: boolean,
test: boolean,
return_url: string | null,
months?: number,
trial_days?: number,
quantity?: number,
metadata: {
type: string,
isExternalTransaction: boolean,
showBillingCyclePicker: boolean,
icon: string,
description?: string,
}
}
}
```

### Methods

#### `startTransaction(charge: Charge, metadata: Metadata): Promise<void>`

This method allows you to pass a registered charge and accompanying metadata to the HelpDesk App. The payment modal will then be displayed to the customer, enabling them to complete the transaction. For more information on registering a charge, refer to the [Billing API documentation](https://platform.text.com/docs/monetization/billing-api).

```ts
const charge = {...} // Billing API charge object
const metadata = {
icon: "https://icon.url";
description: "This is a description of the transaction.";
showBillingCyclePicker: true; // optional, use if you want to display the billing cycle picker to the customer
}

widget.startTransaction(charge, metadata);
```

## Details widget (`IDetailsWidget`)

A type of widget that has access to the Chat Details context.
Expand Down
4 changes: 3 additions & 1 deletion packages/helpdesk-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './widgets/fullscreen';
export { Charge, IDirectCharge, IRecurrentCharge, Metadata, TransactionError, TransactionEvent, UpdateBillingCycleEvent } from '@livechat/widget-core-sdk';
export * from './widgets/details';
export * from './widgets/fullscreen';

19 changes: 5 additions & 14 deletions packages/helpdesk-sdk/src/widgets/details/details-widget.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import {
createWidget,
withAmplitude,
createConnection,
IConnection
} from '@livechat/widget-core-sdk';
import { withTicketInfo } from './ticket-info';
import { createConnection, createWidget, IConnection, withAmplitude, withPayments } from '@livechat/widget-core-sdk';
import assertSection from './custom-sections';
import {
IDetailsWidgetEvents,
IDetailsWidgetApi,
ISection
} from './interfaces';
import { IDetailsWidgetApi, IDetailsWidgetEvents, ISection } from './interfaces';
import { withTicketInfo } from './ticket-info';

export function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
const base = createWidget<IDetailsWidgetApi, IDetailsWidgetEvents>(
Expand All @@ -23,12 +14,12 @@ export function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
}
);

const widget = withAmplitude(withTicketInfo(base));
const widget = withAmplitude(withTicketInfo(withPayments(base)));

return widget;
}

export interface IDetailsWidget extends ReturnType<typeof DetailsWidget> {}
export interface IDetailsWidget extends ReturnType<typeof DetailsWidget> { }

export default function createDetailsWidget(): Promise<IDetailsWidget> {
let widget: IDetailsWidget;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
createWidget,
withAmplitude,
createConnection,
IConnection
} from '@livechat/widget-core-sdk';
import { createConnection, createWidget, IConnection, withAmplitude, withPayments } from '@livechat/widget-core-sdk';
import { IFullscreenWidgetApi, IFullscreenWidgetEvents } from './interfaces';

export function FullscreenWidget(
Expand All @@ -21,11 +16,11 @@ export function FullscreenWidget(
}
);

return withAmplitude(base);
return withAmplitude(withPayments(base));
}

export interface IFullscreenWidget
extends ReturnType<typeof FullscreenWidget> {}
extends ReturnType<typeof FullscreenWidget> { }

export default function createFullscreenWidget(): Promise<IFullscreenWidget> {
return createConnection<IFullscreenWidgetEvents>().then(connection =>
Expand Down
4 changes: 3 additions & 1 deletion packages/widget-core-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './widget';
export * from './amplitude';
export * from './connection';
export * from './payments';
export * from './widget';

Loading

0 comments on commit 1f78de6

Please sign in to comment.