Skip to content

Commit

Permalink
standalone component ui
Browse files Browse the repository at this point in the history
  • Loading branch information
ribeiroguilherme committed Dec 3, 2024
1 parent 30fe041 commit 5687ba4
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 57 deletions.
8 changes: 5 additions & 3 deletions packages/lib/src/components/Dropin/Dropin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ class DropinElement extends UIElement<DropinConfiguration> implements IDropin {

const commonProps = getCommonProps({ ...this.props, elementRef: this.elementRef });

const elements = showPaymentMethods ? createElements(paymentMethods, paymentMethodsConfiguration, commonProps, this.core) : [];
const instantPaymentElements = createInstantPaymentElements(instantPaymentMethods, paymentMethodsConfiguration, commonProps, this.core);
const storedElements = showStoredPaymentMethods
? createStoredElements(storedPaymentMethods, paymentMethodsConfiguration, commonProps, this.core)
: [];
const elements = showPaymentMethods ? createElements(paymentMethods, paymentMethodsConfiguration, commonProps, this.core) : [];
const instantPaymentElements = createInstantPaymentElements(instantPaymentMethods, paymentMethodsConfiguration, commonProps, this.core);
const fastlanePaymentElement = createElements([fastlanePaymentMethod], paymentMethodsConfiguration, commonProps, this.core);
const fastlanePaymentElement = fastlanePaymentMethod
? createElements([fastlanePaymentMethod], paymentMethodsConfiguration, commonProps, this.core)
: [];

return [storedElements, elements, instantPaymentElements, fastlanePaymentElement];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Button from '../../internal/Button';
export class DropinComponent extends Component<DropinComponentProps, DropinComponentState> {
public state: DropinComponentState = {
elements: [],
fastlanePaymentElement: null,
fastlanePaymentElement: [],
instantPaymentElements: [],
storedPaymentElements: [],
orderStatus: null,
Expand All @@ -41,7 +41,7 @@ export class DropinComponent extends Component<DropinComponentProps, DropinCompo
elements,
instantPaymentElements,
storedPaymentElements,
fastlanePaymentElement: fastlanePaymentElement[0],
fastlanePaymentElement,
showPaymentMethodList: fastlanePaymentElement.length === 0
});

Expand All @@ -65,6 +65,7 @@ export class DropinComponent extends Component<DropinComponentProps, DropinCompo
}

public setStatus = (status: UIElementStatus, props: DropinStatusProps = {}) => {
console.log(' dropin - setstatus');
this.setState({ status: { type: status, props } });
};

