Passed
Pull Request — master (#74)
by oleksandr
04:28
created

src/SprykerEco/Yves/Payone/Theme/default/components/molecules/payone-credit-card/payone-credit-card.ts   A

Complexity

Total Complexity 19
Complexity/F 1.73

Size

Lines of Code 227
Function Count 11

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 19
eloc 174
mnd 8
bc 8
fnc 11
dl 0
loc 227
bpm 0.7272
cpm 1.7272
noi 0
c 0
b 0
f 0
rs 10

11 Functions

Rating   Name   Duplication   Size   Complexity  
A PayoneCreditCard.setPaymentToValid 0 3 1
A PayoneCreditCard.checkCreditCard 0 10 2
A PayoneCreditCard.checkCallback 0 11 2
A PayoneCreditCard.readyCallback 0 2 1
A PayoneCreditCard.onScriptLoad 0 4 1
A PayoneCreditCard.mapEvents 0 4 1
A PayoneCreditCard.addCheckCallbackToGlobalScope 0 3 1
A PayoneCreditCard.onSubmit 0 12 3
A PayoneCreditCard.loadPayoneIFrame 0 6 1
A PayoneCreditCard.enableSubmit 0 13 2
A PayoneCreditCard.init 0 13 1
1
/* tslint:disable: no-any */
2
/* tslint:disable: max-file-line-count */
3
declare var Payone: any;
4
5
import Component from 'ShopUi/models/component';
6
import ScriptLoader from 'ShopUi/components/molecules/script-loader/script-loader';
7
8
const CURRENT_PAYMENT_METHOD = 'payoneCreditCard';
9
const CHECK_CALLBACK_ID = 'checkCallback';
10
const CHECK_CALLBACK_VALID_RESPONSE_STATUS = 'VALID';
11
12
// configuration for Hosted Iframe.
13
// https://github.com/fjbender/simple-php-integration#build-the-form
14
const defaultHostedIFramesConfig = {
15
    fields: {
16
        cardtype: {
17
            selector: 'cardtype',
18
            cardtypes: ['V', 'M'],
19
        },
20
        cardpan: {
21
            selector: 'cardpan',
22
            type: 'text',
23
        },
24
        cardcvc2: {
25
            selector: 'cardcvc2',
26
            type: 'password',
27
            size: '3',
28
            maxlength: '3',
29
            length: { V: 3, M: 3 },
30
        },
31
        cardexpiremonth: {
32
            selector: 'cardexpiremonth',
33
            type: 'select',
34
            size: '2',
35
            maxlength: '2',
36
            iframe: {
37
                width: '100%',
38
            },
39
        },
40
        cardexpireyear: {
41
            selector: 'cardexpireyear',
42
            type: 'select',
43
            iframe: {
44
                width: '100%',
45
            },
46
        },
47
    },
48
49
    defaultStyle: {
50
        input: `font-size: 0.875em; height: 2rem; width: 100%; border: 0; outline: 1px solid #dadada; outline-offset: -1px;`,
51
        select: `font-size: 0.875em; height: 2rem; width: 100%; border: 0; outline: 1px solid #dadada; outline-offset: -1px; background-color: #fefefe;`,
52
        iframe: {
53
            height: '35px',
54
            width: '100%',
55
        },
56
    },
57
58
    error: 'errorOutput',
59
};
60
61
export default class PayoneCreditCard extends Component {
62
    scriptLoader: ScriptLoader;
63
    form: HTMLFormElement;
64
    hostedIFramesApi: any;
65
    cardTypeInput: HTMLInputElement;
66
    cardHolderInput: HTMLInputElement;
67
    clientApiConfigInput: HTMLInputElement;
68
    languageInput: HTMLInputElement;
69
    pseudoCardPanInput: HTMLInputElement;
70
    errorElement: HTMLElement;
71
    protected isPaymentValid: boolean = false;
72
73
    protected submitButton: HTMLButtonElement[];
74
75
    protected readyCallback(): void {}
76
77
    protected init(): void {
78
        this.scriptLoader = <ScriptLoader>this.querySelector('script-loader');
79
        this.form = <HTMLFormElement>document.querySelector(this.formSelector);
80
        this.cardHolderInput = <HTMLInputElement>this.querySelector(this.cardHolderSelector);
81
        this.clientApiConfigInput = <HTMLInputElement>this.querySelector(this.clientApiConfigSelector);
82
        this.languageInput = <HTMLInputElement>this.querySelector(this.languageSelector);
83
        this.pseudoCardPanInput = <HTMLInputElement>this.querySelector(this.pseudoCardPanSelector);
84
        this.errorElement = this.querySelector(this.errorContainer);
85
        this.submitButton = <HTMLButtonElement[]>Array.from(
86
            document.getElementsByClassName(`${this.jsName}__submit`)
87
        );
88
89
        this.mapEvents();
90
    }
91
92
    protected mapEvents(): void {
93
        this.scriptLoader.addEventListener('scriptload', (event: Event) => this.onScriptLoad(event));
94
        this.form.addEventListener('submit', (event: Event) => this.onSubmit(event));
95
    }
96
97
    protected onScriptLoad(event: Event): void {
98
        this.addCheckCallbackToGlobalScope();
99
        this.loadPayoneIFrame();
100
    }
101
102
    protected onSubmit(event: Event): void {
103
        if (!this.isCurrentPaymentMethod) {
104
            return;
105
        }
106
107
        event.preventDefault();
108
109
        if (this.isPaymentValid) {
110
            this.form.submit();
111
        }
112
113
        this.checkCreditCard();
114
    }
115
116
    protected addCheckCallbackToGlobalScope(): void {
117
        window[CHECK_CALLBACK_ID] = this.checkCallback.bind(this);
118
    }
119
120
    protected async checkCallback(response: any): Promise<void> {
121
        if (response.status !== CHECK_CALLBACK_VALID_RESPONSE_STATUS) {
122
            setTimeout(() => this.enableSubmit(), 0);
123
124
            return;
125
        }
126
127
        this.pseudoCardPanInput.value = await Promise.resolve(response.pseudocardpan);
128
        this.setPaymentToValid();
129
        this.form.submit();
130
    }
131
132
    protected checkCreditCard(): void {
133
        if (this.hostedIFramesApi.isComplete() && this.cardHolderInput.value) {
134
            this.hostedIFramesApi.creditCardCheck(CHECK_CALLBACK_ID);
135
136
            return;
137
        }
138
139
        this.errorElement.innerHTML = this.hostedIFramesConfig.language.transactionRejected;
140
        setTimeout(() => this.enableSubmit(), 0);
141
    }
142
143
    protected enableSubmit(): void {
144
        if (this.submitButton.length) {
145
            this.submitButton.forEach(button => {
146
                button.removeAttribute('disabled');
147
            });
148
149
            return;
150
        }
151
152
        const buttons = <HTMLButtonElement[]>Array.from(this.form.getElementsByTagName('button'));
153
        buttons.forEach(button => {
154
            button.removeAttribute('disabled');
155
        });
156
    }
157
158
    protected loadPayoneIFrame(): void {
159
        this.hostedIFramesApi = new Payone.ClientApi.HostedIFrames(this.hostedIFramesConfig, this.clientApiConfig);
160
161
        Payone.ClientApi.Language.de.placeholders.cardpan = '_ _ _ _  _ _ _ _  _ _ _ _  _ _ _ _';
162
        Payone.ClientApi.Language.de.placeholders.cvc = '• • •';
163
    }
164
165
    protected setPaymentToValid(): void {
166
        this.isPaymentValid = true;
167
    }
168
169
    get isCurrentPaymentMethod(): boolean | null {
170
        const currentPaymentMethodInput = <HTMLInputElement>document.querySelector(this.currentPaymentMethodSelector);
171
172
        return currentPaymentMethodInput?.value
173
            ? currentPaymentMethodInput.value === CURRENT_PAYMENT_METHOD
174
            : null;
175
    }
176
177
    get language(): string {
178
        const languageCodeLenght = 2;
179
        const languageCode = !!this.languageInput.value ? this.languageInput.value.substr(0, languageCodeLenght) : 'de';
180
181
        return Payone.ClientApi.Language[languageCode] || Payone.ClientApi.Language.de;
182
    }
183
184
    get hostedIFramesConfig(): any {
185
        return {
186
            ...defaultHostedIFramesConfig,
187
            language: this.language
188
        };
189
    }
190
191
    get clientApiConfig(): any {
192
        return JSON.parse(this.clientApiConfigInput.value);
193
    }
194
195
    get formSelector(): string {
196
        return this.getAttribute('form-selector');
197
    }
198
199
    get clientApiConfigSelector(): string {
200
        return this.getAttribute('client-api-config-selector');
201
    }
202
203
    get languageSelector(): string {
204
        return this.getAttribute('language-selector');
205
    }
206
207
    get cardTypeSelector(): string {
208
        return this.getAttribute('card-type-selector');
209
    }
210
211
    get cardHolderSelector(): string {
212
        return this.getAttribute('card-holder-selector');
213
    }
214
215
    get pseudoCardPanSelector(): string {
216
        return this.getAttribute('pseudo-card-pan-selector');
217
    }
218
219
    get errorContainer(): string {
220
        return this.getAttribute('error-container-selector');
221
    }
222
223
    get currentPaymentMethodSelector(): string {
224
        return this.getAttribute('current-payment-method-selector');
225
    }
226
}
227