@miden-npm/angular 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/buzapay-checkout/index.d.ts +114 -13
- package/fesm2022/miden-npm-angular-buzapay-checkout.mjs +743 -35
- package/fesm2022/miden-npm-angular-buzapay-checkout.mjs.map +1 -1
- package/fesm2022/miden-npm-angular.mjs +314 -14
- package/fesm2022/miden-npm-angular.mjs.map +1 -1
- package/index.d.ts +231 -44
- package/package.json +32 -22
- package/styles.css +1 -1
|
@@ -1,47 +1,400 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import { EventEmitter, Output, Input, ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
|
|
3
3
|
import * as i1 from '@miden-npm/angular';
|
|
4
|
-
import { ButtonComponent, InputComponent, SelectComponent, LabelInfoComponent, CopyComponent,
|
|
5
|
-
import * as i2 from '@angular/
|
|
6
|
-
import {
|
|
4
|
+
import { getValidationErrorMessage, cardType, checkObjectTruthy, getQueryParams, ButtonComponent, InputComponent, SelectComponent, formatAmount, LabelInfoComponent, CopyComponent, CurrencyAmountComponent, IconArrowSwapComponent, RadioGroupComponent, ImageComponent, SuccessComponent, CardComponent, IconLoaderComponent, InputErrorComponent } from '@miden-npm/angular';
|
|
5
|
+
import * as i2 from '@angular/forms';
|
|
6
|
+
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
7
7
|
import { tap, finalize } from 'rxjs';
|
|
8
|
+
import * as i2$1 from '@angular/common';
|
|
9
|
+
import { CommonModule } from '@angular/common';
|
|
8
10
|
|
|
9
11
|
class PayByCardComponent {
|
|
12
|
+
resources;
|
|
13
|
+
cdr;
|
|
14
|
+
checkout;
|
|
15
|
+
encryptService;
|
|
16
|
+
constructor(resources, cdr, checkout, encryptService) {
|
|
17
|
+
this.resources = resources;
|
|
18
|
+
this.cdr = cdr;
|
|
19
|
+
this.checkout = checkout;
|
|
20
|
+
this.encryptService = encryptService;
|
|
21
|
+
}
|
|
22
|
+
secretKey = '';
|
|
23
|
+
environment = '';
|
|
24
|
+
paymentObject = {
|
|
25
|
+
merchantName: '',
|
|
26
|
+
amount: 0,
|
|
27
|
+
currency: '',
|
|
28
|
+
email: '',
|
|
29
|
+
phoneNumber: '',
|
|
30
|
+
narration: '',
|
|
31
|
+
redirectUrl: '',
|
|
32
|
+
};
|
|
33
|
+
paymentAuthorized = new EventEmitter();
|
|
34
|
+
loading = false;
|
|
35
|
+
loadingCountries = false;
|
|
36
|
+
loadingStates = false;
|
|
37
|
+
isMakingPayment = false;
|
|
38
|
+
cardType = '';
|
|
39
|
+
message = '';
|
|
40
|
+
transactionReference = '';
|
|
41
|
+
countries = [];
|
|
42
|
+
countryStates = [];
|
|
10
43
|
formIndex = 0;
|
|
11
44
|
setFormIndex(index) {
|
|
12
45
|
this.formIndex = index;
|
|
13
46
|
}
|
|
14
|
-
|
|
15
|
-
|
|
47
|
+
billingForm = new FormGroup({
|
|
48
|
+
address1: new FormControl('', [Validators.required]),
|
|
49
|
+
address2: new FormControl(''),
|
|
50
|
+
postalCode: new FormControl('', [Validators.required]),
|
|
51
|
+
state: new FormControl('', [Validators.required]),
|
|
52
|
+
city: new FormControl('', [Validators.required]),
|
|
53
|
+
country: new FormControl('', [Validators.required]),
|
|
54
|
+
emailAddress: new FormControl('', [Validators.required, Validators.email]),
|
|
55
|
+
phoneNumber: new FormControl('', [Validators.required]),
|
|
56
|
+
});
|
|
57
|
+
payForm = new FormGroup({
|
|
58
|
+
customerName: new FormControl('', [Validators.required]),
|
|
59
|
+
cardNo: new FormControl('', [Validators.required]),
|
|
60
|
+
expireDate: new FormControl('', [Validators.required]),
|
|
61
|
+
cvv: new FormControl('', [Validators.required]),
|
|
62
|
+
cardPin: new FormControl(''), // Only required for Verve cards
|
|
63
|
+
});
|
|
64
|
+
getError(formKey, controlName, label) {
|
|
65
|
+
const control = formKey === 'billing' ? this.billingForm.get(controlName) : this.payForm.get(controlName);
|
|
66
|
+
return getValidationErrorMessage(control, label);
|
|
67
|
+
}
|
|
68
|
+
cardNumberInputHandler(event) {
|
|
69
|
+
this.cardType = cardType(event);
|
|
70
|
+
this.updatePinValidation();
|
|
71
|
+
}
|
|
72
|
+
updatePinValidation() {
|
|
73
|
+
const cardPinControl = this.payForm.get('cardPin');
|
|
74
|
+
if (this.cardType === 'Verve') {
|
|
75
|
+
cardPinControl?.setValidators([Validators.required]);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
cardPinControl?.clearValidators();
|
|
79
|
+
}
|
|
80
|
+
cardPinControl?.updateValueAndValidity();
|
|
81
|
+
}
|
|
82
|
+
async getAllCountries() {
|
|
83
|
+
this.loadingCountries = true;
|
|
84
|
+
this.cdr.markForCheck();
|
|
85
|
+
this.resources
|
|
86
|
+
.getCountries(this.environment, this.secretKey)
|
|
87
|
+
.pipe(tap((res) => {
|
|
88
|
+
if (res?.isSuccessful) {
|
|
89
|
+
this.countries = (res.data ?? []).map((c) => {
|
|
90
|
+
return { label: c.countryName, value: c.iso3 };
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}), finalize(() => {
|
|
94
|
+
this.loadingCountries = false;
|
|
95
|
+
this.cdr.markForCheck();
|
|
96
|
+
}))
|
|
97
|
+
.subscribe();
|
|
98
|
+
}
|
|
99
|
+
async getCountryStates(countryIso3) {
|
|
100
|
+
this.loadingStates = true;
|
|
101
|
+
this.cdr.markForCheck();
|
|
102
|
+
this.resources
|
|
103
|
+
.getCountryStates(countryIso3, this.environment, this.secretKey)
|
|
104
|
+
.pipe(tap((res) => {
|
|
105
|
+
if (res?.isSuccessful) {
|
|
106
|
+
this.countryStates = (res.data ?? []).map((s) => {
|
|
107
|
+
return { label: s.name, value: s.name };
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}), finalize(() => {
|
|
111
|
+
this.loadingStates = false;
|
|
112
|
+
this.cdr.markForCheck();
|
|
113
|
+
}))
|
|
114
|
+
.subscribe();
|
|
115
|
+
}
|
|
116
|
+
async generatePaymentLinkHandler() {
|
|
117
|
+
if (!this.secretKey) {
|
|
118
|
+
return (this.message = 'Secret key is required.');
|
|
119
|
+
}
|
|
120
|
+
if (!checkObjectTruthy(this.paymentObject)) {
|
|
121
|
+
return (this.message = 'Kindly ensure you are passing all the required data.');
|
|
122
|
+
}
|
|
123
|
+
this.loading = true;
|
|
124
|
+
this.cdr.markForCheck();
|
|
125
|
+
this.checkout
|
|
126
|
+
.createPaymentLink(this.paymentObject, this.environment, this.secretKey)
|
|
127
|
+
.pipe(tap((res) => {
|
|
128
|
+
if (res?.isSuccessful) {
|
|
129
|
+
this.message = 'Payment link created successfully';
|
|
130
|
+
const queryParams = getQueryParams(res.launchUrl ?? '');
|
|
131
|
+
this.transactionReference = queryParams['paymentReference'];
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this.message = 'Failed to create payment link';
|
|
135
|
+
}
|
|
136
|
+
}), finalize(() => {
|
|
137
|
+
this.loading = false;
|
|
138
|
+
this.cdr.markForCheck();
|
|
139
|
+
}))
|
|
140
|
+
.subscribe();
|
|
141
|
+
}
|
|
142
|
+
async proceedHandler() {
|
|
143
|
+
if (this.formIndex === 0) {
|
|
144
|
+
if (this.billingForm && this.billingForm.valid) {
|
|
145
|
+
this.checkout.setBillingInfo({ ...this.billingForm.value });
|
|
146
|
+
this.setFormIndex(1);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
this.billingForm.markAllAsTouched();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
if (this.payForm && this.payForm.valid) {
|
|
154
|
+
try {
|
|
155
|
+
this.isMakingPayment = true;
|
|
156
|
+
// Create card details object for encryption
|
|
157
|
+
const cardDetails = {
|
|
158
|
+
pan: this.payForm.value.cardNo ?? '',
|
|
159
|
+
expiryDate: this.payForm.value.expireDate ?? '',
|
|
160
|
+
cvv: this.payForm.value.cvv ?? '',
|
|
161
|
+
cardScheme: this.cardType,
|
|
162
|
+
nameOnCard: this.payForm.value.customerName ?? '',
|
|
163
|
+
...(this.cardType === 'Verve' && { pin: this.payForm.value.cardPin ?? '' }),
|
|
164
|
+
};
|
|
165
|
+
// Get billing details from the form control
|
|
166
|
+
const billingDetails = {
|
|
167
|
+
address2: this.billingForm.value.address2 ?? '',
|
|
168
|
+
address1: this.billingForm.value.address1 ?? '',
|
|
169
|
+
postalCode: this.billingForm.value.postalCode ?? '',
|
|
170
|
+
state: this.billingForm.value.state ?? '',
|
|
171
|
+
city: this.billingForm.value.city ?? '',
|
|
172
|
+
country: this.billingForm.value.country ?? '',
|
|
173
|
+
emailAddress: this.billingForm.value.emailAddress ?? '',
|
|
174
|
+
phoneNumber: this.billingForm.value.phoneNumber ?? '',
|
|
175
|
+
};
|
|
176
|
+
// Encrypt card details using payload encryption method
|
|
177
|
+
const encryptedCardDetails = this.encryptService.encryptPayload(this.environment, cardDetails);
|
|
178
|
+
// Test: Decrypt to verify encryption works
|
|
179
|
+
const decryptedTest = this.encryptService.decryptPayload(this.environment, encryptedCardDetails.requestParam);
|
|
180
|
+
const payload = {
|
|
181
|
+
customerId: this.paymentObject?.email || this.payForm.value.customerName || '',
|
|
182
|
+
amount: this.paymentObject?.amount.toString(),
|
|
183
|
+
currency: this.paymentObject?.currency || 'USD',
|
|
184
|
+
narration: this.paymentObject?.narration || 'Test transaction',
|
|
185
|
+
encryptedCardDetails: encryptedCardDetails.requestParam, // Use the encrypted card details
|
|
186
|
+
billingDetails: billingDetails,
|
|
187
|
+
redirectUrl: this.paymentObject?.redirectUrl || '',
|
|
188
|
+
paymentReference: this.transactionReference,
|
|
189
|
+
isCheckout: true,
|
|
190
|
+
};
|
|
191
|
+
this.checkout
|
|
192
|
+
.authorizeCardPayment(this.environment, {
|
|
193
|
+
...payload,
|
|
194
|
+
merchantId: this.secretKey,
|
|
195
|
+
})
|
|
196
|
+
.subscribe({
|
|
197
|
+
next: async (response) => {
|
|
198
|
+
let processedResponse = response;
|
|
199
|
+
// Check if response is encrypted (has responseParam)
|
|
200
|
+
if (response?.responseParam) {
|
|
201
|
+
// Decrypt the response
|
|
202
|
+
processedResponse = this.encryptService.decryptPayload(this.environment, response.responseParam);
|
|
203
|
+
}
|
|
204
|
+
if (processedResponse?.isSuccessful) {
|
|
205
|
+
// Check for 3DS authentication requirement
|
|
206
|
+
if (processedResponse.threeDsInteractionRequired === true) {
|
|
207
|
+
// Store 3DS data for the authentication page
|
|
208
|
+
const threeDsData = {
|
|
209
|
+
transactionReference: processedResponse.transactionReference,
|
|
210
|
+
threeDsHtml: processedResponse.threeDsHtml,
|
|
211
|
+
amount: processedResponse.amount,
|
|
212
|
+
responseMessage: processedResponse.responseMessage,
|
|
213
|
+
// Pass all 3DS details
|
|
214
|
+
paReq: processedResponse.threeDsHtml?.paReq,
|
|
215
|
+
termUrl: processedResponse.threeDsHtml?.termUrl,
|
|
216
|
+
action: processedResponse.threeDsHtml?.action,
|
|
217
|
+
acsUrl: processedResponse.threeDsHtml?.acsUrl,
|
|
218
|
+
md: processedResponse.threeDsHtml?.md,
|
|
219
|
+
};
|
|
220
|
+
// Store 3DS data in localStorage for the new tab
|
|
221
|
+
localStorage.setItem('threeDsData', JSON.stringify(threeDsData));
|
|
222
|
+
// Open 3DS authentication page in a new tab
|
|
223
|
+
const threeDsUrl = `${window.location.origin}/account/three-ds-confirm`;
|
|
224
|
+
window.open(threeDsUrl, '_blank', 'noopener,noreferrer');
|
|
225
|
+
this.message =
|
|
226
|
+
'3D Secure authentication opened in new tab. Please complete the verification';
|
|
227
|
+
this.isMakingPayment = false;
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
// Fallback check: if response message indicates 3DS is required
|
|
231
|
+
if (processedResponse.responseMessage === 'Payer Interaction Required' &&
|
|
232
|
+
processedResponse.threeDsHtml) {
|
|
233
|
+
// Store 3DS data for the authentication page
|
|
234
|
+
const threeDsData = {
|
|
235
|
+
transactionReference: processedResponse.transactionReference,
|
|
236
|
+
threeDsHtml: processedResponse.threeDsHtml,
|
|
237
|
+
amount: processedResponse.amount,
|
|
238
|
+
responseMessage: processedResponse.responseMessage,
|
|
239
|
+
// Pass all 3DS details
|
|
240
|
+
paReq: processedResponse.threeDsHtml?.paReq,
|
|
241
|
+
termUrl: processedResponse.threeDsHtml?.termUrl,
|
|
242
|
+
action: processedResponse.threeDsHtml?.action,
|
|
243
|
+
acsUrl: processedResponse.threeDsHtml?.acsUrl,
|
|
244
|
+
md: processedResponse.threeDsHtml?.md,
|
|
245
|
+
};
|
|
246
|
+
// Store 3DS data in localStorage for the new tab
|
|
247
|
+
localStorage.setItem('threeDsData', JSON.stringify(threeDsData));
|
|
248
|
+
// Open 3DS authentication page in a new tab
|
|
249
|
+
const threeDsUrl = `${window.location.origin}/account/three-ds-confirm`;
|
|
250
|
+
window.open(threeDsUrl, '_blank', 'noopener,noreferrer');
|
|
251
|
+
this.message =
|
|
252
|
+
'3D Secure authentication opened in new tab. Please complete the verification';
|
|
253
|
+
this.isMakingPayment = false;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
// Emit the transaction reference to parent component
|
|
257
|
+
if (processedResponse.transactionReference &&
|
|
258
|
+
processedResponse.transactionReference.trim() !== '') {
|
|
259
|
+
this.paymentAuthorized.emit({
|
|
260
|
+
paymentId: processedResponse.transactionReference,
|
|
261
|
+
paymentDate: response.data.updatedAt,
|
|
262
|
+
paymentStatus: 'Authorized',
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
this.message = 'Card payment authorized successfully';
|
|
266
|
+
// Handle legacy 3DS logic for backward compatibility
|
|
267
|
+
// if (processedResponse.provider === 'myRoute2') {
|
|
268
|
+
// if (processedResponse.requires3DS === true) {
|
|
269
|
+
// this.router.navigateByUrl('account/visa-card-payment-confirm');
|
|
270
|
+
// } else {
|
|
271
|
+
// if (processedResponse.responseCode === 'T00') {
|
|
272
|
+
// } else if (processedResponse.responseCode === '000') {
|
|
273
|
+
// this.message = 'Please confirm transaction !!';
|
|
274
|
+
// } else {
|
|
275
|
+
// this.message = processedResponse.responseMessage;
|
|
276
|
+
// }
|
|
277
|
+
// }
|
|
278
|
+
// } else if (processedResponse.provider === 'myRoute1') {
|
|
279
|
+
// if (processedResponse.requires3DS === true) {
|
|
280
|
+
// this.router.navigateByUrl('account/visa-card-payment-confirm2');
|
|
281
|
+
// }
|
|
282
|
+
// }
|
|
283
|
+
this.isMakingPayment = false;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
this.isMakingPayment = false;
|
|
287
|
+
this.message = processedResponse.responseMessage || 'Payment failed';
|
|
288
|
+
this.paymentAuthorized.emit({
|
|
289
|
+
paymentId: processedResponse.transactionReference,
|
|
290
|
+
paymentDate: response.data.updatedAt,
|
|
291
|
+
paymentStatus: 'Payment failed',
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
error: (err) => {
|
|
296
|
+
this.isMakingPayment = false;
|
|
297
|
+
if (err.error?.responseParam) {
|
|
298
|
+
// Decrypt error response
|
|
299
|
+
const decryptedErrorResponse = this.encryptService.decryptPayload(this.environment, err.error.responseParam);
|
|
300
|
+
this.message = decryptedErrorResponse.responseMessage || 'Payment failed';
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
this.message = err.error.responseMessage || err.error.message || 'Payment failed';
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
this.isMakingPayment = false;
|
|
310
|
+
this.message = 'An unexpected error occurred';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
this.payForm.markAllAsTouched();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async ngOnInit() {
|
|
319
|
+
await this.generatePaymentLinkHandler();
|
|
320
|
+
await this.getAllCountries();
|
|
321
|
+
}
|
|
322
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByCardComponent, deps: [{ token: i1.ResourceService }, { token: i0.ChangeDetectorRef }, { token: i1.CheckoutService }, { token: i1.EncryptService }], target: i0.ɵɵFactoryTarget.Component });
|
|
323
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: PayByCardComponent, isStandalone: true, selector: "pay-by-card", inputs: { secretKey: "secretKey", environment: "environment", paymentObject: "paymentObject" }, outputs: { paymentAuthorized: "paymentAuthorized" }, ngImport: i0, template: "<div class=\"flex flex-col gap-6\">\n <!-- Billing Details -->\n @if (formIndex === 0) {\n <form [formGroup]=\"billingForm\">\n <div class=\"grid grid-cols-2 gap-6 overflow-y-auto\">\n <div class=\"col-span-2\">\n <base-input\n formControlName=\"address1\"\n label=\"Address Line 1\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'address1', 'Address Line 1') || ''\"\n ></base-input>\n </div>\n <div class=\"col-span-2\">\n <base-input formControlName=\"address2\" label=\"Address Line 2\"></base-input>\n </div>\n <base-select\n formControlName=\"country\"\n label=\"Select Country\"\n [required]=\"true\"\n [options]=\"countries\"\n [loading]=\"loadingCountries\"\n [validationError]=\"getError('billing', 'country', 'Country') || ''\"\n (onSelectChange)=\"getCountryStates($event)\"\n ></base-select>\n <base-select\n formControlName=\"state\"\n label=\"Select State\"\n [required]=\"true\"\n [options]=\"countryStates\"\n [loading]=\"loadingStates\"\n [validationError]=\"getError('billing', 'state', 'State') || ''\"\n ></base-select>\n <base-input\n formControlName=\"city\"\n label=\"City\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'city', 'City') || ''\"\n ></base-input>\n <base-input\n formControlName=\"postalCode\"\n label=\"Postal Code\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'postalCode', 'Postal Code') || ''\"\n ></base-input>\n <base-input\n formControlName=\"emailAddress\"\n label=\"Email\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'emailAddress', 'Email Address') || ''\"\n ></base-input>\n <base-input\n formControlName=\"phoneNumber\"\n label=\"Phone Number\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'phoneNumber', 'Phone Number') || ''\"\n ></base-input>\n </div>\n </form>\n }\n\n <!-- Card Details -->\n @if (formIndex === 1) {\n <form [formGroup]=\"payForm\">\n <div class=\"grid grid-cols-2 gap-6 overflow-y-auto\" style=\"max-height: 320px\">\n <div class=\"col-span-2\">\n <base-input\n formControlName=\"customerName\"\n label=\"Card Name\"\n [required]=\"true\"\n [validationError]=\"getError('pay', 'customerName', 'Customer Name') || ''\"\n ></base-input>\n </div>\n <div class=\"col-span-2\">\n <base-input\n formControlName=\"cardNo\"\n label=\"Card Number\"\n [required]=\"true\"\n mask=\"0000 0000 0000 0000\"\n placeholder=\"0000 0000 0000 0000\"\n [validationError]=\"getError('pay', 'cardNo', 'Card Number') || ''\"\n (onInputChange)=\"cardNumberInputHandler($event)\"\n ></base-input>\n </div>\n <base-input\n formControlName=\"expireDate\"\n label=\"Expiry Date\"\n [required]=\"true\"\n mask=\"00/00\"\n placeholder=\"00/00\"\n [validationError]=\"getError('pay', 'expireDate', 'Expiry Date') || ''\"\n ></base-input>\n <base-input\n formControlName=\"cvv\"\n label=\"CVV\"\n [required]=\"true\"\n mask=\"000\"\n placeholder=\"000\"\n [validationError]=\"getError('pay', 'cvv', 'CVV') || ''\"\n ></base-input>\n\n @if (cardType === 'Verve') {\n <base-input\n formControlName=\"cardPin\"\n label=\"Card Pin\"\n type=\"password\"\n placeholder=\"0000\"\n mask=\"0000\"\n [required]=\"true\"\n [validationError]=\"getError('pay', 'cardPin', 'Card Pin') || ''\"\n ></base-input>\n <div class=\"text-sm text-blue-600 mb-4\">\n <i class=\"fas fa-info-circle mr-1\"></i>\n Pin is required for Verve cards\n </div>\n }\n </div>\n </form>\n }\n\n <base-button\n [label]=\"formIndex === 0 ? 'Proceed' : 'Pay'\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isMakingPayment\"\n (onClick)=\"proceedHandler()\"\n ></base-button>\n</div>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "base-button", inputs: ["label", "type", "size", "paddingClassX", "disabled", "loading", "customClass"], outputs: ["onClick"] }, { kind: "component", type: InputComponent, selector: "base-input", inputs: ["label", "type", "placeholder", "validationError", "hint", "mask", "rules", "isAmountInput", "required", "disabled", "loading", "showCopyIcon"], outputs: ["onInputChange", "onInputBlur"] }, { kind: "component", type: SelectComponent, selector: "base-select", inputs: ["options", "placeholder", "hasSearch", "disabled", "loading", "validationError", "label", "hint", "required", "itemImageType"], outputs: ["onSelectChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
16
324
|
}
|
|
17
325
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByCardComponent, decorators: [{
|
|
18
326
|
type: Component,
|
|
19
|
-
args: [{ selector: 'pay-by-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent, InputComponent, SelectComponent], template: "<div class=\"flex flex-col gap-6\">\n <!-- Billing Details -->\n @if (formIndex === 0) {\n <div class=\"grid grid-cols-2 gap-6 overflow-y-auto\">\n
|
|
20
|
-
}] }
|
|
327
|
+
args: [{ selector: 'pay-by-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent, InputComponent, SelectComponent, ReactiveFormsModule], template: "<div class=\"flex flex-col gap-6\">\n <!-- Billing Details -->\n @if (formIndex === 0) {\n <form [formGroup]=\"billingForm\">\n <div class=\"grid grid-cols-2 gap-6 overflow-y-auto\">\n <div class=\"col-span-2\">\n <base-input\n formControlName=\"address1\"\n label=\"Address Line 1\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'address1', 'Address Line 1') || ''\"\n ></base-input>\n </div>\n <div class=\"col-span-2\">\n <base-input formControlName=\"address2\" label=\"Address Line 2\"></base-input>\n </div>\n <base-select\n formControlName=\"country\"\n label=\"Select Country\"\n [required]=\"true\"\n [options]=\"countries\"\n [loading]=\"loadingCountries\"\n [validationError]=\"getError('billing', 'country', 'Country') || ''\"\n (onSelectChange)=\"getCountryStates($event)\"\n ></base-select>\n <base-select\n formControlName=\"state\"\n label=\"Select State\"\n [required]=\"true\"\n [options]=\"countryStates\"\n [loading]=\"loadingStates\"\n [validationError]=\"getError('billing', 'state', 'State') || ''\"\n ></base-select>\n <base-input\n formControlName=\"city\"\n label=\"City\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'city', 'City') || ''\"\n ></base-input>\n <base-input\n formControlName=\"postalCode\"\n label=\"Postal Code\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'postalCode', 'Postal Code') || ''\"\n ></base-input>\n <base-input\n formControlName=\"emailAddress\"\n label=\"Email\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'emailAddress', 'Email Address') || ''\"\n ></base-input>\n <base-input\n formControlName=\"phoneNumber\"\n label=\"Phone Number\"\n [required]=\"true\"\n [validationError]=\"getError('billing', 'phoneNumber', 'Phone Number') || ''\"\n ></base-input>\n </div>\n </form>\n }\n\n <!-- Card Details -->\n @if (formIndex === 1) {\n <form [formGroup]=\"payForm\">\n <div class=\"grid grid-cols-2 gap-6 overflow-y-auto\" style=\"max-height: 320px\">\n <div class=\"col-span-2\">\n <base-input\n formControlName=\"customerName\"\n label=\"Card Name\"\n [required]=\"true\"\n [validationError]=\"getError('pay', 'customerName', 'Customer Name') || ''\"\n ></base-input>\n </div>\n <div class=\"col-span-2\">\n <base-input\n formControlName=\"cardNo\"\n label=\"Card Number\"\n [required]=\"true\"\n mask=\"0000 0000 0000 0000\"\n placeholder=\"0000 0000 0000 0000\"\n [validationError]=\"getError('pay', 'cardNo', 'Card Number') || ''\"\n (onInputChange)=\"cardNumberInputHandler($event)\"\n ></base-input>\n </div>\n <base-input\n formControlName=\"expireDate\"\n label=\"Expiry Date\"\n [required]=\"true\"\n mask=\"00/00\"\n placeholder=\"00/00\"\n [validationError]=\"getError('pay', 'expireDate', 'Expiry Date') || ''\"\n ></base-input>\n <base-input\n formControlName=\"cvv\"\n label=\"CVV\"\n [required]=\"true\"\n mask=\"000\"\n placeholder=\"000\"\n [validationError]=\"getError('pay', 'cvv', 'CVV') || ''\"\n ></base-input>\n\n @if (cardType === 'Verve') {\n <base-input\n formControlName=\"cardPin\"\n label=\"Card Pin\"\n type=\"password\"\n placeholder=\"0000\"\n mask=\"0000\"\n [required]=\"true\"\n [validationError]=\"getError('pay', 'cardPin', 'Card Pin') || ''\"\n ></base-input>\n <div class=\"text-sm text-blue-600 mb-4\">\n <i class=\"fas fa-info-circle mr-1\"></i>\n Pin is required for Verve cards\n </div>\n }\n </div>\n </form>\n }\n\n <base-button\n [label]=\"formIndex === 0 ? 'Proceed' : 'Pay'\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isMakingPayment\"\n (onClick)=\"proceedHandler()\"\n ></base-button>\n</div>\n" }]
|
|
328
|
+
}], ctorParameters: () => [{ type: i1.ResourceService }, { type: i0.ChangeDetectorRef }, { type: i1.CheckoutService }, { type: i1.EncryptService }], propDecorators: { secretKey: [{
|
|
329
|
+
type: Input
|
|
330
|
+
}], environment: [{
|
|
331
|
+
type: Input
|
|
332
|
+
}], paymentObject: [{
|
|
333
|
+
type: Input
|
|
334
|
+
}], paymentAuthorized: [{
|
|
335
|
+
type: Output
|
|
336
|
+
}] } });
|
|
21
337
|
|
|
22
338
|
class PayByTransferComponent {
|
|
339
|
+
checkout;
|
|
23
340
|
cdr;
|
|
341
|
+
constructor(checkout, cdr) {
|
|
342
|
+
this.checkout = checkout;
|
|
343
|
+
this.cdr = cdr;
|
|
344
|
+
}
|
|
345
|
+
secretKey = '';
|
|
346
|
+
environment = '';
|
|
347
|
+
paymentObject = {
|
|
348
|
+
merchantName: '',
|
|
349
|
+
amount: 0,
|
|
350
|
+
currency: '',
|
|
351
|
+
email: '',
|
|
352
|
+
phoneNumber: '',
|
|
353
|
+
narration: '',
|
|
354
|
+
redirectUrl: '',
|
|
355
|
+
};
|
|
356
|
+
paymentAuthorized = new EventEmitter();
|
|
357
|
+
message = '';
|
|
358
|
+
generatingLink = false;
|
|
359
|
+
isMakingPayment = false;
|
|
360
|
+
isFetchingPaymentDetails = false;
|
|
361
|
+
isConfirmCall = false;
|
|
362
|
+
paymentMade = false;
|
|
363
|
+
isPaymentConfirmed = false;
|
|
364
|
+
paymentAccountDetails = null;
|
|
365
|
+
paymentReferenceDetails = null;
|
|
366
|
+
transactionReference = '';
|
|
367
|
+
paymentReferenceStatus = '';
|
|
24
368
|
countDownTime = '';
|
|
25
369
|
remainingSeconds = 30 * 60;
|
|
26
370
|
intervalId = null;
|
|
27
|
-
constructor(cdr) {
|
|
28
|
-
this.cdr = cdr;
|
|
29
|
-
}
|
|
30
371
|
updateDisplay() {
|
|
31
372
|
const minutes = Math.floor(this.remainingSeconds / 60);
|
|
32
373
|
const seconds = this.remainingSeconds % 60;
|
|
33
374
|
this.countDownTime = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
34
375
|
this.cdr.markForCheck(); // 👈 notify OnPush to re-render
|
|
35
376
|
}
|
|
377
|
+
transferForm = new FormGroup({
|
|
378
|
+
customerName: new FormControl('', [Validators.required]),
|
|
379
|
+
});
|
|
380
|
+
getError(controlName, label) {
|
|
381
|
+
const control = this.transferForm.get(controlName);
|
|
382
|
+
return getValidationErrorMessage(control, label);
|
|
383
|
+
}
|
|
384
|
+
get formatAmountHandler() {
|
|
385
|
+
return formatAmount(this.paymentObject.amount, this.paymentObject.currency);
|
|
386
|
+
}
|
|
36
387
|
startTimer() {
|
|
388
|
+
if (this.intervalId) {
|
|
389
|
+
clearInterval(this.intervalId);
|
|
390
|
+
this.intervalId = null;
|
|
391
|
+
}
|
|
37
392
|
this.updateDisplay();
|
|
38
393
|
this.intervalId = setInterval(() => {
|
|
39
394
|
this.remainingSeconds--;
|
|
40
395
|
if (this.remainingSeconds < 0) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.intervalId = null;
|
|
44
|
-
}
|
|
396
|
+
clearInterval(this.intervalId);
|
|
397
|
+
this.intervalId = null;
|
|
45
398
|
this.countDownTime = '00:00';
|
|
46
399
|
this.cdr.markForCheck();
|
|
47
400
|
return;
|
|
@@ -49,8 +402,129 @@ class PayByTransferComponent {
|
|
|
49
402
|
this.updateDisplay();
|
|
50
403
|
}, 1000);
|
|
51
404
|
}
|
|
52
|
-
|
|
405
|
+
async generatePaymentLinkHandler() {
|
|
406
|
+
if (!this.secretKey) {
|
|
407
|
+
return (this.message = 'Secret key is required.');
|
|
408
|
+
}
|
|
409
|
+
if (!checkObjectTruthy(this.paymentObject)) {
|
|
410
|
+
return (this.message = 'Kindly ensure you are passing all the required data.');
|
|
411
|
+
}
|
|
412
|
+
this.generatingLink = true;
|
|
413
|
+
this.cdr.markForCheck();
|
|
414
|
+
this.checkout
|
|
415
|
+
.createPaymentLink(this.paymentObject, this.environment, this.secretKey)
|
|
416
|
+
.pipe(tap((res) => {
|
|
417
|
+
if (res?.isSuccessful) {
|
|
418
|
+
this.message = 'Payment link created successfully';
|
|
419
|
+
const queryParams = getQueryParams(res.launchUrl ?? '');
|
|
420
|
+
this.transactionReference = queryParams['paymentReference'];
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
this.message = 'Failed to create payment link';
|
|
424
|
+
}
|
|
425
|
+
}), finalize(() => {
|
|
426
|
+
this.generatingLink = false;
|
|
427
|
+
this.cdr.markForCheck();
|
|
428
|
+
}))
|
|
429
|
+
.subscribe();
|
|
430
|
+
}
|
|
431
|
+
async payHandler() {
|
|
432
|
+
if (this.transferForm && this.transferForm.valid) {
|
|
433
|
+
const payload = {
|
|
434
|
+
paymentReference: this.transactionReference,
|
|
435
|
+
channel: 'virtual_account',
|
|
436
|
+
customerName: this.transferForm.value.customerName ?? '',
|
|
437
|
+
merchantId: this.secretKey,
|
|
438
|
+
};
|
|
439
|
+
this.isMakingPayment = true;
|
|
440
|
+
await this.checkout.generatePaymentAccount(this.environment, payload).subscribe({
|
|
441
|
+
next: async (response) => {
|
|
442
|
+
if (response?.isSuccessful) {
|
|
443
|
+
this.paymentAccountDetails = response.data;
|
|
444
|
+
this.startTimer();
|
|
445
|
+
this.message = 'Virtual account generated successfully for payment.';
|
|
446
|
+
this.isMakingPayment = false;
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
error: (err) => {
|
|
450
|
+
this.isMakingPayment = false;
|
|
451
|
+
this.message = err.error.responseMessage || err.error.message;
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
this.transferForm?.markAllAsTouched();
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async getReferenceDetails() {
|
|
460
|
+
this.isFetchingPaymentDetails = true;
|
|
461
|
+
await this.checkout
|
|
462
|
+
.getPaymentReferenceDetails(this.environment, this.transactionReference)
|
|
463
|
+
.subscribe({
|
|
464
|
+
next: async (response) => {
|
|
465
|
+
if (response?.isSuccessful) {
|
|
466
|
+
this.paymentReferenceDetails = response.data;
|
|
467
|
+
// Check if payment has been made (paymentStatus is "Payment Received")
|
|
468
|
+
if (response.data?.paymentStatus === 'Payment Received') {
|
|
469
|
+
this.paymentMade = true;
|
|
470
|
+
}
|
|
471
|
+
if (response.data?.finalTransactionStatus === null ||
|
|
472
|
+
response.data?.paymentStatus === null) {
|
|
473
|
+
if (this.isConfirmCall) {
|
|
474
|
+
this.message = 'Transaction not confirmed !!';
|
|
475
|
+
}
|
|
476
|
+
// Only set to pending if payment hasn't been confirmed locally or made locally
|
|
477
|
+
if (!this.isPaymentConfirmed && !this.paymentMade) {
|
|
478
|
+
this.paymentReferenceStatus = 'pending';
|
|
479
|
+
this.paymentAuthorized.emit({
|
|
480
|
+
paymentId: this.transactionReference,
|
|
481
|
+
paymentDate: response.data.updatedAt,
|
|
482
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
this.paymentReferenceStatus = 'confirmed';
|
|
487
|
+
this.paymentAuthorized.emit({
|
|
488
|
+
paymentId: this.transactionReference,
|
|
489
|
+
paymentDate: response.data.updatedAt,
|
|
490
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else if (response.data?.finalTransactionStatus === 'Success' ||
|
|
495
|
+
response.data?.paymentStatus === 'Received' ||
|
|
496
|
+
response.data?.paymentStatus === 'Payment Received') {
|
|
497
|
+
this.paymentAuthorized.emit({
|
|
498
|
+
paymentId: this.transactionReference,
|
|
499
|
+
paymentDate: response.data.updatedAt,
|
|
500
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
501
|
+
});
|
|
502
|
+
this.message = 'Transaction confirmed !!';
|
|
503
|
+
this.paymentReferenceStatus = 'confirmed';
|
|
504
|
+
this.isPaymentConfirmed = true;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
else if (!response?.isSuccessful && response?.responseCode === '119') {
|
|
508
|
+
this.paymentReferenceStatus = 'used';
|
|
509
|
+
this.message = response.responseMessage;
|
|
510
|
+
this.paymentAuthorized.emit({
|
|
511
|
+
paymentId: this.transactionReference,
|
|
512
|
+
paymentDate: null,
|
|
513
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
this.isFetchingPaymentDetails = false;
|
|
517
|
+
},
|
|
518
|
+
error: (err) => {
|
|
519
|
+
this.paymentReferenceStatus = '';
|
|
520
|
+
this.isFetchingPaymentDetails = false;
|
|
521
|
+
this.message = err.error.responseMessage || err.error.message;
|
|
522
|
+
},
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
async ngOnInit() {
|
|
53
526
|
this.startTimer();
|
|
527
|
+
await this.generatePaymentLinkHandler();
|
|
54
528
|
}
|
|
55
529
|
ngOnDestroy() {
|
|
56
530
|
if (this.intervalId) {
|
|
@@ -58,38 +532,255 @@ class PayByTransferComponent {
|
|
|
58
532
|
this.intervalId = null;
|
|
59
533
|
}
|
|
60
534
|
}
|
|
61
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByTransferComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
62
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
535
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByTransferComponent, deps: [{ token: i1.CheckoutService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
536
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: PayByTransferComponent, isStandalone: true, selector: "pay-by-transfer", inputs: { secretKey: "secretKey", environment: "environment", paymentObject: "paymentObject" }, outputs: { paymentAuthorized: "paymentAuthorized" }, ngImport: i0, template: "<div class=\"flex flex-col gap-10\">\n @if (!paymentAccountDetails) {\n <form [formGroup]=\"transferForm\">\n <div class=\"flex flex-col gap-10\">\n <base-input\n formControlName=\"customerName\"\n label=\"Card Name\"\n [required]=\"true\"\n [validationError]=\"getError('customerName', 'Customer Name') || ''\"\n ></base-input>\n\n <base-button\n [label]=\"'Pay ' + formatAmountHandler\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isMakingPayment\"\n (onClick)=\"payHandler()\"\n ></base-button>\n </div>\n </form>\n }\n\n @if (paymentAccountDetails) {\n <div class=\"flex flex-col gap-10\">\n <div class=\"bg-[#EFF7FF] p-4 rounded-lg flex flex-col gap-6\">\n <base-label-info\n label=\"Bank Name\"\n [value]=\"paymentAccountDetails.bank + ' - ' + paymentAccountDetails.accountName\"\n ></base-label-info>\n <div class=\"flex items-center justify-between\">\n <base-label-info\n label=\"Account Number\"\n [value]=\"paymentAccountDetails.accountNumber\"\n ></base-label-info>\n <base-copy color=\"#9DBFDE\" [copyText]=\"paymentAccountDetails.accountNumber\"></base-copy>\n </div>\n <div class=\"flex items-center justify-between\">\n <base-label-info label=\"Amount\" [value]=\"formatAmountHandler\"></base-label-info>\n <base-copy color=\"#9DBFDE\" [copyText]=\"formatAmountHandler\"></base-copy>\n </div>\n </div>\n\n <p class=\"w-2/3 mx-auto text-center text-body-2xs font-medium text-sub-copy\">\n This account is for this transaction only and expires in\n <span class=\"text-orange-500\">{{ countDownTime }}</span>\n </p>\n\n <div class=\"flex flex-col gap-4\">\n <base-button\n label=\"I have paid the money\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isFetchingPaymentDetails\"\n (onClick)=\"getReferenceDetails()\"\n ></base-button>\n <p class=\"text-heading-text text-body-2xs font-medium text-center py-2 cursor-pointer\">\n Cancel Payment\n </p>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: LabelInfoComponent, selector: "base-label-info", inputs: ["type", "label", "labelCustomClass", "valueImageSrc", "valueImageCustomClass", "valueImagePosition", "hasValueCopy", "value", "valueCustomClass", "alignRight"] }, { kind: "component", type: CopyComponent, selector: "base-copy", inputs: ["copyText", "color"] }, { kind: "component", type: ButtonComponent, selector: "base-button", inputs: ["label", "type", "size", "paddingClassX", "disabled", "loading", "customClass"], outputs: ["onClick"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: InputComponent, selector: "base-input", inputs: ["label", "type", "placeholder", "validationError", "hint", "mask", "rules", "isAmountInput", "required", "disabled", "loading", "showCopyIcon"], outputs: ["onInputChange", "onInputBlur"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
63
537
|
}
|
|
64
538
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByTransferComponent, decorators: [{
|
|
65
539
|
type: Component,
|
|
66
|
-
args: [{ selector: 'pay-by-transfer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
67
|
-
|
|
540
|
+
args: [{ selector: 'pay-by-transfer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
541
|
+
LabelInfoComponent,
|
|
542
|
+
CopyComponent,
|
|
543
|
+
ButtonComponent,
|
|
544
|
+
ReactiveFormsModule,
|
|
545
|
+
InputComponent,
|
|
546
|
+
], template: "<div class=\"flex flex-col gap-10\">\n @if (!paymentAccountDetails) {\n <form [formGroup]=\"transferForm\">\n <div class=\"flex flex-col gap-10\">\n <base-input\n formControlName=\"customerName\"\n label=\"Card Name\"\n [required]=\"true\"\n [validationError]=\"getError('customerName', 'Customer Name') || ''\"\n ></base-input>\n\n <base-button\n [label]=\"'Pay ' + formatAmountHandler\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isMakingPayment\"\n (onClick)=\"payHandler()\"\n ></base-button>\n </div>\n </form>\n }\n\n @if (paymentAccountDetails) {\n <div class=\"flex flex-col gap-10\">\n <div class=\"bg-[#EFF7FF] p-4 rounded-lg flex flex-col gap-6\">\n <base-label-info\n label=\"Bank Name\"\n [value]=\"paymentAccountDetails.bank + ' - ' + paymentAccountDetails.accountName\"\n ></base-label-info>\n <div class=\"flex items-center justify-between\">\n <base-label-info\n label=\"Account Number\"\n [value]=\"paymentAccountDetails.accountNumber\"\n ></base-label-info>\n <base-copy color=\"#9DBFDE\" [copyText]=\"paymentAccountDetails.accountNumber\"></base-copy>\n </div>\n <div class=\"flex items-center justify-between\">\n <base-label-info label=\"Amount\" [value]=\"formatAmountHandler\"></base-label-info>\n <base-copy color=\"#9DBFDE\" [copyText]=\"formatAmountHandler\"></base-copy>\n </div>\n </div>\n\n <p class=\"w-2/3 mx-auto text-center text-body-2xs font-medium text-sub-copy\">\n This account is for this transaction only and expires in\n <span class=\"text-orange-500\">{{ countDownTime }}</span>\n </p>\n\n <div class=\"flex flex-col gap-4\">\n <base-button\n label=\"I have paid the money\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isFetchingPaymentDetails\"\n (onClick)=\"getReferenceDetails()\"\n ></base-button>\n <p class=\"text-heading-text text-body-2xs font-medium text-center py-2 cursor-pointer\">\n Cancel Payment\n </p>\n </div>\n </div>\n }\n</div>\n" }]
|
|
547
|
+
}], ctorParameters: () => [{ type: i1.CheckoutService }, { type: i0.ChangeDetectorRef }], propDecorators: { secretKey: [{
|
|
548
|
+
type: Input
|
|
549
|
+
}], environment: [{
|
|
550
|
+
type: Input
|
|
551
|
+
}], paymentObject: [{
|
|
552
|
+
type: Input
|
|
553
|
+
}], paymentAuthorized: [{
|
|
554
|
+
type: Output
|
|
555
|
+
}] } });
|
|
68
556
|
|
|
69
557
|
class PayByStableCoinComponent {
|
|
70
|
-
|
|
558
|
+
resource;
|
|
559
|
+
checkout;
|
|
560
|
+
cdr;
|
|
561
|
+
constructor(resource, checkout, cdr) {
|
|
562
|
+
this.resource = resource;
|
|
563
|
+
this.checkout = checkout;
|
|
564
|
+
this.cdr = cdr;
|
|
565
|
+
}
|
|
566
|
+
secretKey = '';
|
|
567
|
+
environment = '';
|
|
568
|
+
paymentObject = {
|
|
569
|
+
merchantName: '',
|
|
570
|
+
amount: 0,
|
|
571
|
+
currency: '',
|
|
572
|
+
email: '',
|
|
573
|
+
phoneNumber: '',
|
|
574
|
+
narration: '',
|
|
575
|
+
redirectUrl: '',
|
|
576
|
+
};
|
|
577
|
+
paymentAuthorized = new EventEmitter();
|
|
578
|
+
message = '';
|
|
579
|
+
transactionReference = '';
|
|
580
|
+
paymentReferenceStatus = '';
|
|
581
|
+
generateAddressPayload = null;
|
|
582
|
+
addressDetails = null;
|
|
583
|
+
paymentReferenceDetails = null;
|
|
584
|
+
stableCoins = [];
|
|
585
|
+
networkList = [];
|
|
586
|
+
loadingStableCoins = false;
|
|
587
|
+
generatingAddress = false;
|
|
588
|
+
isConfirmingPayment = false;
|
|
589
|
+
loading = false;
|
|
590
|
+
loadingStableCoinNetworks = false;
|
|
71
591
|
formIndex = 0;
|
|
72
592
|
setFormIndex(index) {
|
|
73
593
|
this.formIndex = index;
|
|
74
594
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
595
|
+
stableCoinForm = new FormGroup({
|
|
596
|
+
stableCoin: new FormControl('', [Validators.required]),
|
|
597
|
+
network: new FormControl('', [Validators.required]),
|
|
598
|
+
});
|
|
599
|
+
getError(controlName, label) {
|
|
600
|
+
const control = this.stableCoinForm.get(controlName);
|
|
601
|
+
return getValidationErrorMessage(control, label);
|
|
78
602
|
}
|
|
79
|
-
|
|
80
|
-
|
|
603
|
+
get amountPlusNetworkFee() {
|
|
604
|
+
return this.addressDetails
|
|
605
|
+
? Number(this.addressDetails.transactionAmount) + this.addressDetails.networkFee
|
|
606
|
+
: 0;
|
|
607
|
+
}
|
|
608
|
+
async generatePaymentLinkHandler() {
|
|
609
|
+
if (!this.secretKey) {
|
|
610
|
+
return (this.message = 'Secret key is required.');
|
|
611
|
+
}
|
|
612
|
+
if (!checkObjectTruthy(this.paymentObject)) {
|
|
613
|
+
return (this.message = 'Kindly ensure you are passing all the required data.');
|
|
614
|
+
}
|
|
615
|
+
this.loading = true;
|
|
616
|
+
this.cdr.markForCheck();
|
|
617
|
+
this.checkout
|
|
618
|
+
.createPaymentLink(this.paymentObject, this.environment, this.secretKey)
|
|
619
|
+
.pipe(tap((res) => {
|
|
620
|
+
if (res?.isSuccessful) {
|
|
621
|
+
this.message = 'Payment link created successfully';
|
|
622
|
+
const queryParams = getQueryParams(res.launchUrl ?? '');
|
|
623
|
+
this.transactionReference = queryParams['paymentReference'];
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
this.message = 'Failed to create payment link';
|
|
627
|
+
}
|
|
628
|
+
}), finalize(() => {
|
|
629
|
+
this.loading = false;
|
|
630
|
+
this.cdr.markForCheck();
|
|
631
|
+
}))
|
|
632
|
+
.subscribe();
|
|
633
|
+
}
|
|
634
|
+
generateAddress() {
|
|
635
|
+
if (!this.generateAddressPayload)
|
|
636
|
+
return;
|
|
637
|
+
this.generatingAddress = true;
|
|
638
|
+
this.cdr.markForCheck();
|
|
639
|
+
this.checkout
|
|
640
|
+
.generateStableCoinAddress(this.environment, this.generateAddressPayload)
|
|
641
|
+
.pipe(tap((response) => {
|
|
642
|
+
if (response?.isSuccessful) {
|
|
643
|
+
this.addressDetails = response.data;
|
|
644
|
+
this.setFormIndex(1);
|
|
645
|
+
}
|
|
646
|
+
}), finalize(() => {
|
|
647
|
+
this.generatingAddress = false;
|
|
648
|
+
this.cdr.markForCheck();
|
|
649
|
+
}))
|
|
650
|
+
.subscribe({
|
|
651
|
+
error: (err) => {
|
|
652
|
+
this.message = err.error.responseMessage || err.error.message;
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
async payHandler() {
|
|
657
|
+
if (this.stableCoinForm && this.stableCoinForm.valid) {
|
|
658
|
+
this.generateAddressPayload = {
|
|
659
|
+
paymentReference: this.transactionReference,
|
|
660
|
+
currency: this.stableCoinForm.get('stableCoin')?.value ?? '',
|
|
661
|
+
chain: this.stableCoinForm.get('network')?.value ?? '',
|
|
662
|
+
transactionAmount: this.paymentObject?.amount,
|
|
663
|
+
merchantId: this.secretKey,
|
|
664
|
+
};
|
|
665
|
+
await this.generateAddress();
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
this.stableCoinForm?.markAllAsTouched();
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
async getStableCoins() {
|
|
672
|
+
this.loadingStableCoins = true;
|
|
673
|
+
await this.resource.getStableCoins(this.environment).subscribe({
|
|
674
|
+
next: async (response) => {
|
|
675
|
+
if (response?.isSuccessful) {
|
|
676
|
+
this.stableCoins =
|
|
677
|
+
response.data?.map((c) => ({
|
|
678
|
+
label: c.name,
|
|
679
|
+
value: c.name,
|
|
680
|
+
})) ?? [];
|
|
681
|
+
this.loadingStableCoins = false;
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
error: (err) => {
|
|
685
|
+
this.loadingStableCoins = false;
|
|
686
|
+
this.message = err.error.responseMessage || err.error.message;
|
|
687
|
+
},
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
async getStableCoinNetworks() {
|
|
691
|
+
const stableCoin = this.stableCoinForm.get('stableCoin')?.value;
|
|
692
|
+
this.loadingStableCoinNetworks = true;
|
|
693
|
+
await this.resource.getStableCoinNetworks(this.environment, stableCoin ?? '').subscribe({
|
|
694
|
+
next: async (response) => {
|
|
695
|
+
if (response?.isSuccessful) {
|
|
696
|
+
this.networkList =
|
|
697
|
+
response.networks?.map((n) => ({
|
|
698
|
+
label: n,
|
|
699
|
+
value: n,
|
|
700
|
+
})) ?? [];
|
|
701
|
+
this.loadingStableCoinNetworks = false;
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
error: (err) => {
|
|
705
|
+
this.loadingStableCoinNetworks = false;
|
|
706
|
+
this.message = err.error.responseMessage || err.error.message;
|
|
707
|
+
},
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
async confirmPaymentHandler() {
|
|
711
|
+
this.isConfirmingPayment = true;
|
|
712
|
+
await this.checkout
|
|
713
|
+
.getPaymentReferenceDetails(this.environment, this.transactionReference)
|
|
714
|
+
.subscribe({
|
|
715
|
+
next: async (response) => {
|
|
716
|
+
if (response?.isSuccessful) {
|
|
717
|
+
this.paymentReferenceDetails = response.data;
|
|
718
|
+
if (response.data?.finalTransactionStatus === null ||
|
|
719
|
+
response.data?.paymentStatus === null) {
|
|
720
|
+
this.message = 'Transaction not confirmed !!';
|
|
721
|
+
this.paymentReferenceStatus = 'pending';
|
|
722
|
+
this.paymentAuthorized.emit({
|
|
723
|
+
paymentId: this.transactionReference,
|
|
724
|
+
paymentDate: response.data.updatedAt,
|
|
725
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
else if (response.data?.finalTransactionStatus === 'Success' ||
|
|
729
|
+
response.data?.paymentStatus === 'Payment Received') {
|
|
730
|
+
this.message = 'Transaction confirmed !!';
|
|
731
|
+
this.paymentReferenceStatus = 'confirmed';
|
|
732
|
+
this.paymentAuthorized.emit({
|
|
733
|
+
paymentId: this.transactionReference,
|
|
734
|
+
paymentDate: response.data.updatedAt,
|
|
735
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
else if (!response?.isSuccessful && response?.responseCode === '119') {
|
|
740
|
+
this.paymentReferenceStatus = 'used';
|
|
741
|
+
this.message = response.responseMessage;
|
|
742
|
+
this.paymentAuthorized.emit({
|
|
743
|
+
paymentId: this.transactionReference,
|
|
744
|
+
paymentDate: null,
|
|
745
|
+
paymentStatus: this.paymentReferenceStatus,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
this.isConfirmingPayment = false;
|
|
749
|
+
},
|
|
750
|
+
error: (err) => {
|
|
751
|
+
this.paymentReferenceStatus = '';
|
|
752
|
+
this.isConfirmingPayment = false;
|
|
753
|
+
this.message = err.error.responseMessage || err.error.message;
|
|
754
|
+
},
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
async ngOnInit() {
|
|
758
|
+
await this.generatePaymentLinkHandler();
|
|
759
|
+
await this.getStableCoins();
|
|
760
|
+
}
|
|
761
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByStableCoinComponent, deps: [{ token: i1.ResourceService }, { token: i1.CheckoutService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
762
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: PayByStableCoinComponent, isStandalone: true, selector: "pay-by-stable-coin", inputs: { secretKey: "secretKey", environment: "environment", paymentObject: "paymentObject" }, outputs: { paymentAuthorized: "paymentAuthorized" }, ngImport: i0, template: "<div class=\"flex flex-col gap-6\">\n @if (formIndex === 0) {\n <form [formGroup]=\"stableCoinForm\" class=\"grid grid-cols-1 gap-6\">\n <div class=\"grid grid-cols-1 gap-6\">\n <base-select\n formControlName=\"stableCoin\"\n label=\"Select Crypto\"\n [required]=\"true\"\n [options]=\"stableCoins\"\n [validationError]=\"getError('stableCoin', 'Select Crypto') ?? ''\"\n [loading]=\"loadingStableCoins\"\n (onSelectChange)=\"getStableCoinNetworks()\"\n ></base-select>\n <base-select\n formControlName=\"network\"\n label=\"Select Network\"\n [required]=\"true\"\n [options]=\"networkList\"\n [validationError]=\"getError('network', 'Network') ?? ''\"\n [loading]=\"loadingStableCoinNetworks\"\n ></base-select>\n </div>\n\n <base-button\n label=\"Pay\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"generatingAddress\"\n (onClick)=\"payHandler()\"\n ></base-button>\n </form>\n }\n\n @if (formIndex === 1) {\n <div class=\"flex flex-col gap-6\">\n <div class=\"mx-auto\">\n <!-- <base-image\n src=\"../../../assets/images/stable-coin-qr-code.png\"\n alt=\"QR Code\"\n [width]=\"122\"\n [height]=\"122\"\n class=\"mb-1\"\n ></base-image> -->\n <p class=\"mb-0 text-body-4xs text-light-copy font-normal text-center\">USDC</p>\n </div>\n\n <div class=\"flex flex-col gap-6 border-c border-grey-100 p-4 rounded-2xl bg-light-white-50\">\n <div class=\"border-b border-grey-border pb-4 flex flex-col gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">Network</p>\n <div class=\"flex justify-between\">\n <div class=\"flex flex-col gap-1\">\n <p class=\"mb-0 text-body-2xs font-medium text-sub-copy\">\n {{ addressDetails?.chain }}\n </p>\n <div class=\"flex items-center gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">*Est. arrival = 3 mins</p>\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">|</p>\n <base-currency-amount\n [currency]=\"generateAddressPayload?.currency ?? ''\"\n [amount]=\"addressDetails?.networkFee ?? 0\"\n textClass=\"mb-0 text-body-3xs text-light-copy font-normal\"\n iconColorClass=\"#557591\"\n iconWidth=\"12\"\n iconHeight=\"12\"\n ></base-currency-amount>\n </div>\n </div>\n <icon-arrow-swap></icon-arrow-swap>\n </div>\n </div>\n\n <div class=\"pb-4 flex flex-col gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">Deposit Address ></p>\n <div class=\"flex justify-between\">\n <p class=\"mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words\">\n {{ addressDetails?.walletAddress }}\n </p>\n <base-copy [copyText]=\"addressDetails?.walletAddress ?? ''\"></base-copy>\n </div>\n </div>\n\n <!-- <div class=\"pb-4 flex flex-col gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">Memo ></p>\n <div class=\"flex justify-between\">\n <p\n class=\"mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words\"\n >\n 0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6\n </p>\n <app-copy\n [isCopyIcon]=\"true\"\n [copyText]=\"'0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6'\"\n ></app-copy>\n </div>\n </div> -->\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <div class=\"flex items-center justify-between border-b border-grey-border py-3\">\n <p class=\"mb-0 text-body-2xs font-medium text-primary-black\">Network fee</p>\n <base-currency-amount\n [currency]=\"generateAddressPayload?.currency ?? ''\"\n [amount]=\"addressDetails?.networkFee ?? 0\"\n textClass=\"mb-0 text-body-2xs font-extrabold text-primary-black\"\n iconColorClass=\"#231F20\"\n ></base-currency-amount>\n </div>\n\n <div class=\"flex items-center justify-between py-4\">\n <p class=\"mb-0 text-body-lg font-semibold text-primary-black\">Pay</p>\n <base-currency-amount\n [currency]=\"generateAddressPayload?.currency ?? ''\"\n [amount]=\"amountPlusNetworkFee\"\n textClass=\"mb-0 text-body-lg font-extrabold text-primary-black\"\n iconColorClass=\"#231F20\"\n iconWidth=\"20\"\n iconHeight=\"20\"\n ></base-currency-amount>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-6\">\n <base-button\n label=\"Confirm Payment\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isConfirmingPayment\"\n (onClick)=\"confirmPaymentHandler()\"\n ></base-button>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: SelectComponent, selector: "base-select", inputs: ["options", "placeholder", "hasSearch", "disabled", "loading", "validationError", "label", "hint", "required", "itemImageType"], outputs: ["onSelectChange"] }, { kind: "component", type: ButtonComponent, selector: "base-button", inputs: ["label", "type", "size", "paddingClassX", "disabled", "loading", "customClass"], outputs: ["onClick"] }, { kind: "component", type:
|
|
763
|
+
// ImageComponent,
|
|
764
|
+
CurrencyAmountComponent, selector: "base-currency-amount", inputs: ["currency", "amount", "textClass", "iconColorClass", "iconWidth", "iconHeight"] }, { kind: "component", type: CopyComponent, selector: "base-copy", inputs: ["copyText", "color"] }, { kind: "component", type: IconArrowSwapComponent, selector: "icon-arrow-swap", inputs: ["color", "width", "height"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
81
765
|
}
|
|
82
766
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: PayByStableCoinComponent, decorators: [{
|
|
83
767
|
type: Component,
|
|
84
768
|
args: [{ selector: 'pay-by-stable-coin', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
85
769
|
SelectComponent,
|
|
86
770
|
ButtonComponent,
|
|
87
|
-
ImageComponent,
|
|
771
|
+
// ImageComponent,
|
|
88
772
|
CurrencyAmountComponent,
|
|
89
773
|
CopyComponent,
|
|
90
774
|
IconArrowSwapComponent,
|
|
91
|
-
|
|
92
|
-
|
|
775
|
+
ReactiveFormsModule,
|
|
776
|
+
], template: "<div class=\"flex flex-col gap-6\">\n @if (formIndex === 0) {\n <form [formGroup]=\"stableCoinForm\" class=\"grid grid-cols-1 gap-6\">\n <div class=\"grid grid-cols-1 gap-6\">\n <base-select\n formControlName=\"stableCoin\"\n label=\"Select Crypto\"\n [required]=\"true\"\n [options]=\"stableCoins\"\n [validationError]=\"getError('stableCoin', 'Select Crypto') ?? ''\"\n [loading]=\"loadingStableCoins\"\n (onSelectChange)=\"getStableCoinNetworks()\"\n ></base-select>\n <base-select\n formControlName=\"network\"\n label=\"Select Network\"\n [required]=\"true\"\n [options]=\"networkList\"\n [validationError]=\"getError('network', 'Network') ?? ''\"\n [loading]=\"loadingStableCoinNetworks\"\n ></base-select>\n </div>\n\n <base-button\n label=\"Pay\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"generatingAddress\"\n (onClick)=\"payHandler()\"\n ></base-button>\n </form>\n }\n\n @if (formIndex === 1) {\n <div class=\"flex flex-col gap-6\">\n <div class=\"mx-auto\">\n <!-- <base-image\n src=\"../../../assets/images/stable-coin-qr-code.png\"\n alt=\"QR Code\"\n [width]=\"122\"\n [height]=\"122\"\n class=\"mb-1\"\n ></base-image> -->\n <p class=\"mb-0 text-body-4xs text-light-copy font-normal text-center\">USDC</p>\n </div>\n\n <div class=\"flex flex-col gap-6 border-c border-grey-100 p-4 rounded-2xl bg-light-white-50\">\n <div class=\"border-b border-grey-border pb-4 flex flex-col gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">Network</p>\n <div class=\"flex justify-between\">\n <div class=\"flex flex-col gap-1\">\n <p class=\"mb-0 text-body-2xs font-medium text-sub-copy\">\n {{ addressDetails?.chain }}\n </p>\n <div class=\"flex items-center gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">*Est. arrival = 3 mins</p>\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">|</p>\n <base-currency-amount\n [currency]=\"generateAddressPayload?.currency ?? ''\"\n [amount]=\"addressDetails?.networkFee ?? 0\"\n textClass=\"mb-0 text-body-3xs text-light-copy font-normal\"\n iconColorClass=\"#557591\"\n iconWidth=\"12\"\n iconHeight=\"12\"\n ></base-currency-amount>\n </div>\n </div>\n <icon-arrow-swap></icon-arrow-swap>\n </div>\n </div>\n\n <div class=\"pb-4 flex flex-col gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">Deposit Address ></p>\n <div class=\"flex justify-between\">\n <p class=\"mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words\">\n {{ addressDetails?.walletAddress }}\n </p>\n <base-copy [copyText]=\"addressDetails?.walletAddress ?? ''\"></base-copy>\n </div>\n </div>\n\n <!-- <div class=\"pb-4 flex flex-col gap-2\">\n <p class=\"mb-0 text-body-3xs text-light-copy font-normal\">Memo ></p>\n <div class=\"flex justify-between\">\n <p\n class=\"mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words\"\n >\n 0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6\n </p>\n <app-copy\n [isCopyIcon]=\"true\"\n [copyText]=\"'0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6'\"\n ></app-copy>\n </div>\n </div> -->\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <div class=\"flex items-center justify-between border-b border-grey-border py-3\">\n <p class=\"mb-0 text-body-2xs font-medium text-primary-black\">Network fee</p>\n <base-currency-amount\n [currency]=\"generateAddressPayload?.currency ?? ''\"\n [amount]=\"addressDetails?.networkFee ?? 0\"\n textClass=\"mb-0 text-body-2xs font-extrabold text-primary-black\"\n iconColorClass=\"#231F20\"\n ></base-currency-amount>\n </div>\n\n <div class=\"flex items-center justify-between py-4\">\n <p class=\"mb-0 text-body-lg font-semibold text-primary-black\">Pay</p>\n <base-currency-amount\n [currency]=\"generateAddressPayload?.currency ?? ''\"\n [amount]=\"amountPlusNetworkFee\"\n textClass=\"mb-0 text-body-lg font-extrabold text-primary-black\"\n iconColorClass=\"#231F20\"\n iconWidth=\"20\"\n iconHeight=\"20\"\n ></base-currency-amount>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-6\">\n <base-button\n label=\"Confirm Payment\"\n type=\"primary\"\n customClass=\"w-full\"\n [loading]=\"isConfirmingPayment\"\n (onClick)=\"confirmPaymentHandler()\"\n ></base-button>\n </div>\n </div>\n }\n</div>\n" }]
|
|
777
|
+
}], ctorParameters: () => [{ type: i1.ResourceService }, { type: i1.CheckoutService }, { type: i0.ChangeDetectorRef }], propDecorators: { secretKey: [{
|
|
778
|
+
type: Input
|
|
779
|
+
}], environment: [{
|
|
780
|
+
type: Input
|
|
781
|
+
}], paymentObject: [{
|
|
782
|
+
type: Input
|
|
783
|
+
}], paymentAuthorized: [{
|
|
93
784
|
type: Output
|
|
94
785
|
}] } });
|
|
95
786
|
|
|
@@ -98,6 +789,7 @@ class CheckoutCardComponent {
|
|
|
98
789
|
secretKey = '';
|
|
99
790
|
environment = 'sandbox';
|
|
100
791
|
paymentObject = {
|
|
792
|
+
merchantName: '',
|
|
101
793
|
amount: 0,
|
|
102
794
|
currency: '',
|
|
103
795
|
email: '',
|
|
@@ -108,7 +800,12 @@ class CheckoutCardComponent {
|
|
|
108
800
|
ready = new EventEmitter();
|
|
109
801
|
validityChange = new EventEmitter();
|
|
110
802
|
tokenize = new EventEmitter();
|
|
111
|
-
|
|
803
|
+
successObject = {
|
|
804
|
+
paymentDate: '',
|
|
805
|
+
paymentId: '',
|
|
806
|
+
paymentStatus: '',
|
|
807
|
+
};
|
|
808
|
+
checkoutState = 'PENDING';
|
|
112
809
|
countryOptions = [
|
|
113
810
|
{
|
|
114
811
|
label: 'Nigeria',
|
|
@@ -137,11 +834,20 @@ class CheckoutCardComponent {
|
|
|
137
834
|
paymentTypeHandler(event) {
|
|
138
835
|
this.paymentType = event;
|
|
139
836
|
}
|
|
140
|
-
|
|
141
|
-
this.
|
|
837
|
+
setSuccess(event) {
|
|
838
|
+
this.successObject = { ...event };
|
|
839
|
+
if (this.successObject.paymentStatus === 'pending') {
|
|
840
|
+
this.checkoutState = 'PENDING';
|
|
841
|
+
}
|
|
842
|
+
else if (this.successObject.paymentStatus === 'used') {
|
|
843
|
+
this.checkoutState = 'USED';
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
this.checkoutState = 'SUCCESS';
|
|
847
|
+
}
|
|
142
848
|
}
|
|
143
849
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CheckoutCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
144
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: CheckoutCardComponent, isStandalone: true, selector: "bzp-checkout-card", inputs: { options: "options", secretKey: "secretKey", environment: "environment", paymentObject: "paymentObject" }, outputs: { ready: "ready", validityChange: "validityChange", tokenize: "tokenize" }, ngImport: i0, template: "<base-card
|
|
850
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: CheckoutCardComponent, isStandalone: true, selector: "bzp-checkout-card", inputs: { options: "options", secretKey: "secretKey", environment: "environment", paymentObject: "paymentObject" }, outputs: { ready: "ready", validityChange: "validityChange", tokenize: "tokenize" }, ngImport: i0, template: "<base-card>\n <div class=\"grid grid-cols-3\">\n @if (checkoutState === 'PENDING') {\n <div class=\"bg-[#EFF7FF] px-6 py-8 flex flex-col gap-5 col-span-1 rounded-l-xl\">\n <p class=\"text-heading-text text-body-xs font-semibold\">Pay with</p>\n <base-radio-group\n [options]=\"filteredPaymentTypeOptions\"\n (selectedChange)=\"paymentTypeHandler($event)\"\n ></base-radio-group>\n </div>\n }\n\n <div [class]=\"checkoutState === 'SUCCESS' ? 'col-span-3' : 'col-span-2'\">\n @if (checkoutState === 'PENDING') {\n <div class=\"flex items-center justify-between px-12 py-8\">\n @if (options?.imageUrl) {\n <base-image\n [src]=\"options?.imageUrl ?? ''\"\n alt=\"Merchant Logo\"\n [width]=\"52\"\n [height]=\"52\"\n class=\"rounded-lg\"\n ></base-image>\n } @else {\n <div\n class=\"bg-heading-text rounded flex flex-col justify-center\"\n style=\"width: 52px; height: 52px\"\n >\n <p class=\"text-white text-center text-body-2xs font-medium\">Logo</p>\n </div>\n }\n\n <div class=\"flex flex-col gap-1\">\n <p class=\"text-body-2xs font-regular text-sub-copy text-right\">\n {{ paymentObject.merchantName }}\n </p>\n <p class=\"text-body-2xs font-regular text-sub-copy text-right\">\n Pay:\n <span class=\"text-orange-500 font-extrabold\">{{ formatAmountHandler }}</span>\n </p>\n </div>\n </div>\n\n <div class=\"overflow-y-scroll px-10 pb-10 pt-2\">\n @if (paymentType === 'CARD') {\n <pay-by-card\n [environment]=\"environment\"\n [secretKey]=\"secretKey\"\n [paymentObject]=\"paymentObject\"\n (paymentAuthorized)=\"setSuccess($event)\"\n ></pay-by-card>\n } @else if (paymentType === 'BANK_TRANSFER') {\n <pay-by-transfer\n [environment]=\"environment\"\n [secretKey]=\"secretKey\"\n [paymentObject]=\"paymentObject\"\n (paymentAuthorized)=\"setSuccess($event)\"\n ></pay-by-transfer>\n } @else {\n <pay-by-stable-coin\n [environment]=\"environment\"\n [secretKey]=\"secretKey\"\n [paymentObject]=\"paymentObject\"\n (paymentAuthorized)=\"setSuccess($event)\"\n ></pay-by-stable-coin>\n }\n </div>\n } @else if (checkoutState === 'SUCCESS') {\n <base-success\n [amount]=\"paymentObject.amount\"\n [currency]=\"paymentObject.currency\"\n [redirectUrl]=\"paymentObject.redirectUrl\"\n [successObject]=\"successObject\"\n ></base-success>\n }\n </div>\n </div>\n</base-card>\n", dependencies: [{ kind: "component", type: RadioGroupComponent, selector: "base-radio-group", inputs: ["options", "type"], outputs: ["selectedChange"] }, { kind: "component", type: ImageComponent, selector: "base-image", inputs: ["src", "alt", "isFullWidth", "width", "height", "customClass"], outputs: ["onClick"] }, { kind: "component", type: PayByCardComponent, selector: "pay-by-card", inputs: ["secretKey", "environment", "paymentObject"], outputs: ["paymentAuthorized"] }, { kind: "component", type: PayByTransferComponent, selector: "pay-by-transfer", inputs: ["secretKey", "environment", "paymentObject"], outputs: ["paymentAuthorized"] }, { kind: "component", type: PayByStableCoinComponent, selector: "pay-by-stable-coin", inputs: ["secretKey", "environment", "paymentObject"], outputs: ["paymentAuthorized"] }, { kind: "component", type: SuccessComponent, selector: "base-success", inputs: ["successObject", "amount", "currency", "redirectUrl"] }, { kind: "component", type: CardComponent, selector: "base-card", inputs: ["showBackButton"], outputs: ["back"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
145
851
|
}
|
|
146
852
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CheckoutCardComponent, decorators: [{
|
|
147
853
|
type: Component,
|
|
@@ -153,7 +859,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImpor
|
|
|
153
859
|
PayByStableCoinComponent,
|
|
154
860
|
SuccessComponent,
|
|
155
861
|
CardComponent,
|
|
156
|
-
], template: "<base-card
|
|
862
|
+
], template: "<base-card>\n <div class=\"grid grid-cols-3\">\n @if (checkoutState === 'PENDING') {\n <div class=\"bg-[#EFF7FF] px-6 py-8 flex flex-col gap-5 col-span-1 rounded-l-xl\">\n <p class=\"text-heading-text text-body-xs font-semibold\">Pay with</p>\n <base-radio-group\n [options]=\"filteredPaymentTypeOptions\"\n (selectedChange)=\"paymentTypeHandler($event)\"\n ></base-radio-group>\n </div>\n }\n\n <div [class]=\"checkoutState === 'SUCCESS' ? 'col-span-3' : 'col-span-2'\">\n @if (checkoutState === 'PENDING') {\n <div class=\"flex items-center justify-between px-12 py-8\">\n @if (options?.imageUrl) {\n <base-image\n [src]=\"options?.imageUrl ?? ''\"\n alt=\"Merchant Logo\"\n [width]=\"52\"\n [height]=\"52\"\n class=\"rounded-lg\"\n ></base-image>\n } @else {\n <div\n class=\"bg-heading-text rounded flex flex-col justify-center\"\n style=\"width: 52px; height: 52px\"\n >\n <p class=\"text-white text-center text-body-2xs font-medium\">Logo</p>\n </div>\n }\n\n <div class=\"flex flex-col gap-1\">\n <p class=\"text-body-2xs font-regular text-sub-copy text-right\">\n {{ paymentObject.merchantName }}\n </p>\n <p class=\"text-body-2xs font-regular text-sub-copy text-right\">\n Pay:\n <span class=\"text-orange-500 font-extrabold\">{{ formatAmountHandler }}</span>\n </p>\n </div>\n </div>\n\n <div class=\"overflow-y-scroll px-10 pb-10 pt-2\">\n @if (paymentType === 'CARD') {\n <pay-by-card\n [environment]=\"environment\"\n [secretKey]=\"secretKey\"\n [paymentObject]=\"paymentObject\"\n (paymentAuthorized)=\"setSuccess($event)\"\n ></pay-by-card>\n } @else if (paymentType === 'BANK_TRANSFER') {\n <pay-by-transfer\n [environment]=\"environment\"\n [secretKey]=\"secretKey\"\n [paymentObject]=\"paymentObject\"\n (paymentAuthorized)=\"setSuccess($event)\"\n ></pay-by-transfer>\n } @else {\n <pay-by-stable-coin\n [environment]=\"environment\"\n [secretKey]=\"secretKey\"\n [paymentObject]=\"paymentObject\"\n (paymentAuthorized)=\"setSuccess($event)\"\n ></pay-by-stable-coin>\n }\n </div>\n } @else if (checkoutState === 'SUCCESS') {\n <base-success\n [amount]=\"paymentObject.amount\"\n [currency]=\"paymentObject.currency\"\n [redirectUrl]=\"paymentObject.redirectUrl\"\n [successObject]=\"successObject\"\n ></base-success>\n }\n </div>\n </div>\n</base-card>\n" }]
|
|
157
863
|
}], propDecorators: { options: [{
|
|
158
864
|
type: Input
|
|
159
865
|
}], secretKey: [{
|
|
@@ -194,6 +900,7 @@ class CheckoutIframeComponent {
|
|
|
194
900
|
};
|
|
195
901
|
environment = 'sandbox';
|
|
196
902
|
paymentObject = {
|
|
903
|
+
merchantName: '',
|
|
197
904
|
amount: 0,
|
|
198
905
|
currency: '',
|
|
199
906
|
email: '',
|
|
@@ -256,7 +963,7 @@ class CheckoutIframeComponent {
|
|
|
256
963
|
await this.generatePaymentLinkHandler();
|
|
257
964
|
}
|
|
258
965
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CheckoutIframeComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.CheckoutService }], target: i0.ɵɵFactoryTarget.Component });
|
|
259
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: CheckoutIframeComponent, isStandalone: true, selector: "bzp-checkout-iframe", inputs: { secretKey: "secretKey", url: "url", style: "style", environment: "environment", paymentObject: "paymentObject" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "<div class=\"relative\" [ngStyle]=\"blockStyle\">\n <div #container class=\"w-full h-full\"></div>\n\n @if (loading) {\n <div class=\"absolute inset-0 grid place-items-center bg-white/60\">\n <icon-loader></icon-loader>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: IconLoaderComponent, selector: "icon-loader", inputs: ["color", "size"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
966
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.1", type: CheckoutIframeComponent, isStandalone: true, selector: "bzp-checkout-iframe", inputs: { secretKey: "secretKey", url: "url", style: "style", environment: "environment", paymentObject: "paymentObject" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "<div class=\"relative\" [ngStyle]=\"blockStyle\">\n <div #container class=\"w-full h-full\"></div>\n\n @if (loading) {\n <div class=\"absolute inset-0 grid place-items-center bg-white/60\">\n <icon-loader></icon-loader>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: IconLoaderComponent, selector: "icon-loader", inputs: ["color", "size"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
260
967
|
}
|
|
261
968
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.1", ngImport: i0, type: CheckoutIframeComponent, decorators: [{
|
|
262
969
|
type: Component,
|
|
@@ -291,6 +998,7 @@ class CheckoutButtonComponent {
|
|
|
291
998
|
environment = 'sandbox';
|
|
292
999
|
mode = 'redirect';
|
|
293
1000
|
paymentObject = {
|
|
1001
|
+
merchantName: '',
|
|
294
1002
|
amount: 0,
|
|
295
1003
|
currency: '',
|
|
296
1004
|
email: '',
|