-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dfa4a75
commit 697fae5
Showing
18 changed files
with
720 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { resolveEnvironments } from '../../core/Environment'; | ||
import requestFastlaneToken from './services/request-fastlane-token'; | ||
import Script from '../../utils/Script'; | ||
|
||
import type { Fastlane, AuthenticatedCustomerResult, ShowShippingAddressSelectorResult } from './types'; | ||
import type { FastlaneTokenData } from './services/request-fastlane-token'; | ||
import type { CoreConfiguration } from '../../core/types'; | ||
|
||
export interface FastlaneSDKConfiguration { | ||
clientKey: string; | ||
locale?: 'en_us' | 'es_us' | 'fr_rs' | 'zh_us'; | ||
environment?: CoreConfiguration['environment']; | ||
} | ||
|
||
class FastlaneSDK { | ||
private readonly clientKey: string; | ||
private readonly checkoutShopperURL: string; | ||
private readonly locale: string; | ||
|
||
private fastlaneSdk: Fastlane; | ||
|
||
constructor(configuration: FastlaneSDKConfiguration) { | ||
const { apiUrl } = resolveEnvironments(configuration.environment); | ||
|
||
this.checkoutShopperURL = apiUrl; | ||
this.clientKey = configuration.clientKey; | ||
this.locale = configuration.locale || 'en_us'; | ||
} | ||
|
||
public async initialize(): Promise<FastlaneSDK> { | ||
const tokenData = await this.requestClientToken(); | ||
await this.fetchSdk(tokenData.value, tokenData.clientId); | ||
await this.initializeFastlane(); | ||
return this; | ||
} | ||
|
||
public async authenticate(email: string): Promise<AuthenticatedCustomerResult> { | ||
const { customerContextId } = await this.fastlaneSdk.identity.lookupCustomerByEmail(email); | ||
|
||
if (customerContextId) { | ||
return this.fastlaneSdk.identity.triggerAuthenticationFlow(customerContextId); | ||
} else { | ||
return { | ||
authenticationState: 'not_found', | ||
profileData: undefined | ||
}; | ||
} | ||
} | ||
|
||
public showShippingAddressSelector(): Promise<ShowShippingAddressSelectorResult> { | ||
if (!this.fastlaneSdk.profile) return null; | ||
return this.fastlaneSdk.profile.showShippingAddressSelector(); | ||
} | ||
|
||
public async mountWatermark(container: HTMLElement | string, options?) { | ||
const component = await this.fastlaneSdk.FastlaneWatermarkComponent(options); | ||
component.render(container); | ||
} | ||
|
||
private requestClientToken(): Promise<FastlaneTokenData> { | ||
return requestFastlaneToken(this.checkoutShopperURL, this.clientKey); | ||
} | ||
|
||
private async fetchSdk(clientToken: string, clientId: string) { | ||
const url = `https://www.paypal.com/sdk/js?client-id=${clientId}&components=buttons,fastlane`; | ||
const script = new Script(url, 'body', {}, { sdkClientToken: clientToken }); | ||
|
||
try { | ||
await script.load(); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
} | ||
|
||
private async initializeFastlane() { | ||
this.fastlaneSdk = await window.paypal.Fastlane({}); | ||
this.fastlaneSdk.setLocale(this.locale); | ||
} | ||
} | ||
|
||
export default FastlaneSDK; |
9 changes: 9 additions & 0 deletions
9
packages/lib/src/components/PayPalFastlane/initializeFastlane.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import FastlaneSDK from './FastlaneSDK'; | ||
import type { FastlaneSDKConfiguration } from './FastlaneSDK'; | ||
|
||
async function initializeFastlane(configuration: FastlaneSDKConfiguration): Promise<FastlaneSDK> { | ||
const fastlane = new FastlaneSDK(configuration); | ||
return await fastlane.initialize(); | ||
} | ||
|
||
export default initializeFastlane; |
24 changes: 24 additions & 0 deletions
24
packages/lib/src/components/PayPalFastlane/services/request-fastlane-token.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { httpPost } from '../../../core/Services/http'; | ||
|
||
export interface FastlaneTokenData { | ||
id: string; | ||
clientId: string; | ||
value: string; | ||
expiresAt: string; | ||
} | ||
|
||
function requestFastlaneToken(url: string, clientKey: string): Promise<FastlaneTokenData> { | ||
// @ts-ignore ignore for now | ||
const path = `utility/v1/payPalFastlane/tokens?clientKey=${clientKey}`; | ||
|
||
return Promise.resolve({ | ||
id: '2747bd08-783a-45c6-902b-3efbda5497b7', | ||
clientId: 'AXy9hIzWB6h_LjZUHjHmsbsiicSIbL4GKOrcgomEedVjduUinIU4C2llxkW5p0OG0zTNgviYFceaXEnj', | ||
merchantId: 'C3UCKQHMW4948', | ||
value: 'eyJraWQiOiJkMTA2ZTUwNjkzOWYxMWVlYjlkMTAyNDJhYzEyMDAwMiIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwczovL2FwaS5zYW5kYm94LnBheXBhbC5jb20iLCJhdWQiOlsiaHR0cHM6Ly9hcGkuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJjaGVja291dC1wbGF5Z3JvdW5kLm5ldGxpZnkuYXBwIl0sInN1YiI6Ik02VE5BRVNaNUZHTk4iLCJhY3IiOlsiY2xpZW50Il0sInNjb3BlIjpbIkJyYWludHJlZTpWYXVsdCJdLCJvcHRpb25zIjp7fSwiYXoiOiJjY2cxOC5zbGMiLCJleHRlcm5hbF9pZCI6WyJQYXlQYWw6QzNVQ0tRSE1XNDk0OCIsIkJyYWludHJlZTozZGI4aG5rdHJ0bXpzMmd0Il0sImV4cCI6MTczMDg5Nzk4NSwiaWF0IjoxNzMwODk3MDg1LCJqdGkiOiJVMkFBS05JdjBkbjZxaWtEQUMweVctdmJKSWhra3VPYTVSQ2MwMlJNdXVMWWVFUUQ2NE85UjJ1eWtRcFpucjZPanhyT3I3OVdLd0ZadGtwdi1LdUZiWHBHWkxFLU9uUEJEXzdUb1Z0RzI2dE9rM2ZNeHEyaVNna2RUd3UzRk5wQSJ9.p2lVHnIM29OsQQq4Q6N5UeHAs3AWDWs9OZ0DmYG-aMng_Dul6j1zdK4T5WoyWMu8eoM3DXHuRSQfZvD4eUPjLA', | ||
expiresAt: '2024-11-01T13:34:01.804+00:00' | ||
}); | ||
// return httpPost<FastlaneTokenData>({ loadingContext: url, path, errorLevel: 'fatal' }); | ||
} | ||
|
||
export default requestFastlaneToken; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
export type FastlaneConstructor = (options: FastlaneOptions) => Promise<Fastlane>; | ||
|
||
/** | ||
* PayPal Fastlane Reference: | ||
* https://developer.paypal.com/docs/checkout/fastlane/reference/#link-customizeyourintegration | ||
*/ | ||
|
||
// TODO: Verify if we pass options here | ||
// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
export interface FastlaneOptions {} | ||
|
||
export interface Fastlane { | ||
identity: { | ||
lookupCustomerByEmail: (email: string) => Promise<{ customerContextId: string }>; | ||
triggerAuthenticationFlow: (customerContextId: string, options?: AuthenticationFlowOptions) => Promise<AuthenticatedCustomerResult>; | ||
}; | ||
profile: { | ||
showShippingAddressSelector: () => Promise<ShowShippingAddressSelectorResult>; | ||
showCardSelector: () => ShowCardSelectorResult; | ||
}; | ||
setLocale: (locale: string) => void; | ||
FastlaneWatermarkComponent: (options: FastlaneWatermarkOptions) => Promise<FastlaneWatermarkComponent>; | ||
} | ||
|
||
interface FastlaneWatermarkOptions { | ||
includeAdditionalInfo: boolean; | ||
} | ||
interface FastlaneWatermarkComponent { | ||
render: (container) => null; | ||
} | ||
|
||
// TODO: fill this in after workshop | ||
// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
interface AuthenticationFlowOptions {} | ||
|
||
/** | ||
* The AuthenticatedCustomerResult object type is returned from the identity.triggerAuthenticationFlow() call. | ||
*/ | ||
export interface AuthenticatedCustomerResult { | ||
authenticationState: 'succeeded' | 'failed' | 'canceled' | 'not_found'; | ||
profileData: FastlaneProfile; | ||
} | ||
interface FastlaneProfile { | ||
name: Name; | ||
shippingAddress: FastlaneShipping; | ||
card: PaymentToken; | ||
} | ||
|
||
interface Name { | ||
firstName: string; | ||
lastName: string; | ||
fullName: string; | ||
} | ||
|
||
interface Phone { | ||
nationalNumber: string; | ||
countryCode: string; | ||
} | ||
|
||
export interface FastlaneAddress { | ||
addressLine1: string; | ||
addressLine2: string; | ||
adminArea1: string; | ||
adminArea2: string; | ||
postalCode: string; | ||
countryCode: string; | ||
phone: Phone; | ||
} | ||
|
||
export interface FastlaneShipping { | ||
name: Name; | ||
address: FastlaneAddress; | ||
phoneNumber: Phone; | ||
} | ||
|
||
interface PaymentToken { | ||
id: string; | ||
paymentSource: PaymentSource; | ||
} | ||
interface PaymentSource { | ||
card: CardPaymentSource; | ||
} | ||
|
||
interface CardPaymentSource { | ||
brand: string; | ||
expiry: string; | ||
lastDigits: string; | ||
name: string; | ||
billingAddress: FastlaneAddress; | ||
} | ||
|
||
/** | ||
* Profile method reference types | ||
*/ | ||
export interface ShowShippingAddressSelectorResult { | ||
selectionChanged: boolean; | ||
selectedAddress: FastlaneShipping; | ||
} | ||
|
||
interface ShowCardSelectorResult { | ||
selectionChanged: boolean; | ||
selectedCard: PaymentToken; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
packages/lib/storybook/stories/wallets/Fastlane/Fastlane.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { MetaConfiguration, StoryConfiguration } from '../../types'; | ||
import { FastlaneInSinglePageApp } from './FastlaneInSinglePageApp'; | ||
|
||
type FastlaneStory = StoryConfiguration<{}>; | ||
|
||
const meta: MetaConfiguration<FastlaneStory> = { | ||
title: 'Wallets/Fastlane' | ||
}; | ||
|
||
export const Default: FastlaneStory = { | ||
render: checkoutConfig => { | ||
const allowedPaymentTypes = ['scheme', 'paypal']; | ||
return <FastlaneInSinglePageApp checkoutConfig={{ allowedPaymentTypes, ...checkoutConfig }} />; | ||
} | ||
}; | ||
|
||
export default meta; |
37 changes: 37 additions & 0 deletions
37
packages/lib/storybook/stories/wallets/Fastlane/FastlaneInSinglePageApp.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { h } from 'preact'; | ||
import { useState } from 'preact/hooks'; | ||
|
||
import Dropin from '../../../../src/components/Dropin'; | ||
import Card from '../../../../src/components/Card'; | ||
import PayPal from '../../../../src/components/PayPal'; | ||
|
||
import { Checkout } from '../../Checkout'; | ||
import { ComponentContainer } from '../../ComponentContainer'; | ||
import { GuestShopperForm } from './components/GuestShopperForm'; | ||
import './components/FastlaneStory.scss'; | ||
|
||
import { GlobalStoryProps } from '../../types'; | ||
|
||
interface Props { | ||
checkoutConfig: GlobalStoryProps; | ||
} | ||
|
||
export const FastlaneInSinglePageApp = ({ checkoutConfig }: Props) => { | ||
const [fastlaneData, setFastlaneData] = useState<any>(null); | ||
|
||
const handleOnCheckoutStep = (fastlaneSdk, fastlaneData) => { | ||
setFastlaneData(fastlaneData); | ||
}; | ||
|
||
if (!fastlaneData) { | ||
return <GuestShopperForm onCheckoutStep={handleOnCheckoutStep} />; | ||
} | ||
|
||
return ( | ||
<Checkout checkoutConfig={checkoutConfig}> | ||
{checkout => ( | ||
<ComponentContainer element={new Dropin(checkout, { showStoredPaymentMethods: false, paymentMethodComponents: [Card, PayPal] })} /> | ||
)} | ||
</Checkout> | ||
); | ||
}; |
Oops, something went wrong.