From be955bdd83ae26d1fedca6e2ecbb03a67b4d70f4 Mon Sep 17 00:00:00 2001 From: "a.kornienko" Date: Thu, 13 Jul 2023 07:57:39 +0300 Subject: [PATCH] feat(PAYMENTS-14328): add legal component --- package-lock.json | 264 ++++++++++++++++-- package.json | 3 +- src/assets/icons/logo.svg | 8 + src/assets/images.d.ts | 1 + src/core/event-name.enum.ts | 3 + .../legal-config-event-message.guard.ts | 16 ++ .../web-component-tag-name.enum.ts | 1 + src/core/web-components/web-components.map.ts | 2 + ...get-legal-component-config.handler.spec.ts | 22 ++ .../get-legal-component-config.handler.ts | 21 ++ .../legal/handlers/legal-ping-handler.ts | 15 + .../legal/handlers/legal-pong.handler.ts | 14 + .../legal/legal-component.config.interface.ts | 10 + .../legal/legal.component.tempate.ts | 78 ++++++ .../web-components/legal/legal.component.ts | 87 ++++++ .../secure-connection.component.template.ts | 36 +++ src/translations/en.json | 8 +- src/web-components.ts | 8 +- webpack.config.js | 5 + 19 files changed, 568 insertions(+), 34 deletions(-) create mode 100644 src/assets/icons/logo.svg create mode 100644 src/assets/images.d.ts create mode 100644 src/core/guards/legal-config-event-message.guard.ts create mode 100644 src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.spec.ts create mode 100644 src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.ts create mode 100644 src/features/headless-checkout/web-components/legal/handlers/legal-ping-handler.ts create mode 100644 src/features/headless-checkout/web-components/legal/handlers/legal-pong.handler.ts create mode 100644 src/features/headless-checkout/web-components/legal/legal-component.config.interface.ts create mode 100644 src/features/headless-checkout/web-components/legal/legal.component.tempate.ts create mode 100644 src/features/headless-checkout/web-components/legal/legal.component.ts create mode 100644 src/features/headless-checkout/web-components/legal/secure-connection.component.template.ts diff --git a/package-lock.json b/package-lock.json index e267842..7b4e922 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "stylelint-config-prettier-scss": "^1.0.0", "stylelint-config-standard-scss": "^9.0.0", "stylelint-order": "^6.0.3", + "svgo-loader": "^4.0.0", "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.82.1", @@ -78,9 +79,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", - "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -153,16 +154,16 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", - "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.5", + "@babel/compat-data": "^7.22.9", "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.3", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -181,9 +182,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -273,9 +274,9 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { "@babel/types": "^7.22.5" @@ -1135,6 +1136,15 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", "dev": true }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -2152,6 +2162,12 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2263,9 +2279,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", "dev": true, "funding": [ { @@ -2275,13 +2291,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -2399,9 +2419,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001488", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz", - "integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==", + "version": "1.0.30001515", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz", + "integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==", "dev": true, "funding": [ { @@ -3015,6 +3035,22 @@ "webpack": "^5.0.0" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -3028,6 +3064,18 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3040,6 +3088,39 @@ "node": ">=4" } }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -3246,6 +3327,20 @@ "void-elements": "^2.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, "node_modules/domain-browser": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", @@ -3258,6 +3353,47 @@ "url": "https://bevry.me/fund" } }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -3283,9 +3419,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.397", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.397.tgz", - "integrity": "sha512-jwnPxhh350Q/aMatQia31KAIQdhEsYS0fFZ0BQQlN9tfvOEwShu6ZNwI4kL/xBabjcB/nTy6lSt17kNIluJZ8Q==", + "version": "1.4.457", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.457.tgz", + "integrity": "sha512-/g3UyNDmDd6ebeWapmAoiyy+Sy2HyJ+/X8KyvNeHfKRFfHaA2W8oF5fxD5F3tjBDcjpwo0iek6YNgxNXDBoEtA==", "dev": true }, "node_modules/elliptic": { @@ -3382,6 +3518,18 @@ "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -6912,9 +7060,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/normalize-package-data": { @@ -6953,6 +7101,18 @@ "node": ">=8" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -9011,6 +9171,48 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, + "node_modules/svgo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/svgo-loader/-/svgo-loader-4.0.0.tgz", + "integrity": "sha512-bdk2H73AHP8Vo9zgMuA8piEzi5pjFzllK4EwfebDF3hDjmHQpmmqXMoDd6abDtVFrlKTJuveepmnc2kuTdt/WA==", + "dev": true, + "dependencies": { + "svgo": "^3.0.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/table": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", diff --git a/package.json b/package.json index b058c15..4060097 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "devDependencies": { "@commitlint/cli": "^17.6.5", "@commitlint/config-conventional": "^17.6.5", - "@types/jasmine": "^4.3.2", "@types/i18next": "^13.0.0", + "@types/jasmine": "^4.3.2", "@types/prettier": "^2.7.2", "@typescript-eslint/eslint-plugin": "^5.59.6", "@typescript-eslint/parser": "^5.59.6", @@ -56,6 +56,7 @@ "stylelint-config-prettier-scss": "^1.0.0", "stylelint-config-standard-scss": "^9.0.0", "stylelint-order": "^6.0.3", + "svgo-loader": "^4.0.0", "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.82.1", diff --git a/src/assets/icons/logo.svg b/src/assets/icons/logo.svg new file mode 100644 index 0000000..5cedc5c --- /dev/null +++ b/src/assets/icons/logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/images.d.ts b/src/assets/images.d.ts new file mode 100644 index 0000000..bff9471 --- /dev/null +++ b/src/assets/images.d.ts @@ -0,0 +1 @@ +declare module '*.svg'; diff --git a/src/core/event-name.enum.ts b/src/core/event-name.enum.ts index b36ea09..e11322e 100644 --- a/src/core/event-name.enum.ts +++ b/src/core/event-name.enum.ts @@ -6,4 +6,7 @@ export const enum EventName { getSavedMethods = 'getSavedMethods', getUserBalance = 'getUserBalance', submitButton = 'submitButton', + getLegalComponentConfig = 'getLegalComponentConfig', + legalComponentPing = 'legalComponentPing', + legalComponentPong = 'legalComponentPong', } diff --git a/src/core/guards/legal-config-event-message.guard.ts b/src/core/guards/legal-config-event-message.guard.ts new file mode 100644 index 0000000..0cc81f9 --- /dev/null +++ b/src/core/guards/legal-config-event-message.guard.ts @@ -0,0 +1,16 @@ +import { Message } from '../../core/message.interface'; +import { isEventMessage } from './event-message.guard'; +import { EventName } from '../../core/event-name.enum'; +import { LegalComponentConfig } from '../../features/headless-checkout/web-components/legal/legal-component.config.interface'; + +export const isLegalConfigEventMessage = ( + messageData: unknown +): messageData is Message<{ config: LegalComponentConfig }> => { + if (isEventMessage(messageData)) { + return ( + messageData.name === EventName.getLegalComponentConfig && + (messageData.data as { [key: string]: unknown })?.config !== undefined + ); + } + return false; +}; diff --git a/src/core/web-components/web-component-tag-name.enum.ts b/src/core/web-components/web-component-tag-name.enum.ts index 82ceda5..7234557 100644 --- a/src/core/web-components/web-component-tag-name.enum.ts +++ b/src/core/web-components/web-component-tag-name.enum.ts @@ -2,4 +2,5 @@ export enum WebComponentTagName { CardNumberComponent = 'psdk-card-number', SubmitButtonComponent = 'psdk-submit-button', PaymentMethodsComponent = 'psdk-payment-methods', + LegalComponent = 'psdk-legal', } diff --git a/src/core/web-components/web-components.map.ts b/src/core/web-components/web-components.map.ts index 21bb4a0..62cc671 100644 --- a/src/core/web-components/web-components.map.ts +++ b/src/core/web-components/web-components.map.ts @@ -2,6 +2,7 @@ import { CardNumberComponent } from '../../features/headless-checkout/web-compon import { SubmitButtonComponent } from '../../features/headless-checkout/web-components/submit-button/submit-button.component'; import { WebComponentTagName } from './web-component-tag-name.enum'; import { PaymentMethodsComponent } from '../../features/headless-checkout/web-components/payment-methods/payment-methods.component'; +import { LegalComponent } from '../../features/headless-checkout/web-components/legal/legal.component'; export const webComponents: { [key in WebComponentTagName]: CustomElementConstructor; @@ -9,4 +10,5 @@ export const webComponents: { [WebComponentTagName.CardNumberComponent]: CardNumberComponent, [WebComponentTagName.SubmitButtonComponent]: SubmitButtonComponent, [WebComponentTagName.PaymentMethodsComponent]: PaymentMethodsComponent, + [WebComponentTagName.LegalComponent]: LegalComponent, }; diff --git a/src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.spec.ts b/src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.spec.ts new file mode 100644 index 0000000..b463256 --- /dev/null +++ b/src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.spec.ts @@ -0,0 +1,22 @@ +import { EventName } from '../../../core/event-name.enum'; +import { Message } from '../../../core/message.interface'; +import { getLegalComponentConfigHandler } from './get-legal-component-config.handler'; +import { LegalComponentConfig } from '../web-components/legal/legal-component.config.interface'; + +const mockMessage: Message<{ config: LegalComponentConfig }> = { + name: EventName.getLegalComponentConfig, + data: { config: {} as unknown as LegalComponentConfig }, +}; +describe('getLegalComponentConfigHandler', () => { + it('Should handle data', () => { + expect(getLegalComponentConfigHandler(mockMessage)).toEqual({ + isHandled: true, + value: {} as unknown as LegalComponentConfig, + }); + }); + it('Should return null', () => { + expect( + getLegalComponentConfigHandler({ name: EventName.initPayment }) + ).toBeNull(); + }); +}); diff --git a/src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.ts b/src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.ts new file mode 100644 index 0000000..6e92c96 --- /dev/null +++ b/src/features/headless-checkout/post-messages-handlers/get-legal-component-config.handler.ts @@ -0,0 +1,21 @@ +import { Handler } from '../../../core/post-messages-client/handler.type'; +import { Message } from '../../../core/message.interface'; +import { EventName } from '../../../core/event-name.enum'; +import { LegalComponentConfig } from '../web-components/legal/legal-component.config.interface'; +import { isLegalConfigEventMessage } from '../../../core/guards/legal-config-event-message.guard'; + +export const getLegalComponentConfigHandler: Handler = ( + message: Message +): { isHandled: boolean; value: LegalComponentConfig } | null => { + if ( + isLegalConfigEventMessage(message) && + message.name === EventName.getLegalComponentConfig + ) { + const config = message.data?.config; + return { + isHandled: true, + value: config!, + }; + } + return null; +}; diff --git a/src/features/headless-checkout/web-components/legal/handlers/legal-ping-handler.ts b/src/features/headless-checkout/web-components/legal/handlers/legal-ping-handler.ts new file mode 100644 index 0000000..b917a47 --- /dev/null +++ b/src/features/headless-checkout/web-components/legal/handlers/legal-ping-handler.ts @@ -0,0 +1,15 @@ +import { Handler } from '../../../../../core/post-messages-client/handler.type'; +import { Message } from '../../../../../core/message.interface'; +import { EventName } from '../../../../../core/event-name.enum'; + +export const legalPingHandler: Handler = ( + message: Message +): { isHandled: boolean } | null => { + console.log(message); + if (message.name === EventName.legalComponentPing) { + return { + isHandled: true, + }; + } + return null; +}; diff --git a/src/features/headless-checkout/web-components/legal/handlers/legal-pong.handler.ts b/src/features/headless-checkout/web-components/legal/handlers/legal-pong.handler.ts new file mode 100644 index 0000000..1c73f6f --- /dev/null +++ b/src/features/headless-checkout/web-components/legal/handlers/legal-pong.handler.ts @@ -0,0 +1,14 @@ +import { Handler } from '../../../../../core/post-messages-client/handler.type'; +import { Message } from '../../../../../core/message.interface'; +import { EventName } from '../../../../../core/event-name.enum'; + +export const legalPongHandler: Handler = ( + message: Message +): { isHandled: boolean } | null => { + if (message.name === EventName.legalComponentPong) { + return { + isHandled: true, + }; + } + return null; +}; diff --git a/src/features/headless-checkout/web-components/legal/legal-component.config.interface.ts b/src/features/headless-checkout/web-components/legal/legal-component.config.interface.ts new file mode 100644 index 0000000..730c295 --- /dev/null +++ b/src/features/headless-checkout/web-components/legal/legal-component.config.interface.ts @@ -0,0 +1,10 @@ +export interface LegalComponentConfig { + isJapanUser: boolean; + refundPolicyUrl: string; + sctlPolicyUrl?: string; + secureConnection: { + secureConnectionUrl?: string; + isWhiteLabel?: boolean; + }; + disclaimer?: string; +} diff --git a/src/features/headless-checkout/web-components/legal/legal.component.tempate.ts b/src/features/headless-checkout/web-components/legal/legal.component.tempate.ts new file mode 100644 index 0000000..c299701 --- /dev/null +++ b/src/features/headless-checkout/web-components/legal/legal.component.tempate.ts @@ -0,0 +1,78 @@ +import { LegalComponentConfig } from './legal-component.config.interface'; +import { getSecureConnectionTemplate } from './secure-connection.component.template'; +import i18next from 'i18next'; + +export const getLegalComponentTemplate = ( + config: LegalComponentConfig +): string => { + const { + isJapanUser, + refundPolicyUrl, + sctlPolicyUrl, + secureConnection, + disclaimer, + } = config; + return ` + ${ + disclaimer + ? ` +
+ ${disclaimer} +
` + : '' + } + ${getSecureConnectionTemplate(secureConnection)} + `; +}; diff --git a/src/features/headless-checkout/web-components/legal/legal.component.ts b/src/features/headless-checkout/web-components/legal/legal.component.ts new file mode 100644 index 0000000..96d6bc7 --- /dev/null +++ b/src/features/headless-checkout/web-components/legal/legal.component.ts @@ -0,0 +1,87 @@ +import { WebComponentAbstract } from '../../../../core/web-components/web-component.abstract'; +import { container } from 'tsyringe'; +import { PostMessagesClient } from '../../../../core/post-messages-client/post-messages-client'; +import { legalPingHandler } from './handlers/legal-ping-handler'; +import { EventName } from '../../../../core/event-name.enum'; +import { HeadlessCheckout } from '../../headless-checkout'; +import { legalPongHandler } from './handlers/legal-pong.handler'; +import { getLegalComponentTemplate } from './legal.component.tempate'; +import { Message } from '../../../../core/message.interface'; +import { HeadlessCheckoutSpy } from '../../../../core/headless-checkout-spy/headless-checkout-spy'; +import { getLegalComponentConfigHandler } from '../../post-messages-handlers/get-legal-component-config.handler'; +import { LegalComponentConfig } from './legal-component.config.interface'; + +export class LegalComponent extends WebComponentAbstract { + private readonly postMessagesClient: PostMessagesClient; + private readonly headlessCheckout: HeadlessCheckout; + private readonly headlessCheckoutSpy: HeadlessCheckoutSpy; + private config?: LegalComponentConfig; + private subscription?: () => void; + + public constructor() { + super(); + this.headlessCheckoutSpy = container.resolve(HeadlessCheckoutSpy); + this.headlessCheckout = container.resolve(HeadlessCheckout); + this.postMessagesClient = container.resolve(PostMessagesClient); + } + + protected connectedCallback(): void { + if (!this.headlessCheckoutSpy.appWasInit) { + this.headlessCheckoutSpy.listenAppInit(() => this.connectedCallback()); + return; + } + void this.getLegalComponentConfig().then(this.configLoadedHandler); + } + + protected readonly configLoadedHandler = ( + config: LegalComponentConfig + ): void => { + this.config = config; + + super.render(); + + if (this.config) { + this.listenPings(); + } + }; + + protected listenPings(): void { + this.subscription = this.headlessCheckout.events.onCoreEvent( + EventName.legalComponentPing, + legalPingHandler, + this.pongCallback + ); + } + + protected disconnectedCallback(): void { + super.disconnectedCallback(); + if (this.subscription) { + this.subscription(); + } + } + + protected async getLegalComponentConfig(): Promise { + const msg: Message = { + name: EventName.getLegalComponentConfig, + }; + + return this.postMessagesClient.send( + msg, + getLegalComponentConfigHandler + ) as Promise; + } + + protected getHtml(): string { + if (this.config) { + return getLegalComponentTemplate(this.config); + } + return ''; + } + + private readonly pongCallback = (): void => { + void this.headlessCheckout.events.send( + { name: EventName.legalComponentPong }, + legalPongHandler + ); + }; +} diff --git a/src/features/headless-checkout/web-components/legal/secure-connection.component.template.ts b/src/features/headless-checkout/web-components/legal/secure-connection.component.template.ts new file mode 100644 index 0000000..36d8427 --- /dev/null +++ b/src/features/headless-checkout/web-components/legal/secure-connection.component.template.ts @@ -0,0 +1,36 @@ +import { LegalComponentConfig } from './legal-component.config.interface'; +import logo from '../../../../assets/icons/logo.svg'; +import i18next from 'i18next'; +export const getSecureConnectionTemplate = ( + secureConnection?: LegalComponentConfig['secureConnection'] +): string => { + const isWhiteLabel = secureConnection?.isWhiteLabel; + const secureConnectionUrl = secureConnection?.secureConnectionUrl; + return ` +
+
+ ${ + !isWhiteLabel && secureConnectionUrl + ? ` + + ` + : ` + + ` + } +
+ ${i18next.t('secure-connection')} +
+
+
+`; +}; diff --git a/src/translations/en.json b/src/translations/en.json index 4fa6b8b..a59c99a 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1,7 +1,13 @@ { "en": { "translation": { - "hello": "Hello world!" + "hello": "Hello world!", + "legal": "Legal", + "cookie-policy": "Cookie Policy", + "privacy-policy": "Privacy Policy", + "refund-policy": "Refund policy", + "sctl-indications": "SCTL Indications", + "secure-connection": "Secure connection" } } } diff --git a/src/web-components.ts b/src/web-components.ts index 283b291..f83dbd2 100644 --- a/src/web-components.ts +++ b/src/web-components.ts @@ -1,5 +1,11 @@ import { SubmitButtonComponent } from './features/headless-checkout/web-components/submit-button/submit-button.component'; import { CardNumberComponent } from './features/headless-checkout/web-components/card-number/card-number.component'; import { PaymentMethodsComponent } from './features/headless-checkout/web-components/payment-methods/payment-methods.component'; +import { LegalComponent } from './features/headless-checkout/web-components/legal/legal.component'; -export { SubmitButtonComponent, CardNumberComponent, PaymentMethodsComponent }; +export { + SubmitButtonComponent, + CardNumberComponent, + PaymentMethodsComponent, + LegalComponent, +}; diff --git a/webpack.config.js b/webpack.config.js index d0c631c..5ff190c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,6 +20,11 @@ const config = { 'sass-loader', ], }, + { + test: /\.svg$/, + type: 'asset', + use: 'svgo-loader', + }, ], }, resolve: {