diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..0980e8e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "parserOptions": { + "project": "./tsconfig.json" + }, + "extends": [ + "plugin:@stencil-community/recommended" + ] +} \ No newline at end of file diff --git a/.storybook/main.js b/.storybook/main.js index 481124b..bae1177 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -8,7 +8,9 @@ module.exports = { "@storybook/addon-essentials", "@chromatic-com/storybook", "@storybook/addon-interactions", - "@chromatic-com/storybook" + "@chromatic-com/storybook", + "@storybook/addon-mdx-gfm", + "@storybook/addon-webpack5-compiler-swc" ], "framework": { name: "@storybook/html-webpack5", @@ -32,7 +34,5 @@ module.exports = { return config; }, staticDirs: ['../dist'], - docs: { - autodocs: true - } + docs: {} }; diff --git a/.storybook/preview.js b/.storybook/preview.js index f243f02..2e9ccbb 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -11,8 +11,9 @@ export const parameters = { }, viewMode: 'docs', docs: { - source: { - state: 'open', - }, + canvas: { + sourceState: 'shown' + } } } +export const tags = ['autodocs']; diff --git a/.storybook/stories/1.Installation.mdx b/.storybook/stories/1.Installation.mdx index 13daf1d..88ae6ed 100644 --- a/.storybook/stories/1.Installation.mdx +++ b/.storybook/stories/1.Installation.mdx @@ -2,16 +2,20 @@ import { Meta } from '@storybook/blocks'; -

easyCredit-Ratenkauf Web Components

+

easyCredit Web Components

-

Die easyCredit-Ratenkauf Web Components sind ein Set von Webkomponenten, die universell in E-Commerce-Plattformen wie Magento oder Shopware eingesetzt werden können. Die Webkomponenten erleichtern die Integration der easyCredit-Ratenkauf Zahlungslösung durch vielseitige Web-Frontend-Elemente für Marketing, Checkout und Händlerverwaltung.

+

Die easyCredit Web Components sind ein Set von Web-Komponenten, die universell in E-Commerce-Plattformen, wie z.B. Magento, Shopware oder wooCommerce eingesetzt werden können. Die Webkomponenten erleichtern die Integration der easyCredit-Zahlungslösung durch vielseitige Web-Frontend-Elemente für Marketing, Checkout und Händlerverwaltung.

Installation