Expand Down Expand Up @@ -158,7 +159,6 @@ export class DropinComponent extends Component<DropinComponentProps, DropinCompo
props,
{
elements,
// fastlaneElement,
fastlanePaymentElement,
instantPaymentElements,
storedPaymentElements,
Expand All @@ -172,6 +172,8 @@ export class DropinComponent extends Component<DropinComponentProps, DropinCompo
const isRedirecting = status.type === 'redirect';
const hasPaymentMethodsToBeDisplayed = elements?.length || instantPaymentElements?.length || storedPaymentElements?.length;

console.log(' Dropin component');

switch (status.type) {
case 'success':
return <Status.Success message={props?.amount?.value === 0 ? 'resultMessages.preauthorized' : status.props?.message} />;
Expand All @@ -193,8 +195,8 @@ export class DropinComponent extends Component<DropinComponentProps, DropinCompo
<Fragment>
<PaymentMethodList
isLoading={isLoading || isRedirecting}
isDisablingPaymentMethod={this.state.isDisabling}
paymentMethods={[fastlanePaymentElement]}
// isDisablingPaymentMethod={this.state.isDisabling}
paymentMethods={fastlanePaymentElement}
// instantPaymentMethods={instantPaymentElements}
// storedPaymentMethods={storedPaymentElements}
activePaymentMethod={activePaymentMethod}
Expand All @@ -203,8 +205,7 @@ export class DropinComponent extends Component<DropinComponentProps, DropinCompo
// orderStatus={this.state.orderStatus}
// onOrderCancel={this.onOrderCancel}
onSelect={this.handleOnSelectPaymentMethod}
openPaymentMethod={this.props.openPaymentMethod}
openFirstPaymentMethod={this.props.openFirstPaymentMethod}
openFirstPaymentMethod
// openFirstStoredPaymentMethod={this.props.openFirstStoredPaymentMethod}
// onDisableStoredPaymentMethod={this.handleDisableStoredPaymentMethod}
// showRemovePaymentMethodButton={this.props.showRemovePaymentMethodButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ interface PaymentMethodListProps extends Omit<PaymentMethodsContainerProps, 'lab
}

const PaymentMethodList = ({
paymentMethods = [], // Non-stored payments
instantPaymentMethods = [],
storedPaymentMethods = [],
paymentMethods,
instantPaymentMethods,
storedPaymentMethods,
openFirstStoredPaymentMethod,
openFirstPaymentMethod,
openPaymentMethod,
Expand All @@ -37,13 +37,13 @@ const PaymentMethodList = ({
}: PaymentMethodListProps) => {
const { i18n } = useCoreContext();
const brandLogoConfiguration = useBrandLogoConfiguration(paymentMethods);
const hasInstantPaymentMethods = instantPaymentMethods.length > 0;
const hasStoredPaymentMethods = storedPaymentMethods.length > 0;
const hasInstantPaymentMethods = instantPaymentMethods?.length > 0;
const hasStoredPaymentMethods = storedPaymentMethods?.length > 0;
const pmListLabel = hasInstantPaymentMethods || hasStoredPaymentMethods ? i18n.get('paymentMethodsList.otherPayments.label') : '';

useEffect(() => {
if (openPaymentMethod?.type) {
const paymentMethod = paymentMethods.find(paymentMethod => paymentMethod.type === openPaymentMethod?.type);
const paymentMethod = paymentMethods?.find(paymentMethod => paymentMethod.type === openPaymentMethod?.type);
if (!paymentMethod) {
console.warn(`Drop-in: payment method type "${openPaymentMethod?.type}" not found`);
} else {
Expand All @@ -53,8 +53,8 @@ const PaymentMethodList = ({
}

// Open first PaymentMethodItem
const firstStoredPayment = storedPaymentMethods[0];
const firstNonStoredPayment = paymentMethods[0];
const firstStoredPayment = storedPaymentMethods?.[0];
const firstNonStoredPayment = paymentMethods?.[0];

if (firstStoredPayment || firstNonStoredPayment) {
const shouldOpenFirstStored = openFirstStoredPaymentMethod && getProp(firstStoredPayment, 'props.oneClick') === true;
Expand All @@ -69,6 +69,8 @@ const PaymentMethodList = ({
}
}, [storedPaymentMethods, paymentMethods, openFirstStoredPaymentMethod, openFirstPaymentMethod, openPaymentMethod]);

console.log('PaymentMethodList');

return (
<Fragment>
{orderStatus && (
Expand Down
13 changes: 11 additions & 2 deletions packages/lib/src/components/Dropin/elements/splitPaymentMethods.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { InstantPaymentTypes } from '../types';
import PaymentMethods from '../../../core/ProcessResponse/PaymentMethods';

function splitPaymentMethods(paymentMethods: PaymentMethods, instantPaymentTypes: InstantPaymentTypes[]) {
import type { InstantPaymentTypes } from '../types';
import type { PaymentMethod, StoredPaymentMethod } from '../../../types/global-types';

interface SplitPaymentMethods {
fastlanePaymentMethod: PaymentMethod | undefined;
storedPaymentMethods: StoredPaymentMethod[];
paymentMethods: PaymentMethod[];
instantPaymentMethods: PaymentMethod[];
}

function splitPaymentMethods(paymentMethods: PaymentMethods, instantPaymentTypes: InstantPaymentTypes[]): SplitPaymentMethods {
return {
fastlanePaymentMethod: paymentMethods.paymentMethods.find(({ type }) => ['fastlane'].includes(type)),
instantPaymentMethods: paymentMethods.paymentMethods.filter(({ type }) => instantPaymentTypes.includes(type as InstantPaymentTypes)),
Expand Down
3 changes: 1 addition & 2 deletions packages/lib/src/components/Dropin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,7 @@ export interface DropinStatusProps {

export interface DropinComponentState {
elements: any[];
fastlanePaymentElement: UIElement | null;
// fastlaneElement: UIElement | null;
fastlanePaymentElement: UIElement[];
instantPaymentElements: UIElement[];
storedPaymentElements: UIElement[];
status: DropinStatus;
Expand Down
30 changes: 26 additions & 4 deletions packages/lib/src/components/PayPalFastlane/Fastlane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import UIElement from '../internal/UIElement';
import { CoreProvider } from '../../core/Context/CoreProvider';
import { TxVariants } from '../tx-variants';
import { UIElementProps } from '../internal/UIElement/types';
import FastlaneComponent from './components/FastlaneComponent';

interface FastlaneConfiguration extends UIElementProps {
tokenId: string;
customerId: string;
lastFour: string;
brand: string;
email: string;
/**
* List of brands accepted by the component
* @internal
*/
brands?: string[];
/**
* Configuration returned by the backend
* @internal
Expand All @@ -22,6 +28,10 @@ interface FastlaneConfiguration extends UIElementProps {
class Fastlane extends UIElement<FastlaneConfiguration> {
public static type = TxVariants.fastlane;

protected static defaultProps = {
keepBrandsVisible: true
};

protected override formatData() {
return {
paymentMethod: {
Expand Down Expand Up @@ -49,13 +59,25 @@ class Fastlane extends UIElement<FastlaneConfiguration> {
return true;
}

render() {
console.log('FASTLANE RENDER');
public override get icon(): string {
return this.props.icon ?? this.resources.getImage()('card');
}

public get brands(): { icon: string; name: string }[] {
const { brands } = this.props;
return brands.map(brand => ({ icon: this.props.modules.resources.getImage()(brand), name: brand }));
}

render() {
return (
<CoreProvider i18n={this.props.i18n} loadingContext={this.props.loadingContext} resources={this.resources}>
<div> **** {this.props.lastFour} </div>
<button>pay</button>
<FastlaneComponent
lastFour={this.props.lastFour}
brand={this.props.brand}
payButton={this.payButton}
setComponentRef={this.setComponentRef}
showPayButton={this.props.showPayButton}
/>
</CoreProvider>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { h } from 'preact';
import useImage from '../../../core/Context/useImage';
import Img from '../../internal/Img';
import { getFullBrandName } from '../../Card/components/CardInput/utils';

interface FastlaneBrandIconProps {
brand: string;
}

const FastlaneBrandIcon = ({ brand }: FastlaneBrandIconProps) => {
const getImage = useImage();

return (
<span className="adyen-checkout-fastlane__card-brand--wrapper">
<Img src={getImage()(brand)} alt={getFullBrandName(brand)} />
</span>
);
};

export default FastlaneBrandIcon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@import 'styles/variable-generator';

.adyen-checkout-fastlane__card-brand--wrapper {
position: relative;
display: flex;
width: token(spacer-110);
height: 26px;
justify-content: center;
align-items: center;
border-radius: token(border-radius-s);
overflow: hidden;
box-shadow: token(shadow-low);
margin-right: 12px;
}


.adyen-checkout-fastlane__card-section {
display: flex;
align-items: center;
}

.adyen-checkout-fastlane__card-number {
line-height: 20px;
font-size: 14px;
font-weight: 500;
}

.adyen-checkout-fastlane__brand {
display: flex;
justify-content: center;
margin-top: 16px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { h } from 'preact';
import { ComponentMethodsRef, PayButtonFunctionProps, UIElementStatus } from '../../internal/UIElement/types';
import { useEffect, useRef, useState } from 'preact/hooks';
import FastlaneBrandIcon from './FaslaneBrandIcon';
import { PREFIX } from '../../internal/Icon/constants';
import useImage from '../../../core/Context/useImage';
import Img from '../../internal/Img';
import './Fastlane.scss';

interface FastlaneComponentProps {
lastFour: string;
brand: string;
showPayButton: boolean;
setComponentRef: (ref: ComponentMethodsRef) => void;
payButton(props?: PayButtonFunctionProps): h.JSX.Element;
}

const FastlaneComponent = ({ lastFour, brand, payButton, setComponentRef, showPayButton }: FastlaneComponentProps) => {
const getImage = useImage();
const [status, setStatus] = useState<UIElementStatus>('ready');
const fastlaneRef = useRef({
setStatus: (status: UIElementStatus) => setStatus(status)
});

useEffect(() => {
setComponentRef(fastlaneRef.current);
}, []);

return (
<div className="adyen-checkout-fastlane">
<div className="adyen-checkout-fastlane__card-section">
<FastlaneBrandIcon brand={brand} />
<span className="adyen-checkout-fastlane__card-number">•••• {lastFour}</span>
</div>

{showPayButton && payButton({ status, icon: getImage({ imageFolder: 'components/' })(`${PREFIX}lock`) })}

<div className="adyen-checkout-fastlane__brand">
<Img width="95px" src={getImage({ imageFolder: 'components/' })(`paypal_fastlane_gray`)} alt="Fastlane brand" />
</div>
</div>
);
};

export default FastlaneComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ export interface FastlaneTokenData {
}

function requestFastlaneToken(url: string, clientKey: string): Promise<FastlaneTokenData> {
const path = `utility/v1/payPalFastlane/tokens?clientKey=${clientKey}`;
return httpPost<FastlaneTokenData>({ loadingContext: url, path, errorLevel: 'fatal' });
// const path = `utility/v1/payPalFastlane/tokens?clientKey=${clientKey}`;
// return httpPost<FastlaneTokenData>({ loadingContext: url, path, errorLevel: 'fatal' });

/**
* TODO: Endpoint is not ready. The only way to test right now is mocking the response here
*/
// return Promise.resolve({
// id: '2747bd08-783a-45c6-902b-3efbda5497b7',
// clientId: 'AXy9hIzWB6h_LjZUHjHmsbsiicSIbL4GKOrcgomEedVjduUinIU4C2llxkW5p0OG0zTNgviYFceaXEnj',
// merchantId: 'C3UCKQHMW4948',
// value: 'xxxeyJraWQiOiJkMTA2ZTUwNjkzOWYxMWVlYjlkMTAyNDJhYzEyMDAwMiIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwczovL2FwaS5zYW5kYm94LnBheXBhbC5jb20iLCJhdWQiOlsiaHR0cHM6Ly9hcGkuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJjaGVja291dC1wbGF5Z3JvdW5kLm5ldGxpZnkuYXBwIl0sInN1YiI6Ik02VE5BRVNaNUZHTk4iLCJhY3IiOlsiY2xpZW50Il0sInNjb3BlIjpbIkJyYWludHJlZTpWYXVsdCJdLCJvcHRpb25zIjp7fSwiYXoiOiJjY2cxOC5zbGMiLCJleHRlcm5hbF9pZCI6WyJQYXlQYWw6QzNVQ0tRSE1XNDk0OCIsIkJyYWludHJlZTozZGI4aG5rdHJ0bXpzMmd0Il0sImV4cCI6MTczMjc5NjA4NywiaWF0IjoxNzMyNzk1MTg3LCJqdGkiOiJVMkFBTEV0ZjNVbHZiQWFBT0Y5cEtla29YTEREY1NqTmtnS3kzYjJ5YnNuUWlnV01VTEtpaXFYYXBUeTdqTy1EWllhTnU1ZEZBVy05bVRybU5Cay1nTi1qS0VVdnVJSDYtR3h5dV9wMUVXZlRydjdrVmJ4V2NnM2psUDI5aGhtQSJ9.57b4zg2TeN44I5aehBkfXdUf5kqWp8sjo58LKHOFNsuBlcmuWAmqQnprNgys3aL0Y8FqBVqhp69yF_v8_Qiy2w',
// expiresAt: '2024-11-01T13:34:01.804+00:00'
// });
return Promise.resolve({
id: '2747bd08-783a-45c6-902b-3efbda5497b7',
clientId: 'AXy9hIzWB6h_LjZUHjHmsbsiicSIbL4GKOrcgomEedVjduUinIU4C2llxkW5p0OG0zTNgviYFceaXEnj',
merchantId: 'C3UCKQHMW4948',
value: 'eyJraWQiOiJkMTA2ZTUwNjkzOWYxMWVlYjlkMTAyNDJhYzEyMDAwMiIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJodHRwczovL2FwaS5zYW5kYm94LnBheXBhbC5jb20iLCJhdWQiOlsiaHR0cHM6Ly9hcGkuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJjaGVja291dC1wbGF5Z3JvdW5kLm5ldGxpZnkuYXBwIl0sInN1YiI6Ik02VE5BRVNaNUZHTk4iLCJhY3IiOlsiY2xpZW50Il0sInNjb3BlIjpbIkJyYWludHJlZTpWYXVsdCJdLCJvcHRpb25zIjp7fSwiYXoiOiJjY2cxOC5zbGMiLCJleHRlcm5hbF9pZCI6WyJQYXlQYWw6QzNVQ0tRSE1XNDk0OCIsIkJyYWludHJlZTozZGI4aG5rdHJ0bXpzMmd0Il0sImV4cCI6MTczMzE2MTgwNiwiaWF0IjoxNzMzMTYwOTA2LCJqdGkiOiJVMkFBSXBGY25XbEJQNEwwaWJlSk14SmR1ZTFodG0yUGFXNzlMeDRzMktVZkJXYl8wWUw4S1BIOEFQUC0yNnhISm5WRmFPQWxObGVMVzdCRktlcGRVaERMOEJMWVBHdXRkMEFBVUZEc0V1UDRUOUlzNzc2WHNyUG9BMXBxN0ZQZyJ9.VN6t5fDUJknJf6RZO9LSYVSMmkITU5XOl0VVeFeVeJiMeU-1w5S8J0vPROv4_vBrDflWtx-YRs6bcvXTDq1NHg',
expiresAt: '2024-11-01T13:34:01.804+00:00'
});
}

export default requestFastlaneToken;
3 changes: 2 additions & 1 deletion packages/lib/src/components/internal/UIElement/UIElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps> exten
}

protected makePaymentsCall(): Promise<CheckoutAdvancedFlowResponse | CheckoutSessionPaymentResponse> {
console.log('makePaymentsCall');

this.setElementStatus('loading');

if (this.props.onSubmit) {
Expand Down Expand Up @@ -446,7 +448,6 @@ export abstract class UIElement<P extends UIElementProps = UIElementProps> exten
/**
* Get the element icon URL for the current environment
*/

public get icon(): string {
const type = this.props.paymentMethodType || this.type;
return this.props.icon ?? this.resources.getImage()(type);
Expand Down
11 changes: 3 additions & 8 deletions packages/lib/storybook/stories/ComponentContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@ export const ComponentContainer = ({ element }: IContainer) => {
addToWindow(element);

if (element.isAvailable) {
element
.isAvailable()
.then(() => {
element.mount(container.current);
})
.catch(error => {
setErrorMessage(error.toString());
});
element.isAvailable().then(() => {
element.mount(container.current);
});
} else {
element.mount(container.current);
}
Expand Down
Loading

0 comments on commit 5687ba4

Please sign in to comment.