diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4a32168e3..71de05d03 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,6 @@ - @akash-c-k @ArushKapoorJuspay @PritishBudhiraja @seekshiva +* @PritishBudhiraja @seekshiva @ArushKapoorJuspay docs/ @akash-c-k LICENSE @akash-c-k README.md @akash-c-k @@ -17,5 +18,5 @@ webpack.dev.js @ArushKapoorJuspay @PritishBudhiraja @seekshiva webpack.common.js @ArushKapoorJuspay @PritishBudhiraja @seekshiva src/ @seekshiva @PritishBudhiraja @ArushKapoorJuspay -src/orca-log-catcher @Sanskar2001 +src/hyper-log-catcher @Sanskar2001 cypress-tests/ @seekshiva @Sanskar2001 diff --git a/CHANGELOG.md b/CHANGELOG.md index 657b56bd3..b311c1fe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,186 @@ +## [0.99.5](https://github.com/juspay/hyperswitch-web/compare/v0.99.4...v0.99.5) (2024-11-06) + +## [0.99.4](https://github.com/juspay/hyperswitch-web/compare/v0.99.3...v0.99.4) (2024-11-05) + + +### Bug Fixes + +* card brand update to prevent multiple error messages ([#767](https://github.com/juspay/hyperswitch-web/issues/767)) ([17892d9](https://github.com/juspay/hyperswitch-web/commit/17892d9ff7470ac12e251e878afe9ae9affffd50)) + +## [0.99.3](https://github.com/juspay/hyperswitch-web/compare/v0.99.2...v0.99.3) (2024-11-05) + + +### Bug Fixes + +* remove blue border of iframe in firefox ([#766](https://github.com/juspay/hyperswitch-web/issues/766)) ([f629219](https://github.com/juspay/hyperswitch-web/commit/f629219492ef234c2df76a52a99fb135def7b428)) + +## [0.99.2](https://github.com/juspay/hyperswitch-web/compare/v0.99.1...v0.99.2) (2024-11-04) + + +### Reverts + +* reverting fetchAPI changes ([3108148](https://github.com/juspay/hyperswitch-web/commit/31081488d47d81590a980cc147efdb918b2a8235)) + +## [0.99.1](https://github.com/juspay/hyperswitch-web/compare/v0.99.0...v0.99.1) (2024-11-04) + + +### Bug Fixes + +* card input error text correction ([#759](https://github.com/juspay/hyperswitch-web/issues/759)) ([f426662](https://github.com/juspay/hyperswitch-web/commit/f426662c04e78d170c303fa01193eb37934c7636)) + +# [0.99.0](https://github.com/juspay/hyperswitch-web/compare/v0.98.6...v0.99.0) (2024-11-04) + + +### Features + +* paze integration ([#738](https://github.com/juspay/hyperswitch-web/issues/738)) ([64fab0a](https://github.com/juspay/hyperswitch-web/commit/64fab0aac5323613f77c92537973e43f89a165d2)) + +## [0.98.6](https://github.com/juspay/hyperswitch-web/compare/v0.98.5...v0.98.6) (2024-11-04) + +## [0.98.5](https://github.com/juspay/hyperswitch-web/compare/v0.98.4...v0.98.5) (2024-11-04) + + +### Bug Fixes + +* format function refactor for better logs readability ([#757](https://github.com/juspay/hyperswitch-web/issues/757)) ([4f4ee6b](https://github.com/juspay/hyperswitch-web/commit/4f4ee6be28975b3060c955388f0536d2f6cea7ea)) + +## [0.98.4](https://github.com/juspay/hyperswitch-web/compare/v0.98.3...v0.98.4) (2024-10-30) + + +### Bug Fixes + +* Google pay log issue fix ([#762](https://github.com/juspay/hyperswitch-web/issues/762)) ([df629e9](https://github.com/juspay/hyperswitch-web/commit/df629e9d053f6e2fd443c833a9e343b3cf841f90)) + +## [0.98.3](https://github.com/juspay/hyperswitch-web/compare/v0.98.2...v0.98.3) (2024-10-30) + + +### Bug Fixes + +* Gpay unified checkout fix ([#761](https://github.com/juspay/hyperswitch-web/issues/761)) ([45ee508](https://github.com/juspay/hyperswitch-web/commit/45ee50849c1d048e3dba0b35c5252bd4e2ffac89)) + +## [0.98.2](https://github.com/juspay/hyperswitch-web/compare/v0.98.1...v0.98.2) (2024-10-30) + + +### Reverts + +* remove changes of pr [#746](https://github.com/juspay/hyperswitch-web/issues/746) ([#758](https://github.com/juspay/hyperswitch-web/issues/758)) ([cdae75e](https://github.com/juspay/hyperswitch-web/commit/cdae75ec21525e21aa2049f7bbfd513adebfef89)) + +## [0.98.1](https://github.com/juspay/hyperswitch-web/compare/v0.98.0...v0.98.1) (2024-10-29) + + +### Bug Fixes + +* remove contact and password icon in safari ([#747](https://github.com/juspay/hyperswitch-web/issues/747)) ([ebeca6e](https://github.com/juspay/hyperswitch-web/commit/ebeca6e1380c8b76830aa81b0df9e3bd07d4c880)) + +# [0.98.0](https://github.com/juspay/hyperswitch-web/compare/v0.97.0...v0.98.0) (2024-10-29) + + +### Features + +* added dynamic fields for SEPA ([#624](https://github.com/juspay/hyperswitch-web/issues/624)) ([63f536e](https://github.com/juspay/hyperswitch-web/commit/63f536ef22dc0304b01d703a232ce99819743608)) + +# [0.97.0](https://github.com/juspay/hyperswitch-web/compare/v0.96.3...v0.97.0) (2024-10-29) + + +### Features + +* tax calculation in google pay ([#750](https://github.com/juspay/hyperswitch-web/issues/750)) ([0039fbe](https://github.com/juspay/hyperswitch-web/commit/0039fbe65ec7ff958d637d00c58aed710fed5b1f)) + +## [0.96.3](https://github.com/juspay/hyperswitch-web/compare/v0.96.2...v0.96.3) (2024-10-29) + + +### Bug Fixes + +* remove blue border in firefox ([#746](https://github.com/juspay/hyperswitch-web/issues/746)) ([40ef7a5](https://github.com/juspay/hyperswitch-web/commit/40ef7a5578b3a687c9b596a27818f4533758f136)) + +## [0.96.2](https://github.com/juspay/hyperswitch-web/compare/v0.96.1...v0.96.2) (2024-10-28) + +## [0.96.1](https://github.com/juspay/hyperswitch-web/compare/v0.96.0...v0.96.1) (2024-10-25) + + +### Bug Fixes + +* card cvc bug fix ([#748](https://github.com/juspay/hyperswitch-web/issues/748)) ([6122d9d](https://github.com/juspay/hyperswitch-web/commit/6122d9d200b934969ee8643e598754d724a786a4)) + +# [0.96.0](https://github.com/juspay/hyperswitch-web/compare/v0.95.3...v0.96.0) (2024-10-23) + + +### Features + +* added apple pay support inside an iframe ([#743](https://github.com/juspay/hyperswitch-web/issues/743)) ([44ed3a8](https://github.com/juspay/hyperswitch-web/commit/44ed3a83b9686b140470575f7aa15c516cac1cc8)) + +## [0.95.3](https://github.com/juspay/hyperswitch-web/compare/v0.95.2...v0.95.3) (2024-10-21) + + +### Bug Fixes + +* add text overflow with ellipsis in dropdown ([#745](https://github.com/juspay/hyperswitch-web/issues/745)) ([9061306](https://github.com/juspay/hyperswitch-web/commit/90613062e9bcc1f19e538117d7aebddd3bd5fb76)) + +## [0.95.2](https://github.com/juspay/hyperswitch-web/compare/v0.95.1...v0.95.2) (2024-10-21) + + +### Bug Fixes + +* extra scroll in safari ([#744](https://github.com/juspay/hyperswitch-web/issues/744)) ([5254446](https://github.com/juspay/hyperswitch-web/commit/52544466899116be2222c5a4db1da16241f4fa4b)) + +## [0.95.1](https://github.com/juspay/hyperswitch-web/compare/v0.95.0...v0.95.1) (2024-10-16) + + +### Bug Fixes + +* closed loader before calling merchant callback ([#741](https://github.com/juspay/hyperswitch-web/issues/741)) ([c0d4e15](https://github.com/juspay/hyperswitch-web/commit/c0d4e157e133d6c1f0a867ef2b9a8480eb314488)) + +# [0.95.0](https://github.com/juspay/hyperswitch-web/compare/v0.94.2...v0.95.0) (2024-10-16) + + +### Features + +* dynamic tax calculation in paypal ([#739](https://github.com/juspay/hyperswitch-web/issues/739)) ([9a5b87d](https://github.com/juspay/hyperswitch-web/commit/9a5b87d2f0f60c152a861d1f6e9837e49ef6a0ba)) + +## [0.94.2](https://github.com/juspay/hyperswitch-web/compare/v0.94.1...v0.94.2) (2024-10-15) + +## [0.94.1](https://github.com/juspay/hyperswitch-web/compare/v0.94.0...v0.94.1) (2024-10-15) + + +### Bug Fixes + +* callback fix ([5b7e78b](https://github.com/juspay/hyperswitch-web/commit/5b7e78b49fe4ce7e05fafb4e259dfa6a3f71919e)) + +# [0.94.0](https://github.com/juspay/hyperswitch-web/compare/v0.93.0...v0.94.0) (2024-10-15) + + +### Features + +* added click handler ([#732](https://github.com/juspay/hyperswitch-web/issues/732)) ([9c09ff2](https://github.com/juspay/hyperswitch-web/commit/9c09ff2d90ece78583c897c9cb29f2f45f346f90)) + +# [0.93.0](https://github.com/juspay/hyperswitch-web/compare/v0.92.1...v0.93.0) (2024-10-15) + + +### Features + +* added confirm handler ([#731](https://github.com/juspay/hyperswitch-web/issues/731)) ([4f65ecb](https://github.com/juspay/hyperswitch-web/commit/4f65ecbeb48022dbe9da507d98344e43c308b691)) + +## [0.92.1](https://github.com/juspay/hyperswitch-web/compare/v0.92.0...v0.92.1) (2024-10-10) + + +### Bug Fixes + +* web package added ([#726](https://github.com/juspay/hyperswitch-web/issues/726)) ([ecf0db3](https://github.com/juspay/hyperswitch-web/commit/ecf0db3d2fdb811f572bdffb5a61e468284a1c51)) + +# [0.92.0](https://github.com/juspay/hyperswitch-web/compare/v0.91.10...v0.92.0) (2024-10-10) + + +### Features + +* added bubblegum theme ([#723](https://github.com/juspay/hyperswitch-web/issues/723)) ([7df22f3](https://github.com/juspay/hyperswitch-web/commit/7df22f3f9c0dd1c8687d67e64faf7a0591e3e59b)) + +## [0.91.10](https://github.com/juspay/hyperswitch-web/compare/v0.91.9...v0.91.10) (2024-10-10) + + +### Bug Fixes + +* fixed applePay for headless fow ([#725](https://github.com/juspay/hyperswitch-web/issues/725)) ([6e513a3](https://github.com/juspay/hyperswitch-web/commit/6e513a3bab9444a75dbc976945ab3113ced76b51)) + ## [0.91.9](https://github.com/juspay/hyperswitch-web/compare/v0.91.8...v0.91.9) (2024-10-07) diff --git a/cypress-tests/cypress/e2e/cvc-checks-e2e-test.cy.ts b/cypress-tests/cypress/e2e/cvc-checks-e2e-test.cy.ts new file mode 100644 index 000000000..883aaa5bf --- /dev/null +++ b/cypress-tests/cypress/e2e/cvc-checks-e2e-test.cy.ts @@ -0,0 +1,84 @@ +import * as testIds from "../../../src/Utilities/TestUtils.bs"; +import { getClientURL, amexTestCard, visaTestCard, createPaymentBody } from "../support/utils"; + +describe("Card CVC Checks", () => { + let getIframeBody: () => Cypress.Chainable>; + const publishableKey = Cypress.env('HYPERSWITCH_PUBLISHABLE_KEY') + const secretKey = Cypress.env('HYPERSWITCH_SECRET_KEY') + let iframeSelector = + "#orca-payment-element-iframeRef-orca-elements-payment-element-payment-element"; + + + beforeEach(() => { + getIframeBody = () => cy.iframe(iframeSelector); + cy.createPaymentIntent(secretKey, createPaymentBody).then(() => { + cy.getGlobalState("clientSecret").then((clientSecret) => { + + cy.visit(getClientURL(clientSecret, publishableKey)); + }); + + }) + }); + + + + + it("title rendered correctly", () => { + cy.contains("Hyperswitch Unified Checkout").should("be.visible"); + }); + + it("orca-payment-element iframe loaded", () => { + cy.get( + "#orca-payment-element-iframeRef-orca-elements-payment-element-payment-element" + ) + .should("be.visible") + .its("0.contentDocument") + .its("body"); + }); + + + it('user can enter 4 digit cvc in card form', () => { + getIframeBody().find(`[data-testid=${testIds.addNewCardIcon}]`).click() + getIframeBody().find(`[data-testid=${testIds.cardNoInputTestId}]`).type(amexTestCard) + getIframeBody().find(`[data-testid=${testIds.expiryInputTestId}]`).type("0444") + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).type("1234").then(() => { + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).should('have.value', '1234'); + }) + + + }) + it('user can enter 3 digit cvc on saved payment methods screen', () => { + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).type('123').then(() => { + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).should('have.value', '123'); + }) + + }) + + it('user can enter 3 digit cvc in card form', () => { + getIframeBody().find(`[data-testid=${testIds.addNewCardIcon}]`).click() + getIframeBody().find(`[data-testid=${testIds.cardNoInputTestId}]`).type(visaTestCard) + getIframeBody().find(`[data-testid=${testIds.expiryInputTestId}]`).type("0444") + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).type("123").then(() => { + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).should('have.value', '123'); + }) + }) + + it('user can enter 4 digit cvc on saved payment methods screen', () => { + cy.wait(2000) + getIframeBody() + .contains('div', '4 digit cvc test card') + .should('exist') + .trigger('click') + cy.wait(1000) + + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).type("1234").then(() => { + getIframeBody().find(`[data-testid=${testIds.cardCVVInputTestId}]`).should('have.value', '1234'); + }) + + }) + +}) + + + + diff --git a/cypress-tests/cypress/support/utils.ts b/cypress-tests/cypress/support/utils.ts index 08a516365..496d55606 100644 --- a/cypress-tests/cypress/support/utils.ts +++ b/cypress-tests/cypress/support/utils.ts @@ -6,6 +6,16 @@ export const getClientURL = (clientSecret, publishableKey) => { return `${CLIENT_BASE_URL}?isCypressTestMode=true&clientSecret=${clientSecret}&publishableKey=${publishableKey}`; } +export const enum connectorEnum{ + TRUSTPAY, + ADYEN, + STRIPE +} +export const connectorProfileIdMapping = new Map([ + [connectorEnum.TRUSTPAY, "pro_eP323T9e4ApKpilWBfPA"], + [connectorEnum.ADYEN, "pro_Kvqzu8WqBZsT1OjHlCj4"], + [connectorEnum.STRIPE, "pro_5fVcCxU8MFTYozgtf0P8"], +]); export const createPaymentBody = { currency: "USD", @@ -116,3 +126,5 @@ export const confirmBody = { export const stripeTestCard = "4000000000003220"; export const adyenTestCard = "4917610000000000"; export const bluesnapTestCard = "4000000000001091"; +export const amexTestCard = "378282246310005" +export const visaTestCard = "4242424242424242"; diff --git a/package-lock.json b/package-lock.json index 148c04525..facd283d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.91.9", + "version": "0.99.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.91.9", + "version": "0.99.5", "hasInstallScript": true, "dependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/package.json b/package.json index dbd504b7b..e87738c56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.91.9", + "version": "0.99.5", "main": "index.js", "private": true, "dependencies": { @@ -16,23 +16,22 @@ "webpack-merge": "^5.9.0" }, "scripts": { - "build:dev": "cross-env sdkEnv=sandbox webpack --config webpack.dev.js", - "build:dev-integ": "cross-env sdkEnv=integ webpack --config webpack.dev.js", - "start": "cross-env sdkEnv=local webpack serve --config webpack.dev.js", - "build:prod": "cross-env sdkEnv=prod webpack --config webpack.common.js", "build": "webpack --config webpack.common.js", - "build:sandbox": "cross-env sdkEnv=sandbox webpack --config webpack.common.js", - "build:integ": "cross-env sdkEnv=integ webpack --config webpack.common.js", - "test": "cd cypress-tests && npm run cypress:run", + "build:integ": "cross-env sdkEnv=integ enableLogging=false webpack --config webpack.common.js", + "build:playground": "npm run setup:playground && npm run build", + "build:prod": "cross-env sdkEnv=prod enableLogging=true webpack --config webpack.common.js", + "build:sandbox": "cross-env sdkEnv=sandbox enableLogging=true webpack --config webpack.common.js", + "deploy-to-s3": "node ./scripts/pushToS3.js", + "postinstall": "cd Hyperswitch-React-Demo-App && npm i", + "prepare": "husky install", "re:build": "rescript", "re:clean": "rescript clean", - "re:start": "rescript -w", "re:format": "rescript format -all", - "start:playground": "npm run postinstall && cd Hyperswitch-React-Demo-App && node promptScript.js && npm run start", - "build:playground": "npm run postinstall && cd Hyperswitch-React-Demo-App && node promptScript.js && npm run build", - "prepare": "husky install", - "deploy-to-s3": "node ./scripts/pushToS3.js", - "postinstall": "cd Hyperswitch-React-Demo-App && npm i", + "re:start": "rescript -w", + "setup:playground": "npm run postinstall && cd Hyperswitch-React-Demo-App && node promptScript.js", + "start": "cross-env sdkEnv=local enableLogging=false webpack serve --config webpack.dev.js", + "start:playground": "npm run setup:playground && npm run start", + "test": "cd cypress-tests && npm run cypress:run", "test:hooks": "npx eslint src/" }, "eslintConfig": { diff --git a/public/icons/orca.svg b/public/icons/orca.svg index 7d6d7eba7..dcdab264b 100644 --- a/public/icons/orca.svg +++ b/public/icons/orca.svg @@ -1014,19 +1014,72 @@ License) - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/src/App.res b/src/App.res index 020d9cd9a..b1ff97128 100644 --- a/src/App.res +++ b/src/App.res @@ -7,7 +7,7 @@ let make = () => { let paymentMode = CardUtils.getQueryParamsDictforKey(url.search, "componentName") let paymentType = paymentMode->CardThemeType.getPaymentMode let (logger, initTimestamp) = React.useMemo0(() => { - (OrcaLogger.make(~source=Elements(paymentType)), Date.now()) + (HyperLogger.make(~source=Elements(paymentType)), Date.now()) }) let fullscreenMode = CardUtils.getQueryParamsDictforKey(url.search, "fullscreenType") @@ -16,6 +16,38 @@ let make = () => { None }, [logger]) + React.useEffect0(() => { + let handleMetaDataPostMessage = (ev: Window.event) => { + let json = ev.data->Utils.safeParse + let dict = json->Utils.getDictFromJson + + if dict->Dict.get("metadata")->Option.isSome { + let metadata = dict->Utils.getJsonObjectFromDict("metadata") + let config = metadata->Utils.getDictFromJson->Dict.get("config") + + switch config { + | Some(config) => { + let config = CardTheme.itemToObjMapper( + config->Utils.getDictFromJson, + DefaultTheme.default, + DefaultTheme.defaultRules, + logger, + ) + + CardUtils.generateFontsLink(config.fonts) + let dict = config.appearance.rules->Utils.getDictFromJson + if dict->Dict.toArray->Array.length > 0 { + Utils.generateStyleSheet("", dict, "mystyle") + } + } + | None => () + } + } + } + Window.addEventListener("message", handleMetaDataPostMessage) + Some(() => Window.removeEventListener("message", handleMetaDataPostMessage)) + }) + let renderFullscreen = switch paymentMode { | "paymentMethodCollect" => @@ -25,6 +57,7 @@ let make = () => { switch fullscreenMode { | "paymentloader" => | "plaidSDK" => + | "pazeWallet" => | "fullscreen" =>
diff --git a/src/BubblegumTheme.res b/src/BubblegumTheme.res new file mode 100644 index 000000000..b380e7d67 --- /dev/null +++ b/src/BubblegumTheme.res @@ -0,0 +1,224 @@ +open CardThemeType +let bubblegum = { + fontFamily: "", + fontSizeBase: "1rem", + colorPrimary: "#f360a6", + colorBackground: "#ffffff", + colorText: "#545454", + colorDanger: "#fd1717", + colorDangerText: "#fd1717", + borderRadius: "2px", + fontVariantLigatures: "", + fontVariationSettings: "", + spacingUnit: "11px", + fontWeightLight: "400", + fontWeightNormal: "500", + fontWeightMedium: "600", + fontWeightBold: "700", + fontLineHeight: "", + fontSize2Xl: "24px", + fontSizeXl: "16px", + fontSizeLg: "14px", + fontSizeSm: "12px", + fontSizeXs: "10px", + fontSize2Xs: "8px", + fontSize3Xs: "6px", + colorSuccess: "", + colorWarning: "", + colorPrimaryText: "#5469d4", + colorBackgroundText: "", + colorSuccessText: "", + colorWarningText: "", + colorTextSecondary: "#6d6e78", + colorTextPlaceholder: "", + spacingTab: "12px", + borderColor: "#e6e6e6", + spacingAccordionItem: "10px", + colorIconCardCvc: "", + colorIconCardCvcError: "#fd1717", + colorIconCardError: "#fd1717", + spacingGridColumn: "20px", + spacingGridRow: "20px", + buttonBackgroundColor: "#006df9", + buttonHeight: "48px", + buttonWidth: "100%", + buttonBorderRadius: "4px", + buttonBorderColor: "#ffffff", + buttonTextColor: "#ffffff", + buttonTextFontSize: "16px", + buttonTextFontWeight: "500", + buttonBorderWidth: "0px", +} +let bubblegumRules = theme => + { + ".Tab": { + "border": "0", + "borderRadius": theme.borderRadius, + "backgroundColor": theme.colorBackground, + "color": theme.colorTextSecondary, + "alignItems": "start", + "transition": "background .15s ease, border .15s ease, box-shadow .15s ease", + "boxShadow": "0px 3px 10px rgba(18, 42, 66, 0.08)" + }, + ".Tab:hover": { + "border": "0", + "color": theme.colorText, + }, + ".Tab:focus":{ + "border": "0" + }, + ".Label": { + "color": theme.colorText, + "opacity": "10", + "textAlign": "left", + }, + ".Tab--selected": { + "color": "#fff", + "backgroundColor": "#f360a6", + "boxShadow": `0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02), 0 0 0 2px ${theme.colorPrimary}`, + }, + ".Tab--selected:hover": { + "color": "#fff", + "backgroundColor": "#f360a6", + "boxShadow": `0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02), 0 0 0 2px ${theme.colorPrimary}`, + }, + ".Tab--selected:focus": { + "color": "#fff", + "backgroundColor": "#f360a6", + "boxShadow": `0 0 0 2px ${theme.colorPrimary}4c, 0 1px 1px 0 ${theme.colorBackground}, 0 0 0 1px ${theme.colorPrimary}4c`, + }, + ".TabMore:focus": { + "border": `1px solid ${theme.colorPrimary}`, + "boxShadow": `${theme.colorPrimary}4c 0px 0px 0px 3px`, + }, + ".TabMore": { + "border": `1px solid ${theme.borderColor}`, + }, + ".Input": { + "border": `1px solid #e6e6e6`, + "color": theme.colorText, + "fontWeight": theme.fontWeightLight, + "borderRadius": theme.borderRadius, + "boxShadow": "0px 3px 10px rgba(18, 42, 66, 0.08)", + "transition": "background 0.15s ease, border 0.15s ease, box-shadow 0.15s ease, color 0.15s ease", + }, + ".Input-Compressed": { + "border": `1px solid #e6e6e6`, + "color": theme.colorText, + "fontWeight": theme.fontWeightLight, + "boxShadow": `0px 1px 1px rgb(0 0 0 / 3%), 0px 3px 6px rgb(0 0 0 / 2%)`, + "transition": "background 0.15s ease, border 0.15s ease, box-shadow 0.15s ease, color 0.15s ease", + }, + ".Input:-webkit-autofill": { + "transition": "background-color 5000s ease-in-out 0s", + "-webkitTextFillColor": `${theme.colorText} !important`, + }, + ".Input:focus": { + "border": `1px solid ${theme.colorPrimary}`, + "boxShadow": `${theme.colorPrimary}4c 0px 0px 0px 3px`, + }, + ".Input-Compressed:focus": { + "border": `1px solid ${theme.colorPrimary}`, + "boxShadow": `${theme.colorPrimary}4c 0px 0px 0px 2px`, + "position": "relative", + "zIndex": "2", + }, + ".Input--invalid": { + "color": theme.colorDanger, + "border": `1px solid ${theme.colorDanger}`, + "transition": "border 0.15s ease, box-shadow 0.15s ease, color 0.15s ease", + }, + ".Input::placeholder": { + "fontWeight": theme.fontWeightLight, + "color": theme.colorTextPlaceholder, + }, + ".TabLabel": { + "transition": "color .1s ease", + "textAlign": "start", + }, + ".TabIcon": { + "transition": "color .1s ease", + }, + ".Block": { + "backgroundColor": theme.colorBackground, + "borderRadius": theme.borderRadius, + // "border": `1px solid ${theme.borderColor}`, + "borderColor": "transparent", + "boxShadow": "0px 3px 10px rgba(18, 42, 66, 0.08)" + }, + ".BlockDivider": { + "backgroundColor": "#ebebeb", + // "border": `1px solid ${theme.borderColor}`, + }, + ".AccordionItem": { + "backgroundColor": theme.colorBackground, + "color": theme.colorTextSecondary, + "transition": "height 1s ease", + "boxShadow": "0px 1px 1px rgb(0 0 0 / 3%), 0px 3px 6px rgb(0 0 0 / 2%)", + "padding": "20px", + }, + ".AccordionMore": { + "backgroundColor": theme.colorBackground, + "color": theme.colorTextSecondary, + "border": `1px solid ${theme.borderColor}`, + }, + ".AccordionMore:hover": { + "color": theme.colorText, + }, + ".AccordionItem:hover": { + "color": theme.colorText, + }, + ".AccordionItem--selected": { + "color": theme.colorPrimary, + }, + ".AccordionItem--selected:hover": { + "color": theme.colorPrimary, + }, + ".AccordionItemLabel": { + "transition": "color .1s ease", + }, + ".AccordionItemLabel--selected": { + "color": theme.colorPrimary, + }, + ".AccordionItemIcon--selected": { + "color": theme.colorPrimary, + }, + ".PickerItem": { + "backgroundColor": theme.colorBackground, + "borderRadius": theme.borderRadius, + "border": `1px solid ${theme.borderColor}`, + "color": theme.colorTextSecondary, + "padding": theme.spacingUnit, + "transition": "height 1s ease", + "boxShadow": "0px 1px 1px rgb(0 0 0 / 3%), 0px 3px 6px rgb(0 0 0 / 2%)", + }, + ".PickerItem:hover": { + "color": theme.colorText, + }, + ".PickerItem--selected": { + "color": theme.colorPrimary, + "border": `1px solid ${theme.colorPrimary}`, + "boxShadow": `${theme.colorPrimary}4c 0px 0px 0px 3px`, + }, + ".PickerItem--selected:hover": { + "color": theme.colorPrimary, + "border": `1px solid ${theme.colorPrimary}`, + "boxShadow": `${theme.colorPrimary}4c 0px 0px 0px 3px`, + }, + ".Checkbox": { + "fontWeight": theme.fontWeightLight, + "fontSize": theme.fontSizeLg, + }, + ".CheckboxInput":{ + "boxShadow": "0px 3px 10px rgba(18, 42, 66, 0.08)" + }, + ".PaymentMethodsHeaderLabel": { + "color": theme.colorText, + "fontSize": theme.fontSize2Xl, + "fontWeight": theme.fontWeightMedium, + "marginBottom": "1.5rem", + }, + }->Identity.anyTypeToJson + +let default = bubblegum +let defaultRules = bubblegumRules diff --git a/src/CardTheme.res b/src/CardTheme.res index 17f9fd8ec..c5cd8eb1d 100644 --- a/src/CardTheme.res +++ b/src/CardTheme.res @@ -3,16 +3,17 @@ open Utils open ErrorUtils let getTheme = (val, logger) => { - switch val { + switch val->String.toLowerCase { | "default" => Default | "brutal" => Brutal | "midnight" => Midnight | "charcoal" => Charcoal | "soft" => Soft + | "bubblegum" => Bubblegum | "none" => NONE | str => { str->unknownPropValueWarning( - ["default", "midnight", "brutal", "charcoal", "soft", "none"], + ["default", "midnight", "brutal", "charcoal", "soft", "bubblegum", "none"], "appearance.theme", ~logger, ) @@ -359,7 +360,7 @@ let getAppearance = ( variables: getVariables("variables", json, default, logger), rules: mergeJsons(rulesJson, getJsonObjectFromDict(json, "rules")), innerLayout: getWarningString(json, "innerLayout", "spaced", ~logger)->getInnerLayout, - labels: switch getWarningString(json, "labels", "above", ~logger) { + labels: switch getWarningString(json, "labels", "above", ~logger)->String.toLowerCase { | "above" => Above | "floating" => Floating | "none" => Never diff --git a/src/CardUtils.res b/src/CardUtils.res index 02a4bd55f..e917851b9 100644 --- a/src/CardUtils.res +++ b/src/CardUtils.res @@ -424,7 +424,7 @@ let cvcNumberInRange = (val, cardBrand) => { }) cvcLengthInRange } -let genreateFontsLink = (fonts: array) => { +let generateFontsLink = (fonts: array) => { if fonts->Array.length > 0 { fonts ->Array.map(item => @@ -671,3 +671,7 @@ let getEligibleCoBadgedCardSchemes = (~matchedCardSchemes, ~enabledCardSchemes) enabledCardSchemes->Array.includes(ele->String.toLowerCase) }) } + +let getCardBrandFromStates = (cardBrand, cardScheme, showFields) => { + !showFields ? cardScheme : cardBrand +} diff --git a/src/Components/AddBankAccount.res b/src/Components/AddBankAccount.res index b89e379a2..d49f5787e 100644 --- a/src/Components/AddBankAccount.res +++ b/src/Components/AddBankAccount.res @@ -6,7 +6,7 @@ module ToolTip = { let {themeObj} = Recoil.useRecoilValueFromAtom(configAtom)
- O + O
diff --git a/src/Payments/ACHBankDebit.res b/src/Payments/ACHBankDebit.res index 1dfb6e605..55eb6184a 100644 --- a/src/Payments/ACHBankDebit.res +++ b/src/Payments/ACHBankDebit.res @@ -127,7 +127,7 @@ let make = (~paymentType: CardThemeType.mode) => { - +
diff --git a/src/Payments/ApplePay.res b/src/Payments/ApplePay.res index afbc951e0..0152259eb 100644 --- a/src/Payments/ApplePay.res +++ b/src/Payments/ApplePay.res @@ -5,9 +5,10 @@ let make = (~sessionObj: option, ~walletOptions, ~paymentType: CardTheme let url = RescriptReactRouter.useUrl() let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName") let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) - let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom( - RecoilAtoms.keys, + let sdkHandleIsThere = Recoil.useRecoilValueFromAtom( + RecoilAtoms.isPaymentButtonHandlerProvidedAtom, ) + let {publishableKey} = Recoil.useRecoilValueFromAtom(RecoilAtoms.keys) let isApplePayReady = Recoil.useRecoilValueFromAtom(RecoilAtoms.isApplePayReady) let setIsShowOrPayUsing = Recoil.useSetRecoilState(RecoilAtoms.isShowOrPayUsing) let (showApplePay, setShowApplePay) = React.useState(() => false) @@ -212,7 +213,7 @@ let make = (~sessionObj: option, ~walletOptions, ~paymentType: CardTheme ~paymentMethod="APPLE_PAY", ) setApplePayClicked(_ => true) - makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment) + makeOneClickHandlerPromise(sdkHandleIsThere) ->then(result => { let result = result->JSON.Decode.bool->Option.getOr(false) if result { @@ -241,7 +242,11 @@ let make = (~sessionObj: option, ~walletOptions, ~paymentType: CardTheme ~isManualRetryEnabled, ) } else { - ApplePayHelpers.handleApplePayButtonClicked(~sessionObj, ~componentName, ~paymentMethodListValue) + ApplePayHelpers.handleApplePayButtonClicked( + ~sessionObj, + ~componentName, + ~paymentMethodListValue, + ) } } else { let bodyDict = PaymentBody.applePayRedirectBody(~connectors) diff --git a/src/Payments/BankDebitModal.res b/src/Payments/BankDebitModal.res index 2476e3f40..86e9a6d88 100644 --- a/src/Payments/BankDebitModal.res +++ b/src/Payments/BankDebitModal.res @@ -106,7 +106,7 @@ module AccountNumberCard = { let clearSpaces = str => str->String.replaceRegExp(%re("/\D+/g"), "") @react.component -let make = (~setModalData) => { +let make = (~setModalData, ~paymentType: CardThemeType.mode) => { let selectedOption = Recoil.useRecoilValueFromAtom(RecoilAtoms.selectedOptionAtom) let (routingNumber, setRoutingNumber) = React.useState(_ => "") let (iban, setIban) = React.useState(_ => "") @@ -116,6 +116,8 @@ let make = (~setModalData) => { let {themeObj, config, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom) let (accountType, setAccountType) = React.useState(() => "Savings") + let (requiredFieldsBody, setRequiredFieldsBody) = React.useState(_ => Dict.make()) + let (openModal, setOpenModal) = React.useState(_ => false) let (accountNum, setAccountNum) = React.useState(_ => "") @@ -183,25 +185,66 @@ let make = (~setModalData) => { iban !== "" || (accountNum->String.length > 0 && sortCode->String.length > 0) - -
-
-
- {React.string(localeString.billingDetailsText)} -
-
- -
-
- {React.string("Bank Details")} -
+ let onClickHandler = () => { + setModalData(_ => Some({ + routingNumber, + accountNumber: accountNum, + accountHolderName, + accountType: accountType->String.toLowerCase, + iban, + sortCode, + requiredFieldsBody, + })) + Modal.close(setOpenModal) + } + + let dynamicFieldsModalBody = + <> + + + + + let nonDynamicFieldsModalBody = + <> +
+ {React.string(localeString.billingDetailsText)} +
+
+ +
+
+ {React.string("Bank Details")} +
+
+ {React.string("Account Holder Name")} +
+ setInputFocus(_ => NONE)} + /> +
{ color: themeObj.colorText, marginBottom: "5px", }> - {React.string("Account Holder Name")} + {React.string("IBAN")}
setInputFocus(_ => NONE)} + value=iban + onChange=changeIBAN + type_="text" + maxLength=42 + inputRef=ibanRef + placeholder="eg: DE00 0000 0000 0000 0000 00" /> - -
- {React.string("IBAN")} + +
+ +
+
+ {React.string("Routing number")} +
+ setInputFocus(_ => Routing)} + />
-
-
- -
-
- {React.string("Routing number")} -
- setInputFocus(_ => Routing)} - /> + +
+
+ {React.string("Account number")}
- - -
-
- {React.string("Account number")} -
- setInputFocus(_ => Account)} - onBlur={_ => setInputFocus(_ => NONE)} - /> -
-
-
- -
- setInputFocus(_ => Account)} + onBlur={_ => setInputFocus(_ => NONE)} />
- -
- {React.string("BSB")} -
- + +
+ - -
+
+ +
+ {React.string("BSB")} +
+ +
+ +} diff --git a/src/Payments/PazeTypes.res b/src/Payments/PazeTypes.res new file mode 100644 index 000000000..1452ee620 --- /dev/null +++ b/src/Payments/PazeTypes.res @@ -0,0 +1,44 @@ +type client = { + id: string, + name: string, + profileId: string, +} +type initialize = {client: client} + +type canCheckout = {emailAddress: string} + +type transactionValue = { + transactionAmount: string, + transactionCurrencyCode: string, +} + +type transactionOptions = { + billingPreference: string, + merchantCategoryCode: string, + payloadTypeIndicator: string, +} + +type checkout = { + acceptedPaymentCardNetworks: array, + emailAddress?: string, + sessionId: string, + actionCode: string, + transactionValue: transactionValue, + shippingPreference: string, +} + +type complete = { + transactionOptions: transactionOptions, + transactionId: string, + emailAddress?: string, + sessionId: string, + transactionType: string, + transactionValue: transactionValue, +} + +type digitalWalletSdk = { + canCheckout: canCheckout => promise, + checkout: checkout => promise, + complete: complete => promise, + initialize: initialize => promise, +} diff --git a/src/Payments/PazeWallet.res b/src/Payments/PazeWallet.res new file mode 100644 index 000000000..f815f2ba2 --- /dev/null +++ b/src/Payments/PazeWallet.res @@ -0,0 +1,137 @@ +open PazeTypes + +@val @scope("window") +external digitalWalletSdk: digitalWalletSdk = "DIGITAL_WALLET_SDK" + +@react.component +let make = () => { + open Promise + open Utils + + React.useEffect0(() => { + let handle = (ev: Window.event) => { + let json = ev.data->safeParse + let metaData = json->getDictFromJson->getDictFromDict("metadata") + if metaData->getString("wallet", "") === "Paze" { + let clientId = metaData->getString("clientId", "") + let clientName = metaData->getString("clientName", "") + let clientProfileId = metaData->getString("clientProfileId", "") + let sessionId = metaData->getString("sessionId", "") + let publishableKey = metaData->getString("publishableKey", "") + let emailAddress = metaData->getString("emailAddress", "") + let transactionAmount = metaData->getString("transactionAmount", "") + let transactionCurrencyCode = metaData->getString("transactionCurrencyCode", "") + + let mountPazeSDK = () => { + let pazeScriptURL = + publishableKey->String.startsWith("pk_snd") + ? `https://sandbox.digitalwallet.earlywarning.com/web/resources/js/digitalwallet-sdk.js` + : `https://checkout.paze.com/web/resources/js/digitalwallet-sdk.js` + + let loadPazeSDK = async _ => { + try { + let val = await digitalWalletSdk.initialize({ + client: { + id: clientId, + name: clientName, + profileId: clientProfileId, + }, + }) + + Console.log2("PAZE --- init completed", val) + + let consumerPresent = await digitalWalletSdk.canCheckout({ + emailAddress: emailAddress, + }) + + Console.log("PAZE --- canCheckout completed") + Console.log2("PAZE --- consumerPresent: ", consumerPresent) + + let transactionValue = { + transactionAmount, + transactionCurrencyCode, + } + + let transactionOptions = { + billingPreference: "ALL", + merchantCategoryCode: "US", + payloadTypeIndicator: "PAYMENT", + } + + let checkoutResponse = await digitalWalletSdk.checkout({ + acceptedPaymentCardNetworks: ["VISA", "MASTERCARD"], + emailAddress, + sessionId, + actionCode: "START_FLOW", + transactionValue, + shippingPreference: "ALL", + }) + + Console.log2("PAZE --- Checkout Response Object: ", checkoutResponse) + + let completeObj = { + transactionOptions, + transactionId: "", + sessionId, + transactionType: "PURCHASE", + transactionValue, + } + + let completeResponse = await digitalWalletSdk.complete(completeObj) + + Console.log2("PAZE --- Complete Response Object: ", completeResponse) + + messageParentWindow([ + ("fullscreen", false->JSON.Encode.bool), + ("isPaze", true->JSON.Encode.bool), + ( + "completeResponse", + completeResponse + ->getDictFromJson + ->getString("completeResponse", "") + ->JSON.Encode.string, + ), + ]) + + resolve() + } catch { + | _ => + messageParentWindow([ + ("fullscreen", false->JSON.Encode.bool), + ("isPaze", true->JSON.Encode.bool), + ("flowExited", "stop"->JSON.Encode.string), + ]) + resolve() + } + } + + let pazeScript = Window.createElement("script") + pazeScript->Window.elementSrc(pazeScriptURL) + pazeScript->Window.elementOnerror(exn => { + let err = exn->Identity.anyTypeToJson->JSON.stringify + Console.log2("PAZE --- errrorrr", err) + }) + pazeScript->Window.elementOnload(_ => loadPazeSDK()->ignore) + Window.body->Window.appendChild(pazeScript) + } + + if ( + [ + clientId, + clientName, + clientProfileId, + sessionId, + transactionCurrencyCode, + ]->Array.every(x => x != "") + ) { + mountPazeSDK() + } + } + } + Window.addEventListener("message", handle) + messageParentWindow([("iframeMountedCallback", true->JSON.Encode.bool)]) + Some(() => {Window.removeEventListener("message", handle)}) + }) + +
+} diff --git a/src/Payments/PlaidSDKIframe.res b/src/Payments/PlaidSDKIframe.res index e3716d663..7b1c11ac1 100644 --- a/src/Payments/PlaidSDKIframe.res +++ b/src/Payments/PlaidSDKIframe.res @@ -9,7 +9,7 @@ let make = () => { let (clientSecret, setClientSecret) = React.useState(_ => "") let (isForceSync, setIsForceSync) = React.useState(_ => false) let logger = React.useMemo(() => { - OrcaLogger.make(~source=Elements(Payment), ~clientSecret, ~merchantId=publishableKey) + HyperLogger.make(~source=Elements(Payment), ~clientSecret, ~merchantId=publishableKey) }, (publishableKey, clientSecret)) React.useEffect0(() => { diff --git a/src/Payments/PreMountLoader.res b/src/Payments/PreMountLoader.res index c600b7a84..8f976ca43 100644 --- a/src/Payments/PreMountLoader.res +++ b/src/Payments/PreMountLoader.res @@ -19,7 +19,7 @@ let make = ( false ) let (sessionTokensResponseSent, setSessionTokensResponseSent) = React.useState(_ => false) - let logger = OrcaLogger.make( + let logger = HyperLogger.make( ~sessionId, ~source=Loader, ~merchantId=publishableKey, diff --git a/src/Payments/SepaBankDebit.res b/src/Payments/SepaBankDebit.res index 8570a25b0..00c1d6a07 100644 --- a/src/Payments/SepaBankDebit.res +++ b/src/Payments/SepaBankDebit.res @@ -1,5 +1,4 @@ open RecoilAtoms -open RecoilAtomTypes open Utils open PaymentModeType @@ -17,12 +16,7 @@ let make = (~paymentType: CardThemeType.mode) => { let (fullName, _) = Recoil.useLoggedRecoilState(userFullName, "fullName", loggerState) let (email, _) = Recoil.useLoggedRecoilState(userEmailAddress, "email", loggerState) - let (line1, _) = Recoil.useLoggedRecoilState(userAddressline1, "line1", loggerState) - let (line2, _) = Recoil.useLoggedRecoilState(userAddressline2, "line2", loggerState) - let (country, _) = Recoil.useLoggedRecoilState(userAddressCountry, "country", loggerState) - let (city, _) = Recoil.useLoggedRecoilState(userAddressCity, "city", loggerState) - let (postalCode, _) = Recoil.useLoggedRecoilState(userAddressPincode, "postal_code", loggerState) - let (state, _) = Recoil.useLoggedRecoilState(userAddressState, "state", loggerState) + let setComplete = Recoil.useSetRecoilState(fieldsComplete) let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue) @@ -35,21 +29,23 @@ let make = (~paymentType: CardThemeType.mode) => { let isVerifyPMAuthConnectorConfigured = displaySavedPaymentMethods && pmAuthMapper->Dict.get("sepa")->Option.isSome - let complete = - email.value != "" && - fullName.value != "" && - email.isValid->Option.getOr(false) && - switch modalData { - | Some(val: ACHTypes.data) => val.iban !== "" || val.accountHolderName !== "" - | None => false - } - let empty = - email.value == "" || - fullName.value == "" || - switch modalData { - | Some(val: ACHTypes.data) => val.iban === "" || val.accountHolderName === "" - | None => true - } + let complete = switch modalData { + | Some(data: ACHTypes.data) => + data.requiredFieldsBody + ->Option.getOr(Dict.make()) + ->Dict.valuesToArray + ->Array.reduce(true, (acc, ele) => acc && ele !== ""->JSON.Encode.string) + | None => false + } + + let empty = switch modalData { + | Some(data: ACHTypes.data) => + data.requiredFieldsBody + ->Option.getOr(Dict.make()) + ->Dict.valuesToArray + ->Array.reduce(true, (acc, ele) => acc && ele !== ""->JSON.Encode.string) + | None => true + } UtilityHooks.useHandlePostMessages(~complete, ~empty, ~paymentType="sepa_bank_debit") @@ -60,60 +56,49 @@ let make = (~paymentType: CardThemeType.mode) => { let submitCallback = React.useCallback((ev: Window.event) => { let json = ev.data->safeParse - let confirm = json->Utils.getDictFromJson->ConfirmType.itemToObjMapper + let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper if confirm.doSubmit { if complete { switch modalData { - | Some(data: ACHTypes.data) => { - let body = PaymentBody.sepaBankDebitBody( - ~fullName=fullName.value, - ~email=email.value, - ~data, - ~line1=line1.value, - ~line2=line2.value, - ~country=getCountryCode(country.value).isoAlpha2, - ~city=city.value, - ~postalCode=postalCode.value, - ~state=state.value, - ) - intent( - ~bodyArr=body, - ~confirmParam=confirm.confirmParams, - ~handleUserError=false, - ~manualRetry=isManualRetryEnabled, - ) - } + | Some(data: ACHTypes.data) => + let bodyFields = data.requiredFieldsBody->Option.getOr(Dict.make()) + let sepaBody = + PaymentBody.dynamicPaymentBody("bank_debit", "sepa") + ->Dict.fromArray + ->JSON.Encode.object + ->flattenObject(true) + ->mergeTwoFlattenedJsonDicts(bodyFields) + ->getArrayOfTupleFromDict + intent( + ~bodyArr=sepaBody, + ~confirmParam=confirm.confirmParams, + ~handleUserError=false, + ~manualRetry=isManualRetryEnabled, + ) | None => () } - () } else { postFailedSubmitResponse(~errortype="validation_error", ~message="Please enter all fields") } } }, (email, fullName, modalData, isManualRetryEnabled)) useSubmitPaymentData(submitCallback) - <> - - - - -
+ :
- - - +
- - } let default = make diff --git a/src/ThreeDSAuth.res b/src/ThreeDSAuth.res index 5d5f9a6f6..84ad15273 100644 --- a/src/ThreeDSAuth.res +++ b/src/ThreeDSAuth.res @@ -8,7 +8,7 @@ let make = () => { let threeDsAuthoriseUrl = React.useRef("") let (expiryTime, setExpiryTime) = React.useState(_ => 600000.0) - let logger = OrcaLogger.make(~source=Elements(Payment)) + let logger = HyperLogger.make(~source=Elements(Payment)) let handleFrictionLess = () => { let ele = Window.querySelector("#threeDsAuthDiv") @@ -145,7 +145,13 @@ let make = () => {
` let iframeDiv = Window.createElement("div") @@ -90,6 +90,7 @@ let make = ( let clientSecretReMatch = Re.test(`.+_secret_[A-Za-z0-9]+`->Re.fromString, clientSecret) let preMountLoaderIframeDiv = mountPreMountLoaderIframe() + let isTaxCalculationEnabled = ref(false) let unMountPreMountLoaderIframe = () => { switch preMountLoaderIframeDiv->Nullable.toOption { @@ -128,13 +129,27 @@ let make = ( } } + let onPazeCallback = mountedIframeRef => { + (ev: Types.event) => { + let json = ev.data->Identity.anyTypeToJson + let dict = json->getDictFromJson + let isPazeExist = dict->getBool("isPaze", false) + if isPazeExist { + mountedIframeRef->Window.iframePostMessage([("data", json)]->Dict.fromArray) + } + } + } + let fetchPaymentsList = (mountedIframeRef, componentType) => { let handlePaymentMethodsLoaded = (event: Types.event) => { let json = event.data->Identity.anyTypeToJson let dict = json->getDictFromJson let isPaymentMethodsData = dict->getString("data", "") === "payment_methods" if isPaymentMethodsData { + isTaxCalculationEnabled.contents = + dict->getDictFromDict("response")->getBool("is_tax_calculation_enabled", false) addSmartEventListener("message", onPlaidCallback(mountedIframeRef), "onPlaidCallback") + addSmartEventListener("message", onPazeCallback(mountedIframeRef), "onPazeCallback") let json = dict->getJsonFromDict("response", JSON.Encode.null) let isApplePayPresent = PaymentMethodsRecord.getPaymentMethodTypeFromList( @@ -296,34 +311,45 @@ let make = ( ("loader", loader), ("fonts", fonts), ]->getJsonFromArrayOfJson - let message = - [ - ( - "paymentElementCreate", - componentType->getIsComponentTypeForPaymentElementCreate->JSON.Encode.bool, - ), - ("otherElements", otherElements->JSON.Encode.bool), - ("options", newOptions), - ("componentType", componentType->JSON.Encode.string), - ("paymentOptions", widgetOptions), - ("iframeId", selectorString->JSON.Encode.string), - ("publishableKey", publishableKey->JSON.Encode.string), - ("endpoint", endpoint->JSON.Encode.string), - ("sdkSessionId", sdkSessionId->JSON.Encode.string), - ("blockConfirm", blockConfirm->JSON.Encode.bool), - ("customPodUri", customPodUri->JSON.Encode.string), - ("sdkHandleOneClickConfirmPayment", sdkHandleOneClickConfirmPayment->JSON.Encode.bool), - ("parentURL", "*"->JSON.Encode.string), - ("analyticsMetadata", analyticsMetadata), - ("launchTime", launchTime->JSON.Encode.float), - ("customBackendUrl", customBackendUrl->JSON.Encode.string), - ]->Dict.fromArray + let message = [ + ( + "paymentElementCreate", + componentType->getIsComponentTypeForPaymentElementCreate->JSON.Encode.bool, + ), + ("otherElements", otherElements->JSON.Encode.bool), + ("options", newOptions), + ("componentType", componentType->JSON.Encode.string), + ("paymentOptions", widgetOptions), + ("iframeId", selectorString->JSON.Encode.string), + ("publishableKey", publishableKey->JSON.Encode.string), + ("endpoint", endpoint->JSON.Encode.string), + ("sdkSessionId", sdkSessionId->JSON.Encode.string), + ("blockConfirm", blockConfirm->JSON.Encode.bool), + ("customPodUri", customPodUri->JSON.Encode.string), + ("sdkHandleOneClickConfirmPayment", sdkHandleOneClickConfirmPayment->JSON.Encode.bool), + ("parentURL", "*"->JSON.Encode.string), + ("analyticsMetadata", analyticsMetadata), + ("launchTime", launchTime->JSON.Encode.float), + ("customBackendUrl", customBackendUrl->JSON.Encode.string), + ( + "isPaymentButtonHandlerProvided", + LoaderPaymentElement.isPaymentButtonHandlerProvided.contents->JSON.Encode.bool, + ), + ( + "onCompleteDoThisUsed", + EventListenerManager.eventListenerMap + ->Dict.get("onCompleteDoThis") + ->Option.isSome + ->JSON.Encode.bool, + ), + ]->Dict.fromArray let wallets = PaymentType.getWallets(newOptions->getDictFromJson, "wallets", logger) let handleApplePayMounted = (event: Types.event) => { let json = event.data->anyTypeToJson let dict = json->getDictFromJson + let componentName = getString(dict, "componentName", "payment") if dict->Dict.get("applePayMounted")->Option.isSome { if wallets.applePay === Auto { @@ -331,8 +357,11 @@ let make = ( | Some(session) => try { if session.canMakePayments() { - let msg = [("applePayCanMakePayments", true->JSON.Encode.bool)]->Dict.fromArray - event.source->Window.sendPostMessage(msg) + let msg = [ + ("hyperApplePayCanMakePayments", true->JSON.Encode.bool), + ("componentName", componentName->JSON.Encode.string), + ] + messageTopWindow(msg) } else { Console.log("CANNOT MAKE PAYMENT USING APPLE PAY") logger.setLogInfo( @@ -364,6 +393,28 @@ let make = ( ~logType=INFO, ) } + } else if dict->Dict.get("applePayCanMakePayments")->Option.isSome { + let applePayCanMakePayments = getBool(dict, "applePayCanMakePayments", false) + + if applePayCanMakePayments { + try { + let msg = [("applePayCanMakePayments", true->JSON.Encode.bool)]->Dict.fromArray + + handleApplePayIframePostMessage(msg, componentName, mountedIframeRef) + } catch { + | exn => { + let exnString = exn->anyTypeToJson->JSON.stringify + + Console.log("CANNOT MAKE PAYMENT USING APPLE PAY: " ++ exnString) + logger.setLogInfo( + ~value=exnString, + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + ~logType=ERROR, + ) + } + } + } } } @@ -782,6 +833,8 @@ let make = ( let handleApplePayMessages = (applePayEvent: Types.event) => { let json = applePayEvent.data->Identity.anyTypeToJson let dict = json->getDictFromJson + let componentName = dict->getString("componentName", "payment") + switch ( dict->Dict.get("applePayButtonClicked"), dict->Dict.get("applePayPaymentRequest"), @@ -807,33 +860,45 @@ let make = ( ~paymentMethod="APPLE_PAY", ) - let callBackFunc = payment => { - let msg = - [ - ("applePayProcessPayment", payment.token), - ("applePayBillingContact", payment.billingContact), - ("applePayShippingContact", payment.shippingContact), - ]->Dict.fromArray - applePayEvent.source->Window.sendPostMessage(msg) - } - - ApplePayHelpers.startApplePaySession( - ~paymentRequest, - ~applePaySessionRef, - ~applePayPresent, - ~logger, - ~applePayEvent=Some(applePayEvent), - ~callBackFunc, - ~clientSecret, - ~publishableKey, - ~isTaxCalculationEnabled, - ) + let msg = [ + ("hyperApplePayButtonClicked", true->JSON.Encode.bool), + ("paymentRequest", paymentRequest), + ("applePayPresent", applePayPresent->Option.getOr(JSON.Encode.null)), + ("clientSecret", clientSecret->JSON.Encode.string), + ("publishableKey", publishableKey->JSON.Encode.string), + ("isTaxCalculationEnabled", isTaxCalculationEnabled->JSON.Encode.bool), + ("sdkSessionId", sdkSessionId->JSON.Encode.string), + ("analyticsMetadata", analyticsMetadata), + ("componentName", componentName->JSON.Encode.string), + ] + messageTopWindow(msg) } - } else { - () } | _ => () } + + if dict->Dict.get("applePayPaymentToken")->Option.isSome { + let token = dict->getJsonFromDict("applePayPaymentToken", JSON.Encode.null) + let billingContact = + dict->getJsonFromDict("applePayBillingContact", JSON.Encode.null) + let shippingContact = + dict->getJsonFromDict("applePayShippingContact", JSON.Encode.null) + + let msg = + [ + ("applePayPaymentToken", token), + ("applePayBillingContact", billingContact), + ("applePayShippingContact", shippingContact), + ]->Dict.fromArray + + handleApplePayIframePostMessage(msg, componentName, mountedIframeRef) + } + + if dict->Dict.get("showApplePayButton")->Option.isSome { + let msg = [("showApplePayButton", true->JSON.Encode.bool)]->Dict.fromArray + + handleApplePayIframePostMessage(msg, componentName, mountedIframeRef) + } } addSmartEventListener("message", handleApplePayMessages, "onApplePayMessages") @@ -866,13 +931,112 @@ let make = ( ) try { - let gPayClient = GooglePayType.google( + let transactionInfo = gpayobj.transaction_info->getDictFromJson + + let onPaymentDataChanged = intermediatePaymentData => { + let shippingAddress = + intermediatePaymentData + ->getDictFromJson + ->getDictFromDict("shippingAddress") + ->billingContactItemToObjMapper + let newShippingAddress = + [ + ("state", shippingAddress.administrativeArea->JSON.Encode.string), + ("country", shippingAddress.countryCode->JSON.Encode.string), + ("zip", shippingAddress.postalCode->JSON.Encode.string), + ]->getJsonFromArrayOfJson + + let paymentMethodType = "google_pay"->JSON.Encode.string + + let currentPaymentRequest = [ + ( + "newTransactionInfo", + [ + ( + "countryCode", + transactionInfo + ->getString("country_code", "") + ->JSON.Encode.string, + ), + ( + "currencyCode", + transactionInfo + ->getString("currency_code", "") + ->JSON.Encode.string, + ), + ("totalPriceStatus", "FINAL"->JSON.Encode.string), + ( + "totalPrice", + transactionInfo + ->getString("total_price", "") + ->JSON.Encode.string, + ), + ]->getJsonFromArrayOfJson, + ), + ]->getJsonFromArrayOfJson + + if isTaxCalculationEnabled.contents { + TaxCalculation.calculateTax( + ~shippingAddress=[ + ("address", newShippingAddress), + ]->getJsonFromArrayOfJson, + ~logger, + ~publishableKey, + ~clientSecret, + ~paymentMethodType, + )->then(resp => { + switch resp->TaxCalculation.taxResponseToObjMapper { + | Some(taxCalculationResponse) => { + let updatePaymentRequest = [ + ( + "newTransactionInfo", + [ + ( + "countryCode", + shippingAddress.countryCode->JSON.Encode.string, + ), + ( + "currencyCode", + transactionInfo + ->getString("currency_code", "") + ->JSON.Encode.string, + ), + ("totalPriceStatus", "FINAL"->JSON.Encode.string), + ( + "totalPrice", + taxCalculationResponse.net_amount + ->minorUnitToString + ->JSON.Encode.string, + ), + ]->getJsonFromArrayOfJson, + ), + ]->getJsonFromArrayOfJson + updatePaymentRequest->resolve + } + | None => currentPaymentRequest->resolve + } + }) + } else { + currentPaymentRequest->resolve + } + } + let gpayClientRequest = if componentType->getIsExpressCheckoutComponent { { "environment": publishableKey->String.startsWith("pk_prd_") ? "PRODUCTION" : "TEST", - }->Identity.anyTypeToJson, - ) + "paymentDataCallbacks": { + "onPaymentDataChanged": onPaymentDataChanged, + }, + }->Identity.anyTypeToJson + } else { + { + "environment": publishableKey->String.startsWith("pk_prd_") + ? "PRODUCTION" + : "TEST", + }->Identity.anyTypeToJson + } + let gPayClient = GooglePayType.google(gpayClientRequest) gPayClient.isReadyToPay(payRequest) ->then(res => { @@ -895,6 +1059,7 @@ let make = ( let handleGooglePayMessages = (event: Types.event) => { let evJson = event.data->anyTypeToJson + let gpayClicked = evJson ->getOptionalJsonFromJson("GpayClicked") diff --git a/src/orca-loader/Hyper.res b/src/hyper-loader/Hyper.res similarity index 89% rename from src/orca-loader/Hyper.res rename to src/hyper-loader/Hyper.res index 6941d62a7..347f05276 100644 --- a/src/orca-loader/Hyper.res +++ b/src/hyper-loader/Hyper.res @@ -60,6 +60,80 @@ let preloader = () => { preloadFile(~type_="script", ~href="https://js.braintreegateway.com/web/3.88.4/js/client.min.js") } +let handleHyperApplePayMounted = (event: Types.event) => { + open ApplePayTypes + let json = event.data->anyTypeToJson + let dict = json->getDictFromJson + let applePaySessionRef = ref(Nullable.null) + + let componentName = dict->getString("componentName", "payment") + + if dict->Dict.get("hyperApplePayCanMakePayments")->Option.isSome { + let msg = + [ + ("applePayCanMakePayments", true->JSON.Encode.bool), + ("componentName", componentName->JSON.Encode.string), + ] + ->Dict.fromArray + ->JSON.Encode.object + event.source->Window.sendPostMessageJSON(msg) + } else if dict->Dict.get("hyperApplePayButtonClicked")->Option.isSome { + let paymentRequest = dict->Dict.get("paymentRequest")->Option.getOr(JSON.Encode.null) + let applePayPresent = dict->Dict.get("applePayPresent") + let clientSecret = dict->getString("clientSecret", "") + let publishableKey = dict->getString("publishableKey", "") + let isTaxCalculationEnabled = dict->getBool("isTaxCalculationEnabled", false) + let sdkSessionId = dict->getString("sdkSessionId", "") + let analyticsMetadata = dict->getJsonFromDict("analyticsMetadata", JSON.Encode.null) + + let logger = HyperLogger.make( + ~sessionId=sdkSessionId, + ~source=Loader, + ~merchantId=publishableKey, + ~metadata=analyticsMetadata, + ~clientSecret, + ) + + let callBackFunc = payment => { + let msg = + [ + ("applePayPaymentToken", payment.token), + ("applePayBillingContact", payment.billingContact), + ("applePayShippingContact", payment.shippingContact), + ("componentName", componentName->JSON.Encode.string), + ] + ->Dict.fromArray + ->JSON.Encode.object + event.source->Window.sendPostMessageJSON(msg) + } + + let resolvePromise = _ => { + let msg = + [ + ("showApplePayButton", true->JSON.Encode.bool), + ("componentName", componentName->JSON.Encode.string), + ] + ->Dict.fromArray + ->JSON.Encode.object + event.source->Window.sendPostMessageJSON(msg) + } + + ApplePayHelpers.startApplePaySession( + ~paymentRequest, + ~applePaySessionRef, + ~applePayPresent, + ~logger, + ~callBackFunc, + ~clientSecret, + ~publishableKey, + ~isTaxCalculationEnabled, + ~resolvePromise, + ) + } +} + +addSmartEventListener("message", handleHyperApplePayMounted, "onHyperApplePayMount") + let make = (publishableKey, options: option, analyticsInfo: option) => { try { let isPreloadEnabled = @@ -81,7 +155,7 @@ let make = (publishableKey, options: option, analyticsInfo: optiongetString("sessionID", "hyp_" ++ Utils.generateRandomString(8)) let sdkTimestamp = analyticsInfoDict->getString("timeStamp", Date.now()->Float.toString) - let logger = OrcaLogger.make( + let logger = HyperLogger.make( ~sessionId=sessionID, ~source=Loader, ~merchantId=publishableKey, diff --git a/src/orca-loader/HyperLoader.res b/src/hyper-loader/HyperLoader.res similarity index 78% rename from src/orca-loader/HyperLoader.res rename to src/hyper-loader/HyperLoader.res index 1e3ba9e77..885933ad2 100644 --- a/src/orca-loader/HyperLoader.res +++ b/src/hyper-loader/HyperLoader.res @@ -3,7 +3,7 @@ let loadHyper = (str, option) => { } let loadStripe = (str, option) => { - ErrorUtils.manageErrorWarning(DEPRECATED_LOADSTRIPE, ~logger=OrcaLogger.defaultLoggerConfig) + ErrorUtils.manageErrorWarning(DEPRECATED_LOADSTRIPE, ~logger=HyperLogger.defaultLoggerConfig) loadHyper(str, option) } diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/hyper-loader/LoaderPaymentElement.res similarity index 87% rename from src/orca-loader/LoaderPaymentElement.res rename to src/hyper-loader/LoaderPaymentElement.res index 028e50132..b702e6c5a 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/hyper-loader/LoaderPaymentElement.res @@ -6,6 +6,8 @@ open Identity @val @scope(("navigator", "clipboard")) external writeText: string => promise<'a> = "writeText" +let onCompleteDoThisUsed = ref(false) +let isPaymentButtonHandlerProvided = ref(false) let make = ( componentType, options, @@ -32,6 +34,48 @@ let make = ( true, ) + let asyncWrapper = async fn => { + try { + await fn() + } catch { + | err => Console.log2("Async function call failure", err) + } + } + + let currEventHandler = ref(Some(() => Promise.make((_, _) => {()}))) + let walletOneClickEventHandler = (event: Types.event) => { + let json = try { + event.data->anyTypeToJson + } catch { + | _ => JSON.Encode.null + } + + let dict = json->getDictFromJson + if dict->Dict.get("oneClickConfirmTriggered")->Option.isSome { + switch currEventHandler.contents { + | Some(eH) => + asyncWrapper(eH) + ->Promise.then(() => { + let msg = [("walletClickEvent", true->JSON.Encode.bool)]->Dict.fromArray + event.source->Window.sendPostMessage(msg) + Promise.resolve() + }) + ->ignore + + | None => () + } + } + } + + Window.addEventListener("message", walletOneClickEventHandler) + + let onSDKHandleClick = (eventHandler: option RescriptCore.Promise.t<'a>>) => { + currEventHandler := eventHandler + if eventHandler->Option.isSome { + isPaymentButtonHandlerProvided := true + } + } + let on = (eventType, eventHandler) => { switch eventType->eventTypeMapper { | Escape => @@ -47,6 +91,15 @@ let make = ( }, "onEscape", ) + | CompleteDoThis => + if eventHandler->Option.isSome { + eventHandlerFunc( + ev => ev.data.completeDoThis, + eventHandler, + CompleteDoThis, + "onCompleteDoThis", + ) + } | Change => eventHandlerFunc( ev => ev.data.elementType === componentType, @@ -281,6 +334,10 @@ let make = ( ("options", options), ]->Dict.fromArray, ) + let fullScreenEle = Window.querySelector(`#orca-fullscreen`) + fullScreenEle->Window.iframePostMessage( + [("metadata", fullscreenMetadata.contents)]->Dict.fromArray, + ) } } addSmartEventListener( @@ -328,7 +385,7 @@ let make = ( src="${ApiEndpoint.sdkDomainUrl}/index.html?componentName=${componentType}" allow="payment *" name="orca-payment" - style="border: 0px; ${additionalIframeStyle}" + style="border: 0px; ${additionalIframeStyle} outline: none;" width="100%" >
` @@ -361,6 +418,7 @@ let make = ( destroy, update, mount, + onSDKHandleClick, } } catch { | e => { diff --git a/src/orca-loader/PaymentMethodsManagementElements.res b/src/hyper-loader/PaymentMethodsManagementElements.res similarity index 98% rename from src/orca-loader/PaymentMethodsManagementElements.res rename to src/hyper-loader/PaymentMethodsManagementElements.res index 720a2cf69..5b9a0ea11 100644 --- a/src/orca-loader/PaymentMethodsManagementElements.res +++ b/src/hyper-loader/PaymentMethodsManagementElements.res @@ -9,14 +9,14 @@ let make = ( ~ephemeralKey, ~sdkSessionId, ~publishableKey, - ~logger: option, + ~logger: option, ~analyticsMetadata, ~customBackendUrl, ) => { let hyperComponentName = PaymentMethodsManagementElements try { let iframeRef = [] - let logger = logger->Option.getOr(OrcaLogger.defaultLoggerConfig) + let logger = logger->Option.getOr(HyperLogger.defaultLoggerConfig) let savedPaymentElement = Dict.make() let localOptions = options->JSON.Decode.object->Option.getOr(Dict.make()) @@ -56,6 +56,7 @@ let make = ( src="${ApiEndpoint.sdkDomainUrl}/index.html?fullscreenType=${componentType}&publishableKey=${publishableKey}&ephemeralKey=${ephemeralKey}&sessionId=${sdkSessionId}&endpoint=${endpoint}&hyperComponentName=${hyperComponentName->getStrFromHyperComponentName}" allow="*" name="orca-payment" + style="outline: none;" >
` let iframeDiv = Window.createElement("div") diff --git a/src/orca-loader/PaymentSession.res b/src/hyper-loader/PaymentSession.res similarity index 87% rename from src/orca-loader/PaymentSession.res rename to src/hyper-loader/PaymentSession.res index 751ebc0bb..78107c024 100644 --- a/src/orca-loader/PaymentSession.res +++ b/src/hyper-loader/PaymentSession.res @@ -4,10 +4,10 @@ let make = ( options, ~clientSecret, ~publishableKey, - ~logger: option, + ~logger: option, ~ephemeralKey, ) => { - let logger = logger->Option.getOr(OrcaLogger.defaultLoggerConfig) + let logger = logger->Option.getOr(HyperLogger.defaultLoggerConfig) let customPodUri = options ->JSON.Decode.object diff --git a/src/orca-loader/PaymentSessionMethods.res b/src/hyper-loader/PaymentSessionMethods.res similarity index 97% rename from src/orca-loader/PaymentSessionMethods.res rename to src/hyper-loader/PaymentSessionMethods.res index 0130a64d7..fb80a5614 100644 --- a/src/orca-loader/PaymentSessionMethods.res +++ b/src/hyper-loader/PaymentSessionMethods.res @@ -35,7 +35,7 @@ let getCustomerSavedPaymentMethods = ( customerPaymentMethods->Array.sort((a, b) => compareLogic(a.lastUsedAt, b.lastUsedAt)) let customerPaymentMethodsRef = ref(customerPaymentMethods) - let applePayTokenRef = ref(JSON.Encode.null) + let applePayTokenRef = ref(defaultHeadlessApplePayToken) let googlePayTokenRef = ref(JSON.Encode.null) let isApplePayPresent = @@ -187,13 +187,14 @@ let getCustomerSavedPaymentMethods = ( } ApplePayHelpers.startApplePaySession( - ~paymentRequest=applePayTokenRef.contents, + ~paymentRequest=applePayTokenRef.contents.paymentRequestData, ~applePaySessionRef, - ~applePayPresent=Some(applePayTokenRef.contents), + ~applePayPresent=applePayTokenRef.contents.sessionTokenData, ~logger, ~callBackFunc=processPayment, ~clientSecret, ~publishableKey, + ~resolvePromise, ) } @@ -425,7 +426,10 @@ let getCustomerSavedPaymentMethods = ( ~sessionObj=optToken, ~componentName, ) - applePayTokenRef := paymentRequest + applePayTokenRef := { + paymentRequestData: paymentRequest, + sessionTokenData: optToken, + } } | _ => updateCustomerPaymentMethodsRef(~isFilterApplePay=true) } diff --git a/src/orca-loader/Types.res b/src/hyper-loader/Types.res similarity index 94% rename from src/orca-loader/Types.res rename to src/hyper-loader/Types.res index 5186769da..932612800 100644 --- a/src/orca-loader/Types.res +++ b/src/hyper-loader/Types.res @@ -4,6 +4,7 @@ type eventData = { blur: bool, ready: bool, clickTriggered: bool, + completeDoThis: bool, elementType: string, classChange: bool, newClassType: string, @@ -30,6 +31,7 @@ type paymentElement = { mount: string => unit, focus: unit => unit, clear: unit => unit, + onSDKHandleClick: option Promise.t> => unit, } type element = { @@ -106,6 +108,8 @@ let fetchUpdates = () => { setTimeout(() => resolve(Dict.make()->JSON.Encode.object), 1000)->ignore }) } + +let fnArgument = Some(() => Promise.make((_, _) => {()})) let defaultPaymentElement = { on: (_str, _func) => (), collapse: () => (), @@ -116,6 +120,7 @@ let defaultPaymentElement = { mount: _string => (), focus: () => (), clear: () => (), + onSDKHandleClick: fnArgument => (), } let create = (_componentType, _options) => { @@ -184,7 +189,16 @@ let defaultHyperInstance = { } type eventType = - Escape | Change | Click | Ready | Focus | Blur | ConfirmPayment | OneClickConfirmPayment | None + | Escape + | Change + | Click + | Ready + | Focus + | Blur + | CompleteDoThis + | ConfirmPayment + | OneClickConfirmPayment + | None let eventTypeMapper = event => { switch event { @@ -192,6 +206,7 @@ let eventTypeMapper = event => { | "change" => Change | "clickTriggered" => Click | "ready" => Ready + | "completeDoThis" => CompleteDoThis | "focus" => Focus | "blur" => Blur | "confirmTriggered" => ConfirmPayment diff --git a/src/orca-log-catcher/ErrorBoundary.res b/src/hyper-log-catcher/ErrorBoundary.res similarity index 95% rename from src/orca-log-catcher/ErrorBoundary.res rename to src/hyper-log-catcher/ErrorBoundary.res index 4f95da757..c2ea81446 100644 --- a/src/orca-log-catcher/ErrorBoundary.res +++ b/src/hyper-log-catcher/ErrorBoundary.res @@ -126,7 +126,7 @@ module ErrorCard = { let make = (~error: Sentry.ErrorBoundary.fallbackArg, ~level, ~componentName) => { let beaconApiCall = data => { if data->Array.length > 0 { - let logData = data->Array.map(OrcaLogger.logFileToObj)->JSON.Encode.array->JSON.stringify + let logData = data->Array.map(HyperLogger.logFileToObj)->JSON.Encode.array->JSON.stringify Window.Navigator.sendBeacon(GlobalVars.logEndpoint, logData) } } @@ -142,7 +142,7 @@ module ErrorCard = { errorDict->Dict.set("componentName", componentName->JSON.Encode.string) - let errorLog: OrcaLogger.logFile = { + let errorLog: HyperLogger.logFile = { logType: ERROR, timestamp: Date.now()->Float.toString, sessionId: "", @@ -153,8 +153,8 @@ module ErrorCard = { category: USER_ERROR, paymentId: "", merchantId: "", - browserName: OrcaLogger.arrayOfNameAndVersion->Array.get(0)->Option.getOr("Others"), - browserVersion: OrcaLogger.arrayOfNameAndVersion->Array.get(1)->Option.getOr("0"), + browserName: HyperLogger.arrayOfNameAndVersion->Array.get(0)->Option.getOr("Others"), + browserVersion: HyperLogger.arrayOfNameAndVersion->Array.get(1)->Option.getOr("0"), platform: Window.Navigator.platform, userAgent: Window.Navigator.userAgent, appId: "", diff --git a/src/orca-log-catcher/OrcaLogger.res b/src/hyper-log-catcher/HyperLogger.res similarity index 85% rename from src/orca-log-catcher/OrcaLogger.res rename to src/hyper-log-catcher/HyperLogger.res index bdcc4e4cb..715ed5609 100644 --- a/src/orca-log-catcher/OrcaLogger.res +++ b/src/hyper-log-catcher/HyperLogger.res @@ -84,92 +84,10 @@ type eventName = | DELETE_PAYMENT_METHODS_CALL_INIT | DELETE_PAYMENT_METHODS_CALL | EXTERNAL_TAX_CALCULATION + | POST_SESSION_TOKENS_CALL + | POST_SESSION_TOKENS_CALL_INIT -let eventNameToStrMapper = eventName => { - switch eventName { - | APP_RENDERED => "APP_RENDERED" - | PAYMENT_METHOD_CHANGED => "PAYMENT_METHOD_CHANGED" - | PAYMENT_DATA_FILLED => "PAYMENT_DATA_FILLED" - | PAYMENT_ATTEMPT => "PAYMENT_ATTEMPT" - | PAYMENT_SUCCESS => "PAYMENT_SUCCESS" - | PAYMENT_FAILED => "PAYMENT_FAILED" - | INPUT_FIELD_CHANGED => "INPUT_FIELD_CHANGED" - | RETRIEVE_CALL_INIT => "RETRIEVE_CALL_INIT" - | RETRIEVE_CALL => "RETRIEVE_CALL" - | AUTHENTICATION_CALL_INIT => "AUTHENTICATION_CALL_INIT" - | AUTHENTICATION_CALL => "AUTHENTICATION_CALL" - | CONFIRM_CALL_INIT => "CONFIRM_CALL_INIT" - | CONFIRM_CALL => "CONFIRM_CALL" - | CONFIRM_PAYOUT_CALL_INIT => "CONFIRM_PAYOUT_CALL_INIT" - | CONFIRM_PAYOUT_CALL => "CONFIRM_PAYOUT_CALL" - | SESSIONS_CALL_INIT => "SESSIONS_CALL_INIT" - | SESSIONS_CALL => "SESSIONS_CALL" - | PAYMENT_METHODS_CALL => "PAYMENT_METHODS_CALL" - | PAYMENT_METHODS_CALL_INIT => "PAYMENT_METHODS_CALL_INIT" - | CUSTOMER_PAYMENT_METHODS_CALL => "CUSTOMER_PAYMENT_METHODS_CALL" - | CUSTOMER_PAYMENT_METHODS_CALL_INIT => "CUSTOMER_PAYMENT_METHODS_CALL_INIT" - | CREATE_CUSTOMER_PAYMENT_METHODS_CALL_INIT => "CREATE_CUSTOMER_PAYMENT_METHODS_CALL_INIT" - | CREATE_CUSTOMER_PAYMENT_METHODS_CALL => "CREATE_CUSTOMER_PAYMENT_METHODS_CALL" - | TRUSTPAY_SCRIPT => "TRUSTPAY_SCRIPT" - | PM_AUTH_CONNECTOR_SCRIPT => "PM_AUTH_CONNECTOR_SCRIPT" - | GOOGLE_PAY_SCRIPT => "GOOGLE_PAY_SCRIPT" - | APPLE_PAY_FLOW => "APPLE_PAY_FLOW" - | GOOGLE_PAY_FLOW => "GOOGLE_PAY_FLOW" - | PAYPAL_FLOW => "PAYPAL_FLOW" - | PAYPAL_SDK_FLOW => "PAYPAL_SDK_FLOW" - | APP_INITIATED => "APP_INITIATED" - | APP_REINITIATED => "APP_REINITIATED" - | LOG_INITIATED => "LOG_INITIATED" - | LOADER_CALLED => "LOADER_CALLED" - | ORCA_ELEMENTS_CALLED => "ORCA_ELEMENTS_CALLED" - | PAYMENT_OPTIONS_PROVIDED => "PAYMENT_OPTIONS_PROVIDED" - | BLUR => "BLUR" - | FOCUS => "FOCUS" - | CLEAR => "CLEAR" - | CONFIRM_PAYMENT => "CONFIRM_PAYMENT" - | CONFIRM_CARD_PAYMENT => "CONFIRM_CARD_PAYMENT" - | SDK_CRASH => "SDK_CRASH" - | INVALID_PK => "INVALID_PK" - | DEPRECATED_LOADSTRIPE => "DEPRECATED_LOADSTRIPE" - | REQUIRED_PARAMETER => "REQUIRED_PARAMETER" - | UNKNOWN_KEY => "UNKNOWN_KEY" - | UNKNOWN_VALUE => "UNKNOWN_VALUE" - | TYPE_BOOL_ERROR => "TYPE_BOOL_ERROR" - | TYPE_INT_ERROR => "TYPE_INT_ERROR" - | TYPE_STRING_ERROR => "TYPE_STRING_ERROR" - | INVALID_FORMAT => "INVALID_FORMAT" - | SDK_CONNECTOR_WARNING => "SDK_CONNECTOR_WARNING" - | VALUE_OUT_OF_RANGE => "VALUE_OUT_OF_RANGE" - | HTTP_NOT_ALLOWED => "HTTP_NOT_ALLOWED" - | INTERNAL_API_DOWN => "INTERNAL_API_DOWN" - | REDIRECTING_USER => "REDIRECTING_USER" - | DISPLAY_BANK_TRANSFER_INFO_PAGE => "DISPLAY_BANK_TRANSFER_INFO_PAGE" - | DISPLAY_QR_CODE_INFO_PAGE => "DISPLAY_QR_CODE_INFO_PAGE" - | DISPLAY_VOUCHER => "DISPLAY_VOUCHER" - | DISPLAY_THREE_DS_SDK => "DISPLAY_THREE_DS_SDK" - | THREE_DS_METHOD => "THREE_DS_METHOD" - | THREE_DS_METHOD_RESULT => "THREE_DS_METHOD_RESULT" - | PAYMENT_METHODS_RESPONSE => "PAYMENT_METHODS_RESPONSE" - | LOADER_CHANGED => "LOADER_CHANGED" - | PAYMENT_SESSION_INITIATED => "PAYMENT_SESSION_INITIATED" - | POLL_STATUS_CALL_INIT => "POLL_STATUS_CALL_INIT" - | POLL_STATUS_CALL => "POLL_STATUS_CALL" - | COMPLETE_AUTHORIZE_CALL_INIT => "COMPLETE_AUTHORIZE_CALL_INIT" - | COMPLETE_AUTHORIZE_CALL => "COMPLETE_AUTHORIZE_CALL" - | PLAID_SDK => "PLAID_SDK" - | PAYMENT_METHODS_AUTH_EXCHANGE_CALL => "PAYMENT_METHODS_AUTH_EXCHANGE_CALL" - | PAYMENT_METHODS_AUTH_LINK_CALL => "PAYMENT_METHODS_AUTH_LINK_CALL" - | PAYMENT_METHODS_AUTH_EXCHANGE_CALL_INIT => "PAYMENT_METHODS_AUTH_EXCHANGE_CALL_INIT" - | PAYMENT_METHODS_AUTH_LINK_CALL_INIT => "PAYMENT_METHODS_AUTH_LINK_CALL_INIT" - | SAVED_PAYMENT_METHODS_CALL => "SAVED_PAYMENT_METHODS_CALL" - | SAVED_PAYMENT_METHODS_CALL_INIT => "SAVED_PAYMENT_METHODS_CALL_INIT" - | PAYMENT_MANAGEMENT_ELEMENTS_CALLED => "PAYMENT_MANAGEMENT_ELEMENTS_CALLED" - | DELETE_SAVED_PAYMENT_METHOD => "DELETE_SAVED_PAYMENT_METHOD" - | DELETE_PAYMENT_METHODS_CALL_INIT => "DELETE_PAYMENT_METHODS_CALL_INIT" - | DELETE_PAYMENT_METHODS_CALL => "DELETE_PAYMENT_METHODS_CALL" - | EXTERNAL_TAX_CALCULATION => "EXTERNAL_TAX_CALCULATION" - } -} +let eventNameToStrMapper = (eventName: eventName) => (eventName :> string) let getPaymentId = clientSecret => String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("") @@ -321,7 +239,7 @@ let logFileToObj = logFile => { }->JSON.Encode.string, ), ("source", logFile.source->convertToScreamingSnakeCase->JSON.Encode.string), - ("version", logFile.version->JSON.Encode.string), // repoversion of orca-android + ("version", logFile.version->JSON.Encode.string), ("value", logFile.value->JSON.Encode.string), ("internal_metadata", logFile.internalMetadata->JSON.Encode.string), ("session_id", logFile.sessionId->JSON.Encode.string), diff --git a/src/orca-log-catcher/ReusableReactSuspense.res b/src/hyper-log-catcher/ReusableReactSuspense.res similarity index 100% rename from src/orca-log-catcher/ReusableReactSuspense.res rename to src/hyper-log-catcher/ReusableReactSuspense.res diff --git a/src/orca-log-catcher/Sentry.res b/src/hyper-log-catcher/Sentry.res similarity index 100% rename from src/orca-log-catcher/Sentry.res rename to src/hyper-log-catcher/Sentry.res diff --git a/src/index.css b/src/index.css index 651ed53e7..762b4af6c 100644 --- a/src/index.css +++ b/src/index.css @@ -1,16 +1,16 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +/* Remove blue outline of input, button in firefox */ +@-moz-document url-prefix() { + *:focus, + *:focus-visible, + *:focus-within, + *:active, + *:visited { + outline: none !important; + } } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +/* Remove contact and password icon in safari */ +input::-webkit-credentials-auto-fill-button, +input::-webkit-contacts-auto-fill-button { + width: 0 !important; } diff --git a/src/libraries/Recoil.res b/src/libraries/Recoil.res index 0c23c1668..20d0c6b1c 100644 --- a/src/libraries/Recoil.res +++ b/src/libraries/Recoil.res @@ -20,7 +20,7 @@ external useSetRecoilState: recoilAtom<'valueT> => ('valueT => 'valueT) => unit @module("recoil") external useRecoilValueFromAtom: recoilAtom<'valueT> => 'valueT = "useRecoilValue" -let useLoggedRecoilState = (atomName, type_, logger: OrcaLogger.loggerMake) => { +let useLoggedRecoilState = (atomName, type_, logger: HyperLogger.loggerMake) => { let (state, setState) = useRecoilState(atomName) let newSetState = value => { LoggerUtils.logInputChangeInfo(type_, logger) @@ -29,7 +29,7 @@ let useLoggedRecoilState = (atomName, type_, logger: OrcaLogger.loggerMake) => { (state, newSetState) } -let useLoggedSetRecoilState = (atomName, type_, logger: OrcaLogger.loggerMake) => { +let useLoggedSetRecoilState = (atomName, type_, logger: HyperLogger.loggerMake) => { let setState = useSetRecoilState(atomName) let newSetState = value => { LoggerUtils.logInputChangeInfo(type_, logger) diff --git a/webpack.common.js b/webpack.common.js index fdd7f08e3..c3cea6c8f 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -14,6 +14,7 @@ const getEnvVariable = (variable, defaultValue) => process.env[variable] ?? defaultValue; const sdkEnv = getEnvVariable("sdkEnv", "local"); +const enableLogging = getEnvVariable("enableLogging", "false") === "true"; const envSdkUrl = getEnvVariable("ENV_SDK_URL", ""); const envBackendUrl = getEnvVariable("ENV_BACKEND_URL", ""); const envLoggingUrl = getEnvVariable("ENV_LOGGING_URL", ""); @@ -22,7 +23,7 @@ const repoVersion = require("./package.json").version; const majorVersion = "v" + repoVersion.split(".")[0]; const repoName = require("./package.json").name; const repoPublicPath = - sdkEnv === "local" ? "" : `/${repoVersion}/${majorVersion}`; + sdkEnv === "local" ? "" : `/web/${repoVersion}/${majorVersion}`; const getSdkUrl = (env, customUrl) => { if (customUrl) return customUrl; @@ -60,14 +61,13 @@ const confirmEndPoint = const logEndpoint = envLoggingUrl || `https://${logDomain}.hyperswitch.io/logs/sdk`; -const enableLogging = true; const loggingLevel = "DEBUG"; const maxLogsPushedPerEventName = 100; module.exports = (publicPath = "auto") => { const entries = { app: "./index.js", - HyperLoader: "./src/orca-loader/HyperLoader.bs.js", + HyperLoader: "./src/hyper-loader/HyperLoader.bs.js", }; const plugins = [ new MiniCssExtractPlugin(), @@ -84,7 +84,7 @@ module.exports = (publicPath = "auto") => { logEndpoint: JSON.stringify(logEndpoint), sentryDSN: JSON.stringify(process.env.SENTRY_DSN), sentryScriptUrl: JSON.stringify(process.env.SENTRY_SCRIPT_URL), - enableLogging: JSON.stringify(enableLogging), + enableLogging: enableLogging, loggingLevel: JSON.stringify(loggingLevel), maxLogsPushedPerEventName: JSON.stringify(maxLogsPushedPerEventName), }),