Zur Integration der Web Components in ein beliebiges System fügen Sie die folgenden Zeilen in den `` Ihres Shops ein: ```html - +// Pre-Release zur Entwicklung + + +// endgültige URL bei Release der Komponenten + ``` Jetzt können Sie jede der Komponenten innerhalb der Website verwenden: @@ -20,6 +24,8 @@ Jetzt können Sie jede der Komponenten innerhalb der Website verwenden: ``` +Die Komponenten werden bei Einbindung nicht vollständig geladen, sondern erst bei Einfügen in die Seite asynchron nachgeladen. Dadurch ist der entstehende Overhead durch die Einbindung zu vernachlässigen. +

In ein bestehendes JavaScript-Projekt installieren

Um die Komponenten in einem JavaScript-Projekt zu verwenden, installieren Sie das NPM-Package:

diff --git a/.storybook/stories/2.Changelog.mdx b/.storybook/stories/2.Changelog.mdx index 41f7097..b741048 100644 --- a/.storybook/stories/2.Changelog.mdx +++ b/.storybook/stories/2.Changelog.mdx @@ -4,6 +4,10 @@ import { Meta } from "@storybook/blocks"; # Changelog +## 2.0.0 + +* die Web-Komponenten wurden für easyCredit-Rechnung überarbeitet + ## 1.2.10 #### `` @@ -14,6 +18,7 @@ import { Meta } from "@storybook/blocks"; * der Error-Timeout wurde auf 10 Sekunden erhöht * der Performance-Observer wurde entfernt, weil er durch die Same-Origin-Policy keine Wirkung hatte +======= ## 1.2.9 diff --git a/.storybook/stories/3.Consent-Management.mdx b/.storybook/stories/3.Consent-Management.mdx index 673c26f..8f4db71 100644 --- a/.storybook/stories/3.Consent-Management.mdx +++ b/.storybook/stories/3.Consent-Management.mdx @@ -2,7 +2,7 @@ import { Meta } from "@storybook/blocks"; -

Integration der easyCredit-Ratenkauf Web Components mit einem Consent-Management Tool

+

Integration der easyCredit Web Components mit einem Consent-Management Tool

Sollen die Web Components vorbehaltlich der Zustimmung des Kunden eingefügt werden, muss darauf geachtet werden, dass die Komponenten als ESM-Modul eingebunden werden. Dabei muss darauf geachtet werden, dass bestimmte Komponenten im Checkout verwendet werden. Stimmt der Nutzer nicht zu, werden auch diese Komponenten nicht angezeigt. @@ -11,7 +11,7 @@ Sollen die Web Components vorbehaltlich der Zustimmung des Kunden eingefügt wer In diesem Fall behelfen wir uns mit einem normalen Skript-Tag der konditional ausgeführt wird, und wiederum das ESM-Modul einfügt: ```html - +``` + +

Anpassung des Anfrage-Headers

+ +Im folgenden Beispiel ist gezeigt, wie der Anfrage-Header beeinflusst werden kann. In diesem Fall wird ein bereits existierender Bearer token vewrwendet um gegen die API zu authentifizieren: ```html +``` +

Anpassung der Basis-URL zu Testzwecken

+ +Zu Testzwecken kann die Basis-URL für API-Anfragen angepasst werden. Dies ist für die Benutzung der Komponenten im Normalfall aber nicht notwendig. + +```html + ``` + +

Implementierungsbeispiele

+ +Unter den folgenden Links sind einige Implementierungsbeispiele der Konfiguration und der +Interaktion der Merchant-Komponenten zu finden: + +* [Implementierung in wooCommerce](https://github.com/teambank/ratenkaufbyeasycredit-plugin-woocommerce/blob/68f05a8c715af1ed557264ed926c3810944ed5c5/src/woocommerce-gateway-ratenkaufbyeasycredit/includes/order-management.php#L65C21-L65C38) +* [Implementierung in Shopware 5](https://github.com/teambank/ratenkaufbyeasycredit-plugin-shopware-5/blob/2f511d8983180dd9e4d95b10440858ce450c6944/src/Frontend/NetzkollektivEasyCredit/Subscriber/BackendMerchant.php#L41) +* [Implementierung in Shopware 6](https://github.com/teambank/ratenkaufbyeasycredit-plugin-shopware-6/blob/54a995bff40ac324fc047fa67002df6cb07d73a8/src/Resources/app/administration/src/module/easycredit-payment/component/easycredit-tx-widget/index.js#L37) +* [Implementierung in Magento 2](https://github.com/teambank/ratenkaufbyeasycredit-plugin-magento-2/blob/d38f12f1d2dd4e14f5bc9dae2de922c3c28ecf03/Block/Adminhtml/Merchant/Config.php#L43) diff --git a/.storybook/stories/5.Developer.mdx b/.storybook/stories/5.Developer.mdx new file mode 100644 index 0000000..eda0a33 --- /dev/null +++ b/.storybook/stories/5.Developer.mdx @@ -0,0 +1,59 @@ +import { Meta } from "@storybook/blocks"; + + + +

Hinweise für Entwickler

+ + +

Warten auf Komponenten-Initialisierung mit `whenDefined`

+ +Um die Komponenten und deren Methoden ansprechen zu können, muss das jeweilige Element definiert sein. Um festzustellen, ob eine Komponente bereits angesprochen werden kann, kann die Funktion `whenDefined` verwendet werden: + +```html + +``` + +

dynamisches Hinzufügen von EventHandlern

+ +Möglicherweise wird die Komponente nicht bereits beim Laden der Seite, sondern erst später durch JavaScript der Seite hinzugefügt oder aktualisiert. Um auf Veränderungen im DOM reagieren zu können, kann die folgende Funktion hilfreich sein: + +```html + +``` \ No newline at end of file diff --git a/.storybook/theme.js b/.storybook/theme.js index a802f44..90418ba 100644 --- a/.storybook/theme.js +++ b/.storybook/theme.js @@ -2,7 +2,7 @@ import { create } from '@storybook/theming'; export default create({ base: 'light', - brandTitle: 'easyCredit-Ratenkauf Web Components', + brandTitle: 'easyCredit Web Components', brandUrl: 'https://easycredit-ratenkauf.de', - brandImage: `data:image/svg+xml,%3Csvg id='Ebene_1' data-name='Ebene 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 283.46 135.07'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:%230066b3;%7D%3C/style%3E%3C/defs%3E%3Cpath class='cls-1' d='M12,27.73a8.84,8.84,0,0,1,8.84-6.85c4.38,0,5.85,3.13,5.85,6.85Zm19.4,11a27,27,0,0,1-10.83,2.39c-7.3,0-9.16-2.92-9.3-6.64H35.81A38.7,38.7,0,0,0,36.67,28c0-10.49-6.84-15.08-15.94-15.08C5.31,12.91,0,25.27,0,33.31,0,42,6.24,49.12,17.8,49.12a44.26,44.26,0,0,0,12.09-1.93Z'/%3E%3Cpath class='cls-1' d='M104.81,39.15a24.3,24.3,0,0,0,9.7,2c1.92,0,6.71-.19,6.71-3,0-4.92-14.29-2.39-14.29-13.82,0-8.1,9.44-11.36,17.47-11.36A40,40,0,0,1,135.9,15l-2.53,7.84a23.9,23.9,0,0,0-9.56-1.93c-2.66,0-5.58.6-5.58,3,0,3.86,14.94,3.59,14.94,12.29S125.93,49,117,49.12a54.67,54.67,0,0,1-14.54-1.8Z'/%3E%3Cpath class='cls-1' d='M141.1,69l-1.33,7.11h.14c1.92-4.05,5.78-7.91,10.7-7.91a13.41,13.41,0,0,1,5,.87l-2.73,10.56c-1.53-1.19-3.25-1.46-5.52-1.46-5,0-8,4.38-8.9,9.5l-3.39,15.94h-12L130.45,69Z'/%3E%3Cpath class='cls-1' d='M166.12,83A8.83,8.83,0,0,1,175,76.19c4.39,0,5.85,3.12,5.85,6.84Zm19.39,11a27.14,27.14,0,0,1-10.82,2.39c-7.31,0-9.17-2.92-9.3-6.64H189.9a38.8,38.8,0,0,0,.86-6.52c0-10.49-6.84-15.08-15.94-15.08-15.41,0-20.73,12.36-20.73,20.4,0,8.7,6.25,15.81,17.81,15.81A44,44,0,0,0,184,102.49Z'/%3E%3Cpath class='cls-1' d='M211.48,95.25c-3.79,0-5.72-2.85-5.72-7.11,0-5.38,3.39-10.76,9-10.76,4,0,5.71,3.59,5.71,7C220.51,89,217.12,95.25,211.48,95.25Zm6.57,8.37h11c.14-1.39.34-3.12.73-5.18L239,53.8H227.29L223.1,74.59H223c-1.8-3.72-6-6.38-12-6.38-11.82,0-17.53,10.57-17.53,21.93,0,7.77,5.44,14.28,12.88,14.28,6.65,0,9.5-2.46,12.56-6.31H219Z'/%3E%3Cpath class='cls-1' d='M241.2,69h12.09l-7.17,34.61H234Zm3.06-14.41h12.09l-1.86,8.77H242.4Z'/%3E%3Cpath class='cls-1' d='M256.49,69h6.84L265,61.57l12.62-3.39L275.23,69h8.23L282,77.38h-8.7L271.24,87a32.65,32.65,0,0,0-1,6,3.65,3.65,0,0,0,3.92,3.86,11.73,11.73,0,0,0,3.86-1l-1.33,7.91a49.5,49.5,0,0,1-7.44.66c-6.11,0-11-3-11-10.23a32.58,32.58,0,0,1,1.06-7.11l2.06-9.7H255Z'/%3E%3Cpath class='cls-1' d='M165,13.71,153.25,35.56h-.13L150,13.71H137.84l7.64,34.48L144.2,50.3c-1.77,3.26-3.59,5.71-7,5.71a14.75,14.75,0,0,1-3.92-.55l-1.87,8.88a29.07,29.07,0,0,0,7.18.84c7.64,0,11.57-4.06,15.09-10.17L155,52.9,177.7,13.71Z'/%3E%3Cpath class='cls-1' d='M121.49,93a26.42,26.42,0,0,1-11.06,2.26c-7.44,0-12.68-3.85-12.68-12.09,0-8.77,6-21.13,18.42-21.13a36.35,36.35,0,0,1,11.46,1.57l1.87-8.91c-2.78-.91-7.55-1.83-15.26-1.83-17.4,0-29.25,14.56-29.25,30,0,12.75,8.57,21.59,23.52,21.59a47.81,47.81,0,0,0,10.86-1.36Z'/%3E%3Cpath class='cls-1' d='M78.18,28.72c0-4.19-2.58-7.14-6.6-7.14-5.88,0-10,6.07-10,11.42,0,4.19,2.5,7.31,6.69,7.31C74,40.31,78.18,34.33,78.18,28.72Z'/%3E%3Cpath class='cls-1' d='M101.23,38.5A31.26,31.26,0,1,1,98.63,17a17.57,17.57,0,0,1,1.63,7.54c0,11-10.4,15.78-14.86,15.78A1.18,1.18,0,0,1,84.07,39a14,14,0,0,1,.62-3l4.9-21.66H82.1L81,18.55a12,12,0,0,0-10.34-5.7c-10.16,0-18.36,9.72-18.36,21.48C52.33,43,58.75,49,66.15,49c3.65,0,6.77-2.14,9-4.63h.18A4.53,4.53,0,0,0,80.14,49C84.12,49,94.75,46.07,101.23,38.5Z'/%3E%3Cpath class='cls-1' d='M135.3,122.1a7,7,0,0,0,.87-3.57,6.35,6.35,0,0,0-1-3.57,6.15,6.15,0,0,0-2.86-2.24,12.22,12.22,0,0,0-4.58-.77h-6.34L117,134.6h4.85l1.55-8h2.92l.49,0,3.24,8h5.42l-4.27-9a10,10,0,0,0,1.81-1A7.68,7.68,0,0,0,135.3,122.1ZM130.65,121a3.61,3.61,0,0,1-1.65,1.45,6,6,0,0,1-2.55.51h-2.33l1.41-7.28h1.79a4.49,4.49,0,0,1,2.9.81,2.8,2.8,0,0,1,1,2.32A4.11,4.11,0,0,1,130.65,121Z'/%3E%3Cpath class='cls-1' d='M150.35,121.83a4.69,4.69,0,0,0-.65-1.21,4.45,4.45,0,0,0-1.7-1.31,5.7,5.7,0,0,0-2.33-.45,6.9,6.9,0,0,0-3.07.73,8.27,8.27,0,0,0-2.56,2,10,10,0,0,0-1.73,3,10.15,10.15,0,0,0-.62,3.59,8.42,8.42,0,0,0,.73,3.62,5.7,5.7,0,0,0,2.05,2.43,5.5,5.5,0,0,0,3.09.86,5.69,5.69,0,0,0,2.14-.4,5.79,5.79,0,0,0,1.82-1.15,4.73,4.73,0,0,0,.81-1l-.27,2.1h4.26l3-15.26H151Zm-1.43,6.82a4.27,4.27,0,0,1-1.46,1.68,3.58,3.58,0,0,1-2.06.63,3.23,3.23,0,0,1-1.63-.4,2.66,2.66,0,0,1-1.09-1.16,4,4,0,0,1-.37-1.78,5.09,5.09,0,0,1,.53-2.34,4.38,4.38,0,0,1,1.48-1.68,3.56,3.56,0,0,1,2-.63,3.19,3.19,0,0,1,1.64.41,2.8,2.8,0,0,1,1.07,1.16,3.85,3.85,0,0,1,.39,1.77A5,5,0,0,1,148.92,128.65Z'/%3E%3Cpath class='cls-1' d='M166.41,115.05l-4.94,1.31-.57,3H158l-.78,3.81h2.92l-1,5.37c-.08.41-.15.77-.21,1.06s-.1.53-.13.73-.05.36-.06.5,0,.28,0,.42a3.51,3.51,0,0,0,1.2,2.85,5,5,0,0,0,3.33,1,14.77,14.77,0,0,0,2.84-.32l.59-3.52a4.19,4.19,0,0,1-1.43.27,1.6,1.6,0,0,1-1.19-.43,1.71,1.71,0,0,1-.42-1.24,4.65,4.65,0,0,1,.12-1c.08-.37.17-.82.27-1.36l.83-4.35h3.34l.75-3.81h-3.34Z'/%3E%3Cpath class='cls-1' d='M178.12,118.86a8.67,8.67,0,0,0-3.47.69,8,8,0,0,0-2.75,1.91,8.67,8.67,0,0,0-1.82,2.89,9.76,9.76,0,0,0-.66,3.63,7.49,7.49,0,0,0,.57,3,6,6,0,0,0,1.61,2.23,7.13,7.13,0,0,0,2.55,1.4,10.88,10.88,0,0,0,3.41.49,9.2,9.2,0,0,0,1.12-.07l1.28-.18c.44-.07.89-.16,1.32-.27s.84-.22,1.2-.34l.62-3.79a9.05,9.05,0,0,1-2.28.81,10.56,10.56,0,0,1-2.25.27,6.13,6.13,0,0,1-3.54-.79,3.32,3.32,0,0,1-1.2-2.61h10.52a10,10,0,0,0,.32-1.52,13.83,13.83,0,0,0,.1-1.52,5.93,5.93,0,0,0-1.76-4.54A6.82,6.82,0,0,0,178.12,118.86Zm2.37,6.2a3,3,0,0,1,0,.33H174.1a5.06,5.06,0,0,1,1.39-2.34,3.38,3.38,0,0,1,2.43-.91,2.36,2.36,0,0,1,2.59,2.59C180.51,124.83,180.5,124.94,180.49,125.06Z'/%3E%3Cpath class='cls-1' d='M198.42,118.86a5.58,5.58,0,0,0-2.15.43,5.16,5.16,0,0,0-2.54,2.21l.34-2.16h-4.44l-2.95,15.26h4.62l1.58-8.14a5.7,5.7,0,0,1,.67-1.89,3.28,3.28,0,0,1,1.11-1.19,2.75,2.75,0,0,1,1.46-.41,2,2,0,0,1,1.55.53,2.17,2.17,0,0,1,.51,1.59c0,.16,0,.32,0,.49s0,.37-.08.58l-1.64,8.44h4.62l1.73-8.91c.06-.34.1-.68.13-1s0-.65,0-1a5,5,0,0,0-1.22-3.56A4.36,4.36,0,0,0,198.42,118.86Z'/%3E%3Cpolygon class='cls-1' points='223.24 119.34 217.55 119.34 211.5 125.05 214.33 110.46 209.71 110.46 205.03 134.6 209.65 134.6 210.99 127.68 215.7 134.6 221.22 134.6 215.3 126.52 223.24 119.34'/%3E%3Cpath class='cls-1' d='M235.64,121.83a4.43,4.43,0,0,0-.66-1.21,4.31,4.31,0,0,0-1.7-1.31,5.65,5.65,0,0,0-2.32-.45,6.86,6.86,0,0,0-3.07.73,8.27,8.27,0,0,0-2.56,2,9.74,9.74,0,0,0-1.73,3,10.15,10.15,0,0,0-.63,3.59,8.57,8.57,0,0,0,.73,3.62,5.79,5.79,0,0,0,2.06,2.43,5.47,5.47,0,0,0,3.08.86,5.74,5.74,0,0,0,2.15-.4,5.9,5.9,0,0,0,1.82-1.15,4.73,4.73,0,0,0,.81-1l-.28,2.1h4.27l3-15.26h-4.36Zm-1.43,6.82a4.35,4.35,0,0,1-1.46,1.68,3.58,3.58,0,0,1-2.06.63,3.29,3.29,0,0,1-1.64-.4A2.72,2.72,0,0,1,228,129.4a4.13,4.13,0,0,1-.37-1.78,5.1,5.1,0,0,1,.54-2.34,4.44,4.44,0,0,1,1.47-1.68,3.62,3.62,0,0,1,2.05-.63,3.13,3.13,0,0,1,1.63.41,2.76,2.76,0,0,1,1.08,1.16,4,4,0,0,1,.38,1.77A5,5,0,0,1,234.21,128.65Z'/%3E%3Cpath class='cls-1' d='M252.59,127.44a5.2,5.2,0,0,1-1.14,2.57,2.62,2.62,0,0,1-2,.89c-1.36,0-2-.7-2-2.11a5.56,5.56,0,0,1,.12-1.08l1.64-8.37h-4.71l-1.73,8.85a9.85,9.85,0,0,0-.21,2,5,5,0,0,0,1.21,3.57,4.35,4.35,0,0,0,3.35,1.28,5.26,5.26,0,0,0,3-.91A5.36,5.36,0,0,0,252,132l-.4,2.57h4.35l2.95-15.23h-4.71Z'/%3E%3Cpath class='cls-1' d='M270.25,115.26a3,3,0,0,1,2.25-.87,4.61,4.61,0,0,1,2.24.57l.65-3.88a5,5,0,0,0-1.49-.56,9,9,0,0,0-2-.21q-6,0-7.39,7.09l-.37,1.94h-2.55l-.71,3.81h2.53l-2.2,11.45h4.7l2.18-11.45h3.81l.72-3.81h-3.8l.25-1.34A5.38,5.38,0,0,1,270.25,115.26Z'/%3E%3C/svg%3E`, + brandImage: `data:image/svg+xml,%3Csvg id='Ebene_1' data-name='Ebene 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 283.46 104.42'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:%230066b3;%7D%3C/style%3E%3C/defs%3E%3Cpath class='cls-1' d='M34.21,76.25a8.85,8.85,0,0,1,8.84-6.84c4.38,0,5.85,3.12,5.85,6.84Zm19.4,11a27.15,27.15,0,0,1-10.83,2.39c-7.3,0-9.16-2.92-9.3-6.64H58a38.83,38.83,0,0,0,.86-6.51C58.86,66,52,61.44,42.92,61.44c-15.42,0-20.73,12.35-20.73,20.39,0,8.71,6.24,15.81,17.8,15.81a44.35,44.35,0,0,0,12.1-1.92Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M127,87.68a24.34,24.34,0,0,0,9.7,2c1.92,0,6.71-.2,6.71-3,0-4.92-14.29-2.4-14.29-13.82,0-8.11,9.44-11.36,17.47-11.36a39.61,39.61,0,0,1,11.5,2.06l-2.53,7.84A23.73,23.73,0,0,0,146,69.41c-2.66,0-5.58.6-5.58,3,0,3.85,14.94,3.59,14.94,12.29s-7.24,12.82-16.21,13a54.7,54.7,0,0,1-14.54-1.79Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M163.29,117.54,162,124.65h.14c1.92-4.06,5.78-7.91,10.7-7.91a13.41,13.41,0,0,1,5,.87l-2.73,10.56c-1.53-1.2-3.25-1.46-5.52-1.46-5,0-8,4.38-8.9,9.5l-3.39,15.94H145.36l7.28-34.61Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M188.31,131.56a8.82,8.82,0,0,1,8.83-6.85c4.39,0,5.85,3.13,5.85,6.85Zm19.4,11A27,27,0,0,1,196.88,145c-7.31,0-9.17-2.92-9.3-6.64h24.51a38.7,38.7,0,0,0,.86-6.51c0-10.49-6.84-15.08-15.94-15.08-15.41,0-20.73,12.36-20.73,20.4,0,8.7,6.25,15.81,17.81,15.81A44.38,44.38,0,0,0,206.18,151Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M233.67,143.78c-3.79,0-5.72-2.86-5.72-7.11,0-5.38,3.39-10.76,9-10.76,4,0,5.71,3.59,5.71,7C242.7,137.53,239.31,143.78,233.67,143.78Zm6.57,8.37h11c.14-1.4.34-3.12.73-5.18l9.3-44.64H249.48l-4.19,20.79h-.13c-1.79-3.72-6-6.38-12-6.38-11.82,0-17.53,10.56-17.53,21.92,0,7.78,5.44,14.29,12.88,14.29,6.65,0,9.5-2.46,12.56-6.31h.13Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M263.39,117.54h12.09l-7.17,34.61H256.22Zm3.06-14.42h12.09l-1.86,8.77H264.59Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M278.68,117.54h6.85l1.66-7.44,12.62-3.39-2.39,10.83h8.23l-1.46,8.37h-8.7l-2.06,9.63a32.73,32.73,0,0,0-1,6,3.64,3.64,0,0,0,3.92,3.85,12,12,0,0,0,3.86-1l-1.33,7.9a48.27,48.27,0,0,1-7.44.67c-6.11,0-11-3-11-10.23a32.5,32.5,0,0,1,1.06-7.11l2.06-9.7h-6.38Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M187.2,62.24,175.45,84.09h-.14l-3.12-21.85H160l7.64,34.47-1.28,2.11c-1.77,3.27-3.59,5.72-7,5.72a14.81,14.81,0,0,1-3.92-.55l-1.87,8.88a29.15,29.15,0,0,0,7.19.83c7.64,0,11.56-4,15.08-10.16l1.28-2.11,22.72-39.19Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M143.68,141.52a26.42,26.42,0,0,1-11.06,2.26c-7.44,0-12.68-3.85-12.68-12.09,0-8.77,6-21.14,18.42-21.14a36.07,36.07,0,0,1,11.46,1.58l1.87-8.91c-2.78-.91-7.55-1.84-15.26-1.84-17.4,0-29.25,14.56-29.25,30,0,12.75,8.57,21.59,23.52,21.59a47.81,47.81,0,0,0,10.86-1.36Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M100.37,77.24c0-4.19-2.58-7.13-6.6-7.13-5.88,0-10,6.06-10,11.41,0,4.19,2.5,7.31,6.69,7.31C96.18,88.83,100.37,82.86,100.37,77.24Z' transform='translate(-22.19 -48.53)'/%3E%3Cpath class='cls-1' d='M123.42,87a31.26,31.26,0,1,1-2.6-21.52,17.63,17.63,0,0,1,1.63,7.54c0,11.06-10.4,15.78-14.86,15.78a1.17,1.17,0,0,1-1.33-1.33,13.84,13.84,0,0,1,.62-3l4.9-21.67h-7.49l-1.07,4.28a12,12,0,0,0-10.34-5.7c-10.16,0-18.36,9.71-18.36,21.48,0,8.65,6.42,14.71,13.82,14.71,3.65,0,6.77-2.14,9-4.64h.18a4.53,4.53,0,0,0,4.81,4.64C106.31,97.57,116.94,94.59,123.42,87Z' transform='translate(-22.19 -48.53)'/%3E%3C/svg%3E` }); diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 7242329..4fda807 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/package.json b/package.json index ba176d0..bfac89c 100644 --- a/package.json +++ b/package.json @@ -27,37 +27,42 @@ "generate": "stencil generate", "storybook": "storybook dev -p 6006", "storybook:build": "storybook build ./dist", - "storybook:deploy": "source .env && rsync -rvz storybook-static/ $STORYBOOK_DEPLOY_DST", + "storybook:deploy": "bash -c \"source .env && rsync -rvz storybook-static/ $STORYBOOK_DEPLOY_DST\"", + "storybook:deploy:clear-cache": "bash -c \"source .env && env && curl -X DELETE \"https://api.cloudflare.com/client/v4/zones/708da8a58a29a3e65af33fa56a1bf7d9/purge_cache\" -H \"Authorization: Bearer $CF_BEARER\" -H \"Content-Type: application/json\" --data '{\"purge_everything\":true}\"", "release": "yarn build && (cd dist; tar czvf ../easycredit-ratenkauf-webcomponents-$(npm pkg get version | sed 's/\"//g').tar.gz .)" }, "dependencies": { - "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/plugin-transform-optional-chaining": "^7.23.4", "@open-wc/webpack-import-meta-loader": "^0.4.7", "@stencil/core": "^4.17.1", "@stencil/sass": "^3.0.11", "@stencil/store": "^2.0.15", - "@storybook/addon-essentials": "^8.0.9", - "@storybook/addon-interactions": "^8.0.9", - "@storybook/addon-links": "^8.0.9", + "@storybook/addon-essentials": "^8.3.1", + "@storybook/addon-interactions": "^8.3.1", + "@storybook/addon-links": "^8.3.1", + "@storybook/web-components": "^8.3.1", "buffer": "^6.0.3", "case": "^1.6.3", - "storybook": "^8.0.9" + "stencil-fragment": "^1.0.1", + "storybook": "^8.3.1" }, "devDependencies": { "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", "@babel/preset-react": "^7.24.1", "@babel/preset-typescript": "^7.24.1", - "@chromatic-com/storybook": "^1.3.3", - "@storybook/blocks": "^8.0.9", - "@storybook/html": "^8.0.9", - "@storybook/html-webpack5": "^8.0.9", - "@storybook/theming": "^8.0.9", + "@chromatic-com/storybook": "^2.0.2", + "@storybook/addon-mdx-gfm": "^8.3.1", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@storybook/blocks": "^8.3.1", + "@storybook/html": "^8.3.1", + "@storybook/html-webpack5": "^8.3.1", + "@storybook/manager-api": "^8.3.1", + "@storybook/theming": "^8.3.1", "@types/jest": "^29.5.12", "babel-loader": "^9.1.3", "jest": "^29.7.0", "jest-cli": "^29.7.0", - "puppeteer": "^20.9.0", "react": "^18.3.0", "react-dom": "^18.3.0" }, diff --git a/src/components.d.ts b/src/components.d.ts index 7aa736b..edd0b3d 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -5,6 +5,8 @@ * It contains typing information for all components that exist in this project. */ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; +import { InstallmentPlan, InstallmentPlans, METHODS } from "./types"; +export { InstallmentPlan, InstallmentPlans, METHODS } from "./types"; export namespace Components { interface EasycreditAccordion { /** @@ -63,14 +65,14 @@ export namespace Components { interface EasycreditCheckout { "alert": string; "amount": number; - /** - * Disable Flexprice in calculation - */ "disableFlexprice": boolean; "isActive": boolean; "paymentPlan": string; + "paymentType": METHODS; "webshopId": string; } + interface EasycreditCheckoutBillPaymentTimeline { + } interface EasycreditCheckoutInstallments { "installments": any; "rows": number; @@ -78,25 +80,38 @@ export namespace Components { } interface EasycreditCheckoutLabel { "label": string; + "paymentType": METHODS; "slogan": string; } interface EasycreditCheckoutPrivacyApproval { "webshopId": string; } + interface EasycreditCheckoutTotals { + "amount": number; + "installmentPlans": InstallmentPlans; + "selectedInstallment": InstallmentPlan; + } interface EasycreditExpressButton { - "alert": string; "amount": number; - "bgBlue": boolean; "fullWidth": boolean; + "paymentTypes": string; "redirectUrl": string; "webshopId": string; } + interface EasycreditExpressButtonSingle { + "amount": number; + "bgBlue": boolean; + "fullWidth": boolean; + "paymentType": METHODS; + "webshopId": string; + } interface EasycreditFaq { } interface EasycreditInfopage { } interface EasycreditLogo { "alt": string; + "paymentType": METHODS; } interface EasycreditMerchantManager { "date": string; @@ -119,25 +134,11 @@ export namespace Components { "toggle": () => Promise; } interface EasycreditWidget { - /** - * Financing Amount - */ "amount": number; - /** - * Disable Flexprice in calculation - */ "disableFlexprice": boolean; - /** - * Display Type (e.g. clean -> without shadow) - */ "displayType": string; - /** - * Show if out of range - */ "extended": boolean; - /** - * Webshop Id - */ + "paymentTypes": string; "webshopId": string; } } @@ -149,6 +150,10 @@ export interface EasycreditCheckoutInstallmentsCustomEvent extends CustomEven detail: T; target: HTMLEasycreditCheckoutInstallmentsElement; } +export interface EasycreditExpressButtonSingleCustomEvent extends CustomEvent { + detail: T; + target: HTMLEasycreditExpressButtonSingleElement; +} export interface EasycreditModalCustomEvent extends CustomEvent { detail: T; target: HTMLEasycreditModalElement; @@ -214,6 +219,12 @@ declare global { prototype: HTMLEasycreditCheckoutElement; new (): HTMLEasycreditCheckoutElement; }; + interface HTMLEasycreditCheckoutBillPaymentTimelineElement extends Components.EasycreditCheckoutBillPaymentTimeline, HTMLStencilElement { + } + var HTMLEasycreditCheckoutBillPaymentTimelineElement: { + prototype: HTMLEasycreditCheckoutBillPaymentTimelineElement; + new (): HTMLEasycreditCheckoutBillPaymentTimelineElement; + }; interface HTMLEasycreditCheckoutInstallmentsElementEventMap { "selectedInstallment": string; } @@ -243,12 +254,35 @@ declare global { prototype: HTMLEasycreditCheckoutPrivacyApprovalElement; new (): HTMLEasycreditCheckoutPrivacyApprovalElement; }; + interface HTMLEasycreditCheckoutTotalsElement extends Components.EasycreditCheckoutTotals, HTMLStencilElement { + } + var HTMLEasycreditCheckoutTotalsElement: { + prototype: HTMLEasycreditCheckoutTotalsElement; + new (): HTMLEasycreditCheckoutTotalsElement; + }; interface HTMLEasycreditExpressButtonElement extends Components.EasycreditExpressButton, HTMLStencilElement { } var HTMLEasycreditExpressButtonElement: { prototype: HTMLEasycreditExpressButtonElement; new (): HTMLEasycreditExpressButtonElement; }; + interface HTMLEasycreditExpressButtonSingleElementEventMap { + "buttonClicked": string; + } + interface HTMLEasycreditExpressButtonSingleElement extends Components.EasycreditExpressButtonSingle, HTMLStencilElement { + addEventListener(type: K, listener: (this: HTMLEasycreditExpressButtonSingleElement, ev: EasycreditExpressButtonSingleCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLEasycreditExpressButtonSingleElement, ev: EasycreditExpressButtonSingleCustomEvent) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; + } + var HTMLEasycreditExpressButtonSingleElement: { + prototype: HTMLEasycreditExpressButtonSingleElement; + new (): HTMLEasycreditExpressButtonSingleElement; + }; interface HTMLEasycreditFaqElement extends Components.EasycreditFaq, HTMLStencilElement { } var HTMLEasycreditFaqElement: { @@ -313,10 +347,13 @@ declare global { "easycredit-box-modal": HTMLEasycreditBoxModalElement; "easycredit-box-top": HTMLEasycreditBoxTopElement; "easycredit-checkout": HTMLEasycreditCheckoutElement; + "easycredit-checkout-bill-payment-timeline": HTMLEasycreditCheckoutBillPaymentTimelineElement; "easycredit-checkout-installments": HTMLEasycreditCheckoutInstallmentsElement; "easycredit-checkout-label": HTMLEasycreditCheckoutLabelElement; "easycredit-checkout-privacy-approval": HTMLEasycreditCheckoutPrivacyApprovalElement; + "easycredit-checkout-totals": HTMLEasycreditCheckoutTotalsElement; "easycredit-express-button": HTMLEasycreditExpressButtonElement; + "easycredit-express-button-single": HTMLEasycreditExpressButtonSingleElement; "easycredit-faq": HTMLEasycreditFaqElement; "easycredit-infopage": HTMLEasycreditInfopageElement; "easycredit-logo": HTMLEasycreditLogoElement; @@ -371,14 +408,14 @@ declare namespace LocalJSX { interface EasycreditCheckout { "alert"?: string; "amount"?: number; - /** - * Disable Flexprice in calculation - */ "disableFlexprice"?: boolean; "isActive"?: boolean; "paymentPlan"?: string; + "paymentType"?: METHODS; "webshopId"?: string; } + interface EasycreditCheckoutBillPaymentTimeline { + } interface EasycreditCheckoutInstallments { "installments"?: any; "onSelectedInstallment"?: (event: EasycreditCheckoutInstallmentsCustomEvent) => void; @@ -387,25 +424,39 @@ declare namespace LocalJSX { } interface EasycreditCheckoutLabel { "label"?: string; + "paymentType"?: METHODS; "slogan"?: string; } interface EasycreditCheckoutPrivacyApproval { "webshopId"?: string; } + interface EasycreditCheckoutTotals { + "amount"?: number; + "installmentPlans"?: InstallmentPlans; + "selectedInstallment"?: InstallmentPlan; + } interface EasycreditExpressButton { - "alert"?: string; "amount"?: number; - "bgBlue"?: boolean; "fullWidth"?: boolean; + "paymentTypes"?: string; "redirectUrl"?: string; "webshopId"?: string; } + interface EasycreditExpressButtonSingle { + "amount"?: number; + "bgBlue"?: boolean; + "fullWidth"?: boolean; + "onButtonClicked"?: (event: EasycreditExpressButtonSingleCustomEvent) => void; + "paymentType"?: METHODS; + "webshopId"?: string; + } interface EasycreditFaq { } interface EasycreditInfopage { } interface EasycreditLogo { "alt"?: string; + "paymentType"?: METHODS; } interface EasycreditMerchantManager { "date"?: string; @@ -427,25 +478,11 @@ declare namespace LocalJSX { "size"?: string; } interface EasycreditWidget { - /** - * Financing Amount - */ "amount"?: number; - /** - * Disable Flexprice in calculation - */ "disableFlexprice"?: boolean; - /** - * Display Type (e.g. clean -> without shadow) - */ "displayType"?: string; - /** - * Show if out of range - */ "extended"?: boolean; - /** - * Webshop Id - */ + "paymentTypes"?: string; "webshopId"?: string; } interface IntrinsicElements { @@ -457,10 +494,13 @@ declare namespace LocalJSX { "easycredit-box-modal": EasycreditBoxModal; "easycredit-box-top": EasycreditBoxTop; "easycredit-checkout": EasycreditCheckout; + "easycredit-checkout-bill-payment-timeline": EasycreditCheckoutBillPaymentTimeline; "easycredit-checkout-installments": EasycreditCheckoutInstallments; "easycredit-checkout-label": EasycreditCheckoutLabel; "easycredit-checkout-privacy-approval": EasycreditCheckoutPrivacyApproval; + "easycredit-checkout-totals": EasycreditCheckoutTotals; "easycredit-express-button": EasycreditExpressButton; + "easycredit-express-button-single": EasycreditExpressButtonSingle; "easycredit-faq": EasycreditFaq; "easycredit-infopage": EasycreditInfopage; "easycredit-logo": EasycreditLogo; @@ -482,10 +522,13 @@ declare module "@stencil/core" { "easycredit-box-modal": LocalJSX.EasycreditBoxModal & JSXBase.HTMLAttributes; "easycredit-box-top": LocalJSX.EasycreditBoxTop & JSXBase.HTMLAttributes; "easycredit-checkout": LocalJSX.EasycreditCheckout & JSXBase.HTMLAttributes; + "easycredit-checkout-bill-payment-timeline": LocalJSX.EasycreditCheckoutBillPaymentTimeline & JSXBase.HTMLAttributes; "easycredit-checkout-installments": LocalJSX.EasycreditCheckoutInstallments & JSXBase.HTMLAttributes; "easycredit-checkout-label": LocalJSX.EasycreditCheckoutLabel & JSXBase.HTMLAttributes; "easycredit-checkout-privacy-approval": LocalJSX.EasycreditCheckoutPrivacyApproval & JSXBase.HTMLAttributes; + "easycredit-checkout-totals": LocalJSX.EasycreditCheckoutTotals & JSXBase.HTMLAttributes; "easycredit-express-button": LocalJSX.EasycreditExpressButton & JSXBase.HTMLAttributes; + "easycredit-express-button-single": LocalJSX.EasycreditExpressButtonSingle & JSXBase.HTMLAttributes; "easycredit-faq": LocalJSX.EasycreditFaq & JSXBase.HTMLAttributes; "easycredit-infopage": LocalJSX.EasycreditInfopage & JSXBase.HTMLAttributes; "easycredit-logo": LocalJSX.EasycreditLogo & JSXBase.HTMLAttributes; diff --git a/src/components/easycredit-base/assets/easycredit-logo.svg b/src/components/easycredit-base/assets/easycredit-logo.svg new file mode 100644 index 0000000..765fb11 --- /dev/null +++ b/src/components/easycredit-base/assets/easycredit-logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/easycredit-base/assets/icon-info.svg b/src/components/easycredit-base/assets/icon-info.svg new file mode 100644 index 0000000..0513097 --- /dev/null +++ b/src/components/easycredit-base/assets/icon-info.svg @@ -0,0 +1 @@ + diff --git a/src/components/easycredit-base/assets/icon-shipping.svg b/src/components/easycredit-base/assets/icon-shipping.svg new file mode 100644 index 0000000..d379830 --- /dev/null +++ b/src/components/easycredit-base/assets/icon-shipping.svg @@ -0,0 +1 @@ + diff --git a/src/components/easycredit-base/assets/rechnungskauf-logo.svg b/src/components/easycredit-base/assets/rechnungskauf-logo.svg new file mode 100644 index 0000000..dcfa7d0 --- /dev/null +++ b/src/components/easycredit-base/assets/rechnungskauf-logo.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/components/easycredit-box-listing/easycredit-box-listing.scss b/src/components/easycredit-box-listing/easycredit-box-listing.scss index b3a3b15..a56b43d 100644 --- a/src/components/easycredit-box-listing/easycredit-box-listing.scss +++ b/src/components/easycredit-box-listing/easycredit-box-listing.scss @@ -42,7 +42,7 @@ z-index: 4; } - &.circle { + &.ec-circle { z-index: 1; } } @@ -87,7 +87,7 @@ } &__content-heading { margin-bottom: 15px; - font-size: $font-size-heading-sm; + font-size: $font-size-lg; line-height: $line-height-heading-lg; font-weight: bold; } @@ -118,7 +118,7 @@ opacity: 1; } - .circle { + .ec-circle { animation-name: circle-rotation-out; animation-duration: 1s; opacity: 0; diff --git a/src/components/easycredit-box-listing/easycredit-box-listing.tsx b/src/components/easycredit-box-listing/easycredit-box-listing.tsx index 4399cbc..49e2657 100644 --- a/src/components/easycredit-box-listing/easycredit-box-listing.tsx +++ b/src/components/easycredit-box-listing/easycredit-box-listing.tsx @@ -60,8 +60,8 @@ export class EasycreditBoxListing { ['layout-' + this.listingLayout]: this.listingLayout !== '', }} ref={(el) => this.listingElement = el as HTMLElement}>
-
-
+
+
diff --git a/src/components/easycredit-box-modal/easycredit-box-modal.scss b/src/components/easycredit-box-modal/easycredit-box-modal.scss index 504dbf3..1724a55 100644 --- a/src/components/easycredit-box-modal/easycredit-box-modal.scss +++ b/src/components/easycredit-box-modal/easycredit-box-modal.scss @@ -94,7 +94,7 @@ z-index: 4; } - &.circle { + &.ec-circle { z-index: 1; } } @@ -159,10 +159,10 @@ width: 100%; height: 220px; - .circle { + .ec-circle { width: $circle-width-33; } - .circle-secondary { + .ec-circle-secondary { width: $circle-width-33-secondary; } } diff --git a/src/components/easycredit-box-modal/easycredit-box-modal.tsx b/src/components/easycredit-box-modal/easycredit-box-modal.tsx index 9a3fcd3..ba9cfe4 100644 --- a/src/components/easycredit-box-modal/easycredit-box-modal.tsx +++ b/src/components/easycredit-box-modal/easycredit-box-modal.tsx @@ -60,8 +60,8 @@ export class EasycreditBoxModal {
this.toggle()}>
-
-
+
+
diff --git a/src/components/easycredit-checkout-bill-payment-timeline/easycredit-checkout-bill-payment-timeline.scss b/src/components/easycredit-checkout-bill-payment-timeline/easycredit-checkout-bill-payment-timeline.scss new file mode 100644 index 0000000..3e6d5f8 --- /dev/null +++ b/src/components/easycredit-checkout-bill-payment-timeline/easycredit-checkout-bill-payment-timeline.scss @@ -0,0 +1,201 @@ +.ec-checkout { + &__timeline { + margin-bottom: 10px; + padding: 20px 5px 5px 5px; + + background-color: $white; + border-radius: $border-radius-xl; + border: 2px solid $ec-gray; + } + + &__animation-information { + display: flex; + justify-content: space-between; + margin-bottom: 10px; + padding: 0 17px; + color: $ec-darkblue; + + span { + font-size: $font-size; + line-height: $line-height; + } + } + + &__animation { + display: flex; + align-items: center; + justify-content: space-between; + position: relative; + padding: 0 5px; + margin: 35px 6px; + } + + @keyframes highlightBullet { + + 0%, + 100% { + background: $ec-gray; + } + + 5% { + background: $ec-secondary; + } + + 10% { + background: $ec-gray; + } + } + + @keyframes swapStartAfter { + + 0%, + 7% { + background: $ec-secondary; + border: 2px solid $ec-secondary; + } + + 21% { + background: $white; + border: 2px solid $ec-secondary; + } + + 28% { + background: $white; + border: 2px solid $ec-secondary; + } + + 90% { + background: $white; + border: 2px solid $ec-secondary; + } + + 95%, + 100% { + background: $ec-secondary; + border: 2px solid $ec-secondary; + } + } + + @keyframes swapEndAfter { + + 0%, + 7% { + background: $white; + border: 2px solid $ec-secondary; + } + + 21% { + background: $ec-secondary; + } + + 28% { + background: $ec-secondary; + } + + 90% { + background: $ec-secondary; + } + + 95%, + 100% { + background: $white; + border: 2px solid $ec-secondary; + } + } + + &__animation-bullets { + overflow: hidden; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + } + + &__animation-bullet { + min-width: 5px; + height: 5px; + border-radius: 5px; + margin-right: 7px; + background: $ec-gray; + animation: highlightBullet 5s linear infinite; + animation-delay: calc(var(--bullet-index) * 0.057s); + } + + @media (max-width: 380px) { + &__animation-bullet:nth-last-child(-n+5) { + display: none; + } + } + + &__animation-start { + min-width: 27px; + height: 27px; + border-radius: 27px; + background: $ec-gray; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + left: 0; + transition: background 0.3s ease, border-color 0.3s ease; + + &:after { + content: ""; + width: 13px; + height: 13px; + border-radius: 15px; + box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.25); + animation: swapStartAfter 5s linear infinite; + background: $ec-secondary; + border: 2px solid transparent; + } + } + + &__animation-end { + min-width: 27px; + height: 27px; + border-radius: 27px; + background: $ec-gray; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + right: 0; + transition: background 0.3s ease, border-color 0.3s ease; + + &:after { + content: ""; + width: 13px; + height: 13px; + border-radius: 15px; + box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.25); + animation: swapEndAfter 5s linear infinite; + background: $white; + border: 2px solid $ec-secondary; + } + } + + &__information { + background: $ec-darkblue; + color: $white; + text-align: center; + font-size: $font-size-sm; + line-height: $line-height; + font-weight: bold; + padding: 10px 15px; + border-radius: $border-radius-lg-xl; + align-items: center; + display: flex; + justify-content: center; + + .icon { + @include background-svg($icon-shipping); + background-position: center; + background-repeat: no-repeat; + background-size: contain; + height: 25px; + width: 25px; + margin-right: 10px; + } + } +} diff --git a/src/components/easycredit-checkout-bill-payment-timeline/easycredit-checkout-bill-payment-timeline.tsx b/src/components/easycredit-checkout-bill-payment-timeline/easycredit-checkout-bill-payment-timeline.tsx new file mode 100644 index 0000000..b1dedfb --- /dev/null +++ b/src/components/easycredit-checkout-bill-payment-timeline/easycredit-checkout-bill-payment-timeline.tsx @@ -0,0 +1,55 @@ +import { Component, h } from '@stencil/core'; +// import { applyAssetsUrl, getAssetUrl } from '../../utils/utils'; + +@Component({ + tag: 'easycredit-checkout-bill-payment-timeline', + styleUrl: 'easycredit-checkout-bill-payment-timeline.scss' +}) + +export class EasycreditCheckoutBillPaymentTimeline { + render() { + return [ +
+
+ Heute
bestellen
+ in 30 Tagen
bezahlen
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
Ihre Ware wird direkt versandt. +
+
+ ] + } +} \ No newline at end of file diff --git a/src/components/easycredit-checkout-bill-payment-timeline/readme.md b/src/components/easycredit-checkout-bill-payment-timeline/readme.md new file mode 100644 index 0000000..8ad6040 --- /dev/null +++ b/src/components/easycredit-checkout-bill-payment-timeline/readme.md @@ -0,0 +1,25 @@ +# easycredit-checkout-bill-payment-timeline + + + + + + +## Dependencies + +### Used by + + - [easycredit-checkout](../easycredit-checkout) + - [easycredit-express-button](../easycredit-express-button) + +### Graph +```mermaid +graph TD; + easycredit-checkout --> easycredit-checkout-bill-payment-timeline + easycredit-express-button --> easycredit-checkout-bill-payment-timeline + style easycredit-checkout-bill-payment-timeline fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/easycredit-checkout-installments/easycredit-checkout-installments.scss b/src/components/easycredit-checkout-installments/easycredit-checkout-installments.scss index 8a59a5f..1fd04c6 100644 --- a/src/components/easycredit-checkout-installments/easycredit-checkout-installments.scss +++ b/src/components/easycredit-checkout-installments/easycredit-checkout-installments.scss @@ -3,6 +3,7 @@ margin: 0; padding: 0; list-style: none; + background-color: $white; border-width: 0 2px; border-style: solid; border-color: $ec-gray-2; @@ -91,7 +92,7 @@ border-width: 2px; border-style: solid; border-color: transparent; - border-radius: $border-radius-lg; + border-radius: $border-radius-lg-xl; cursor: pointer; transition: color .1s $transition-timing, background-color .1s $transition-timing, border-color .1s $transition-timing; diff --git a/src/components/easycredit-checkout-installments/easycredit-checkout-installments.tsx b/src/components/easycredit-checkout-installments/easycredit-checkout-installments.tsx index d468ee9..743328f 100644 --- a/src/components/easycredit-checkout-installments/easycredit-checkout-installments.tsx +++ b/src/components/easycredit-checkout-installments/easycredit-checkout-installments.tsx @@ -3,7 +3,8 @@ import { formatCurrency, sendFeedback } from '../../utils/utils'; @Component({ tag: 'easycredit-checkout-installments', - styleUrl: 'easycredit-checkout-installments.scss' + styleUrl: 'easycredit-checkout-installments.scss', + shadow: true }) export class EasycreditCheckoutInstallments { @@ -17,6 +18,8 @@ export class EasycreditCheckoutInstallments { @State() _installments @State() selectedInstallmentValue: number + installmentsBase!: HTMLElement; + @Listen('selectedInstallment') selectedInstallmentHandler(e) { this.selectedInstallmentValue = e.detail @@ -24,11 +27,12 @@ export class EasycreditCheckoutInstallments { @Watch('installments') parseInstallmentsProp(newValue: string) { - if (newValue) this._installments = JSON.parse(newValue); + if (newValue) { + this._installments = JSON.parse(newValue) + .sort((a,b) => parseFloat(a.installment) - parseFloat(b.installment)) + } } - installmentsBase!: HTMLElement; - async componentWillLoad () { this.parseInstallmentsProp(this.installments); } diff --git a/src/components/easycredit-checkout-installments/readme.md b/src/components/easycredit-checkout-installments/readme.md index 23f67f0..4bbd7dd 100644 --- a/src/components/easycredit-checkout-installments/readme.md +++ b/src/components/easycredit-checkout-installments/readme.md @@ -26,11 +26,13 @@ ### Used by - [easycredit-checkout](../easycredit-checkout) + - [easycredit-express-button](../easycredit-express-button) ### Graph ```mermaid graph TD; easycredit-checkout --> easycredit-checkout-installments + easycredit-express-button --> easycredit-checkout-installments style easycredit-checkout-installments fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/easycredit-checkout-label/easycredit-checkout-label.scss b/src/components/easycredit-checkout-label/easycredit-checkout-label.scss index 89105fb..5866fc3 100644 --- a/src/components/easycredit-checkout-label/easycredit-checkout-label.scss +++ b/src/components/easycredit-checkout-label/easycredit-checkout-label.scss @@ -17,11 +17,18 @@ top: 50%; transform: translateY(-50%); - @extend .logo-ratenkauf; + &-installment { + @extend .logo-ratenkauf; + } + &-bill { + @extend .logo-rechnungskauf; + } + display: block; width: 60px; - height: 29px; + height: 100%; background-position: right center; + background-size: 100% auto; } strong { diff --git a/src/components/easycredit-checkout-label/easycredit-checkout-label.stories.tsx b/src/components/easycredit-checkout-label/easycredit-checkout-label.stories.tsx index 322e7f1..7b365d8 100644 --- a/src/components/easycredit-checkout-label/easycredit-checkout-label.stories.tsx +++ b/src/components/easycredit-checkout-label/easycredit-checkout-label.stories.tsx @@ -1,4 +1,5 @@ import { buildAttributes } from '../../../.storybook/helpers' +import { METHODS } from '../../types'; export default { title: "Checkout/Label", @@ -11,18 +12,33 @@ export default { } }, argTypes: { + paymentType: { + table: { + defaultValue: { summary: "INSTALLMENT" }, + category: "optional", + }, + description: 'Zahlungsart', + options: [METHODS.INSTALLMENT, METHODS.BILL], + control: { type: 'radio' }, + }, label: { + table: { + category: "optional", + }, description: 'Titel' }, slogan: { + table: { + category: "optional", + }, description: 'Untertitel' } - }, }; let args = { + paymentType: METHODS.INSTALLMENT, label: '', slogan: '' } diff --git a/src/components/easycredit-checkout-label/easycredit-checkout-label.tsx b/src/components/easycredit-checkout-label/easycredit-checkout-label.tsx index b68493f..8bacc16 100644 --- a/src/components/easycredit-checkout-label/easycredit-checkout-label.tsx +++ b/src/components/easycredit-checkout-label/easycredit-checkout-label.tsx @@ -1,5 +1,6 @@ import { Component, Prop, h } from '@stencil/core'; import { applyAssetsUrl } from '../../utils/utils'; +import { METHODS } from '../../types'; @Component({ tag: 'easycredit-checkout-label', @@ -9,13 +10,24 @@ import { applyAssetsUrl } from '../../utils/utils'; export class EasycreditCheckoutLabel { - @Prop({ mutable: true }) label: string = 'easyCredit-Ratenkauf'; - @Prop({ mutable: true }) slogan: string = 'Ganz entspannt in Raten zahlen.'; + @Prop({ mutable: true }) label: string + @Prop({ mutable: true }) slogan: string + @Prop({ mutable: true}) paymentType: METHODS = METHODS.INSTALLMENT connectedCallback() { applyAssetsUrl(EasycreditCheckoutLabel) } + componentWillLoad() { + if (this.paymentType === METHODS.INSTALLMENT) { + this.label ??= 'easyCredit-Ratenkauf' + this.slogan ??= 'Ganz entspannt in Raten zahlen.' + } else if (this.paymentType === METHODS.BILL) { + this.label ??= 'easyCredit-Rechnung' + this.slogan ??= 'Erst kaufen, in 30 Tagen bezahlen.' + } + } + render() { return ([ @@ -24,7 +36,11 @@ export class EasycreditCheckoutLabel { {this.label}
{this.slogan} - +
]) diff --git a/src/components/easycredit-checkout-label/readme.md b/src/components/easycredit-checkout-label/readme.md index bf0d4e1..81c80f9 100644 --- a/src/components/easycredit-checkout-label/readme.md +++ b/src/components/easycredit-checkout-label/readme.md @@ -7,10 +7,11 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| -------- | --------- | ----------- | -------- | ----------------------------------- | -| `label` | `label` | | `string` | `'easyCredit-Ratenkauf'` | -| `slogan` | `slogan` | | `string` | `'Ganz entspannt in Raten zahlen.'` | +| Property | Attribute | Description | Type | Default | +| ------------- | -------------- | ----------- | ------------------------------------- | --------------------- | +| `label` | `label` | | `string` | `undefined` | +| `paymentType` | `payment-type` | | `METHODS.BILL \| METHODS.INSTALLMENT` | `METHODS.INSTALLMENT` | +| `slogan` | `slogan` | | `string` | `undefined` | ---------------------------------------------- diff --git a/src/components/easycredit-checkout-privacy-approval/easycredit-checkout-privacy-approval.tsx b/src/components/easycredit-checkout-privacy-approval/easycredit-checkout-privacy-approval.tsx index 199a0ce..b708b7e 100644 --- a/src/components/easycredit-checkout-privacy-approval/easycredit-checkout-privacy-approval.tsx +++ b/src/components/easycredit-checkout-privacy-approval/easycredit-checkout-privacy-approval.tsx @@ -1,5 +1,6 @@ import { Component, h, State, Prop } from '@stencil/core'; -import { fetchAgreement } from '../../utils/utils'; +import { getWebshopInfo } from '../../utils/utils'; +import state from '../../stores/general'; @Component({ tag: 'easycredit-checkout-privacy-approval', @@ -13,13 +14,12 @@ export class EasycreditCheckoutPrivacyApproval { @State() privacyApprovalForm: string async componentWillLoad () { - fetchAgreement(this.webshopId).then(data => { - this.privacyApprovalForm = data.privacyApprovalForm - }).catch(e => { - console.error(e) - // this.alert = 'Es ist ein Fehler aufgetreten.' - }) - } + try { + getWebshopInfo(this.webshopId) + } catch (e) { + console.error(e) + } + } render () { return ([ @@ -27,7 +27,7 @@ export class EasycreditCheckoutPrivacyApproval { {/*

Mit Klick auf Akzeptieren stimmen Sie der Datenübermittlung zu:

*/}
diff --git a/src/components/easycredit-checkout-totals/easycredit-checkout-totals.scss b/src/components/easycredit-checkout-totals/easycredit-checkout-totals.scss new file mode 100644 index 0000000..c266d4c --- /dev/null +++ b/src/components/easycredit-checkout-totals/easycredit-checkout-totals.scss @@ -0,0 +1,53 @@ +.ec-checkout { + &__totals { + margin-top: 10px; + margin-bottom: 20px; + list-style: none; + padding: 16px 15px; + background-color: $ec-gray; + border-radius: $border-radius-xl; + color: $font-color; + + li { + display: flex; + justify-content: space-between; + padding: 2px 0; + + &.total { + font-weight: bold; + } + } + } + + &__actions { + margin-top: 20px; + margin-bottom: 20px; + } + + &__small-print { + margin-top: 20px; + margin-bottom: 0; + color: #8095AC; + + small { + display: block; + font-size: $font-size-xxs; + line-height: $line-height; + } + } +} + +// Rules for IE10 and above +@media all and (-ms-high-contrast:none) { + easycredit-checkout-installments { + display: none; + } + + .ec-checkout__totals { + display: none; + } + + .ec-checkout__small-print { + display: none; + } +} diff --git a/src/components/easycredit-checkout-totals/easycredit-checkout-totals.tsx b/src/components/easycredit-checkout-totals/easycredit-checkout-totals.tsx new file mode 100644 index 0000000..bbfd347 --- /dev/null +++ b/src/components/easycredit-checkout-totals/easycredit-checkout-totals.tsx @@ -0,0 +1,76 @@ +import { Component, Prop, h } from '@stencil/core'; +import { formatCurrency } from '../../utils/utils'; +import { InstallmentPlan, InstallmentPlans } from '../../types'; +import Fragment from 'stencil-fragment' + +@Component({ + tag: 'easycredit-checkout-totals', + styleUrl: 'easycredit-checkout-totals.scss', + shadow: true, +}) + +export class EasycreditCheckoutTotals { + + @Prop() amount: number + @Prop() selectedInstallment: InstallmentPlan = null + @Prop() installmentPlans: InstallmentPlans = null + + componentWillLoad() { + this.resetSelectedInstallment() + } + + componentWillRender() { + if (!this.selectedInstallment) { + this.resetSelectedInstallment() + } + } + + resetSelectedInstallment() { + this.selectedInstallment = { + installment: 0, + lastInstallment: 0, + numberOfInstallments: 0, + totalInterest: 0, + totalValue: this.amount + } + } + + /*@Listen('selectedInstallment') + selectedInstallmentHandler(e) { + this.selectedInstallment = this.installmentPlans.plans.find(i => i.numberOfInstallments == e.detail) + }*/ + + render () { + return
+
    + {this.amount !== this.selectedInstallment.totalValue && + +
  • + Kaufbetrag + { formatCurrency(this.amount) } +
  • +
  • + + Zinsen + { formatCurrency(this.selectedInstallment.totalInterest) } +
  • +
    + } + +
  • + Gesamtbetrag + { formatCurrency(this.selectedInstallment.totalValue) } +
  • +
+ + + + {this.installmentPlans && + this.amount !== this.selectedInstallment.totalValue && +

+ +

+ } + +
+ } +} \ No newline at end of file diff --git a/src/components/easycredit-checkout-totals/readme.md b/src/components/easycredit-checkout-totals/readme.md new file mode 100644 index 0000000..ebc02aa --- /dev/null +++ b/src/components/easycredit-checkout-totals/readme.md @@ -0,0 +1,34 @@ +# easycredit-checkout-totals + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| --------------------- | --------- | ----------- | ------------------ | ----------- | +| `amount` | `amount` | | `number` | `undefined` | +| `installmentPlans` | -- | | `InstallmentPlans` | `null` | +| `selectedInstallment` | -- | | `InstallmentPlan` | `null` | + + +## Dependencies + +### Used by + + - [easycredit-checkout](../easycredit-checkout) + - [easycredit-express-button](../easycredit-express-button) + +### Graph +```mermaid +graph TD; + easycredit-checkout --> easycredit-checkout-totals + easycredit-express-button --> easycredit-checkout-totals + style easycredit-checkout-totals fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/easycredit-checkout/easycredit-checkout.scss b/src/components/easycredit-checkout/easycredit-checkout.scss index 18dbc49..f77c2fb 100644 --- a/src/components/easycredit-checkout/easycredit-checkout.scss +++ b/src/components/easycredit-checkout/easycredit-checkout.scss @@ -80,6 +80,32 @@ } } + .h4 { + margin-bottom: 10px; + color: $font-color; + } + + &__usp { + list-style: none; + margin-top: 0; + margin-bottom: 20px; + padding: 0; + + li { + margin-bottom: 5px; + padding-left: 26px; + + @include background-svg($icon-checkmark-circle); + background-position: left center; + background-repeat: no-repeat; + background-size: 16px 16px; + + font-size: $font-size-sm; + line-height: $line-height; + color: $font-color; + } + } + &__instalments { margin: 0; padding: 0; @@ -214,35 +240,15 @@ } } - &__totals { - margin-top: 10px; - margin-bottom: 20px; - list-style: none; - padding: 16px 15px; - background-color: $ec-gray; - border-radius: $border-radius-xl; - color: $font-color; - - li { - display: flex; - justify-content: space-between; - padding: 2px 0; - - &.total { - font-weight: bold; - } - } - } - - &__actions { - margin-top: 20px; - margin-bottom: 20px; - } - &__small-print { margin-top: 20px; - margin-bottom: 0; - color: rgba($font-color,.5); + color: #8095AC; + + small { + display: block; + font-size: $font-size-xxs; + line-height: $line-height; + } } .ec-payment-plan { @@ -254,11 +260,4 @@ margin-top: 10px; } } - - // Rules for IE10 and above - @media all and (-ms-high-contrast:none) { - easycredit-checkout-installments { display: none; } - .ec-checkout__totals { display: none; } - .ec-checkout__small-print { display: none; } - } } diff --git a/src/components/easycredit-checkout/easycredit-checkout.stories.tsx b/src/components/easycredit-checkout/easycredit-checkout.stories.tsx index 881eda8..0c82f91 100644 --- a/src/components/easycredit-checkout/easycredit-checkout.stories.tsx +++ b/src/components/easycredit-checkout/easycredit-checkout.stories.tsx @@ -1,4 +1,5 @@ import { buildAttributes } from '../../../.storybook/helpers' +import { METHODS } from '../../types'; export default { title: "Checkout/Checkout", @@ -6,9 +7,9 @@ export default { docs: { description: { component: - `Die Checkout-Komponente ermöglicht eine Interaktion mit dem Ratenkauf bereits im Online-Shop, noch vor Weiterleitung auf die PaymentPage. Die Komponente wird typischerweise in Verbindung mit dem Checkout-Label verwendet und erst dann angezeigt, wenn der Kunde die Zahlart in der Zahlartenauswahl gewählt hat. Die Komponente enthält ein Modal, welches die Zustimmung des Kunden zur Datenweitergabe ermöglicht, bevor er auf die PaymentPage weitergeleitet wird. Die Zustimmungserklärung ist für den jeweiligen Händler personalisiert. + `Die Checkout-Komponente ermöglicht eine Interaktion mit easyCredit bereits im Online-Shop, noch vor Weiterleitung auf die PaymentPage. Die Komponente wird typischerweise in Verbindung mit dem Checkout-Label verwendet und erst dann angezeigt, wenn der Kunde die Zahlart in der Zahlartenauswahl gewählt hat. Die Komponente enthält ein Modal, welches die Zustimmung des Kunden zur Datenweitergabe ermöglicht, bevor er auf die PaymentPage weitergeleitet wird. Die Zustimmungserklärung ist für den jeweiligen Händler personalisiert und wird dynamisch bezogen. -Sobald der Kunde die PaymentPage durchlaufen hat, zeigt das Widget die vom Kunden gewählten Raten statt der Ratenauswahl an. Ist ein Fehler aufgetreten, z.B. wenn der Betrag außerhalb der erlaubten Finanzierungsbeträge liegt, so wird stattdessen der entsprechende Fehler angezeigt.`, +Sobald der Kunde die PaymentPage durchlaufen hat, zeigt das Widget die vom Kunden die Auswahl des Kunden an (${'`paymentPlan`'}). Beim Ratenkauf werden die gewählten Raten gezeigt, beim Rechnungskauf die Zeitleiste bis zur tatsächlichen Zahlung. Ist ein Fehler aufgetreten, z.B. wenn der Betrag außerhalb der erlaubten Finanzierungsbeträge liegt, so wird stattdessen der entsprechende Fehler angezeigt (${'`alert`'})`, } } }, @@ -16,6 +17,10 @@ Sobald der Kunde die PaymentPage durchlaufen hat, zeigt das Widget die vom Kunde webshopId: { description: "die Kennung des Webshops", }, + paymentType: { + options: [METHODS.INSTALLMENT, METHODS.BILL], + control: { type: 'radio' }, + }, amount: { description: "der zu finanzierende Betrag für den die Ratenauswahl angezeigt werden soll", }, @@ -36,17 +41,18 @@ Sobald der Kunde die PaymentPage durchlaufen hat, zeigt das Widget die vom Kunde table: { category: "Events", }, - description: "Wird ausgelöst bei Klick auf 'Akzeptieren'", + description: "Wird ausgelöst bei Klick auf 'Akzeptieren' / 'Weiter zum Rechnungskauf'", } }, }; let args = { - webshopId: '2.de.9999.9999', + webshopId: '2.de.7387.2', amount: 820.31, isActive: true, alert: '', - paymentPlan: '' + paymentPlan: '', + paymentType: METHODS.INSTALLMENT } const Template = (args) => { @@ -59,25 +65,48 @@ const Template = (args) => { const TemplateExample = (args) => { return Template(args) + ` ` } export const CheckoutInitial = TemplateExample.bind({}) -CheckoutInitial.storyName = 'initial' +CheckoutInitial.storyName = 'Ratenkauf (initial)' CheckoutInitial.args = args export const CheckoutCalculated = Template.bind({}) -CheckoutCalculated.storyName = 'berechnet' +CheckoutCalculated.storyName = 'Ratenkauf (berechnet)' CheckoutCalculated.args = { ...args, ... { paymentPlan: '{"orderValue":7702.06,"interest":1803.42,"totalValue":9505.48,"decisionOutcome":"POSITIVE","numberOfInstallments":60,"installment":159,"lastInstallment":124.48,"mtan":{"required":false,"successful":false},"bankAccountCheck":{"required":false}}' }} +export const CheckoutInitialBillPayment = TemplateExample.bind({}) +CheckoutInitialBillPayment.storyName = 'Rechnungskauf (initial)' +CheckoutInitialBillPayment.args = { + ...args, ... { + paymentType: METHODS.BILL + } +} + +export const CheckoutCalculatedBillPayment = Template.bind({}) +CheckoutCalculatedBillPayment.storyName = 'Rechnungskauf (berechnet)' +CheckoutCalculatedBillPayment.args = { + ...args, ... { + paymentType: METHODS.BILL, + paymentPlan: '{"orderValue":7702.06,"interest":1803.42,"totalValue":9505.48,"decisionOutcome":"POSITIVE","numberOfInstallments":60,"installment":159,"lastInstallment":124.48,"mtan":{"required":false,"successful":false},"bankAccountCheck":{"required":false}}' + } +} + export const CheckoutError = Template.bind({}) CheckoutError.storyName = 'Fehler' CheckoutError.args = args diff --git a/src/components/easycredit-checkout/easycredit-checkout.tsx b/src/components/easycredit-checkout/easycredit-checkout.tsx index 0d2dd4a..352b9cb 100644 --- a/src/components/easycredit-checkout/easycredit-checkout.tsx +++ b/src/components/easycredit-checkout/easycredit-checkout.tsx @@ -1,5 +1,8 @@ -import { Component, Prop, State, Listen, Element, h } from '@stencil/core'; -import { formatCurrency, fetchInstallmentPlans, fetchSingleInstallmentPlan, fetchAgreement, sendFeedback, addErrorHandler } from '../../utils/utils'; +import { Component, Prop, State, Listen, Element, Watch, h } from '@stencil/core'; +import { formatCurrency, fetchInstallmentPlans, validateInstallmentPlans, getWebshopInfo, sendFeedback, addErrorHandler } from '../../utils/utils'; +import { validateAmount, Caps } from '../../utils/validation'; +import { InstallmentPlan, InstallmentPlans, METHODS } from '../../types'; +import state from '../../stores/general' @Component({ tag: 'easycredit-checkout', @@ -10,37 +13,26 @@ import { formatCurrency, fetchInstallmentPlans, fetchSingleInstallmentPlan, fetc export class EasycreditCheckout { @Prop() isActive: boolean = true - @Prop() amount: number + @Prop({ mutable: true }) amount: number @Prop() webshopId: string @Prop() alert: string @Prop() paymentPlan: string - - /** - * Disable Flexprice in calculation - */ + @Prop() paymentType: METHODS = METHODS.INSTALLMENT @Prop() disableFlexprice: boolean = false - @State() privacyApprovalForm: string - @State() acceptButtonClicked: boolean = false - - @State() totals = { - interest: 0, - total: 0 - } - @State() installments - @State() selectedInstallment = { - totalInterest: 0, - totalValue: 0, - numberOfInstallments: 0 - } - @State() example + @State() isInitialized: boolean = false + @State() submitButtonClicked: boolean = false + @State() installmentPlans: InstallmentPlans = null + @State() selectedInstallment: InstallmentPlan = null @State() submitDisabled = false modal!: HTMLEasycreditModalElement; + caps: Caps + @Listen('selectedInstallment') selectedInstallmentHandler(e) { - this.selectedInstallment = this.installments.find(i => i.numberOfInstallments == e.detail) + this.selectedInstallment = this.installmentPlans.plans.find(i => i.numberOfInstallments == e.detail) } @Listen('openModal') @@ -53,56 +45,46 @@ export class EasycreditCheckout { this.modal.close() } + isEnabled(type: METHODS) { + return this.caps.isEnabled(type) + } + async componentWillLoad () { + this.caps = new Caps(this.paymentType) + if (this.amount > 0 && !this.alert && !this.paymentPlan) { - const fetchPlans = (this.disableFlexprice) ? - fetchSingleInstallmentPlan.bind(this, this.webshopId, this.amount, { 'withoutFlexprice': true }) : - fetchInstallmentPlans.bind(this, this.webshopId, this.amount) + try { + await getWebshopInfo(this.webshopId) + validateAmount(this.amount, this.paymentType) - await fetchPlans().then((data) => { - if (!data) { - return + if (this.isEnabled(METHODS.INSTALLMENT)) { + const opts = this.disableFlexprice ? { 'withoutFlexprice': this.disableFlexprice } : null + const installmentPlans = await fetchInstallmentPlans(this.webshopId, this.amount, opts) + this.installmentPlans = validateInstallmentPlans(installmentPlans) } - const installment = data.installmentPlans.find(() => true) - if (installment.errors) { - this.alert = installment.errors.violations.find(()=>true).message - if (installment.errors.title === 'INVALID_PRICE') { - this.alert = `Der Finanzierungbetrag liegt außerhalb der zulässigen Beträge (${data.minFinancingAmount} € - ${data.maxFinancingAmount} €)` - } - return - } - - this.installments = installment.plans.reverse() - this.example = installment.example - }).catch(e => { - console.error(e) - }) - if (this.alert) { - return + } catch (error) { + this.alert = error.message ?? 'Es ist ein Fehler aufgetreten.' } + } + this.isInitialized = true + } - fetchAgreement(this.webshopId).then(data => { - this.privacyApprovalForm = data.privacyApprovalForm - - if (this.amount < data.minFinancingAmount - || this.amount > data.maxFinancingAmount - ) { - } - }).catch(e => { - console.error(e) - this.alert = 'Es ist ein Fehler aufgetreten.' - }) + @Watch('amount') watchAmountHandler() { + try { + validateAmount(this.amount, this.paymentType) + } catch (error) { + this.alert = error.message ?? 'Es ist ein Fehler aufgetreten.' } } @Element() el: HTMLElement; - modalSubmitHandler() { + submitHandler() { sendFeedback(this, { component: 'EasycreditCheckout', action: 'submit' }) - this.acceptButtonClicked = true + this.submitButtonClicked = true addErrorHandler(this, () => { this.alert = 'Leider ist eine Zahlung mit easyCredit derzeit nicht möglich. Bitte verwenden Sie eine andere Zahlungsart oder wenden Sie sich an den Händler.' this.modal.close() @@ -113,7 +95,8 @@ export class EasycreditCheckout { cancelable : true, composed: true, detail: { - numberOfInstallments: this.selectedInstallment.numberOfInstallments + paymentType: this.paymentType, + ...(this.selectedInstallment?.numberOfInstallments && { numberOfInstallments: this.selectedInstallment?.numberOfInstallments }) } })) } @@ -135,7 +118,7 @@ export class EasycreditCheckout { return false } - getPaymentPlanFragment () { + getInstallmentPaymentPlanFragment () { if (!this.getPaymentPlan()) { return null } @@ -158,85 +141,138 @@ export class EasycreditCheckout { } - getCheckoutFragment () { + getBillPaymentPlanFragment () { + if (!this.getPaymentPlan()) { + return null + } + return + } + + getCheckoutInstallmentFragment () { if (this.alert) { - return
- { this.alert } + return + } + + return ([
+ + +
+
+ +
+
+
+ ]) + } + + getCheckoutInstallmentUspFragment () { + if (this.alert) { + return } - return ([
- - -
    -
  • - Kaufbetrag - { formatCurrency(this.amount) } -
  • -
  • - + Zinsen - { formatCurrency(this.selectedInstallment.totalInterest) } -
  • -
  • - Gesamtbetrag - { formatCurrency(this.selectedInstallment.totalValue) } -
  • + return ([
    +
    Ihre Vorteile
    +
      +
    • Frühestens 30 Tage nach Lieferung zahlen
    • +
    • Flexible monatliche Wunschrate
    • +
    • Kostenfreie Ratenanpassung & Sondertilgung
    -

    - + {this.getPrivacyFragment({intro: false})}

    ]) } - getPrivacyFragment() { - return
    -

    Mit Klick auf Akzeptieren stimmen Sie der Datenübermittlung zu:

    + getCheckoutBillPaymentFragment () { + if (this.alert) { + return + } + + return ([
    + + +
    +
    +
    + +
    Ihre Vorteile
    +
      +
    • Frühestens 30 Tage nach Lieferung zahlen
    • +
    • Keine zusätzlichen Kosten
    • +
    + +
    + +
    + +

    + {this.getPrivacyFragment({intro: false})} +

    +
    ]) + } + + getPrivacyFragment({intro = true}) { + const html =
    + { intro &&

    Mit Klick auf Akzeptieren stimmen Sie der Datenübermittlung zu:

    }
    -
    +
    + return html } getModalFragment () { return ([ this.modal = el as HTMLEasycreditModalElement} - onModalClosed={() => this.acceptButtonClicked = false } - onModalSubmit={() => this.modalSubmitHandler()} + onModalClosed={() => this.submitButtonClicked = false } + onModalSubmit={() => this.submitHandler()} >
    Weiter zum Ratenkauf
    - {this.getPrivacyFragment()} + {this.getPrivacyFragment({})}
    Akzeptieren
    ]) } - render() { - if (!this.isActive) { + render() { + if (!this.isInitialized || !this.isActive) { return null } return ([
    - { this.getPaymentPlan() && this.getPaymentPlanFragment() } + { this.isEnabled(METHODS.INSTALLMENT) && this.getPaymentPlan() && this.getInstallmentPaymentPlanFragment() } + { this.isEnabled(METHODS.BILL) && this.getPaymentPlan() && this.getBillPaymentPlanFragment() } { !this.getPaymentPlan() &&
    - { this.getCheckoutFragment() } + { this.alert && +
    + { this.alert } +
    + } + { this.isEnabled(METHODS.INSTALLMENT) && this.getCheckoutInstallmentUspFragment() } + { this.isEnabled(METHODS.BILL) && this.getCheckoutBillPaymentFragment() }
    }
    diff --git a/src/components/easycredit-checkout/readme.md b/src/components/easycredit-checkout/readme.md index a938ac9..2c0a514 100644 --- a/src/components/easycredit-checkout/readme.md +++ b/src/components/easycredit-checkout/readme.md @@ -7,27 +7,32 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------ | ------------------- | -------------------------------- | --------- | ----------- | -| `alert` | `alert` | | `string` | `undefined` | -| `amount` | `amount` | | `number` | `undefined` | -| `disableFlexprice` | `disable-flexprice` | Disable Flexprice in calculation | `boolean` | `false` | -| `isActive` | `is-active` | | `boolean` | `true` | -| `paymentPlan` | `payment-plan` | | `string` | `undefined` | -| `webshopId` | `webshop-id` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------ | ------------------- | ----------- | ------------------------------------- | --------------------- | +| `alert` | `alert` | | `string` | `undefined` | +| `amount` | `amount` | | `number` | `undefined` | +| `disableFlexprice` | `disable-flexprice` | | `boolean` | `false` | +| `isActive` | `is-active` | | `boolean` | `true` | +| `paymentPlan` | `payment-plan` | | `string` | `undefined` | +| `paymentType` | `payment-type` | | `METHODS.BILL \| METHODS.INSTALLMENT` | `METHODS.INSTALLMENT` | +| `webshopId` | `webshop-id` | | `string` | `undefined` | ## Dependencies ### Depends on +- [easycredit-checkout-bill-payment-timeline](../easycredit-checkout-bill-payment-timeline) - [easycredit-checkout-installments](../easycredit-checkout-installments) +- [easycredit-checkout-totals](../easycredit-checkout-totals) - [easycredit-modal](../easycredit-modal) ### Graph ```mermaid graph TD; + easycredit-checkout --> easycredit-checkout-bill-payment-timeline easycredit-checkout --> easycredit-checkout-installments + easycredit-checkout --> easycredit-checkout-totals easycredit-checkout --> easycredit-modal style easycredit-checkout fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/easycredit-express-button-single/easycredit-express-button-single.scss b/src/components/easycredit-express-button-single/easycredit-express-button-single.scss new file mode 100644 index 0000000..d17d2d7 --- /dev/null +++ b/src/components/easycredit-express-button-single/easycredit-express-button-single.scss @@ -0,0 +1,127 @@ +.ec-express-button { + --bg-color: #{$ec-primary}; + --bg-color-hover: #{$ec-primary-btn-hover}; + + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; + margin-bottom: 10px; + + transition: opacity 0.35s ease; + + &__btn { + position: relative; + display: block; + padding: 0 36px; + width: 350px; + max-width: 100%; + height: 45px; + box-sizing: border-box; + + background-color: var(--bg-color); + transition: background-color 0.35s ease; + border-radius: $border-radius-xxxl; + cursor: pointer; + + &:hover { + background-color: var(--bg-color-hover); + color: $white; + } + + // Props + &.blue { + --bg-color: #{$ec-darkblue}; + --bg-color-hover: #{$ec-darkblue-btn-hover}; + } + &.full-width { + width: 100% !important; + } + + a { + color: $white; + } + + &__main { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + + font-size: $font-size; + font-weight: bold; + color: $white; + + svg { + flex: 0 0 auto; + margin-right: 10px; + + &.installment { + flex-basis: 59px; + width: 59px; + height: 28px; + } + + &.bill { + flex-basis: 16px; + width: 16px; + height: 20px; + } + } + + .long { + display: block; + max-width: max(0px, calc((100% - 249.5px)*999)); + overflow: hidden; + text-overflow: ellipsis; + + white-space: nowrap; + color: $white; + } + .short { + display: block; + max-width: max(0px, calc(-100% + 250px)*999); + overflow: hidden; + text-overflow: ellipsis; + + white-space: nowrap; + color: $white; + } + } + } + + &__link { + display: flex; + align-items: center; + justify-content: center; + margin-top: 10px; + width: auto; + max-width: 100%; + + cursor: pointer; + + text-align: center; + font-size: $font-size-xxs; + line-height: $line-height; + color: $font-color !important; + + &:hover { + color: rgba($font-color,.7) !important; + } + + .icon { + flex: 21.5px 0 0; + width: 21.5px; + max-width: 21.5px; + + @extend .logo-finanzgruppe-icon; + display: inline-block; + margin-right: 9px; + height: 15px; + + position: relative; + top: -.5px; + } + } +} diff --git a/src/components/easycredit-express-button-single/easycredit-express-button-single.tsx b/src/components/easycredit-express-button-single/easycredit-express-button-single.tsx new file mode 100644 index 0000000..8dd08b0 --- /dev/null +++ b/src/components/easycredit-express-button-single/easycredit-express-button-single.tsx @@ -0,0 +1,91 @@ +import { Component, Prop, State, Element, h, EventEmitter, Event } from '@stencil/core'; +import { applyAssetsUrl } from '../../utils/utils'; +import { METHODS } from '../../types'; +import { validateAmount } from '../../utils/validation'; + +@Component({ + tag: 'easycredit-express-button-single', + styleUrl: 'easycredit-express-button-single.scss', + shadow: true, +}) + +export class EasycreditExpressButtonSingle { + + @Prop() webshopId: string + @Prop() amount: number + @Prop() bgBlue: boolean = false + @Prop() fullWidth: boolean = false + @Prop() paymentType: METHODS = METHODS.INSTALLMENT + + buttonTextDefault: string = 'Jetzt direkt in Raten zahlen' + buttonTextDefaultShort: string = 'Direkt in Raten zahlen' + + @State() buttonOpacity: string = '0' + @State() buttonText: string = this.buttonTextDefault + @State() buttonTextShort: string = this.buttonTextDefaultShort + + @Element() el: HTMLElement; + + connectedCallback() { + applyAssetsUrl(EasycreditExpressButtonSingle) + } + + async componentWillLoad () { + if (this.paymentType === METHODS.BILL) { + this.bgBlue = true + } + } + + @Event() buttonClicked: EventEmitter; + clickButtonHandler(event: Event) { + event.preventDefault(); + event.stopPropagation(); + this.buttonClicked.emit(this.paymentType) + } + + componentDidLoad () { + this.renderButton() + } + + async renderButton () { + await this.setButtonText() + this.buttonOpacity = '1' + } + + private getLogo(): string { + if (this.paymentType === METHODS.BILL) { + return + } else { + return + } + } + + setButtonText () { + if (this.paymentType === METHODS.BILL) { + this.buttonText = 'Heute bestellen - in 30 Tagen zahlen'; + this.buttonTextShort = 'In 30 Tagen zahlen'; + } + } + + render() { + try { + validateAmount(this.amount, this.paymentType) + } catch (e) { + return + } + + return ([ + + ]) + } +} diff --git a/src/components/easycredit-express-button-single/readme.md b/src/components/easycredit-express-button-single/readme.md new file mode 100644 index 0000000..c968675 --- /dev/null +++ b/src/components/easycredit-express-button-single/readme.md @@ -0,0 +1,41 @@ +# easycredit-express-button + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------- | -------------- | ----------- | ------------------------------------- | --------------------- | +| `amount` | `amount` | | `number` | `undefined` | +| `bgBlue` | `bg-blue` | | `boolean` | `false` | +| `fullWidth` | `full-width` | | `boolean` | `false` | +| `paymentType` | `payment-type` | | `METHODS.BILL \| METHODS.INSTALLMENT` | `METHODS.INSTALLMENT` | +| `webshopId` | `webshop-id` | | `string` | `undefined` | + + +## Events + +| Event | Description | Type | +| --------------- | ----------- | --------------------- | +| `buttonClicked` | | `CustomEvent` | + + +## Dependencies + +### Used by + + - [easycredit-express-button](../easycredit-express-button) + +### Graph +```mermaid +graph TD; + easycredit-express-button --> easycredit-express-button-single + style easycredit-express-button-single fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/easycredit-express-button/easycredit-express-button.scss b/src/components/easycredit-express-button/easycredit-express-button.scss index 8ff23f4..0402214 100644 --- a/src/components/easycredit-express-button/easycredit-express-button.scss +++ b/src/components/easycredit-express-button/easycredit-express-button.scss @@ -1,37 +1,8 @@ -@keyframes content { - 0% { - flex-basis: 0; - width: 0; - max-width: 0; - visibility: hidden; - color: transparent; - } - 75% { - flex-basis: 0; - width: 0; - max-width: 0; - visibility: hidden; - color: transparent; - } - 100% { - } -} - .ec-express-button { - --bg-color: #{$ec-primary}; - --bg-color-hover: #{$ec-primary-btn-hover}; - - display: flex; - flex-flow: column; - justify-content: center; - align-items: center; - transition: opacity 0.35s ease; - &__link { display: flex; align-items: center; justify-content: center; - margin-top: 10px; width: auto; max-width: 100%; @@ -43,7 +14,7 @@ color: $font-color !important; &:hover { - color: rgba($font-color,.7) !important; + color: rgba($font-color, .7) !important; } .icon { @@ -60,96 +31,4 @@ top: -.5px; } } - - &__btn { - position: relative; - display: flex; - align-items: center; - width: auto; - max-width: 100%; - height: 45px; - - border-radius: $border-radius-xxl; - cursor: pointer; - - a { - background-color: var(--bg-color); - transition: background-color 0.35s ease; - - color: $white; - - &:hover { - background-color: var(--bg-color-hover); - color: $white; - } - } - - // Props - &.blue { - --bg-color: #{$ec-secondary}; - --bg-color-hover: #{$ec-secondary-btn-hover}; - } - &.full-width { - width: 100% !important; - } - - &__main { - display: flex; - align-items: center; - justify-content: center; - padding-left: 36px; - padding-right: 36px; - width: 100%; - height: 100%; - box-sizing: border-box; - - transition: all ease 0.35s; - border-radius: 30px; - - font-size: $font-size; - font-weight: bold; - color: $white; - - .logo { - flex: 0 0 59px; - width: 59px; - max-width: 59px; - - @extend .logo-ratenkauf-white; - height: 45px; - } - - &__inner { - flex-shrink: 0; - flex-grow: 0; - flex-basis: auto; - width: auto; - max-width: 100%; - - position: relative; - display: flex; - align-items: center; - - height: 100%; - box-sizing: border-box; - overflow: hidden; - visibility: visible; - - animation-name: content; - animation-duration: 2s; - color: $white; - - transition: width .1s ease, flex-basis .1s ease; - } - - span { - display: flex; - white-space: nowrap; - } - - .financing { - padding-left: 10px; - } - } - } } diff --git a/src/components/easycredit-express-button/easycredit-express-button.stories.tsx b/src/components/easycredit-express-button/easycredit-express-button.stories.tsx index 57a25ba..9f0e3a5 100644 --- a/src/components/easycredit-express-button/easycredit-express-button.stories.tsx +++ b/src/components/easycredit-express-button/easycredit-express-button.stories.tsx @@ -1,63 +1,99 @@ import { buildAttributes } from '../../../.storybook/helpers' +import { METHODS } from '../../types'; export default { - title: "Checkout/ExpressButton", - parameters: { - docs: { - description: { - component: 'Der Express Button für den easyCredit-Ratenkauf kann auf Produktseiten oder im Warenkorb integriert werden, um direkt von dort aus aus den Bezahlvorgang zu starten.', - } - } - }, - argTypes: { - // bgBlue: { - // defaultValue: { summary: "false" }, - // description: "Wechselt die Hintergrundfarbe des Buttons von \"eC Orange\" auf \”eC Primärblau\"." - // }, - webshopId: { - description: 'die Kennung des Webshops' + title: "Checkout/ExpressButton", + parameters: { + docs: { + description: { + component: 'Der Express Button für easyCredit kann auf Produktseiten oder im Warenkorb integriert werden, um direkt von dort aus aus den Bezahlvorgang zu starten.', + } + } }, - amount: { - description: 'der zu finanzierende Betrag, für den der Express-Button angezeigt werden soll. Ist der Betrag außerhalb der erlaubten Betragsgrenzen, wird der Button ausgeblendet.' + argTypes: { + webshopId: { + description: 'die Kennung des Webshops' + }, + amount: { + description: 'der zu finanzierende Betrag, für den der Express-Button angezeigt werden soll. Ist der Betrag außerhalb der erlaubten Betragsgrenzen, wird der Button ausgeblendet.' + }, + paymentTypes: { + description: 'die zu berücksichtigenden Zahlungsmethoden, als komma-getrennte Liste', + table: { + defaultValue: { summary: [] }, + category: "optional", + }, + control: 'check', options: [METHODS.INSTALLMENT, METHODS.BILL] + }, + fullWidth: { + table: { + defaultValue: { summary: "false" }, + category: "optional", + }, + description: "Zeigt den Button über 100% der zur Verfügung stehenden Breite an." + }, + submit: { + action: 'submit', + table: { + category: "Events", + }, + description: "Wird ausgelöst bei Klick auf 'Akzeptieren'", + } }, - fullWidth: { - table: { - defaultValue: { summary: "false" }, - category: "optional", - }, - description: "Zeigt den Button über 100% der zur Verfügung stehenden Breite an." - }, - submit: { - action: 'submit', - table: { - category: "Events", - }, - description: "Wird ausgelöst bei Klick auf 'Akzeptieren'", - } - }, } let args = { - webshopId: '2.de.9999.9999', - amount: 299, - // bgBlue: false, - fullWidth: false, - // redirectUrl: 'https://easycredit-ratenkauf.de/' + webshopId: '2.de.7387.2', + amount: 299, + fullWidth: false, + // redirectUrl: 'https://easycredit-ratenkauf.de/' + paymentTypes: '' } const Template = (args) => { - delete args.submit; - return ` + delete args.submit; + return ` `; } -export const ExpressButton = Template.bind({}); -ExpressButton.storyName = 'ExpressButton' -ExpressButton.args = args + +export const ExpressButtonNormal = Template.bind({}); +ExpressButtonNormal.storyName = 'Standard' +ExpressButtonNormal.args = args + +export const ExpressButtonBoth = Template.bind({}); +ExpressButtonBoth.storyName = 'beide Zahlarten' +ExpressButtonBoth.args = { + ...args, ... { + paymentTypes: [METHODS.BILL,METHODS.INSTALLMENT].join(',') + } +} + +export const ExpressButtonInstallment = Template.bind({}); +ExpressButtonInstallment.storyName = 'nur Ratenkauf' +ExpressButtonInstallment.args = args +ExpressButtonInstallment.args = { + ...args, ... { + paymentTypes: METHODS.INSTALLMENT + } +} + +export const ExpressButtonBill = Template.bind({}); +ExpressButtonBill.storyName = 'nur Rechnung' +ExpressButtonBill.args = { + ...args, ... { + paymentTypes: METHODS.BILL + } +} diff --git a/src/components/easycredit-express-button/easycredit-express-button.tsx b/src/components/easycredit-express-button/easycredit-express-button.tsx index 7d2bd82..0bedc43 100644 --- a/src/components/easycredit-express-button/easycredit-express-button.tsx +++ b/src/components/easycredit-express-button/easycredit-express-button.tsx @@ -1,249 +1,272 @@ -import { Component, Prop, State, Element, Listen, Watch, h } from '@stencil/core'; -import { fetchInstallmentPlans, applyAssetsUrl, sendFeedback, addErrorHandler } from '../../utils/utils'; +import { Component, Prop, h, State, Listen, Element, Watch } from '@stencil/core' +import { fetchInstallmentPlans,validateInstallmentPlans, getWebshopInfo, sendFeedback, addErrorHandler } from '../../utils/utils' +import { Caps } from '../../utils/validation'; +import { InstallmentPlan, InstallmentPlans, METHODS } from '../../types'; +import { validateAmount } from '../../utils/validation'; @Component({ tag: 'easycredit-express-button', styleUrl: 'easycredit-express-button.scss', - shadow: true, + shadow: true }) export class EasycreditExpressButton { - @Prop() webshopId: string - @Prop() amount: number - @Prop() alert: string - @Prop() redirectUrl: string - - @Prop() bgBlue: boolean = false + @Prop({ mutable: true }) amount: number + @Prop({ mutable: true }) paymentTypes: string @Prop() fullWidth: boolean = false + @Prop() redirectUrl: string - @State() installments - @State() example - - buttonTextDefault: string = 'Jetzt direkt in Raten zahlen' - buttonTextDefaultShort: string = 'Jetzt in Raten zahlen' - buttonTextHover: string = 'mit easyCredit-Ratenkauf' - @State() buttonTextTimeout = null - - @State() buttonOpacity: string = '0' @State() buttonWidth: string = '100%' - @State() buttonText: string = this.buttonTextDefault - @State() buttonTextWidth: string = 'auto' + @State() selectedPaymentType: METHODS + @State() installmentPlans: InstallmentPlans = null + @State() selectedInstallment: InstallmentPlan = null + @State() paymentTypesEmpty: boolean = false - /* - @Listen('resize', { target: 'window' }) - - } - */ - - @Element() el: HTMLElement; - - checkoutModal!: HTMLEasycreditModalElement infopageModal!: HTMLEasycreditModalElement + checkoutModal!: HTMLEasycreditModalElement paymentModal!: HTMLEasycreditModalElement - connectedCallback() { - applyAssetsUrl(EasycreditExpressButton) - } + @Element() el: HTMLElement; - async componentWillLoad () { - if (this.amount > 0 && !this.alert) { - this.onAmountChanged(this.amount, null); - } + caps: Caps + + @Listen('selectedInstallment', { target: 'window' }) + selectedInstallmentHandler(e) { + this.selectedInstallment = this.installmentPlans.plans.find(i => i.numberOfInstallments == e.detail) } @Listen('openModal') - openModalHandler () { + openModalHandler() { this.checkoutModal.open() sendFeedback(this, { component: 'EasycreditExpressButton', action: 'openCheckoutModal' }) } @Watch('amount') - onAmountChanged(amount: number, oldAmount: number) { + async onAmountChanged(amount: number, oldAmount: number) { if (!amount) { - this.installments = null + this.installmentPlans = null + return } if (amount !== oldAmount && amount > 0) { - fetchInstallmentPlans(this.webshopId, amount).then((data) => { - this.installments = data - }).catch(e => { - this.installments = null + try { + const installmentPlans = await fetchInstallmentPlans(this.webshopId, this.amount) + this.installmentPlans = validateInstallmentPlans(installmentPlans) + } catch (e) { + this.installmentPlans = null console.error(e) - }) + } } } - componentDidLoad () { - this.renderButton() - } - componentDidUpdate () { - this.setButtonTextWidth() + openInfopageModal() { + this.infopageModal.open() + sendFeedback(this, { component: 'EasycreditExpressButton', action: 'openInfopageModal' }) } - async renderButton () { - await this.setButtonText() - await this.setButtonWidth() - await this.setButtonTextWidth() - this.buttonOpacity = '1' + isEnabled(type: METHODS) { + return this.caps.isEnabled(type) } - getButtonTextWidth () { - var textFinancing: HTMLElement = this.el.shadowRoot.querySelector('.financing'); - // var textRate: HTMLElement = this.el.shadowRoot.querySelector('.rate'); - - widthTotal = null; - if ( textFinancing ) { - var widthTotal = textFinancing.offsetWidth; + isValid(type: METHODS) { + let valid; + try { + validateAmount(this.amount, type) + valid = true + } catch (e) { + valid = false } - - return widthTotal; - } - getButtonWidth () { - var button: HTMLElement = this.el.shadowRoot.querySelector('.ec-express-button__btn__main'); - var logo: HTMLElement = this.el.shadowRoot.querySelector('.logo'); - var textWidth = this.getButtonTextWidth(); - - widthTotal = null; - if ( button && logo && textWidth ) { - var widthTotal = parseInt(window.getComputedStyle(button, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(button, null).getPropertyValue('padding-right'), 10) + logo.offsetWidth + textWidth; - } - - return widthTotal; + return this.isEnabled(type) && valid } - setButtonText () { - var component: HTMLElement = this.el.shadowRoot.querySelector('.ec-express-button'); - var buttonWidth = this.getButtonWidth(); - - if ( component && buttonWidth ) { - if ( component.offsetWidth < buttonWidth ) { - this.buttonText = this.buttonTextDefaultShort; - } + async componentWillLoad() { + if (!this.paymentTypes) { + this.paymentTypes = METHODS.INSTALLMENT + this.paymentTypesEmpty = true } - } - setButtonWidth () { - var buttonWidth = this.getButtonWidth(); - if ( buttonWidth ) { - this.buttonWidth = buttonWidth + 'px'; + this.caps = new Caps(this.paymentTypes) + + try { + //const opts = this.disableFlexprice ? { 'withoutFlexprice': this.disableFlexprice } : {} + await getWebshopInfo(this.webshopId) + // validateAmount(this.amount, this.method) + } catch (errorMessage) { + let alert = errorMessage ?? 'Es ist ein Fehler aufgetreten.' + console.error(alert) } - } - setButtonTextWidth () { - var textWidth = this.getButtonTextWidth(); - if ( textWidth ) { - this.buttonTextWidth = textWidth + 'px'; - } + this.onAmountChanged(this.amount, null); } - onMouseEnter () { - window.clearTimeout(this.buttonTextTimeout) - - this.buttonText = this.buttonTextHover; + getInstallmentUspFragment () { + return ([
    +
    Ihre Vorteile
    +
      +
    • Frühestens 30 Tage nach Lieferung zahlen
    • +
    • Flexible monatliche Wunschrate
    • +
    • Kostenfreie Ratenanpassung & Sondertilgung
    • +
    +
    + ]) } - onMouseLeave () { - window.clearTimeout(this.buttonTextTimeout) - this.buttonTextTimeout = window.setTimeout(() => { - this.buttonText = this.buttonTextDefault; - },1000) + + getCheckoutModalFragment() { + return ([ + this.checkoutModal = el as HTMLEasycreditModalElement} + onModalSubmit={() => this.modalSubmitHandler()} + size="checkout" + > +
    +
    +
    +
    + + + { + this.isEnabled(METHODS.INSTALLMENT) && + this.isEnabled(METHODS.BILL) && +
    + + +
    + } + + {this.selectedPaymentType === METHODS.INSTALLMENT && + !this.paymentTypesEmpty && + + } + {this.selectedPaymentType === METHODS.BILL && + + } + + {!this.paymentTypesEmpty && + + } + + {this.paymentTypesEmpty && + this.getInstallmentUspFragment() + } +
    + +
    +
    +
    +
    +
    + +
    +
    + {this.selectedPaymentType === METHODS.INSTALLMENT && + Weiter zum Ratenkauf + } + {this.selectedPaymentType === METHODS.BILL && + Weiter zum Rechnungskauf + } + +

    Mit Klick auf Akzeptieren stimmen Sie der Datenübermittlung zu:

    + +
    +
    +
    +
    + Akzeptieren +
    + ]) } modalSubmitHandler() { - sendFeedback(this, { component: 'EasycreditExpressButton', action: 'submit' }) - if (this.redirectUrl) { - this.paymentModal.open(); - this.checkoutModal.close(); - } else { - addErrorHandler(this, () => { - alert('Leider ist eine Zahlung mit easyCredit derzeit nicht möglich. Bitte verwenden Sie eine andere Zahlungsart oder wenden Sie sich an den Händler.') - this.checkoutModal.close() - }) - this.el.dispatchEvent(new CustomEvent('submit', { - bubbles : true, - cancelable : true, - composed: true, - detail: { - numberOfInstallments: null - } - })) - } + sendFeedback(this, { component: 'EasycreditExpressButton', action: 'submit' }) + if (this.redirectUrl) { + this.paymentModal.open(); + this.checkoutModal.close(); + } else { + addErrorHandler(this, () => { + alert('Leider ist eine Zahlung mit easyCredit derzeit nicht möglich. Bitte verwenden Sie eine andere Zahlungsart oder wenden Sie sich an den Händler.') + this.checkoutModal.close() + }) + this.el.dispatchEvent(new CustomEvent('submit', { + bubbles: true, + cancelable: true, + composed: true, + detail: { + paymentType: this.selectedPaymentType, + ...(this.selectedInstallment?.numberOfInstallments && { numberOfInstallments: this.selectedInstallment?.numberOfInstallments }) + } + })) + } } - getCheckoutModalFragment () { - return ([ - this.checkoutModal = el as HTMLEasycreditModalElement} - onModalSubmit={() => this.modalSubmitHandler()} - size="small" - > - Weiter zum Ratenkauf -
    -

    Mit Klick auf Akzeptieren stimmen Sie der Datenübermittlung zu:

    - -
    - Akzeptieren -
    - ]) + getPaymentModalFragment() { + if (!this.redirectUrl) { + return; + } + + return ([ + this.paymentModal = el as HTMLEasycreditModalElement} size="full"> + + + ]) } - getPaymentModalFragment () { - if (!this.redirectUrl) { - return; - } + clickHandler = (event: CustomEvent) => { + event.preventDefault(); + event.stopPropagation(); - return ([ - this.paymentModal = el as HTMLEasycreditModalElement} size="full"> - - - ]) + if ( event.detail !== this.selectedPaymentType ) { + this.switchPaymentType(event.detail as METHODS) + } + this.checkoutModal.open() } - openInfopageModal () { - this.infopageModal.open() - sendFeedback(this, { component: 'EasycreditExpressButton', action: 'openInfopageModal' }) - + switchPaymentType (paymentType: METHODS) { + this.selectedPaymentType = paymentType + this.selectedInstallment = null + sendFeedback(this, { component: 'EasycreditExpressButton', action:'switchPaymentType', paymentType: this.selectedPaymentType }) } - render() { - if (this.alert) { - return; - } - if ( - this.installments && ( - this.amount < this.installments.minFinancingAmount || - this.amount > this.installments.maxFinancingAmount - ) - ) { - return; + render () { + if (!this.isValid(METHODS.INSTALLMENT) && !this.isValid(METHODS.BILL)) { + return; } + return [ +
    + {this.isEnabled(METHODS.INSTALLMENT) && + + } + {this.isEnabled(METHODS.BILL) && + + } - return ([ -
    - - - this.openInfopageModal() }> + this.openInfopageModal()}>
    -
    Mehr zu easyCredit-Ratenkauf
    +
    Mehr zum Bezahlen mit easyCredit
    + {this.getCheckoutModalFragment()} + {this.getPaymentModalFragment()} + this.infopageModal = el as HTMLEasycreditModalElement} size="infopage">
    - ]) + ] } } diff --git a/src/components/easycredit-express-button/readme.md b/src/components/easycredit-express-button/readme.md index 0f579f0..ecc602a 100644 --- a/src/components/easycredit-express-button/readme.md +++ b/src/components/easycredit-express-button/readme.md @@ -1,4 +1,4 @@ -# easycredit-express-button +# easycredit-express-button-set @@ -7,14 +7,13 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------- | -------------- | ----------- | --------- | ----------- | -| `alert` | `alert` | | `string` | `undefined` | -| `amount` | `amount` | | `number` | `undefined` | -| `bgBlue` | `bg-blue` | | `boolean` | `false` | -| `fullWidth` | `full-width` | | `boolean` | `false` | -| `redirectUrl` | `redirect-url` | | `string` | `undefined` | -| `webshopId` | `webshop-id` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| -------------- | --------------- | ----------- | --------- | ----------- | +| `amount` | `amount` | | `number` | `undefined` | +| `fullWidth` | `full-width` | | `boolean` | `false` | +| `paymentTypes` | `payment-types` | | `string` | `undefined` | +| `redirectUrl` | `redirect-url` | | `string` | `undefined` | +| `webshopId` | `webshop-id` | | `string` | `undefined` | ## Dependencies @@ -22,14 +21,24 @@ ### Depends on - [easycredit-modal](../easycredit-modal) +- [easycredit-logo](../easycredit-logo) +- [easycredit-checkout-installments](../easycredit-checkout-installments) +- [easycredit-checkout-bill-payment-timeline](../easycredit-checkout-bill-payment-timeline) +- [easycredit-checkout-totals](../easycredit-checkout-totals) - [easycredit-checkout-privacy-approval](../easycredit-checkout-privacy-approval) +- [easycredit-express-button-single](../easycredit-express-button-single) - [easycredit-infopage](../easycredit-infopage) ### Graph ```mermaid graph TD; easycredit-express-button --> easycredit-modal + easycredit-express-button --> easycredit-logo + easycredit-express-button --> easycredit-checkout-installments + easycredit-express-button --> easycredit-checkout-bill-payment-timeline + easycredit-express-button --> easycredit-checkout-totals easycredit-express-button --> easycredit-checkout-privacy-approval + easycredit-express-button --> easycredit-express-button-single easycredit-express-button --> easycredit-infopage easycredit-infopage --> easycredit-faq easycredit-faq --> easycredit-accordion diff --git a/src/components/easycredit-infopage/easycredit-infopage.scss b/src/components/easycredit-infopage/easycredit-infopage.scss index dfddabe..5392753 100644 --- a/src/components/easycredit-infopage/easycredit-infopage.scss +++ b/src/components/easycredit-infopage/easycredit-infopage.scss @@ -74,7 +74,7 @@ $infpage-max-width: 650px; font-size: $font-size-lg; &::before { - @include content-svg($icon-checkmark); + @include content-svg($icon-checkmark-circle-lg); margin-right: 20px; width: 41px; height: 41px; diff --git a/src/components/easycredit-logo/easycredit-logo.scss b/src/components/easycredit-logo/easycredit-logo.scss index 977b988..fe3a8ca 100644 --- a/src/components/easycredit-logo/easycredit-logo.scss +++ b/src/components/easycredit-logo/easycredit-logo.scss @@ -1,5 +1,6 @@ -img.ec-logo { - width: 125px; +svg.ec-logo { + display: inline-block; + width: 100px; max-width: 100%; - max-height: 100%; + height: auto; } diff --git a/src/components/easycredit-logo/easycredit-logo.stories.tsx b/src/components/easycredit-logo/easycredit-logo.stories.tsx index 6516b3c..6d287dc 100644 --- a/src/components/easycredit-logo/easycredit-logo.stories.tsx +++ b/src/components/easycredit-logo/easycredit-logo.stories.tsx @@ -6,7 +6,7 @@ export default { docs: { description: { component: - "Das Logo vereinfacht die Einbindung des easyCredit-Ratenkauf Logos und kann statt eines img-Tags eingesetzt werden", + "Das Logo vereinfacht die Einbindung der easyCredit-Logos und kann statt eines img-Tags eingesetzt werden", } } }, diff --git a/src/components/easycredit-logo/easycredit-logo.tsx b/src/components/easycredit-logo/easycredit-logo.tsx index 1704734..2dfd655 100644 --- a/src/components/easycredit-logo/easycredit-logo.tsx +++ b/src/components/easycredit-logo/easycredit-logo.tsx @@ -1,5 +1,5 @@ import { Component, Prop, h } from '@stencil/core'; -import { applyAssetsUrl, getAssetUrl } from '../../utils/utils'; +import { METHODS } from '../../types'; @Component({ tag: 'easycredit-logo', @@ -9,15 +9,21 @@ import { applyAssetsUrl, getAssetUrl } from '../../utils/utils'; export class EasycreditLogo { + @Prop() paymentType: METHODS = METHODS.INSTALLMENT; @Prop({ mutable: true }) alt: string = 'easyCredit-Ratenkauf - Einfach. Fair. In Raten zahlen.'; - connectedCallback() { - applyAssetsUrl(EasycreditLogo) + private getLogo(): string { + if (this.paymentType === METHODS.BILL) { + return + + } else { + return + } } render() { return ([ - + {this.getLogo() } ]) } } diff --git a/src/components/easycredit-logo/readme.md b/src/components/easycredit-logo/readme.md index 509bacd..89771ef 100644 --- a/src/components/easycredit-logo/readme.md +++ b/src/components/easycredit-logo/readme.md @@ -7,11 +7,25 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| -------- | --------- | ----------- | -------- | ---------------------------------------------------------- | -| `alt` | `alt` | | `string` | `'easyCredit-Ratenkauf - Einfach. Fair. In Raten zahlen.'` | +| Property | Attribute | Description | Type | Default | +| ------------- | -------------- | ----------- | ------------------------------------- | ---------------------------------------------------------- | +| `alt` | `alt` | | `string` | `'easyCredit-Ratenkauf - Einfach. Fair. In Raten zahlen.'` | +| `paymentType` | `payment-type` | | `METHODS.BILL \| METHODS.INSTALLMENT` | `METHODS.INSTALLMENT` | +## Dependencies + +### Used by + + - [easycredit-express-button](../easycredit-express-button) + +### Graph +```mermaid +graph TD; + easycredit-express-button --> easycredit-logo + style easycredit-logo fill:#f9f,stroke:#333,stroke-width:4px +``` + ---------------------------------------------- *Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/easycredit-merchant-manager/easycredit-merchant-manager.scss b/src/components/easycredit-merchant-manager/easycredit-merchant-manager.scss index b4b708f..658f8d0 100644 --- a/src/components/easycredit-merchant-manager/easycredit-merchant-manager.scss +++ b/src/components/easycredit-merchant-manager/easycredit-merchant-manager.scss @@ -22,7 +22,7 @@ content: ''; margin-bottom: 15px; - @extend .logo-ratenkauf; + @extend .logo-easycredit; display: block; width: 100%; height: 30px; diff --git a/src/components/easycredit-merchant-manager/easycredit-merchant-manager.stories.tsx b/src/components/easycredit-merchant-manager/easycredit-merchant-manager.stories.tsx index 5d0facc..85ae657 100644 --- a/src/components/easycredit-merchant-manager/easycredit-merchant-manager.stories.tsx +++ b/src/components/easycredit-merchant-manager/easycredit-merchant-manager.stories.tsx @@ -14,7 +14,7 @@ Um die Transaktionen abrufen zu können, müssen für den Merchant Manager die E }, argTypes: { txId: { - description: 'die Transaktions-ID der easyCredit-Ratenkauf Zahlung' + description: 'die Transaktions-ID der easyCredit-Zahlung' }, date: { description: 'Bestelldatum, verwendet zur Unterscheidung zwischen "nicht verfügbar" und "noch nicht verfügbar". Der Wert muss von Date.parse() geparst werden können.' diff --git a/src/components/easycredit-merchant-status-widget/easycredit-merchant-status-widget.stories.tsx b/src/components/easycredit-merchant-status-widget/easycredit-merchant-status-widget.stories.tsx index 7bb16ec..0cfe181 100644 --- a/src/components/easycredit-merchant-status-widget/easycredit-merchant-status-widget.stories.tsx +++ b/src/components/easycredit-merchant-status-widget/easycredit-merchant-status-widget.stories.tsx @@ -14,7 +14,7 @@ Das Merchant StatusWidget benötigt eine initale Konfiguration zum Abruf der Tra }, argTypes: { txId: { - description: 'die Transaktions-ID der easyCredit-Ratenkauf Zahlung' + description: 'die Transaktions-ID der easyCredit-Zahlung' }, date: { description: 'Bestelldatum, verwendet zur Unterscheidung zwischen "nicht verfügbar" und "noch nicht verfügbar". Der Wert muss von Date.parse() geparst werden können.' diff --git a/src/components/easycredit-modal/easycredit-modal.scss b/src/components/easycredit-modal/easycredit-modal.scss index 6bee57d..7c50058 100644 --- a/src/components/easycredit-modal/easycredit-modal.scss +++ b/src/components/easycredit-modal/easycredit-modal.scss @@ -60,8 +60,10 @@ overflow-x: hidden; overflow-y: auto; + transition: $transition-slow; + background-color: $white; - border-radius: $border-radius-xxl; + border-radius: $border-radius-xxxl; box-shadow: $box-shadow; color: $font-color; @@ -79,10 +81,10 @@ padding-bottom: 20px; width: 100vw; max-width: 100vw; - max-height: 100vh; max-height: -webkit-fill-available; overflow: scroll; - border-radius: 0; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; animation-name: modal-mobile; animation-duration: .25s; @@ -100,6 +102,7 @@ height: 27px; @include background-svg($icon-close-blue); + background-color: $white; background-position: center; background-repeat: no-repeat; background-size: 9px; @@ -124,6 +127,15 @@ height: 350px; } } + &.size-medium, + &.size-checkout { + padding: 0; + + @media (min-width: $breakpoint-sm-up) { + width: 800px; + height: 650px; + } + } &.size-payment { width: 499px; // ensures display of payment terminal with mobile layout height: 900px; @@ -213,35 +225,6 @@ } } -.ec-modal-sandbox { - position: fixed; - left: 0; - bottom: 0; - z-index: 100; - padding: 20px 25px; - width: 100%; - box-sizing: border-box; - white-space: nowrap; - overflow: scroll; - background-color: $white; - box-shadow: 0 0 25px rgba(0,0,0,.15); - - &::-webkit-scrollbar { - display: none !important; - } - - strong { - display: inline-block; - margin-right: 15px; - } - - a { - display: inline-block; - margin-right: 15px; - cursor: pointer; - } -} - ::slotted(iframe) { @extend %iframe; } diff --git a/src/components/easycredit-modal/easycredit-modal.tsx b/src/components/easycredit-modal/easycredit-modal.tsx index d0b2514..6e05a2d 100644 --- a/src/components/easycredit-modal/easycredit-modal.tsx +++ b/src/components/easycredit-modal/easycredit-modal.tsx @@ -18,6 +18,7 @@ export class EasycreditModal { @State() hasHeadingSlot: boolean = false @State() submittable: boolean = false @State() submitButtonClicked: boolean = false + @State() elementHeight: number = null @Event() modalOpened: EventEmitter; @Event() modalClosed: EventEmitter; @@ -38,6 +39,23 @@ export class EasycreditModal { } } + setElementHeight(): void { + if ( this.size === 'checkout' ) { + if ( this.elementHeight === null ) { + this.elementHeight = 0; + } + var checkoutModalContentContainer = this.element.querySelector('[slot="content"] .ec-col-method .ec-container'); + + setTimeout(() => { + this.elementHeight = checkoutModalContentContainer.offsetHeight; + }, 100) + setTimeout(() => { + this.elementHeight = checkoutModalContentContainer.offsetHeight; + }, 500) + console.log('Set height: ' + this.elementHeight); + } + } + handleKeydown (e) { if (e.key == "Escape") { this.close() @@ -51,6 +69,8 @@ export class EasycreditModal { this.element.querySelectorAll('[data-src]').forEach((el) => { (el as any).src = (el as any).dataset.src }) + + this.setElementHeight(); } @Method() async close() { @@ -59,6 +79,8 @@ export class EasycreditModal { this.isOpen = false this.submitButtonClicked = false this.modalClosed.emit(); + + this.setElementHeight(); } @Method() async toggle () { @@ -83,7 +105,7 @@ export class EasycreditModal { return } return ([ -
    +
    @@ -108,11 +130,13 @@ export class EasycreditModal { 'ec-modal': true, 'show': this.isOpen, ['size-' + this.size]: this.size !== '' + }} style={{ + 'height': this.elementHeight + 'px' }}>
    this.close()}>
    { this.getHeadingFragment() } -
    +
    this.setElementHeight()}>
    diff --git a/src/components/easycredit-modal/readme.md b/src/components/easycredit-modal/readme.md index 78f8b84..3ec2ce5 100644 --- a/src/components/easycredit-modal/readme.md +++ b/src/components/easycredit-modal/readme.md @@ -68,6 +68,13 @@ Type: `Promise` +## Shadow Parts + +| Part | Description | +| ---------- | ----------- | +| `"submit"` | | + + ## Dependencies ### Used by diff --git a/src/components/easycredit-widget/easycredit-widget.scss b/src/components/easycredit-widget/easycredit-widget.scss index 28e17bf..5868907 100644 --- a/src/components/easycredit-widget/easycredit-widget.scss +++ b/src/components/easycredit-widget/easycredit-widget.scss @@ -8,12 +8,51 @@ .ec-widget { position: relative; - display: block; - padding: 15px 15px 15px 77.5px; + display: flex; + padding: 0 0 0 10px; width: 300px; max-width: 100%; box-sizing: border-box; + >svg { + align-self: center; + margin-right: 7.5px; + flex: 0 0 22.5px; + width: 22.5px; + height: 22.5px; + } + + >span { + display: inline-block; + padding: 6.5px 0; + } + + &__cta { + display: flex; + align-items: center; + justify-content: center; + margin-left: 10px; + flex: 0 0 23px; + width: 23px; + + border-left: 1px solid rgba($ec-darkblue,0.1); + cursor: pointer; + + &:hover { + margin-bottom: -1px; + margin-right: -0.5px; + background: $white linear-gradient(to right, rgba($ec-darkblue,0.05)0%, rgba($ec-darkblue,0) 10%, $white 100%); + border-top-right-radius: $border-radius-xl; + border-bottom-right-radius: $border-radius-xl; + } + + svg { + flex: 0 0 9px; + width: 9px; + height: 9px; + } + } + background-color: $white; text-align: left; @@ -36,7 +75,6 @@ } &.minimal { - display: flex; align-items: flex-start; padding: 0; width: auto; @@ -45,7 +83,6 @@ box-shadow: none; svg { - margin-right: 7.5px; flex: 0 0 20px; width: 20px; height: 20px; @@ -72,38 +109,28 @@ } } - &__logo { - position: absolute; - left: 15px; - top: 50%; - transform: translateY(-50%); - - @extend .logo-ratenkauf; - display: block; - width: 50px; - height: 24px; - } - span { em { font-weight: bold; font-style: normal; - color: $ec-primary; } - } - a { - display: inline-block; - margin-left: 5px; + a { + display: inline-block; - cursor: pointer; - text-decoration: underline !important; - font-weight: bold; - color: $font-color; + cursor: pointer; + text-decoration: underline !important; + font-weight: bold; + color: $font-color; - &:hover { - color: $font-color !important; - text-decoration: none !important; + &:hover { + color: $font-color !important; + text-decoration: none !important; + } + } + + &.ec-widget__separator { + color: rgba($font-color,0.4); } } } diff --git a/src/components/easycredit-widget/easycredit-widget.stories.tsx b/src/components/easycredit-widget/easycredit-widget.stories.tsx index 4d953bc..7e69b6b 100644 --- a/src/components/easycredit-widget/easycredit-widget.stories.tsx +++ b/src/components/easycredit-widget/easycredit-widget.stories.tsx @@ -1,4 +1,5 @@ import { buildAttributes } from '../../../.storybook/helpers' +import { METHODS } from '../../types'; export default { title: "Marketing/Widget", @@ -17,6 +18,13 @@ export default { amount: { description: 'der zu finanzierende Betrag für den die Rate angezeigt werden soll, üblicherweise der Produktpreis' }, + paymentTypes: { + description: 'die zu berücksichtigenden Zahlungsmethoden, als komma-getrennte Liste', + table: { + defaultValue: { summary: 'INSTALLMENT,BILL' }, + }, + control: 'check', options: [METHODS.INSTALLMENT, METHODS.BILL] + }, extended: { description: 'bestimmt, ob das Widget außerhalb der Betragsgrenzen angezeigt wird (optional)', defaultValue: 'false', @@ -45,7 +53,7 @@ export default { }; let args = { - webshopId: '2.de.9999.9999', + webshopId: '2.de.7387.2', amount: 500, extended: true, displayType: '', @@ -66,14 +74,56 @@ export const WidgetNormal = TemplateFirst.bind({}); WidgetNormal.storyName = 'Standard' WidgetNormal.args = args +export const WidgetFull = Template.bind({}); +WidgetFull.storyName = 'beide Zahlarten'; +WidgetFull.args = { + ...args, + paymentTypes: `${METHODS.BILL},${METHODS.INSTALLMENT}` +}; + +export const WidgetBillPayment = Template.bind({}); +WidgetBillPayment.storyName = 'nur Rechnungskauf'; +WidgetBillPayment.args = { + ...args, + paymentTypes: METHODS.BILL, +}; + +export const WidgetInstallmentPayment = Template.bind({}); +WidgetInstallmentPayment.storyName = 'nur Ratenkauf'; +WidgetInstallmentPayment.args = { + ...args, + paymentTypes: METHODS.INSTALLMENT, +}; + +export const WidgetBelowInstallments = Template.bind({}); +WidgetBelowInstallments.storyName = 'Grenzdarstellung (50 - 199 EUR)'; +WidgetBelowInstallments.args = { + ...args, + ...{ + amount: 198, + }, +}; + +export const WidgetAboveBill = Template.bind({}); +WidgetAboveBill.storyName = 'Grenzdarstellung (5001 - 9999 EUR)'; +WidgetAboveBill.args = { + ...args, + ...{ + amount: 6000, + }, +}; + export const WidgetBelow = Template.bind({}); -WidgetBelow.storyName = 'unterhalb Betragsgrenze (99 EUR)' -WidgetBelow.args = { ... args, ... { - amount: 99 -}} +WidgetBelow.storyName = 'Grenzdarstellung (< 50 EUR)'; +WidgetBelow.args = { + ...args, + ...{ + amount: 49, + }, +}; export const WidgetAbove = Template.bind({}); -WidgetAbove.storyName = 'oberhalb Betragsgrenze (12.000 EUR)' +WidgetAbove.storyName = 'Grenzdarstellung (> 10.000 EUR)'; WidgetAbove.args = { ... args, ... { amount: 12000 }} @@ -86,21 +136,21 @@ WidgetExtended.args = { ... args, ... { }} export const WidgetDisplayTypeClean = Template.bind({}); -WidgetDisplayTypeClean.storyName = 'alternative Darstellungsvariante, displayType: clean' +WidgetDisplayTypeClean.storyName = 'displayType: clean' WidgetDisplayTypeClean.args = { ... args, ... { amount: 500, displayType: 'clean' }} export const WidgetDisplayTypeMinimal = Template.bind({}); -WidgetDisplayTypeMinimal.storyName = 'alternative Darstellungsvariante, displayType: minimal' +WidgetDisplayTypeMinimal.storyName = 'displayType: minimal' WidgetDisplayTypeMinimal.args = { ... args, ... { amount: 500, displayType: 'minimal' }} export const WidgetWithoutFlexprice = Template.bind({}); -WidgetWithoutFlexprice.storyName = 'Berechnung ohne Zins-Flex' +WidgetWithoutFlexprice.storyName = 'ohne Zins-Flex' WidgetWithoutFlexprice.args = { ... args, ... { amount: 500, disableFlexprice: true diff --git a/src/components/easycredit-widget/easycredit-widget.tsx b/src/components/easycredit-widget/easycredit-widget.tsx index 1b98c5f..e5a6963 100644 --- a/src/components/easycredit-widget/easycredit-widget.tsx +++ b/src/components/easycredit-widget/easycredit-widget.tsx @@ -1,6 +1,9 @@ import { Component, Prop, State, Watch, h } from '@stencil/core'; -import { formatAmount, fetchInstallmentPlans, fetchSingleInstallmentPlan } from '../../utils/utils'; +import { formatAmount, getWebshopInfo, fetchInstallmentPlans } from '../../utils/utils'; import { applyAssetsUrl, sendFeedback } from '../../utils/utils'; +import { Caps, validateAmount } from '../../utils/validation'; +import { WebshopInfo, InstallmentPlans, METHODS } from '../../types'; +import state from '../../stores/general' @Component({ tag: 'easycredit-widget', @@ -8,61 +11,67 @@ import { applyAssetsUrl, sendFeedback } from '../../utils/utils'; shadow: true, }) export class EasycreditWidget { - /** - * Webshop Id - */ - @Prop() webshopId: string - /** - * Financing Amount - */ - @Prop({ mutable: true }) amount: number - /** - * Display Type (e.g. clean -> without shadow) - */ + @Prop() webshopId: string + @Prop({ mutable: true }) amount: number @Prop() displayType: string - - /** - * Show if out of range - */ + @Prop({ mutable: true }) paymentTypes: string = METHODS.INSTALLMENT @Prop({ mutable: true }) extended: boolean = true - - /** - * Disable Flexprice in calculation - */ @Prop({ mutable: true }) disableFlexprice: boolean = false + @State() installmentPlans: InstallmentPlans + @State() isValid: boolean = false + @State() widgetLayout: string = '' + @State() webshopInfo: WebshopInfo = null + modal!: HTMLEasycreditModalElement; widgetElement!: HTMLElement; - @State() installments - @State() isValid: boolean = false - @State() widgetLayout: string = '' + caps: Caps @Watch('amount') - onAmountChanged(amount: number, oldAmount: number) { - if (amount !== oldAmount) { - - const fetchPlans = (this.disableFlexprice) ? - fetchSingleInstallmentPlan.bind(this, this.webshopId, this.amount, { 'withoutFlexprice': true }) : - fetchInstallmentPlans.bind(this, this.webshopId, this.amount) + async onAmountChanged(amount: number, oldAmount: number) { + if (!this.isEnabled(METHODS.INSTALLMENT)){ + return + } + try { + validateAmount(this.amount, METHODS.INSTALLMENT) + } catch (e) { + return; + } - fetchPlans().then((data) => { + if (amount !== oldAmount) { + try { + const opts = this.disableFlexprice ? { 'withoutFlexprice': this.disableFlexprice } : null + const installmentPlans = await fetchInstallmentPlans(this.webshopId, this.amount, opts); + this.installmentPlans = installmentPlans.installmentPlans?.find(() => true) this.isValid = true - this.installments = data - }).catch(e => { + } catch (e) { + this.installmentPlans = null console.error(e) - }) + } } } connectedCallback() { applyAssetsUrl(EasycreditWidget) } + + isEnabled(type: METHODS) { + return this.caps.isEnabled(type) + } - componentWillLoad() { + async componentWillLoad() { + this.caps = new Caps(this.paymentTypes) this.onAmountChanged(this.amount, 0); + + try { + await getWebshopInfo(this.webshopId) + this.isValid = true + } catch(e) { + console.error(e) + } } componentDidRender() { @@ -70,19 +79,18 @@ export class EasycreditWidget { } getInstallmentPlan() { - if (!this.installments || !this.installments.installmentPlans) { + if (!this.installmentPlans) { return null } - return this.installments.installmentPlans - .find(() => true) + return this.installmentPlans } getMinimumInstallment() { - if (!this.getInstallmentPlan().plans) { + if (!this.getInstallmentPlan()?.plans) { return } return this.getInstallmentPlan().plans - .sort((a,b) => b.numberOfInstallments - a.numberOfInstallments) + .sort((a,b) => a.installment - b.installment) .find(() => true) } @@ -91,49 +99,84 @@ export class EasycreditWidget { } private getLogo(): string { - if (this.displayType === 'minimal') { - return - } - return + return } - private getLinkText(): string { - return 'Mehr Infos' + private getCtaIcon(): string { + return } private getInstallmentText(): string { - if (!this.installments) { + if (!this.isEnabled(METHODS.INSTALLMENT)) { return } - if (this.amount < this.installments.minFinancingAmount) { + + let info = state.webshopInfo + if (this.amount < info.minInstallmentValue) { if (!this.extended) { return } return Finanzieren ab  - {this.installments.minFinancingAmount.toLocaleString('de-DE', {maximumFractionDigits: 0})} € Bestellwert + {info.minInstallmentValue.toLocaleString('de-DE', {maximumFractionDigits: 0})} € Bestellwert } - if (this.amount > this.installments.maxFinancingAmount) { + if (this.amount > info.maxInstallmentValue) { if (!this.extended) { return } return Finanzieren bis  - {this.installments.maxFinancingAmount.toLocaleString('de-DE', {maximumFractionDigits: 0})} € Bestellwert + {info.maxInstallmentValue.toLocaleString('de-DE', {maximumFractionDigits: 0})} € Bestellwert } if (this.getMinimumInstallment()) { return Finanzieren ab  - {formatAmount(this.getMinimumInstallment().installment)} € / Monat + this.openModal(METHODS.INSTALLMENT)}>{formatAmount(this.getMinimumInstallment().installment)} € / Monat } } - openModal (): void { + private getBillPaymentText(): string { + if (!this.isEnabled(METHODS.BILL)) { + return + } + + const info = state.webshopInfo + if (!info) { + return + } + + if (this.amount < info.minBillingValue) { + if (!this.extended) { + return + } + return + mit this.openModal(METHODS.BILL)}>Rechnung bezahlen ab {info.minBillingValue.toLocaleString('de-DE', { maximumFractionDigits: 0 })} € + + } + + if (this.amount > info.maxBillingValue) { + if (!this.extended) { + return + } + return + mit this.openModal(METHODS.BILL)}>Rechnung bezahlen bis {info.maxBillingValue.toLocaleString('de-DE', { maximumFractionDigits: 0 })} € + + } + + const firstLetter = this.getInstallmentText() ? 'h' : 'H' + return + {firstLetter}eute bestellen, in this.openModal(METHODS.BILL)}>30 Tagen zahlen + + } + + openModal (paymentType?: METHODS): void { sendFeedback(this, { component: 'EasycreditWidget', action: 'openModal' }); + + this.modal.querySelector('iframe').dataset.src = this.getModalUrl(paymentType); this.modal.open() } @@ -144,10 +187,35 @@ export class EasycreditWidget { this.widgetLayout = this.widgetElement.getBoundingClientRect().width < 251 ? 'small' : ''; } + getModalUrl (paymentType?: METHODS) { + let url = new URL('https://ratenkauf.easycredit.de/widget/app/#/ratenwunsch'); + + const params = { + bestellwert: this.amount, + shopKennung: '2.de.7387.2', //this.webshopId, + paymentSwitchPossible: this.paymentTypes.split(',').length > 1, + ohneZinsflex: this.disableFlexprice + } + + Object.entries(params).forEach(([key, value]) => { + url.searchParams.append(key, String(value)); + }); + + if (!paymentType) { + const info = state.webshopInfo + paymentType = this.amount >= info.minInstallmentValue && this.amount <= info.maxInstallmentValue ? METHODS.INSTALLMENT : METHODS.BILL; + } + if (this.isEnabled(paymentType)) { + url.searchParams.append('paymentType', paymentType + '_PAYMENT'); + } + return url.origin + url.pathname + url.hash + url.search; + } + getModalFragment () { + //const url = this.getInstallmentPlan()?.url ?? this.getDefaultModalUrl() return ([ this.modal = el as HTMLEasycreditModalElement} size="payment"> - + ]) } @@ -155,7 +223,7 @@ export class EasycreditWidget { render() { return ([ this.isValid && - this.getInstallmentText() && + (this.getInstallmentText() || this.getBillPaymentText()) &&
    {this.getInstallmentText()} - mit easyCredit-Ratenkauf. - this.openModal() }>{this.getLinkText()} + { + this.getInstallmentText() && + this.getBillPaymentText() && + oder + } + {this.getBillPaymentText()} + + {!this.getBillPaymentText() && + mit easyCredit-Ratenkauf. + } + {!this.getInstallmentText() && + mit easyCredit-Rechnung. + } + + { + this.displayType !== 'clean' && + this.displayType !== 'minimal' && + this.openModal()}>{this.getCtaIcon()} + }
    { this.getModalFragment() } diff --git a/src/components/easycredit-widget/readme.md b/src/components/easycredit-widget/readme.md index ba79900..d482810 100644 --- a/src/components/easycredit-widget/readme.md +++ b/src/components/easycredit-widget/readme.md @@ -7,13 +7,14 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------ | ------------------- | ------------------------------------------- | --------- | ----------- | -| `amount` | `amount` | Financing Amount | `number` | `undefined` | -| `disableFlexprice` | `disable-flexprice` | Disable Flexprice in calculation | `boolean` | `false` | -| `displayType` | `display-type` | Display Type (e.g. clean -> without shadow) | `string` | `undefined` | -| `extended` | `extended` | Show if out of range | `boolean` | `true` | -| `webshopId` | `webshop-id` | Webshop Id | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------ | ------------------- | ----------- | --------- | --------------------- | +| `amount` | `amount` | | `number` | `undefined` | +| `disableFlexprice` | `disable-flexprice` | | `boolean` | `false` | +| `displayType` | `display-type` | | `string` | `undefined` | +| `extended` | `extended` | | `boolean` | `true` | +| `paymentTypes` | `payment-types` | | `string` | `METHODS.INSTALLMENT` | +| `webshopId` | `webshop-id` | | `string` | `undefined` | ## Dependencies diff --git a/src/globals/base.scss b/src/globals/base.scss index 62bfcfb..c7e9cd2 100644 --- a/src/globals/base.scss +++ b/src/globals/base.scss @@ -15,9 +15,11 @@ $ec-backdrop: rgba(0,0,0,.3); $white: #fff; $black: #000; $error: #e90202; +$success: #77D400; $ec-primary-btn-hover: darken($ec-primary, 10%); $ec-secondary-btn-hover: darken($ec-secondary, 10%); +$ec-darkblue-btn-hover: lighten($ec-darkblue, 10%); $overlay-orange: rgba($ec-primary, 0.1); $overlay-blue: rgba($ec-secondary, 0.1); @@ -47,15 +49,15 @@ $font-size-heading-xxl: 46px; $font-size-heading-xl: 30px; $font-size-heading-lg: 25px; $font-size-heading: 20px; -$font-size-heading-sm: 16px; +$font-size-heading-sm: 18px; $font-size-xl: 18px; $font-size-lg: 16px; -$font-size-md: 15px; +$font-size-md: 15px; $font-size: 14px; $font-size-sm: 13px; $font-size-xs: 12px; -$font-size-xxs: 10px; +$font-size-xxs: 11px; $font-size-xxxs: 7px; $font-size-running: 13px; @@ -68,9 +70,10 @@ $line-height-heading-lg: 1.25; // - Border $border-radius: 3px; $border-radius-lg: 5px; -$border-radius-lg-xl: 8px; +$border-radius-lg-xl: 7.5px; $border-radius-xl: 10px; $border-radius-xxl: 15px; +$border-radius-xxxl: 30px; // - Transitions $transition-slow: all .35s ease; @@ -78,7 +81,7 @@ $transition: all 0.15s ease-in-out; $transition-timing: cubic-bezier(0.73, 0.32, 0.14, 0.99); // - Box shadows -$box-shadow: 0 0 25px rgba(0,0,0,.1); +$box-shadow: 0 1px 2.5px rgba($ec-darkblue,0.2); // - Circles $circle-width-100: 100%; @@ -92,8 +95,13 @@ $circle-width-33-secondary: calc(100% * 0.33 * 0.33); $ratenkauf-icon: ''; $icon-close-blue: ''; $icon-close-white: ''; -$icon-checkmark: ''; +$icon-checkmark: ''; +$icon-checkmark-circle: ''; +$icon-checkmark-circle-white: ''; +$icon-checkmark-circle-lg: ''; $icon-arrow-down: ''; +$icon-shipping: ''; +$icon-info: ''; // - Circle Images $circle-primary: ''; @@ -203,11 +211,18 @@ $circle-secondary: '