Skip to content

Commit

Permalink
Merge pull request #53 from mediaopt/feature/35153-cardFields
Browse files Browse the repository at this point in the history
Feature/35153 card fields
  • Loading branch information
JonYeb authored Dec 7, 2023
2 parents c731a8e + 3f7a0b9 commit 487c7f6
Show file tree
Hide file tree
Showing 20 changed files with 582 additions and 18 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,18 @@ PayPal components props are based on PayPal props and you can see them on PayPal

PayPal messages props are based on PayPalMessages props and you can see them on PayPal official documentation [_PayPalMessagesComponentOptions_](https://github.com/paypal/react-paypal-js/blob/main/src/components/PayPalMessages.tsx).

### CardFields

- **authenticateThreeDSOrderUrl**: `string`
_POST_-Request
Communicates with commercetools backend to get the 3d Secure validation results and returns an object with the _liability_shift_, _enrollment_status_, and _authentication_status_.
See the examples in our [CoFe integration example repository](https://github.com/mediaopt/paypal-commercetools-cofe-integration/blob/main/packages/poc/backend/payment-paypal/actionControllers/PayPalController.ts)


### HostedFields

HostedFields are deprecated; CardFields is the preferred way to use advanced card payments.

- **getClientTokenUrl**: `string`
_POST_-Request - we get a [_ClientTokenResponse_](src/types/index.ts)
It is **your** responsibility to develop this API
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "paypal-commercetools-client",
"version": "0.0.79",
"version": "0.0.80",
"private": false,
"type": "module",
"license": "MIT",
Expand Down
30 changes: 28 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import { PayPal } from "./components/PayPal";
import { PayPalMessages } from "./components/PayPalMessages";
import { HostedFields } from "./components/HostedFields";
import { PaymentTokens } from "./components/PaymentTokens";
import { CardFields } from "./components/CardFields";
import { PayUponInvoice } from "./components/PayUponInvoice";
import { PayUponInvoiceProps } from "./types";

const CC_FRONTEND_EXTENSION_VERSION: string = "devmajidabbasi";
const CC_FRONTEND_EXTENSION_VERSION: string = "devjonathanyeboah";
const FRONTASTIC_SESSION: string =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3aXNobGlzdElkIjoiNjRhYjAyYjAtYzJjZi00OTNiLWIwMTQtNzU4Njg0N2M0NWI1IiwiY2FydElkIjoiODRkZTBkNDctZjA0Yy00YjZlLTgwNWYtZTYwNGYzMzQxNDc2IiwiYWNjb3VudCI6eyJhY2NvdW50SWQiOiJmMjJhNGZlMy1jMmI4LTQ4MDEtODIwOC00MTRkMjA2MjBlMGIiLCJlbWFpbCI6Im1hamlkLmFiYmFzaUBtZWRpYW9wdC5kZSIsInNhbHV0YXRpb24iOiIiLCJmaXJzdE5hbWUiOiJNYWppZCIsImxhc3ROYW1lIjoiQWJiYXNpIiwiYmlydGhkYXkiOiIxOTg5LTAzLTA1VDAwOjAwOjAwLjAwMFoiLCJjb25maXJtZWQiOnRydWUsImFkZHJlc3NlcyI6W3siYWRkcmVzc0lkIjoiamJUSlhtM00iLCJmaXJzdE5hbWUiOiJNYWppZCIsImxhc3ROYW1lIjoiQWJiYXNpIiwic3RyZWV0TmFtZSI6IkhvY2hzdHJhXHUwMGRmZSAzNyIsInN0cmVldE51bWJlciI6IkhvY2hzdHJhXHUwMGRmZSAzNyIsInBvc3RhbENvZGUiOiIxMzM1NyIsImNpdHkiOiJERSIsImNvdW50cnkiOiJERSIsInBob25lIjoiNTk5MzU3NTYyIiwiaXNEZWZhdWx0QmlsbGluZ0FkZHJlc3MiOmZhbHNlLCJpc0RlZmF1bHRTaGlwcGluZ0FkZHJlc3MiOmZhbHNlfSx7ImFkZHJlc3NJZCI6ImtyelI3bTBRIiwiZmlyc3ROYW1lIjoiTWFqaWQiLCJsYXN0TmFtZSI6IkFiYmFzaSIsInN0cmVldE5hbWUiOiJDb3VudHkgU3QuIE1pYW1pIiwic3RyZWV0TnVtYmVyIjoiNDMyIiwicG9zdGFsQ29kZSI6IjMzMDE4IiwiY2l0eSI6IlVTIiwiY291bnRyeSI6IkRFIiwicGhvbmUiOiI1OTkzNTc1NjIiLCJpc0RlZmF1bHRCaWxsaW5nQWRkcmVzcyI6dHJ1ZSwiaXNEZWZhdWx0U2hpcHBpbmdBZGRyZXNzIjp0cnVlfV19fQ.oWmFPwGAt0rnpUr4dEIIP3HdRkrV-xPwfoDA2CEopqE";
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYXJ0SWQiOiI5ZjAyZjk1Yi1kNzJkLTRlMDYtOTAyYy03Yzg3MDA5MmIwNmMifQ.hmg1giJkzKlLhMCAhav_N32uDqrfFVlBmyGGwslBTMc";

function App() {
const [choosenPaymentMethod, setChoosenPaymentMethod] = useState("");
Expand Down Expand Up @@ -67,6 +68,7 @@ function App() {
onApproveUrl: `${ENDPOINT_URL}/payment/capturePayPalOrder`,
shippingMethodId: "da416140-39bf-4677-8882-8b6cab23d981",
cartInformation: cartInformation,
authenticateThreeDSOrderUrl: `${ENDPOINT_URL}/payment/authenticateThreeDSOrder`,
};

const vaultParams = {
Expand Down Expand Up @@ -241,6 +243,30 @@ function App() {
fundingSource="card"
/>
),
CardFields: (
<CardFields
requestHeader={requestHeader}
{...params}
options={{
...options,
components: "card-fields,buttons",
vault: true,
}}
{...vaultParams}
/>
),
CardFieldsVaultOnly: (
<CardFields
requestHeader={requestHeader}
options={{
...options,
components: "card-fields,buttons",
vault: true,
}}
{...vaultParams}
{...vaultOnlyParams}
/>
),
HostedFields: <HostedFields {...HostedFieldsJson} />,
HostedFieldsVault: (
<HostedFields
Expand Down
2 changes: 1 addition & 1 deletion src/app/useLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const LoaderProvider: FC<
return (
<LoaderContext.Provider value={value}>
{showLoader && (
<div className="fixed top-0 right-0 bottom-0 left-0 z-145 w-full h-full">
<div className="fixed top-0 right-0 bottom-0 left-0 z-[145] w-full h-full">
<LoadingOverlay loadingText={loadingText} textStyles={textStyles} />
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/app/useNotifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const NotificationsProvider: FC<React.PropsWithChildren> = ({

return (
<NotificationContext.Provider value={value}>
<div className="fixed bottom-0 left-0 right-0 z-150 w-full">
<div className="fixed bottom-0 left-0 right-0 z-[150] w-full">
{notifications.map((n) => (
<NotificationTypeBanner
key={n.id}
Expand Down
50 changes: 44 additions & 6 deletions src/app/usePayment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ import {
onApprove,
createVaultSetupToken,
approveVaultSetupToken,
authenticateThreeDSOrder,
} from "../services";

import { useLoader } from "./useLoader";
import { useNotifications } from "./useNotifications";
import { useSettings } from "./useSettings";
import { getClientToken } from "../services/getClientToken";
import { getActionIndex } from "../components/CardFields/constants";
import { useTranslation } from "react-i18next";
import { relevantError } from "../components/PayUponInvoice/RatepayErrorNote";

Expand All @@ -59,13 +61,14 @@ type PaymentContextT = {
handleCreateOrder: (orderData?: CustomOrderData) => Promise<string>;
handleOnApprove: (data: CustomOnApproveData) => Promise<void>;
vaultOnly: boolean;
oderDataLinks?: OrderDataLinks;
orderDataLinks?: OrderDataLinks;
handleCreateVaultSetupToken: (
paymentSource: FUNDING_SOURCE
) => Promise<string>;
handleApproveVaultSetupToken: (
data: ApproveVaultSetupTokenData
) => Promise<void>;
handleAuthenticateThreeDSOrder: (orderID: string) => Promise<number>;
orderId?: string;
};

Expand Down Expand Up @@ -96,7 +99,8 @@ const PaymentContext = createContext<PaymentContextT>({
Promise.resolve(""),
handleApproveVaultSetupToken: (data?: ApproveVaultSetupTokenData) =>
Promise.resolve(),
oderDataLinks: undefined,
handleAuthenticateThreeDSOrder: (orderID: string) => Promise.resolve(0),
orderDataLinks: undefined,
orderId: undefined,
});

Expand All @@ -109,6 +113,7 @@ export const PaymentProvider: FC<
createPaymentUrl,
createOrderUrl,
authorizeOrderUrl,
authenticateThreeDSOrderUrl,

onApproveUrl,
onApproveRedirectionUrl,
Expand All @@ -127,7 +132,7 @@ export const PaymentProvider: FC<
const [showResult, setShowResult] = useState(false);
const [resultSuccess, setResultSuccess] = useState<boolean>();
const [resultMessage, setResultMessage] = useState<string>();
const [oderDataLinks, setOderDataLinks] = useState<OrderDataLinks>();
const [orderDataLinks, setOrderDataLinks] = useState<OrderDataLinks>();
const [orderId, setOrderId] = useState<string>();

const { settings } = useSettings();
Expand Down Expand Up @@ -245,7 +250,7 @@ export const PaymentProvider: FC<
links
) {
setPaymentInfo({ ...paymentInfo, version: paymentVersion });
setOderDataLinks(links);
setOrderDataLinks(links);
setOrderId(id);
return "";
} else {
Expand Down Expand Up @@ -345,6 +350,38 @@ export const PaymentProvider: FC<
createVaultSetupTokenUrl && approveVaultSetupTokenUrl
);

const handleAuthenticateThreeDSOrder = async (
orderID: string
): Promise<number> => {
if (!authenticateThreeDSOrderUrl) {
return 0;
}
const result = await authenticateThreeDSOrder(
requestHeader,
authenticateThreeDSOrderUrl,
orderID,
latestPaymentVersion,
paymentInfo.id
);

if (!result) {
return 0;
}

latestPaymentVersion = result.version;

if (!result.hasOwnProperty("approve")) {
return 2;
}

const action = getActionIndex(
result.approve.three_d_secure.enrollment_status,
result.approve.three_d_secure.authentication_status,
result.approve.liability_shift
);
return settings?.threeDSAction[action];
};

return {
setSuccess,
requestHeader,
Expand All @@ -356,7 +393,8 @@ export const PaymentProvider: FC<
vaultOnly,
handleCreateVaultSetupToken,
handleApproveVaultSetupToken,
oderDataLinks,
handleAuthenticateThreeDSOrder,
orderDataLinks,
orderId,
};
}, [
Expand All @@ -372,7 +410,7 @@ export const PaymentProvider: FC<
settings,
createVaultSetupTokenUrl,
approveVaultSetupTokenUrl,
oderDataLinks,
orderDataLinks,
orderId,
]);

Expand Down
20 changes: 20 additions & 0 deletions src/components/CardFields/CardFields.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { CardFields } from "./CardFields";

import { testParams, testRequestHeader, testOptions } from "../../constants";

const params = {
...testParams,
requestHeader: testRequestHeader,
options: {
...testOptions,
components: "card-fields,buttons",
vault: false,
},
};

test("CardFields is shown", () => {
render(<CardFields {...params} />);
expect(screen).toBeDefined();
});
48 changes: 48 additions & 0 deletions src/components/CardFields/CardFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";

import { RenderTemplate } from "../RenderTemplate";
import { CardFieldsButton } from "./CardFieldsButton";

import { SmartComponentsProps } from "../../types";

export const CardFields: React.FC<SmartComponentsProps> = ({
options,
getSettingsUrl,
createPaymentUrl,
requestHeader,
getClientTokenUrl,
getUserInfoUrl,
shippingMethodId,
cartInformation,
createOrderUrl,
onApproveUrl,
purchaseCallback,
enableVaulting,
authenticateThreeDSOrderUrl,
createVaultSetupTokenUrl,
approveVaultSetupTokenUrl,
authorizeOrderUrl,
}) => {
return (
<RenderTemplate
options={options}
createPaymentUrl={createPaymentUrl}
getSettingsUrl={getSettingsUrl}
getClientTokenUrl={getClientTokenUrl}
requestHeader={requestHeader}
shippingMethodId={shippingMethodId}
cartInformation={cartInformation}
createOrderUrl={createOrderUrl}
onApproveUrl={onApproveUrl}
purchaseCallback={purchaseCallback}
enableVaulting={enableVaulting}
getUserInfoUrl={getUserInfoUrl}
authenticateThreeDSOrderUrl={authenticateThreeDSOrderUrl}
createVaultSetupTokenUrl={createVaultSetupTokenUrl}
approveVaultSetupTokenUrl={approveVaultSetupTokenUrl}
authorizeOrderUrl={authorizeOrderUrl}
>
<CardFieldsButton enableVaulting={enableVaulting} />
</RenderTemplate>
);
};
32 changes: 32 additions & 0 deletions src/components/CardFields/CardFieldsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useEffect, useState } from "react";

import { usePayment } from "../../app/usePayment";
import { CardFieldsMask } from "./CardFieldsMask";
import { CardFieldsProps } from "../../types";
import { useHandleCreatePayment } from "../../app/useHandleCreatePayment";

export const CardFieldsButton: React.FC<CardFieldsProps> = ({
enableVaulting,
}) => {
const { paymentInfo, vaultOnly } = usePayment();
const [showComponent, setShowComponent] = useState<boolean>(false);
useHandleCreatePayment();

useEffect(() => {
let intervall = setInterval(() => {
if (!!window.paypal && (paymentInfo.id || vaultOnly)) {
clearInterval(intervall);
setShowComponent(true);
}
}, 250);
return () => {
clearInterval(intervall);
};
}, [paymentInfo]);

return showComponent ? (
<CardFieldsMask enableVaulting={enableVaulting} />
) : (
<></>
);
};
Loading

0 comments on commit 487c7f6

Please sign in to comment.