UNPKG

wonder-payment

Version:

A lightweight and customizable wonder component for secure and user-friendly credit card input in payment forms.

1 lines 58.6 kB
{"version":3,"sources":["../src/index.ts","#style-inject:#style-inject","../src/index.css","../src/components/card.ts","../env.ts","../src/services/adapter.ts","../src/components/saved-cards.ts","../src/components/google-pay.ts"],"sourcesContent":["import \"@adyen/adyen-web/styles/adyen.css\";\r\nimport \"./index.css\";\r\nimport {\r\n WonderPaymentConfiguration,\r\n WonderPaymentPaymentMethods,\r\n WonderPaymentPaymentMethodsResponse,\r\n} from \"./models\";\r\n\r\nimport renderCardPayment from \"./components/card\";\r\nimport renderStoredCards from \"./components/saved-cards\";\r\nimport renderGooglePay from \"./components/google-pay\";\r\nimport { getPaymentMethods } from \"./services/adapter\";\r\n\r\nclass WonderPayment {\r\n private configuration: WonderPaymentConfiguration;\r\n private element: Element | null | undefined;\r\n\r\n constructor(config: WonderPaymentConfiguration) {\r\n this.configuration = config;\r\n }\r\n\r\n async mount(selector: HTMLElement | string) {\r\n this.element =\r\n typeof selector === \"string\"\r\n ? document.querySelector(selector)\r\n : selector;\r\n\r\n if (!this.element) {\r\n throw new Error(\"Invalid selector provided\");\r\n }\r\n\r\n const response = await this.setupPaymentMethods(\r\n this.configuration.environment,\r\n this.configuration.payfacData\r\n );\r\n\r\n if (response.resultCode === \"Error\") {\r\n this.handleError(response.message || \"An error occurred\");\r\n return;\r\n }\r\n\r\n this.element.innerHTML = `\r\n <div id=\"3ds-container\"></div>\r\n\r\n <div id=\"payment-container\" class=\"payment-container\">\r\n <div class=\"radio-group\">\r\n <div id=\"stored-card-container\" class=\"radio-group-container\"></div>\r\n \r\n <div id=\"card-container\" class=\"radio-group-container\"></div>\r\n\r\n <div id=\"google-pay-container\" class=\"radio-group-container\"></div>\r\n\r\n </div>\r\n </div>\r\n `;\r\n\r\n await renderStoredCards(\r\n this.element.querySelector(\"#stored-card-container\")!,\r\n this.configuration,\r\n response,\r\n this.handleError.bind(this),\r\n this.handleSuccess.bind(this)\r\n );\r\n\r\n await renderCardPayment(\r\n this.element.querySelector(\"#card-container\")!,\r\n this.configuration,\r\n response,\r\n this.handleError.bind(this),\r\n this.handleSuccess.bind(this)\r\n );\r\n\r\n await renderGooglePay(\r\n this.element.querySelector(\"#google-pay-container\")!,\r\n this.configuration,\r\n response,\r\n this.handleError.bind(this),\r\n this.handleSuccess.bind(this)\r\n );\r\n }\r\n\r\n handleError(message: string) {\r\n this.element!.innerHTML = `\r\n <div class=\"error-message\">${message}</div>\r\n `;\r\n document.getElementById(\"payment-container\")!.style.display = \"block\";\r\n }\r\n\r\n handleSuccess(message: string) {\r\n this.element!.innerHTML = `\r\n <div class=\"success-message\">${message}</div>\r\n `;\r\n }\r\n\r\n async setupPaymentMethods(\r\n environment: string,\r\n payfacData: string\r\n ): Promise<WonderPaymentPaymentMethodsResponse> {\r\n try {\r\n const fetchResponse = await getPaymentMethods(environment, {\r\n payfacData,\r\n });\r\n\r\n if (!fetchResponse.ok) {\r\n const errorResponse = await fetchResponse.json();\r\n return {\r\n resultCode: \"Error\",\r\n message: errorResponse.errorMessage,\r\n };\r\n }\r\n\r\n const data: WonderPaymentPaymentMethods = await fetchResponse.json();\r\n\r\n return {\r\n resultCode: \"Success\",\r\n ...data,\r\n };\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n } catch (error: any) {\r\n return {\r\n resultCode: \"Error\",\r\n message: error.message,\r\n };\r\n }\r\n }\r\n}\r\n\r\nexport default WonderPayment;\r\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".payment-container{max-width:440px}.radio-group{display:flex;flex-direction:column;gap:16px;max-width:440px;width:100%}.radio-group-container{display:flex;flex-direction:column;gap:16px}.radio-bubble{position:relative;cursor:pointer;overflow:hidden;background:#fff;border-radius:12px;transition:all .3s ease}.radio-bubble input[type=radio]{position:absolute;opacity:0;cursor:pointer}.bubble-content{display:flex;align-items:center;gap:12px;padding:16px 24px;transition:background-color .3s ease}.brands{display:flex;margin-left:auto}.brands>svg{transition:all .2s ease}.circle{width:20px;height:20px;border:2px solid #002649;border-radius:50%;position:relative;transition:all .3s ease}.circle:after{content:\\\"\\\";position:absolute;width:12px;height:12px;background:#002649;border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%) scale(0);transition:transform .2s ease}.radio-bubble:hover .circle{box-shadow:0 0 0 2px #3e44bd33}.radio-bubble input[type=radio]:checked+.bubble-content .circle:after{transform:translate(-50%,-50%) scale(1)}.text{color:#213547;font-size:1rem}.expandable-content{background:#fff;padding:0 24px;max-height:0;overflow:hidden;transition:all .3s ease;opacity:0}.radio-bubble input[type=radio]:checked~.expandable-content{padding:0 24px 16px;max-height:400px;opacity:1}.expandable-content p{margin:0;color:#213547;font-size:.9rem}.card{display:flex;padding:16px 0;flex-direction:column;gap:24px}.card--label{transform:translate(10px) translateY(-50%);z-index:1;background:linear-gradient(to top,#eef0f2 53%,transparent 50%);position:absolute;font-weight:500;font-size:14px}.card__wrapper.error .card--label{color:#ff4d4f;background:linear-gradient(to top,#fff8f5 53%,transparent 50%)}.card__wrapper{display:flex;flex-direction:column;justify-items:start;position:relative;width:100%}.card__wrapper--input{background:#eef0f2;color:#00112c;display:block;font-family:inherit;border:1px solid transparent;border-radius:8px;font-size:1rem;height:48px;outline:none;padding-left:12px;transition:border .2sease-out,box-shadow .2sease-out;width:100%}.card__wrapper--input:hover{border:1px solid #cdd8e2}.error .card__wrapper--input{background:#fff8f5;border:1px solid #ff4d4f}.card__field-wrapper{display:flex;width:100%;gap:20px}.card__submit-button{background:#002649;border:none;border-radius:8px;color:#fff;cursor:pointer;font-size:1rem;height:40px;outline:none;padding:0 16px;transition:background .2s ease-out;width:100%}.card__submit-button:hover{background:#002649;border:1px solid #dbdee2}.card__submit-button:disabled{background:#72889d;border:1px solid #dbdee2;cursor:not-allowed}.save-checkbox{display:none}.save-checkbox--label{display:inline-flex;align-items:center;cursor:pointer;font-size:14px;position:relative}.save-checkbox--label:before{content:\\\"\\\";width:24px;height:24px;border:1px solid transparent;border-radius:4px;display:inline-block;margin-right:8px;background-color:#eef0f2;transition:all .3s ease}.save-checkbox--label:after{content:\\\"\\\";position:absolute;width:6px;height:13px;border:solid #eef0f2;border-width:0 3px 3px 0;transform:rotate(40deg);left:8px;top:4px;display:none}.save-checkbox:checked+.save-checkbox--label:before{background-color:#002649;border-color:#eef0f2}.save-checkbox:checked+.save-checkbox--label:after{display:block}.save-checkbox--label:hover:before{border-color:#cdd8e2}.save-checkbox:checked+.save-checkbox--label:hover:before{border-color:#002649}.stored-card__delete-button{display:none;background:transparent;border:none;border-radius:4px;color:#ff4d4f;cursor:pointer;font-size:.9rem;padding:8px 12px;transition:background .2s ease}.stored-card__delete-button:hover{text-decoration:underline}.radio-bubble:has(input[type=radio]:checked) .stored-card__delete-button{display:block;margin-left:auto}.stored-card__wrapper{display:flex;gap:20px;width:100%}.stored-card__wrapper--field{flex:1}.stored-card__wrapper--field--value{display:flex;align-items:center}.error-message{color:#ff4d4f;font-size:12px}.adyen-checkout__threeds2__challenge,.adyen-checkout__threeds2__challenge-container{background-color:#fff;border-radius:12px}\\n\")","import {\r\n AdditionalDetailsActions,\r\n AdditionalDetailsData,\r\n AdyenCheckout,\r\n CardAllValidData,\r\n CustomCard,\r\n SubmitActions,\r\n SubmitData,\r\n UIElement,\r\n} from \"@adyen/adyen-web\";\r\nimport { SuccessResponse, WonderPaymentConfiguration } from \"../models\";\r\nimport {\r\n createPaymentDetailsRequest,\r\n createPaymentRequest,\r\n} from \"../services/adapter\";\r\nimport {\r\n ICreatePaymentBody,\r\n ICreatePaymentDetailsBody,\r\n} from \"../services/models\";\r\n\r\nasync function renderCardPayment(\r\n element: HTMLDivElement,\r\n configuration: WonderPaymentConfiguration,\r\n response: SuccessResponse,\r\n handleError: (message: string) => void,\r\n handleSuccess: (message: string) => void\r\n) {\r\n element.innerHTML = `\r\n <label class=\"radio-bubble\">\r\n <input type=\"radio\" name=\"option\" value=\"card\">\r\n <span class=\"bubble-content\">\r\n <span class=\"circle\"></span>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M24 11H0V7H24V11Z\" fill=\"#002649\"/>\r\n <path opacity=\"0.4\" d=\"M21.3333 3C22.8042 3 24 4.19375 24 5.66667V7H0V5.66667C0 4.19375 1.19375 3 2.66667 3H21.3333ZM24 19C24 20.4708 22.8042 21.6667 21.3333 21.6667H2.66667C1.19375 21.6667 0 20.4708 0 19V11H24V19ZM4.66667 16.3333C4.3 16.3333 4 16.6333 4 17C4 17.3667 4.3 17.6667 4.66667 17.6667H7.33333C7.7 17.6667 8 17.3667 8 17C8 16.6333 7.7 16.3333 7.33333 16.3333H4.66667ZM10 17.6667H15.3333C15.7 17.6667 16 17.3667 16 17C16 16.6333 15.7 16.3333 15.3333 16.3333H10C9.63333 16.3333 9.33333 16.6333 9.33333 17C9.33333 17.3667 9.63333 17.6667 10 17.6667Z\" fill=\"#002649\"/>\r\n </svg>\r\n </svg>\r\n <span class=\"text\">Card payment</span>\r\n <span class=\"brands\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" id=\"brand_visa\" width=\"40\" height=\"26\" fill=\"none\" viewBox=\"0 0 40 26\"><path fill=\"#fff\" d=\"M0 0h40v26H0z\"/><path fill=\"#1434CB\" d=\"m15.9 7.7-4.43 10.6h-2.9l-2.2-8.47c-.13-.52-.25-.71-.65-.93C5.05 8.55 3.96 8.2 3 8l.07-.32h4.67c.6 0 1.13.4 1.27 1.09l1.15 6.14 2.86-7.23h2.89Zm11.39 7.15c0-2.8-3.88-2.96-3.85-4.21 0-.38.37-.79 1.16-.9a5.2 5.2 0 0 1 2.71.48l.48-2.25a7.4 7.4 0 0 0-2.57-.47c-2.71 0-4.62 1.44-4.64 3.51-.02 1.53 1.36 2.38 2.4 2.9 1.08.51 1.44.85 1.43 1.31 0 .71-.85 1.03-1.64 1.04-1.39.02-2.19-.37-2.82-.67l-.5 2.33c.64.29 1.82.55 3.05.56 2.89 0 4.78-1.42 4.79-3.63Zm7.17 3.46H37L34.78 7.7h-2.34c-.53 0-.98.3-1.17.78l-4.12 9.84h2.88l.57-1.58h3.53l.33 1.58Zm-3.07-3.76 1.45-3.99.83 4H31.4ZM19.83 7.7l-2.27 10.62h-2.74L17.09 7.7h2.74Z\"/></svg>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" id=\"brand_mc\" width=\"40\" height=\"26\" viewBox=\"0 0 40 26\"><path fill=\"#fff\" d=\"M0 0h40v26H0z\"/><path fill=\"#F06022\" d=\"M16.13 19.29h7.74V6.7h-7.74v12.58z\"/><path fill=\"#EA1D25\" d=\"M16.93 13A7.93 7.93 0 0 1 20 6.71a8.02 8.02 0 0 0-10.65.65 7.96 7.96 0 0 0 0 11.28 8.02 8.02 0 0 0 10.65.65A8.02 8.02 0 0 1 16.93 13\"/><path fill=\"#F79D1D\" d=\"M33 13c0 2.12-.84 4.15-2.34 5.65a8.1 8.1 0 0 1-10.66.64A8.05 8.05 0 0 0 23.07 13 7.96 7.96 0 0 0 20 6.71a8.02 8.02 0 0 1 10.66.64A7.93 7.93 0 0 1 33 13\"/></svg>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" id=\"brand_maestro\" width=\"40\" height=\"26\" fill=\"none\" viewBox=\"0 0 40 26\"><path fill=\"#fff\" d=\"M0 0h40v26H0z\"/><path fill=\"#7773B4\" d=\"M16.13 19.29h7.74V6.7h-7.74v12.58z\"/><path fill=\"#EA1D25\" d=\"M16.93 13A7.93 7.93 0 0 1 20 6.71a8.02 8.02 0 0 0-10.65.65 7.96 7.96 0 0 0 0 11.28 8.02 8.02 0 0 0 10.65.65A8.02 8.02 0 0 1 16.93 13\"/><path fill=\"#139FDA\" d=\"M33 13c0 2.12-.84 4.15-2.34 5.65a8.1 8.1 0 0 1-10.66.64A8.05 8.05 0 0 0 23.07 13 7.96 7.96 0 0 0 20 6.71a8.02 8.02 0 0 1 10.66.64A7.93 7.93 0 0 1 33 13\"/></svg></span>\r\n </span>\r\n <div class=\"expandable-content\">\r\n <div class=\"card\">\r\n <div class=\"card__wrapper\">\r\n <label class=\"card--label\">Card number</label>\r\n <span class=\"card__wrapper--input\" data-cse=\"encryptedCardNumber\"/>\r\n </div>\r\n\r\n <div class=\"card__field-wrapper\">\r\n <div>\r\n <div class=\"card__wrapper\">\r\n <label class=\"card--label\">Expired date</label>\r\n <span class=\"card__wrapper--input\" data-cse=\"encryptedExpiryDate\" />\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <div class=\"card__wrapper\">\r\n <label class=\"card--label\">Security code</label>\r\n <span class=\"card__wrapper--input\" data-cse=\"encryptedSecurityCode\" />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n ${\r\n response.enableStoreDetails === \"AskForConsent\" &&\r\n `<input type=\"checkbox\" id=\"save-checkbox\" class=\"save-checkbox\">\r\n <label for=\"save-checkbox\" class=\"save-checkbox--label\">Store payment information</label>`\r\n }\r\n\r\n <button id=\"card-submit-button\" class=\"card__submit-button\" disabled>${\r\n response.formattedAmount\r\n }</button>\r\n </div>\r\n </div>\r\n </label>`;\r\n\r\n // Initialize the external library with config and the selector\r\n const checkout = await AdyenCheckout({\r\n environment: configuration.environment === \"production\" ? \"live\" : \"test\",\r\n clientKey: response.clientKey,\r\n locale: response.locale,\r\n countryCode: \"IS\",\r\n paymentMethodsResponse: response.paymentMethods,\r\n onPaymentCompleted: configuration.onPaymentCompleted,\r\n onPaymentFailed: configuration.onPaymentFailed,\r\n onSubmit: handleSubmit,\r\n onAdditionalDetails: handleSubmitAdditionalData,\r\n });\r\n\r\n const payButton = document.getElementById(\r\n \"card-submit-button\"\r\n ) as HTMLButtonElement;\r\n\r\n const allBrands =\r\n response.paymentMethods.paymentMethods!.find((x) => x.type === \"scheme\")\r\n ?.brands || [];\r\n\r\n const customCard = new CustomCard(checkout, {\r\n onBrand: (event) => {\r\n if (event.brand === \"card\") {\r\n allBrands.forEach((brand) => {\r\n const brandElement = document.getElementById(\"brand_\" + brand);\r\n if (brandElement) {\r\n brandElement.style.opacity = \"1\";\r\n }\r\n });\r\n return;\r\n }\r\n\r\n allBrands\r\n .filter((brand) => brand !== event.brand)\r\n .forEach((brand) => {\r\n const brandElement = document.getElementById(\"brand_\" + brand);\r\n if (brandElement) {\r\n brandElement.style.opacity = \"0\";\r\n }\r\n });\r\n },\r\n onValidationError: (validationErrors) => {\r\n const elements = document.getElementsByClassName(\"error-message\");\r\n for (let i = elements.length - 1; i >= 0; i--) {\r\n elements[i].parentElement?.classList.remove(\"error\");\r\n elements[i].remove();\r\n }\r\n\r\n validationErrors.forEach((error) => {\r\n const inputElement = element.querySelector(\r\n `[data-cse=\"${error.fieldType}\"]`\r\n );\r\n if (inputElement && error.errorI18n) {\r\n inputElement.parentElement?.classList.add(\"error\");\r\n const errorMessage = document.createElement(\"span\");\r\n errorMessage.className = \"error-message\";\r\n errorMessage.textContent = error.errorI18n;\r\n inputElement.parentElement?.appendChild(errorMessage);\r\n } else if (inputElement) {\r\n inputElement.classList.remove(\"error\");\r\n }\r\n });\r\n },\r\n onAllValid: (event: CardAllValidData) => {\r\n if (payButton) {\r\n payButton.disabled = !event.allValid;\r\n }\r\n },\r\n placeholders: configuration.placeholders,\r\n challengeWindowSize: \"05\", // looks like not working\r\n }).mount(\"#card-container\");\r\n\r\n payButton.addEventListener(\"click\", () => {\r\n customCard!.submit(); // Calls onSubmit when form is valid\r\n });\r\n\r\n async function handleSubmit(\r\n state: SubmitData,\r\n _: UIElement,\r\n actions: SubmitActions\r\n ) {\r\n const data: ICreatePaymentBody = {\r\n ...state.data,\r\n origin: window.location.origin,\r\n storePaymentMethod: getStorePaymentMethod(),\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await createPaymentRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n // We will always get 200 OK unless there is an error in our server code.\r\n // Payment unsuccessful still returns 200 OK, but with resultCode Refused.\r\n if (!fetchResponse.ok) {\r\n actions.reject();\r\n const errorResponse = await fetchResponse.json();\r\n handleError(errorResponse.errorMessage);\r\n return;\r\n }\r\n\r\n const response = await fetchResponse.json();\r\n\r\n // ResultCode should always be either Authorised or Refused or IdentifyShopper. Never empty.\r\n if (!response.resultCode) {\r\n actions.reject();\r\n handleError(\"Payment unsuccessful\");\r\n return;\r\n }\r\n\r\n const { resultCode, action } = response;\r\n\r\n if (resultCode === \"RedirectShopper\" || resultCode === \"IdentifyShopper\") {\r\n document.getElementById(\"payment-container\")!.style.display = \"none\";\r\n\r\n checkout\r\n .createFromAction(action)\r\n .mount(document.getElementById(\"3ds-container\")!);\r\n return;\r\n }\r\n\r\n // If the /payments request from your server is successful, you must call this to resolve whichever of the listed objects are available.\r\n // You must call this, even if the result of the payment is unsuccessful.\r\n actions.resolve({ resultCode, action });\r\n\r\n if (resultCode === \"Authorised\") {\r\n handleSuccess(\"Payment successful\");\r\n } else {\r\n handleError(resultCode);\r\n }\r\n }\r\n\r\n async function handleSubmitAdditionalData(\r\n state: AdditionalDetailsData,\r\n _: UIElement,\r\n actions: AdditionalDetailsActions\r\n ) {\r\n const data: ICreatePaymentDetailsBody = {\r\n ...state.data,\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await createPaymentDetailsRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n // We will always get 200 OK unless there is an error in our server code.\r\n // Payment unsuccessful still returns 200 OK, but with resultCode Refused.\r\n if (!fetchResponse.ok) {\r\n actions.reject();\r\n const errorResponse = await fetchResponse.json();\r\n handleError(errorResponse.errorMessage);\r\n return;\r\n }\r\n\r\n const response = await fetchResponse.json();\r\n\r\n // ResultCode should always be either Authorised or Refused or IdentifyShopper. Never empty.\r\n if (!response.resultCode) {\r\n actions.reject();\r\n handleError(\"Payment unsuccessful\");\r\n return;\r\n }\r\n\r\n const { resultCode, action } = response;\r\n\r\n // If the /payments/details request from\r\n // You must call this, even if the result\r\n actions.resolve({ resultCode, action });\r\n\r\n if (resultCode === \"Authorised\") {\r\n handleSuccess(\"Payment successful\");\r\n } else {\r\n handleError(resultCode);\r\n }\r\n }\r\n\r\n function getStorePaymentMethod() {\r\n if (response.enableStoreDetails === \"AskForConsent\") {\r\n return (document.getElementById(\"save-checkbox\") as HTMLInputElement)\r\n ?.checked;\r\n }\r\n\r\n return response.enableStoreDetails === \"Enabled\";\r\n }\r\n\r\n return element;\r\n}\r\n\r\nexport default renderCardPayment;\r\n","const getEnv = (): Env => {\n return {\n DEVELOPMENT_BASE_URL: \"http://localhost:5012\",\n STAGING_BASE_URL: \"https://hosted-checkout.staging.straumur.is\",\n PRODUCTION_BASE_URL: \"\",\n\n GET_PAYMENT_METHODS_URL: \"wonder/payment-methods\",\n POST_PAYMENT_URL: \"wonder/payment\",\n POST_PAYMENT_DETAILS_URL: \"wonder/payment-details\",\n POST_DISABLE_TOKEN_URL: \"wonder/disable-token\",\n };\n};\n\ninterface Env {\n DEVELOPMENT_BASE_URL: string;\n STAGING_BASE_URL: string;\n PRODUCTION_BASE_URL: string;\n\n GET_PAYMENT_METHODS_URL: string;\n POST_PAYMENT_URL: string;\n POST_PAYMENT_DETAILS_URL: string;\n POST_DISABLE_TOKEN_URL: string;\n}\n\nexport const env = getEnv();\n","import { env } from \"../../env\";\r\nimport {\r\n ICreatePaymentBody,\r\n ICreatePaymentDetailsBody,\r\n IGetPaymentMethodsBody,\r\n IPostDisableTokenBody,\r\n} from \"./models\";\r\n\r\nfunction getBaseUrl(environment: string) {\r\n switch (environment) {\r\n case \"development\":\r\n return env.DEVELOPMENT_BASE_URL;\r\n case \"staging\":\r\n return env.STAGING_BASE_URL;\r\n case \"production\":\r\n return env.PRODUCTION_BASE_URL;\r\n default:\r\n throw new Error(`Unknown environment: ${environment}`);\r\n }\r\n}\r\n\r\nexport function getPaymentMethods(\r\n environment: string,\r\n body: IGetPaymentMethodsBody\r\n) {\r\n return fetch(`${getBaseUrl(environment)}/${env.GET_PAYMENT_METHODS_URL}`, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n}\r\n\r\nexport function createPaymentRequest(\r\n environment: string,\r\n body: ICreatePaymentBody\r\n) {\r\n return fetch(`${getBaseUrl(environment)}/${env.POST_PAYMENT_URL}`, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n}\r\n\r\nexport function createPaymentDetailsRequest(\r\n environment: string,\r\n body: ICreatePaymentDetailsBody\r\n) {\r\n return fetch(`${getBaseUrl(environment)}/${env.POST_PAYMENT_DETAILS_URL}`, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n}\r\n\r\nexport function postDisableTokenRequest(\r\n environment: string,\r\n body: IPostDisableTokenBody\r\n) {\r\n return fetch(`${getBaseUrl(environment)}/${env.POST_DISABLE_TOKEN_URL}`, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n}\r\n","import {\r\n AdditionalDetailsActions,\r\n AdditionalDetailsData,\r\n AdyenCheckout,\r\n CardAllValidData,\r\n CustomCard,\r\n SubmitActions,\r\n SubmitData,\r\n UIElement,\r\n} from \"@adyen/adyen-web\";\r\nimport { SuccessResponse, WonderPaymentConfiguration } from \"../models\";\r\nimport {\r\n createPaymentDetailsRequest,\r\n createPaymentRequest,\r\n postDisableTokenRequest,\r\n} from \"../services/adapter\";\r\nimport {\r\n ICreatePaymentBody,\r\n ICreatePaymentDetailsBody,\r\n IPostDisableTokenBody,\r\n} from \"../services/models\";\r\n\r\nasync function renderSavedCards(\r\n element: Element,\r\n configuration: WonderPaymentConfiguration,\r\n response: SuccessResponse,\r\n handleError: (message: string) => void,\r\n handleSuccess: (message: string) => void\r\n) {\r\n if (!response.paymentMethods?.storedPaymentMethods?.length) {\r\n return;\r\n }\r\n\r\n response.paymentMethods!.storedPaymentMethods!.forEach(\r\n (storedCard, index) => {\r\n element.innerHTML += `\r\n <label class=\"radio-bubble\" id=\"stored-card-${storedCard.id}\">\r\n <input type=\"radio\" name=\"option\" value=\"${index}\">\r\n <span class=\"bubble-content\">\r\n <span class=\"circle\"></span>\r\n ${renderBrandIcon(storedCard.brand!, storedCard.name)}\r\n <div class=\"card-number\">•••• ${storedCard.lastFour}</div>\r\n <button id=\"card-delete-${\r\n storedCard.id\r\n }\" class=\"stored-card__delete-button\">\r\n Delete\r\n </button>\r\n </span>\r\n <div class=\"expandable-content\">\r\n <div class=\"stored-card__wrapper\">\r\n <div class=\"card stored-card__wrapper--field\">\r\n <label class=\"card--label\">Expired date</label>\r\n <div class=\"card__wrapper\">\r\n <span class=\"card__wrapper--input stored-card__wrapper--field--value\">\r\n ${storedCard.expiryMonth}/${storedCard.expiryYear}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card stored-card__wrapper--field\">\r\n <div class=\"card__wrapper\">\r\n <span class=\"card__wrapper--input\" data-cse=\"encryptedSecurityCode\" />\r\n <label class=\"card--label\">Security code</label>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <button id=\"card-submit-${\r\n storedCard.id\r\n }\"class=\"card__submit-button\" disabled>\r\n Pay ${response.formattedAmount}\r\n </button>\r\n </div>\r\n </label>`;\r\n }\r\n );\r\n\r\n response.paymentMethods!.storedPaymentMethods!.forEach(async (storedCard) => {\r\n const storedCardElement = element.querySelector<HTMLDivElement>(\r\n `#stored-card-${storedCard.id}`\r\n )!;\r\n\r\n const deleteButtonElement: HTMLButtonElement =\r\n storedCardElement.querySelector(`#card-delete-${storedCard.id}`)!;\r\n\r\n deleteButtonElement!.addEventListener(\"click\", async function (e) {\r\n e.stopPropagation();\r\n if (confirm(\"Are you sure you want to remove this card?\")) {\r\n const data: IPostDisableTokenBody = {\r\n storedPaymentMethodId: storedCard.id,\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await postDisableTokenRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n if (!fetchResponse.ok) {\r\n alert(\"Error removing card\");\r\n return;\r\n }\r\n\r\n const disableTokenResponse = await fetchResponse.json();\r\n\r\n if (!disableTokenResponse.success) {\r\n alert(\"Card was not removed!\");\r\n return;\r\n }\r\n\r\n storedCardElement.remove();\r\n\r\n if (\r\n !response.paymentMethods?.storedPaymentMethods!.filter(\r\n (x) => x.id !== storedCard.id\r\n ).length\r\n ) {\r\n element.innerHTML = \"\";\r\n }\r\n\r\n response.paymentMethods!.storedPaymentMethods =\r\n response.paymentMethods!.storedPaymentMethods!.filter(\r\n (x) => x.id !== storedCard.id\r\n );\r\n }\r\n });\r\n\r\n // Initialize the external library with config and the selector\r\n const checkout = await AdyenCheckout({\r\n environment: configuration.environment === \"production\" ? \"live\" : \"test\",\r\n clientKey: response.clientKey,\r\n locale: response.locale,\r\n countryCode: \"IS\",\r\n paymentMethodsResponse: response.paymentMethods,\r\n onPaymentCompleted: configuration.onPaymentCompleted,\r\n onPaymentFailed: configuration.onPaymentFailed,\r\n onSubmit: handleSubmit,\r\n onAdditionalDetails: handleSubmitAdditionalData,\r\n });\r\n\r\n const payButtonElement: HTMLButtonElement = storedCardElement.querySelector(\r\n `#card-submit-${storedCard.id}`\r\n )!;\r\n\r\n const customCard = new CustomCard(checkout, {\r\n brands: [storedCard.brand!],\r\n maskSecurityCode: true,\r\n onValidationError: (validationErrors) => {\r\n console.log(\"Validation errors\", validationErrors);\r\n const elements =\r\n storedCardElement.getElementsByClassName(\"error-message\");\r\n for (let i = elements.length - 1; i >= 0; i--) {\r\n elements[i].parentElement?.classList.remove(\"error\");\r\n elements[i].remove();\r\n }\r\n\r\n validationErrors.forEach((error) => {\r\n const inputElement = storedCardElement.querySelector(\r\n `[data-cse=\"${error.fieldType}\"]`\r\n );\r\n if (inputElement && error.errorI18n) {\r\n inputElement.parentElement?.classList.add(\"error\");\r\n const errorMessage = document.createElement(\"span\");\r\n errorMessage.className = \"error-message\";\r\n errorMessage.textContent = error.errorI18n;\r\n inputElement.parentElement?.appendChild(errorMessage);\r\n } else if (inputElement) {\r\n inputElement.classList.remove(\"error\");\r\n }\r\n });\r\n },\r\n onAllValid: (event: CardAllValidData) => {\r\n if (payButtonElement) {\r\n payButtonElement.disabled = !event.allValid;\r\n }\r\n },\r\n placeholders: configuration.placeholders,\r\n }).mount(`#stored-card-${storedCard.id}`);\r\n\r\n payButtonElement.addEventListener(\"click\", () => {\r\n customCard!.submit(); // Calls onSubmit when form is valid\r\n });\r\n\r\n async function handleSubmit(\r\n state: SubmitData,\r\n _: UIElement,\r\n actions: SubmitActions\r\n ) {\r\n const data: ICreatePaymentBody = {\r\n ...state.data,\r\n paymentMethod: {\r\n ...state.data.paymentMethod,\r\n storedPaymentMethodId: storedCard.id,\r\n },\r\n origin: window.location.origin,\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await createPaymentRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n // We will always get 200 OK unless there is an error in our server code.\r\n // Payment unsuccessful still returns 200 OK, but with resultCode Refused.\r\n if (!fetchResponse.ok) {\r\n actions.reject();\r\n const errorResponse = await fetchResponse.json();\r\n handleError(errorResponse.errorMessage);\r\n return;\r\n }\r\n\r\n const response = await fetchResponse.json();\r\n\r\n // ResultCode should always be either Authorised or Refused or IdentifyShopper. Never empty.\r\n if (!response.resultCode) {\r\n actions.reject();\r\n handleError(\"Payment unsuccessful\");\r\n return;\r\n }\r\n\r\n const { resultCode, action } = response;\r\n\r\n if (\r\n resultCode === \"RedirectShopper\" ||\r\n resultCode === \"IdentifyShopper\"\r\n ) {\r\n document.getElementById(\"payment-container\")!.style.display = \"none\";\r\n\r\n checkout\r\n .createFromAction(action)\r\n .mount(document.getElementById(\"3ds-container\")!);\r\n return;\r\n }\r\n\r\n // If the /payments request from your server is successful, you must call this to resolve whichever of the listed objects are available.\r\n // You must call this, even if the result of the payment is unsuccessful.\r\n actions.resolve({ resultCode, action });\r\n\r\n if (resultCode === \"Authorised\") {\r\n handleSuccess(\"Payment successful\");\r\n } else {\r\n handleError(resultCode);\r\n }\r\n }\r\n\r\n async function handleSubmitAdditionalData(\r\n state: AdditionalDetailsData,\r\n _: UIElement,\r\n actions: AdditionalDetailsActions\r\n ) {\r\n const data: ICreatePaymentDetailsBody = {\r\n ...state.data,\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await createPaymentDetailsRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n // We will always get 200 OK unless there is an error in our server code.\r\n // Payment unsuccessful still returns 200 OK, but with resultCode Refused.\r\n if (!fetchResponse.ok) {\r\n actions.reject();\r\n const errorResponse = await fetchResponse.json();\r\n handleError(errorResponse.errorMessage);\r\n return;\r\n }\r\n\r\n const response = await fetchResponse.json();\r\n\r\n // ResultCode should always be either Authorised or Refused or IdentifyShopper. Never empty.\r\n if (!response.resultCode) {\r\n actions.reject();\r\n handleError(\"Payment unsuccessful\");\r\n return;\r\n }\r\n\r\n const { resultCode, action } = response;\r\n\r\n // If the /payments/details request from\r\n // You must call this, even if the result\r\n actions.resolve({ resultCode, action });\r\n\r\n if (resultCode === \"Authorised\") {\r\n handleSuccess(\"Payment successful\");\r\n } else {\r\n handleError(resultCode);\r\n }\r\n }\r\n });\r\n}\r\n\r\nexport default renderSavedCards;\r\n\r\nfunction renderBrandIcon(brand: string, brandFullName: string) {\r\n if (brand === \"visa\") {\r\n return '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24px\" height=\"24px\" viewBox=\"0 -140 780 780\" enable-background=\"new 0 0 780 500\" version=\"1.1\" xml:space=\"preserve\"><rect width=\"780\" height=\"500\" fill=\"#0E4595\"/><path d=\"m293.2 348.73l33.361-195.76h53.36l-33.385 195.76h-53.336zm246.11-191.54c-10.57-3.966-27.137-8.222-47.822-8.222-52.725 0-89.865 26.55-90.18 64.603-0.299 28.13 26.514 43.822 46.752 53.186 20.771 9.595 27.752 15.714 27.654 24.283-0.131 13.121-16.586 19.116-31.922 19.116-21.357 0-32.703-2.967-50.227-10.276l-6.876-3.11-7.489 43.823c12.463 5.464 35.51 10.198 59.438 10.443 56.09 0 92.5-26.246 92.916-66.882 0.199-22.269-14.016-39.216-44.801-53.188-18.65-9.055-30.072-15.099-29.951-24.268 0-8.137 9.668-16.839 30.557-16.839 17.449-0.27 30.09 3.535 39.938 7.5l4.781 2.26 7.232-42.429m137.31-4.223h-41.232c-12.773 0-22.332 3.487-27.941 16.234l-79.244 179.4h56.031s9.16-24.123 11.232-29.418c6.125 0 60.555 0.084 68.338 0.084 1.596 6.853 6.49 29.334 6.49 29.334h49.514l-43.188-195.64zm-65.418 126.41c4.412-11.279 21.26-54.723 21.26-54.723-0.316 0.522 4.379-11.334 7.074-18.684l3.605 16.879s10.219 46.729 12.354 56.528h-44.293zm-363.3-126.41l-52.24 133.5-5.567-27.13c-9.725-31.273-40.025-65.155-73.898-82.118l47.766 171.2 56.456-0.064 84.004-195.39h-56.521\" fill=\"#ffffff\"/><path d=\"m146.92 152.96h-86.041l-0.681 4.073c66.938 16.204 111.23 55.363 129.62 102.41l-18.71-89.96c-3.23-12.395-12.597-16.094-24.186-16.527\" fill=\"#F2AE14\"/></svg>';\r\n }\r\n\r\n if (brand === \"mc\") {\r\n return '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"26\" viewBox=\"0 0 40 26\"><path fill=\"#fff\" d=\"M0 0h40v26H0z\"/><path fill=\"#F06022\" d=\"M16.13 19.29h7.74V6.7h-7.74v12.58z\"/><path fill=\"#EA1D25\" d=\"M16.93 13A7.93 7.93 0 0 1 20 6.71a8.02 8.02 0 0 0-10.65.65 7.96 7.96 0 0 0 0 11.28 8.02 8.02 0 0 0 10.65.65A8.02 8.02 0 0 1 16.93 13\"/><path fill=\"#F79D1D\" d=\"M33 13c0 2.12-.84 4.15-2.34 5.65a8.1 8.1 0 0 1-10.66.64A8.05 8.05 0 0 0 23.07 13 7.96 7.96 0 0 0 20 6.71a8.02 8.02 0 0 1 10.66.64A7.93 7.93 0 0 1 33 13\"/></svg>';\r\n }\r\n\r\n return brandFullName;\r\n}\r\n","import {\r\n AdditionalDetailsActions,\r\n AdditionalDetailsData,\r\n AdyenCheckout,\r\n GooglePay,\r\n GooglePayConfiguration,\r\n SubmitActions,\r\n SubmitData,\r\n UIElement,\r\n} from \"@adyen/adyen-web\";\r\nimport { SuccessResponse, WonderPaymentConfiguration } from \"../models\";\r\nimport {\r\n createPaymentDetailsRequest,\r\n createPaymentRequest,\r\n} from \"../services/adapter\";\r\nimport {\r\n ICreatePaymentBody,\r\n ICreatePaymentDetailsBody,\r\n} from \"../services/models\";\r\n\r\nasync function renderGooglePay(\r\n element: Element,\r\n configuration: WonderPaymentConfiguration,\r\n response: SuccessResponse,\r\n handleError: (message: string) => void,\r\n handleSuccess: (message: string) => void\r\n) {\r\n const hasGooglePay = response.paymentMethods!.paymentMethods?.some(\r\n (x) => x.type === \"googlepay\"\r\n );\r\n\r\n if (hasGooglePay) {\r\n element.innerHTML = `<label class=\"radio-bubble\">\r\n <input type=\"radio\" name=\"option\" value=\"google-pay\">\r\n <span class=\"bubble-content\">\r\n <span class=\"circle\"></span>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"26\" fill=\"none\" viewBox=\"0 0 40 26\"><path fill=\"#fff\" d=\"M29.13 2.41H10.87C5.17 2.41.5 7.18.5 13.01a10.5 10.5 0 0 0 10.37 10.58h18.26c5.7 0 10.37-4.76 10.37-10.59 0-5.82-4.67-10.59-10.37-10.59Z\"/><path fill=\"#3C4043\" d=\"M29.13 3.27c1.28 0 2.52.26 3.7.77a9.6 9.6 0 0 1 5.08 5.19 9.78 9.78 0 0 1 0 7.55 9.83 9.83 0 0 1-5.08 5.18 9.26 9.26 0 0 1-3.7.77H10.87a9.24 9.24 0 0 1-3.7-.77 9.6 9.6 0 0 1-5.08-5.18 9.78 9.78 0 0 1 0-7.55 9.83 9.83 0 0 1 5.08-5.19 9.24 9.24 0 0 1 3.7-.77h18.26Zm0-.86H10.87C5.17 2.41.5 7.18.5 13.01a10.5 10.5 0 0 0 10.37 10.58h18.26c5.7 0 10.37-4.76 10.37-10.59 0-5.82-4.67-10.59-10.37-10.59Z\"/><path fill=\"#3C4043\" d=\"M19.1 13.75v3.2h-1v-7.9h2.64c.67 0 1.24.23 1.7.68.49.46.72 1.01.72 1.67a2.2 2.2 0 0 1-.71 1.68c-.46.45-1.03.67-1.7.67H19.1Zm0-3.73v2.76h1.66c.4 0 .73-.14.99-.4.26-.28.4-.6.4-.98 0-.36-.14-.68-.4-.95a1.28 1.28 0 0 0-.99-.42H19.1Zm6.67 1.35c.73 0 1.31.2 1.74.6.42.4.64.95.64 1.65v3.34h-.95v-.76h-.04a1.9 1.9 0 0 1-1.65.93 2.1 2.1 0 0 1-1.46-.53c-.4-.35-.6-.8-.6-1.32 0-.56.21-1 .63-1.34.41-.33.97-.5 1.66-.5.59 0 1.07.12 1.45.34v-.23c0-.36-.13-.65-.4-.9a1.4 1.4 0 0 0-.97-.37c-.56 0-1 .24-1.32.72l-.88-.56a2.42 2.42 0 0 1 2.15-1.07Zm-1.29 3.92c0 .27.11.5.33.67.22.17.48.26.78.26.42 0 .79-.16 1.12-.48.32-.31.49-.68.49-1.11a2.02 2.02 0 0 0-1.3-.38c-.4 0-.74.1-1.01.3a.9.9 0 0 0-.4.74Zm9.08-3.75-3.32 7.8h-1.02l1.23-2.73-2.19-5.07h1.09l1.57 3.89h.02l1.54-3.89h1.08Z\"/><path fill=\"#4285F4\" d=\"M15.14 13.1c0-.32-.03-.64-.09-.95h-4.17v1.75h2.4a2.1 2.1 0 0 1-.89 1.4v1.14h1.43a4.49 4.49 0 0 0 1.32-3.33Z\"/><path fill=\"#34A853\" d=\"M12.4 15.3a2.66 2.66 0 0 1-4-1.44H6.9v1.18a4.43 4.43 0 0 0 6.91 1.4l-1.43-1.13Z\"/><path fill=\"#FABB05\" d=\"M8.25 13c0-.3.05-.59.14-.86v-1.17H6.9a4.59 4.59 0 0 0 0 4.07l1.48-1.17a2.79 2.79 0 0 1-.14-.86Z\"/><path fill=\"#E94235\" d=\"M10.88 10.27c.66 0 1.24.23 1.7.68l1.27-1.3a4.22 4.22 0 0 0-2.97-1.18 4.44 4.44 0 0 0-3.97 2.5l1.48 1.17a2.66 2.66 0 0 1 2.5-1.87Z\"/></svg>\r\n <span class=\"text\">Google Pay</span>\r\n </span>\r\n <div class=\"expandable-content\">\r\n <div id=\"google-pay-button\"></div>\r\n </div>\r\n </label>`;\r\n\r\n // Initialize the external library with config and the selector\r\n const checkout = await AdyenCheckout({\r\n environment: configuration.environment === \"production\" ? \"live\" : \"test\",\r\n clientKey: response.clientKey,\r\n locale: response.locale,\r\n countryCode: \"IS\",\r\n paymentMethodsResponse: response.paymentMethods,\r\n onPaymentCompleted: configuration.onPaymentCompleted,\r\n onPaymentFailed: configuration.onPaymentFailed,\r\n onSubmit: handleSubmit,\r\n onAdditionalDetails: handleSubmitAdditionalData,\r\n });\r\n\r\n const gpayConfig = response.paymentMethods.paymentMethods!.find(\r\n (x) => x.type === \"googlepay\"\r\n )!.configuration! as { gatewayMerchantId: string; merchantId: string };\r\n\r\n const googlePayConfiguration: GooglePayConfiguration = {\r\n amount: {\r\n value: response.minorUnitsAmount,\r\n currency: response.currency,\r\n },\r\n countryCode: \"IS\",\r\n environment: configuration.environment,\r\n configuration: { ...gpayConfig, merchantName: response.merchantName },\r\n };\r\n\r\n const googlePay = new GooglePay(checkout, googlePayConfiguration);\r\n\r\n googlePay\r\n .isAvailable()\r\n .then(() => {\r\n googlePay.mount(\"#google-pay-button\");\r\n })\r\n .catch((e) => {\r\n //Google Pay is not available\r\n console.error(\"Google Pay is not available\", e);\r\n });\r\n\r\n async function handleSubmit(\r\n state: SubmitData,\r\n _: UIElement,\r\n actions: SubmitActions\r\n ) {\r\n const data: ICreatePaymentBody = {\r\n ...state.data,\r\n origin: window.location.origin,\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await createPaymentRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n // We will always get 200 OK unless there is an error in our server code.\r\n // Payment unsuccessful still returns 200 OK, but with resultCode Refused.\r\n if (!fetchResponse.ok) {\r\n actions.reject();\r\n const errorResponse = await fetchResponse.json();\r\n handleError(errorResponse.errorMessage);\r\n return;\r\n }\r\n\r\n const response = await fetchResponse.json();\r\n\r\n // ResultCode should always be either Authorised or Refused or IdentifyShopper. Never empty.\r\n if (!response.resultCode) {\r\n actions.reject();\r\n handleError(\"Payment unsuccessful\");\r\n return;\r\n }\r\n\r\n const { resultCode, action } = response;\r\n\r\n if (\r\n resultCode === \"RedirectShopper\" ||\r\n resultCode === \"IdentifyShopper\"\r\n ) {\r\n checkout\r\n .createFromAction(action)\r\n .mount(document.getElementById(\"3ds-container\")!);\r\n return;\r\n }\r\n\r\n // If the /payments request from your server is successful, you must call this to resolve whichever of the listed objects are available.\r\n // You must call this, even if the result of the payment is unsuccessful.\r\n actions.resolve({ resultCode, action });\r\n\r\n if (resultCode === \"Authorised\") {\r\n handleSuccess(\"Payment successful\");\r\n } else {\r\n handleError(resultCode);\r\n }\r\n }\r\n\r\n async function handleSubmitAdditionalData(\r\n state: AdditionalDetailsData,\r\n _: UIElement,\r\n actions: AdditionalDetailsActions\r\n ) {\r\n const data: ICreatePaymentDetailsBody = {\r\n ...state.data,\r\n payfacData: configuration.payfacData,\r\n };\r\n\r\n const fetchResponse = await createPaymentDetailsRequest(\r\n configuration.environment,\r\n data\r\n );\r\n\r\n // We will always get 200 OK unless there is an error in our server code.\r\n // Payment unsuccessful still returns 200 OK, but with resultCode Refused.\r\n if (!fetchResponse.ok) {\r\n actions.reject();\r\n const errorResponse = await fetchResponse.json();\r\n handleError(errorResponse.errorMessage);\r\n return;\r\n }\r\n\r\n const response = await fetchResponse.json();\r\n\r\n // ResultCode should always be either Authorised or Refused or IdentifyShopper. Never empty.\r\n if (!response.resultCode) {\r\n actions.reject();\r\n handleError(\"Payment unsuccessful\");\r\n return;\r\n }\r\n\r\n const { resultCode, action } = response;\r\n\r\n // If the /payments/details request from\r\n // You must call this, even if the result\r\n actions.resolve({ resultCode, action });\r\n\r\n if (resultCode === \"Authorised\") {\r\n handleSuccess(\"Payment successful\");\r\n } else {\r\n handleError(resultCode);\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport default renderGooglePay;\r\n"],"mappings":"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