@bloonio/lokotro-pay 1.0.1 → 1.1.0
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/README.md +14 -14
- package/fesm2022/bloonio-lokotro-pay.mjs +2147 -1366
- package/fesm2022/bloonio-lokotro-pay.mjs.map +1 -1
- package/index.d.ts +138 -32
- package/package.json +4 -4
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Injectable, EventEmitter, Output, Input, Component, forwardRef, InjectionToken, NgModule } from '@angular/core';
|
|
3
|
-
import * as i2 from '@angular/common';
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
5
|
-
import * as i1 from '@angular/common/http';
|
|
6
|
-
import { HttpHeaders, HttpErrorResponse, HttpClientModule } from '@angular/common/http';
|
|
7
3
|
import * as i1$1 from '@angular/forms';
|
|
8
4
|
import { FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators } from '@angular/forms';
|
|
9
5
|
import { BehaviorSubject, of, throwError, Subject, interval } from 'rxjs';
|
|
10
|
-
import {
|
|
6
|
+
import { UpperCasePipe } from '@angular/common';
|
|
7
|
+
import { timeout, map, catchError, tap, shareReplay, switchMap, takeUntil } from 'rxjs/operators';
|
|
8
|
+
import * as i1 from '@angular/common/http';
|
|
9
|
+
import { HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Lokotro Pay - Environment Configuration
|
|
@@ -18,7 +17,8 @@ import { timeout, map, catchError, tap, shareReplay, takeUntil } from 'rxjs/oper
|
|
|
18
17
|
*/
|
|
19
18
|
const LOKOTRO_DEV_ENV = {
|
|
20
19
|
environment: 'development',
|
|
21
|
-
apiBaseUrl: '
|
|
20
|
+
apiBaseUrl: 'http://10.37.31.218:6495',
|
|
21
|
+
// apiBaseUrl: 'https://dev.app.api.gtwy.lokotro.com',
|
|
22
22
|
paymentApiVersion: 'v1',
|
|
23
23
|
debugMode: true,
|
|
24
24
|
logLevel: 'debug',
|
|
@@ -29,7 +29,7 @@ const LOKOTRO_DEV_ENV = {
|
|
|
29
29
|
*/
|
|
30
30
|
const LOKOTRO_PROD_ENV = {
|
|
31
31
|
environment: 'production',
|
|
32
|
-
apiBaseUrl: 'https://
|
|
32
|
+
apiBaseUrl: 'https://app.api.gtwy.lokotro.com',
|
|
33
33
|
paymentApiVersion: 'v1',
|
|
34
34
|
debugMode: false,
|
|
35
35
|
logLevel: 'error',
|
|
@@ -126,6 +126,7 @@ class LokotroPayEnv {
|
|
|
126
126
|
return {
|
|
127
127
|
collect: '/payments/collect',
|
|
128
128
|
transaction: '/payments/transaction',
|
|
129
|
+
mobileMoneyStatus: '/payments/mobile-money/status',
|
|
129
130
|
submit: '/payments/submit',
|
|
130
131
|
verifyOtp: '/payments/verify-otp',
|
|
131
132
|
resendOtp: '/payments/resend-otp',
|
|
@@ -458,12 +459,8 @@ var LokotroPayLanguage;
|
|
|
458
459
|
(function (LokotroPayLanguage) {
|
|
459
460
|
LokotroPayLanguage["English"] = "en";
|
|
460
461
|
LokotroPayLanguage["French"] = "fr";
|
|
461
|
-
LokotroPayLanguage["German"] = "de";
|
|
462
462
|
LokotroPayLanguage["Spanish"] = "es";
|
|
463
|
-
LokotroPayLanguage["Italian"] = "it";
|
|
464
463
|
LokotroPayLanguage["Russian"] = "ru";
|
|
465
|
-
LokotroPayLanguage["Hindi"] = "hi";
|
|
466
|
-
LokotroPayLanguage["Japanese"] = "ja";
|
|
467
464
|
LokotroPayLanguage["Chinese"] = "zh";
|
|
468
465
|
LokotroPayLanguage["Lingala"] = "ln";
|
|
469
466
|
})(LokotroPayLanguage || (LokotroPayLanguage = {}));
|
|
@@ -473,12 +470,8 @@ var LokotroPayLanguage;
|
|
|
473
470
|
const LokotroPayLanguageInfo = {
|
|
474
471
|
[LokotroPayLanguage.English]: { displayName: 'English', nativeName: 'English', flagAsset: 'assets/flags/england.svg' },
|
|
475
472
|
[LokotroPayLanguage.French]: { displayName: 'French', nativeName: 'Français', flagAsset: 'assets/flags/france.svg' },
|
|
476
|
-
[LokotroPayLanguage.German]: { displayName: 'German', nativeName: 'Deutsch', flagAsset: 'assets/flags/german.svg' },
|
|
477
473
|
[LokotroPayLanguage.Spanish]: { displayName: 'Spanish', nativeName: 'Español', flagAsset: 'assets/flags/spain.svg' },
|
|
478
|
-
[LokotroPayLanguage.Italian]: { displayName: 'Italian', nativeName: 'Italiano', flagAsset: 'assets/flags/italy.svg' },
|
|
479
474
|
[LokotroPayLanguage.Russian]: { displayName: 'Russian', nativeName: 'Русский', flagAsset: 'assets/flags/russia.svg' },
|
|
480
|
-
[LokotroPayLanguage.Hindi]: { displayName: 'Hindi', nativeName: 'हिंदी', flagAsset: 'assets/flags/india.svg' },
|
|
481
|
-
[LokotroPayLanguage.Japanese]: { displayName: 'Japanese', nativeName: '日本語', flagAsset: 'assets/flags/japanese.svg' },
|
|
482
475
|
[LokotroPayLanguage.Chinese]: { displayName: 'Chinese', nativeName: '中文(普通话)', flagAsset: 'assets/flags/china.svg' },
|
|
483
476
|
[LokotroPayLanguage.Lingala]: { displayName: 'Lingala', nativeName: 'Lingala', flagAsset: 'assets/flags/drc.svg' }
|
|
484
477
|
};
|
|
@@ -490,12 +483,8 @@ const LokotroPayLanguageHelper = {
|
|
|
490
483
|
const languageMap = {
|
|
491
484
|
'en': LokotroPayLanguage.English,
|
|
492
485
|
'fr': LokotroPayLanguage.French,
|
|
493
|
-
'de': LokotroPayLanguage.German,
|
|
494
486
|
'es': LokotroPayLanguage.Spanish,
|
|
495
|
-
'it': LokotroPayLanguage.Italian,
|
|
496
487
|
'ru': LokotroPayLanguage.Russian,
|
|
497
|
-
'hi': LokotroPayLanguage.Hindi,
|
|
498
|
-
'ja': LokotroPayLanguage.Japanese,
|
|
499
488
|
'zh': LokotroPayLanguage.Chinese,
|
|
500
489
|
'ln': LokotroPayLanguage.Lingala
|
|
501
490
|
};
|
|
@@ -639,7 +628,10 @@ const EN_TRANSLATIONS = {
|
|
|
639
628
|
bankAccountSummary: 'Account Details',
|
|
640
629
|
accountLabel: 'Account Label',
|
|
641
630
|
bankTransferProofInstructions: 'A payment link will be sent to your email to upload the proof of transfer.',
|
|
642
|
-
confirmBankTransfer: 'Confirm Transfer'
|
|
631
|
+
confirmBankTransfer: 'Confirm Transfer',
|
|
632
|
+
// Auto-redirect countdown
|
|
633
|
+
redirectingIn: 'Redirecting in {seconds}s',
|
|
634
|
+
tapToCancel: 'Tap to cancel'
|
|
643
635
|
};
|
|
644
636
|
/**
|
|
645
637
|
* French translations
|
|
@@ -744,7 +736,10 @@ const FR_TRANSLATIONS = {
|
|
|
744
736
|
bankAccountSummary: 'Détails du compte',
|
|
745
737
|
accountLabel: 'Libellé du compte',
|
|
746
738
|
bankTransferProofInstructions: 'Un lien de paiement sera envoyé à votre adresse e-mail pour télécharger la preuve de virement.',
|
|
747
|
-
confirmBankTransfer: 'Confirmer le virement'
|
|
739
|
+
confirmBankTransfer: 'Confirmer le virement',
|
|
740
|
+
// Auto-redirect countdown
|
|
741
|
+
redirectingIn: 'Redirection dans {seconds}s',
|
|
742
|
+
tapToCancel: 'Appuyez pour annuler'
|
|
748
743
|
};
|
|
749
744
|
/**
|
|
750
745
|
* Spanish translations
|
|
@@ -849,7 +844,10 @@ const ES_TRANSLATIONS = {
|
|
|
849
844
|
bankAccountSummary: 'Detalles de la cuenta',
|
|
850
845
|
accountLabel: 'Etiqueta de la cuenta',
|
|
851
846
|
bankTransferProofInstructions: 'Se enviará un enlace de pago a su correo electrónico para cargar el comprobante de transferencia.',
|
|
852
|
-
confirmBankTransfer: 'Confirmar transferencia'
|
|
847
|
+
confirmBankTransfer: 'Confirmar transferencia',
|
|
848
|
+
// Auto-redirect countdown
|
|
849
|
+
redirectingIn: 'Redirigiendo en {seconds}s',
|
|
850
|
+
tapToCancel: 'Toque para cancelar'
|
|
853
851
|
};
|
|
854
852
|
/**
|
|
855
853
|
* All translations map
|
|
@@ -858,11 +856,7 @@ const TRANSLATIONS = {
|
|
|
858
856
|
[LokotroPayLanguage.English]: EN_TRANSLATIONS,
|
|
859
857
|
[LokotroPayLanguage.French]: FR_TRANSLATIONS,
|
|
860
858
|
[LokotroPayLanguage.Spanish]: ES_TRANSLATIONS,
|
|
861
|
-
[LokotroPayLanguage.German]: EN_TRANSLATIONS, // Fallback to English
|
|
862
|
-
[LokotroPayLanguage.Italian]: EN_TRANSLATIONS, // Fallback to English
|
|
863
859
|
[LokotroPayLanguage.Russian]: EN_TRANSLATIONS, // Fallback to English
|
|
864
|
-
[LokotroPayLanguage.Hindi]: EN_TRANSLATIONS, // Fallback to English
|
|
865
|
-
[LokotroPayLanguage.Japanese]: EN_TRANSLATIONS, // Fallback to English
|
|
866
860
|
[LokotroPayLanguage.Chinese]: EN_TRANSLATIONS, // Fallback to English
|
|
867
861
|
[LokotroPayLanguage.Lingala]: FR_TRANSLATIONS // Fallback to French
|
|
868
862
|
};
|
|
@@ -908,10 +902,19 @@ class LokotroLocalizationService {
|
|
|
908
902
|
}
|
|
909
903
|
}
|
|
910
904
|
/**
|
|
911
|
-
* Get translation by key
|
|
905
|
+
* Get translation by key with optional interpolation
|
|
906
|
+
* @param key - Translation key
|
|
907
|
+
* @param params - Optional parameters for interpolation (e.g., { seconds: 3 })
|
|
912
908
|
*/
|
|
913
|
-
translate(key) {
|
|
914
|
-
|
|
909
|
+
translate(key, params) {
|
|
910
|
+
let translation = this.translations[key] || key;
|
|
911
|
+
// Handle interpolation if params provided
|
|
912
|
+
if (params) {
|
|
913
|
+
Object.entries(params).forEach(([paramKey, paramValue]) => {
|
|
914
|
+
translation = translation.replace(new RegExp(`\\{${paramKey}\\}`, 'g'), String(paramValue));
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
return translation;
|
|
915
918
|
}
|
|
916
919
|
/**
|
|
917
920
|
* Get all supported languages
|
|
@@ -946,10 +949,10 @@ class LokotroLocalizationService {
|
|
|
946
949
|
this.translationsSubject.next(TRANSLATIONS[language]);
|
|
947
950
|
}
|
|
948
951
|
}
|
|
949
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
950
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
952
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroLocalizationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
953
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroLocalizationService, providedIn: 'root' }); }
|
|
951
954
|
}
|
|
952
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
955
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroLocalizationService, decorators: [{
|
|
953
956
|
type: Injectable,
|
|
954
957
|
args: [{
|
|
955
958
|
providedIn: 'root'
|
|
@@ -1011,104 +1014,114 @@ class LokotroPaymentMethodSelectionComponent {
|
|
|
1011
1014
|
parent.appendChild(placeholder);
|
|
1012
1015
|
}
|
|
1013
1016
|
}
|
|
1014
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1015
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
1017
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentMethodSelectionComponent, deps: [{ token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1018
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroPaymentMethodSelectionComponent, isStandalone: true, selector: "lokotro-payment-method-selection", inputs: { paymentMethods: "paymentMethods", selectedMethod: "selectedMethod" }, outputs: { methodSelected: "methodSelected" }, ngImport: i0, template: `
|
|
1016
1019
|
<div class="lokotro-method-selection">
|
|
1017
1020
|
<h3 class="lokotro-section-title">{{ localization.translate('selectPaymentMethod') }}</h3>
|
|
1018
|
-
|
|
1021
|
+
|
|
1019
1022
|
<div class="lokotro-methods-grid">
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1023
|
+
@for (method of paymentMethods; track method) {
|
|
1024
|
+
<button
|
|
1025
|
+
class="lokotro-method-card"
|
|
1026
|
+
[class.selected]="selectedMethod?.id === method.id"
|
|
1027
|
+
[class.disabled]="!method.isEnabled"
|
|
1028
|
+
[disabled]="!method.isEnabled"
|
|
1029
|
+
(click)="selectMethod(method)">
|
|
1030
|
+
<div class="lokotro-method-icon">
|
|
1031
|
+
@if (method.iconUrl) {
|
|
1032
|
+
<img
|
|
1033
|
+
[src]="method.iconUrl"
|
|
1034
|
+
[alt]="method.displayName"
|
|
1035
|
+
(error)="onImageError($event, method.channel)">
|
|
1036
|
+
}
|
|
1037
|
+
@if (!method.iconUrl) {
|
|
1038
|
+
<div class="lokotro-method-icon-placeholder">
|
|
1039
|
+
{{ getMethodIcon(method.channel) }}
|
|
1040
|
+
</div>
|
|
1041
|
+
}
|
|
1036
1042
|
</div>
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1043
|
+
<div class="lokotro-method-info">
|
|
1044
|
+
<span class="lokotro-method-name">{{ method.displayName }}</span>
|
|
1045
|
+
@if (getMethodDescription(method.channel)) {
|
|
1046
|
+
<span class="lokotro-method-description">
|
|
1047
|
+
{{ getMethodDescription(method.channel) }}
|
|
1048
|
+
</span>
|
|
1049
|
+
}
|
|
1050
|
+
</div>
|
|
1051
|
+
@if (selectedMethod?.id === method.id) {
|
|
1052
|
+
<div class="lokotro-method-check">
|
|
1053
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1054
|
+
<path d="M20 6L9 17l-5-5"/>
|
|
1055
|
+
</svg>
|
|
1056
|
+
</div>
|
|
1057
|
+
}
|
|
1058
|
+
</button>
|
|
1059
|
+
}
|
|
1052
1060
|
</div>
|
|
1053
|
-
|
|
1054
|
-
<button
|
|
1061
|
+
|
|
1062
|
+
<button
|
|
1055
1063
|
class="lokotro-continue-btn"
|
|
1056
1064
|
[disabled]="!selectedMethod"
|
|
1057
1065
|
(click)="onContinue()">
|
|
1058
1066
|
{{ localization.translate('continue') }}
|
|
1059
1067
|
</button>
|
|
1060
1068
|
</div>
|
|
1061
|
-
|
|
1069
|
+
`, isInline: true, styles: [".lokotro-method-selection{display:flex;flex-direction:column;gap:24px}.lokotro-section-title{font-size:20px;font-weight:600;margin:0;color:var(--lokotro-text-primary, #F2F0D5);text-align:center}.lokotro-methods-grid{display:flex;flex-direction:column;gap:12px}.lokotro-method-card{display:flex;align-items:center;gap:16px;padding:16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:16px;cursor:pointer;transition:all .2s ease;text-align:left}.lokotro-method-card:hover:not(.disabled){border-color:var(--lokotro-accent, #3BFBDA);transform:translateY(-2px)}.lokotro-method-card.selected{border-color:var(--lokotro-accent, #3BFBDA);background:linear-gradient(135deg,var(--lokotro-card, #3A4840),var(--lokotro-surface, #2A3832))}.lokotro-method-card.disabled{opacity:.5;cursor:not-allowed}.lokotro-method-icon{width:48px;height:48px;display:flex;align-items:center;justify-content:center;background:var(--lokotro-surface, #2A3832);border-radius:12px;overflow:hidden}.lokotro-method-icon img{width:100%;height:100%;object-fit:contain}.lokotro-method-icon-placeholder{font-size:24px}.lokotro-method-info{flex:1;display:flex;flex-direction:column;gap:4px}.lokotro-method-name{font-size:16px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-method-description{font-size:13px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-method-check{width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:var(--lokotro-accent, #3BFBDA)}.lokotro-continue-btn{width:100%;padding:16px;background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-continue-btn:disabled{opacity:.5;cursor:not-allowed}\n"] }); }
|
|
1062
1070
|
}
|
|
1063
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1071
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentMethodSelectionComponent, decorators: [{
|
|
1064
1072
|
type: Component,
|
|
1065
|
-
args: [{ selector: 'lokotro-payment-method-selection', standalone: true, imports: [
|
|
1073
|
+
args: [{ selector: 'lokotro-payment-method-selection', standalone: true, imports: [], template: `
|
|
1066
1074
|
<div class="lokotro-method-selection">
|
|
1067
1075
|
<h3 class="lokotro-section-title">{{ localization.translate('selectPaymentMethod') }}</h3>
|
|
1068
|
-
|
|
1076
|
+
|
|
1069
1077
|
<div class="lokotro-methods-grid">
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1078
|
+
@for (method of paymentMethods; track method) {
|
|
1079
|
+
<button
|
|
1080
|
+
class="lokotro-method-card"
|
|
1081
|
+
[class.selected]="selectedMethod?.id === method.id"
|
|
1082
|
+
[class.disabled]="!method.isEnabled"
|
|
1083
|
+
[disabled]="!method.isEnabled"
|
|
1084
|
+
(click)="selectMethod(method)">
|
|
1085
|
+
<div class="lokotro-method-icon">
|
|
1086
|
+
@if (method.iconUrl) {
|
|
1087
|
+
<img
|
|
1088
|
+
[src]="method.iconUrl"
|
|
1089
|
+
[alt]="method.displayName"
|
|
1090
|
+
(error)="onImageError($event, method.channel)">
|
|
1091
|
+
}
|
|
1092
|
+
@if (!method.iconUrl) {
|
|
1093
|
+
<div class="lokotro-method-icon-placeholder">
|
|
1094
|
+
{{ getMethodIcon(method.channel) }}
|
|
1095
|
+
</div>
|
|
1096
|
+
}
|
|
1086
1097
|
</div>
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1098
|
+
<div class="lokotro-method-info">
|
|
1099
|
+
<span class="lokotro-method-name">{{ method.displayName }}</span>
|
|
1100
|
+
@if (getMethodDescription(method.channel)) {
|
|
1101
|
+
<span class="lokotro-method-description">
|
|
1102
|
+
{{ getMethodDescription(method.channel) }}
|
|
1103
|
+
</span>
|
|
1104
|
+
}
|
|
1105
|
+
</div>
|
|
1106
|
+
@if (selectedMethod?.id === method.id) {
|
|
1107
|
+
<div class="lokotro-method-check">
|
|
1108
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1109
|
+
<path d="M20 6L9 17l-5-5"/>
|
|
1110
|
+
</svg>
|
|
1111
|
+
</div>
|
|
1112
|
+
}
|
|
1113
|
+
</button>
|
|
1114
|
+
}
|
|
1102
1115
|
</div>
|
|
1103
|
-
|
|
1104
|
-
<button
|
|
1116
|
+
|
|
1117
|
+
<button
|
|
1105
1118
|
class="lokotro-continue-btn"
|
|
1106
1119
|
[disabled]="!selectedMethod"
|
|
1107
1120
|
(click)="onContinue()">
|
|
1108
1121
|
{{ localization.translate('continue') }}
|
|
1109
1122
|
</button>
|
|
1110
1123
|
</div>
|
|
1111
|
-
|
|
1124
|
+
`, styles: [".lokotro-method-selection{display:flex;flex-direction:column;gap:24px}.lokotro-section-title{font-size:20px;font-weight:600;margin:0;color:var(--lokotro-text-primary, #F2F0D5);text-align:center}.lokotro-methods-grid{display:flex;flex-direction:column;gap:12px}.lokotro-method-card{display:flex;align-items:center;gap:16px;padding:16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:16px;cursor:pointer;transition:all .2s ease;text-align:left}.lokotro-method-card:hover:not(.disabled){border-color:var(--lokotro-accent, #3BFBDA);transform:translateY(-2px)}.lokotro-method-card.selected{border-color:var(--lokotro-accent, #3BFBDA);background:linear-gradient(135deg,var(--lokotro-card, #3A4840),var(--lokotro-surface, #2A3832))}.lokotro-method-card.disabled{opacity:.5;cursor:not-allowed}.lokotro-method-icon{width:48px;height:48px;display:flex;align-items:center;justify-content:center;background:var(--lokotro-surface, #2A3832);border-radius:12px;overflow:hidden}.lokotro-method-icon img{width:100%;height:100%;object-fit:contain}.lokotro-method-icon-placeholder{font-size:24px}.lokotro-method-info{flex:1;display:flex;flex-direction:column;gap:4px}.lokotro-method-name{font-size:16px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-method-description{font-size:13px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-method-check{width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:var(--lokotro-accent, #3BFBDA)}.lokotro-continue-btn{width:100%;padding:16px;background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-continue-btn:disabled{opacity:.5;cursor:not-allowed}\n"] }]
|
|
1112
1125
|
}], ctorParameters: () => [{ type: LokotroLocalizationService }], propDecorators: { paymentMethods: [{
|
|
1113
1126
|
type: Input
|
|
1114
1127
|
}], selectedMethod: [{
|
|
@@ -1234,10 +1247,13 @@ class LokotroCountryUtils {
|
|
|
1234
1247
|
* Enhanced HTTP client for Lokotro Pay with modern error handling and logging
|
|
1235
1248
|
*/
|
|
1236
1249
|
class LokotroHttpClientService {
|
|
1250
|
+
static { this.instanceCounter = 0; }
|
|
1237
1251
|
constructor(http) {
|
|
1238
1252
|
this.http = http;
|
|
1239
1253
|
this.acceptLanguage = 'fr';
|
|
1240
1254
|
this.customHeaders = {};
|
|
1255
|
+
this.instanceId = ++LokotroHttpClientService.instanceCounter;
|
|
1256
|
+
console.log(`[Lokotro HTTP] Instance #${this.instanceId} created`);
|
|
1241
1257
|
}
|
|
1242
1258
|
/**
|
|
1243
1259
|
* Configure the HTTP client
|
|
@@ -1257,7 +1273,9 @@ class LokotroHttpClientService {
|
|
|
1257
1273
|
* Set app-key for Lokotro Gateway authentication
|
|
1258
1274
|
*/
|
|
1259
1275
|
setAppKey(appKey) {
|
|
1276
|
+
console.log(`[Lokotro HTTP #${this.instanceId}] setAppKey called with:`, appKey?.substring(0, 20) + '...');
|
|
1260
1277
|
this.appKey = appKey;
|
|
1278
|
+
console.log(`[Lokotro HTTP #${this.instanceId}] appKey now set to:`, this.appKey?.substring(0, 20) + '...');
|
|
1261
1279
|
}
|
|
1262
1280
|
/**
|
|
1263
1281
|
* Remove app-key
|
|
@@ -1281,6 +1299,7 @@ class LokotroHttpClientService {
|
|
|
1281
1299
|
* Build request headers
|
|
1282
1300
|
*/
|
|
1283
1301
|
buildHeaders() {
|
|
1302
|
+
console.log(`[Lokotro HTTP #${this.instanceId}] buildHeaders - appKey value:`, this.appKey?.substring(0, 20) + '...');
|
|
1284
1303
|
let headers = new HttpHeaders({
|
|
1285
1304
|
'Content-Type': 'application/json',
|
|
1286
1305
|
'Accept': 'application/json',
|
|
@@ -1290,6 +1309,10 @@ class LokotroHttpClientService {
|
|
|
1290
1309
|
});
|
|
1291
1310
|
if (this.appKey) {
|
|
1292
1311
|
headers = headers.set('app-key', this.appKey);
|
|
1312
|
+
console.log(`[Lokotro HTTP #${this.instanceId}] app-key header added`);
|
|
1313
|
+
}
|
|
1314
|
+
else {
|
|
1315
|
+
console.warn(`[Lokotro HTTP #${this.instanceId}] WARNING: appKey is not set, app-key header NOT added`);
|
|
1293
1316
|
}
|
|
1294
1317
|
// Add custom headers
|
|
1295
1318
|
Object.entries(this.customHeaders).forEach(([key, value]) => {
|
|
@@ -1375,9 +1398,28 @@ class LokotroHttpClientService {
|
|
|
1375
1398
|
if (error instanceof HttpErrorResponse) {
|
|
1376
1399
|
// Server error
|
|
1377
1400
|
const serverError = error.error;
|
|
1401
|
+
let errorMessage = '';
|
|
1402
|
+
if (serverError?.['message'] && typeof serverError['message'] === 'string') {
|
|
1403
|
+
errorMessage = serverError['message'];
|
|
1404
|
+
}
|
|
1405
|
+
else if (serverError?.['detail']) {
|
|
1406
|
+
const detail = serverError['detail'];
|
|
1407
|
+
if (Array.isArray(detail)) {
|
|
1408
|
+
errorMessage = detail.map((d) => d.msg || d.message || JSON.stringify(d)).join('; ');
|
|
1409
|
+
}
|
|
1410
|
+
else if (typeof detail === 'string') {
|
|
1411
|
+
errorMessage = detail;
|
|
1412
|
+
}
|
|
1413
|
+
else {
|
|
1414
|
+
errorMessage = JSON.stringify(detail);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
else {
|
|
1418
|
+
errorMessage = error.message || 'An error occurred';
|
|
1419
|
+
}
|
|
1378
1420
|
errorResponse = {
|
|
1379
1421
|
data: undefined,
|
|
1380
|
-
message:
|
|
1422
|
+
message: errorMessage,
|
|
1381
1423
|
statusCode: error.status,
|
|
1382
1424
|
isSuccess: false,
|
|
1383
1425
|
apiResponseCode: serverError?.['api_response_code']
|
|
@@ -1432,10 +1474,10 @@ class LokotroHttpClientService {
|
|
|
1432
1474
|
return LokotroPayApiResponseCode.LOK001; // General error
|
|
1433
1475
|
}
|
|
1434
1476
|
}
|
|
1435
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1436
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
1477
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroHttpClientService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1478
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroHttpClientService, providedIn: 'root' }); }
|
|
1437
1479
|
}
|
|
1438
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1480
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroHttpClientService, decorators: [{
|
|
1439
1481
|
type: Injectable,
|
|
1440
1482
|
args: [{
|
|
1441
1483
|
providedIn: 'root'
|
|
@@ -1544,10 +1586,10 @@ class LokotroCountryService {
|
|
|
1544
1586
|
this.countriesCache = undefined;
|
|
1545
1587
|
this.countriesSubject.next([]);
|
|
1546
1588
|
}
|
|
1547
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1548
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
1589
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroCountryService, deps: [{ token: LokotroHttpClientService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1590
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroCountryService, providedIn: 'root' }); }
|
|
1549
1591
|
}
|
|
1550
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1592
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroCountryService, decorators: [{
|
|
1551
1593
|
type: Injectable,
|
|
1552
1594
|
args: [{
|
|
1553
1595
|
providedIn: 'root'
|
|
@@ -1709,8 +1751,8 @@ class LokotroMobileMoneyPhoneInputComponent {
|
|
|
1709
1751
|
}
|
|
1710
1752
|
return null;
|
|
1711
1753
|
}
|
|
1712
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1713
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
1754
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroMobileMoneyPhoneInputComponent, deps: [{ token: LokotroCountryService }, { token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1755
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroMobileMoneyPhoneInputComponent, isStandalone: true, selector: "lokotro-mobile-money-phone-input", inputs: { label: "label", placeholder: "placeholder", initialCountryCode: "initialCountryCode", showPrefixHints: "showPrefixHints", disabled: "disabled" }, outputs: { countryChanged: "countryChanged", phoneChanged: "phoneChanged" }, providers: [
|
|
1714
1756
|
{
|
|
1715
1757
|
provide: NG_VALUE_ACCESSOR,
|
|
1716
1758
|
useExisting: forwardRef(() => LokotroMobileMoneyPhoneInputComponent),
|
|
@@ -1724,26 +1766,34 @@ class LokotroMobileMoneyPhoneInputComponent {
|
|
|
1724
1766
|
], ngImport: i0, template: `
|
|
1725
1767
|
<div class="lokotro-phone-input-container">
|
|
1726
1768
|
<!-- Label -->
|
|
1727
|
-
|
|
1728
|
-
|
|
1769
|
+
@if (label) {
|
|
1770
|
+
<label class="lokotro-label">{{ label }}</label>
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1729
1773
|
<!-- Input Row -->
|
|
1730
1774
|
<div class="lokotro-phone-input-row">
|
|
1731
1775
|
<!-- Country Selector -->
|
|
1732
|
-
<button
|
|
1776
|
+
<button
|
|
1733
1777
|
type="button"
|
|
1734
1778
|
class="lokotro-country-selector"
|
|
1735
1779
|
[disabled]="disabled || isLoading"
|
|
1736
1780
|
(click)="toggleCountryPicker()">
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1781
|
+
@if (selectedCountry && !isLoading) {
|
|
1782
|
+
<span class="lokotro-flag">
|
|
1783
|
+
{{ getFlag(selectedCountry) }}
|
|
1784
|
+
</span>
|
|
1785
|
+
}
|
|
1786
|
+
@if (isLoading) {
|
|
1787
|
+
<span class="lokotro-loading-spinner"></span>
|
|
1788
|
+
}
|
|
1789
|
+
@if (selectedCountry) {
|
|
1790
|
+
<span class="lokotro-country-code">
|
|
1791
|
+
+{{ getPrimaryCode(selectedCountry) }}
|
|
1792
|
+
</span>
|
|
1793
|
+
}
|
|
1744
1794
|
<span class="lokotro-dropdown-arrow">▼</span>
|
|
1745
1795
|
</button>
|
|
1746
|
-
|
|
1796
|
+
|
|
1747
1797
|
<!-- Phone Input -->
|
|
1748
1798
|
<input
|
|
1749
1799
|
type="tel"
|
|
@@ -1756,60 +1806,74 @@ class LokotroMobileMoneyPhoneInputComponent {
|
|
|
1756
1806
|
(input)="onPhoneInput($event)"
|
|
1757
1807
|
(blur)="onTouched()">
|
|
1758
1808
|
</div>
|
|
1759
|
-
|
|
1809
|
+
|
|
1760
1810
|
<!-- Prefix Error -->
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1811
|
+
@if (prefixError) {
|
|
1812
|
+
<div class="lokotro-prefix-error">
|
|
1813
|
+
{{ prefixError }}
|
|
1814
|
+
</div>
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1765
1817
|
<!-- Valid Prefixes Hint -->
|
|
1766
|
-
|
|
1767
|
-
<
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
<span class="lokotro-picker-title">{{ localization.translate('selectCountry') }}</span>
|
|
1784
|
-
<button type="button" class="lokotro-picker-close" (click)="closeCountryPicker()">×</button>
|
|
1818
|
+
@if (selectedCountry && showPrefixHints) {
|
|
1819
|
+
<div class="lokotro-prefix-hints">
|
|
1820
|
+
<span class="lokotro-hint-label">{{ localization.translate('validPrefixes') }}</span>
|
|
1821
|
+
@for (prefix of getVisiblePrefixes(selectedCountry); track prefix) {
|
|
1822
|
+
<span
|
|
1823
|
+
class="lokotro-prefix-chip"
|
|
1824
|
+
>
|
|
1825
|
+
{{ prefix }}
|
|
1826
|
+
</span>
|
|
1827
|
+
}
|
|
1828
|
+
@if (getValidPrefixes(selectedCountry).length > 6) {
|
|
1829
|
+
<span
|
|
1830
|
+
class="lokotro-more-prefixes"
|
|
1831
|
+
>
|
|
1832
|
+
+{{ getValidPrefixes(selectedCountry).length - 6 }} {{ localization.translate('more') }}
|
|
1833
|
+
</span>
|
|
1834
|
+
}
|
|
1785
1835
|
</div>
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
<
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
<!-- Country Picker Dropdown -->
|
|
1839
|
+
@if (showCountryPicker) {
|
|
1840
|
+
<div class="lokotro-country-picker">
|
|
1841
|
+
<div class="lokotro-picker-header">
|
|
1842
|
+
<span class="lokotro-picker-title">{{ localization.translate('selectCountry') }}</span>
|
|
1843
|
+
<button type="button" class="lokotro-picker-close" (click)="closeCountryPicker()">×</button>
|
|
1844
|
+
</div>
|
|
1845
|
+
<div class="lokotro-picker-list">
|
|
1846
|
+
@for (country of countries; track country) {
|
|
1847
|
+
<button
|
|
1848
|
+
type="button"
|
|
1849
|
+
class="lokotro-country-option"
|
|
1850
|
+
[class.selected]="selectedCountry?.refCountry?.id === country.refCountry.id"
|
|
1851
|
+
(click)="selectCountry(country)">
|
|
1852
|
+
<span class="lokotro-option-flag">{{ getFlag(country) }}</span>
|
|
1853
|
+
<span class="lokotro-option-name">{{ country.refCountry.name | uppercase }}</span>
|
|
1854
|
+
<span class="lokotro-option-code">+{{ getPrimaryCode(country) }}</span>
|
|
1855
|
+
@if (selectedCountry?.refCountry?.id === country.refCountry.id) {
|
|
1856
|
+
<span class="lokotro-option-check">✓</span>
|
|
1857
|
+
}
|
|
1858
|
+
</button>
|
|
1859
|
+
}
|
|
1860
|
+
</div>
|
|
1798
1861
|
</div>
|
|
1799
|
-
|
|
1800
|
-
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1801
1864
|
<!-- Backdrop for picker -->
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1865
|
+
@if (showCountryPicker) {
|
|
1866
|
+
<div
|
|
1867
|
+
class="lokotro-picker-backdrop"
|
|
1868
|
+
(click)="closeCountryPicker()">
|
|
1869
|
+
</div>
|
|
1870
|
+
}
|
|
1807
1871
|
</div>
|
|
1808
|
-
|
|
1872
|
+
`, isInline: true, styles: [".lokotro-phone-input-container{position:relative;width:100%}.lokotro-label{display:block;margin-bottom:8px;font-size:14px;font-weight:500;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-phone-input-row{display:flex;gap:12px;align-items:stretch}.lokotro-country-selector{display:flex;align-items:center;gap:8px;padding:12px 14px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);cursor:pointer;transition:border-color .2s;white-space:nowrap}.lokotro-country-selector:hover:not(:disabled){border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-country-selector:disabled{opacity:.6;cursor:not-allowed}.lokotro-flag{font-size:24px;line-height:1}.lokotro-country-code{font-size:16px;font-weight:600}.lokotro-dropdown-arrow{font-size:10px;opacity:.6}.lokotro-loading-spinner{width:20px;height:20px;border:2px solid var(--lokotro-border, #3A473F);border-top-color:var(--lokotro-accent, #3BFBDA);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.lokotro-phone-input{flex:1;padding:14px 16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);font-size:16px;transition:border-color .2s;min-width:0}.lokotro-phone-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-phone-input.error{border-color:var(--lokotro-error, #D97652)}.lokotro-phone-input::placeholder{color:var(--lokotro-text-secondary, #D5D3B8);opacity:.6}.lokotro-phone-input:disabled{opacity:.6;cursor:not-allowed}.lokotro-prefix-error{margin-top:6px;font-size:12px;color:var(--lokotro-error, #D97652)}.lokotro-prefix-hints{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:8px}.lokotro-hint-label{font-size:12px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-prefix-chip{padding:2px 8px;background:#3bfbda1a;border-radius:4px;font-size:12px;font-weight:600;color:var(--lokotro-accent, #3BFBDA)}.lokotro-more-prefixes{font-size:12px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-country-picker{position:absolute;top:100%;left:0;right:0;max-height:300px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;margin-top:4px;z-index:1000;overflow:hidden;display:flex;flex-direction:column}.lokotro-picker-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--lokotro-border, #3A473F)}.lokotro-picker-title{font-size:16px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-picker-close{background:none;border:none;font-size:24px;color:var(--lokotro-text-secondary, #D5D3B8);cursor:pointer;padding:0;line-height:1}.lokotro-picker-list{overflow-y:auto;max-height:250px}.lokotro-country-option{display:flex;align-items:center;gap:12px;width:100%;padding:12px 16px;background:none;border:none;color:var(--lokotro-text-primary, #F2F0D5);cursor:pointer;text-align:left;transition:background-color .2s}.lokotro-country-option:hover{background:var(--lokotro-surface, #2A3832)}.lokotro-country-option.selected{background:#3bfbda1a}.lokotro-option-flag{font-size:28px}.lokotro-option-name{flex:1;font-size:14px;font-weight:500}.lokotro-option-code{font-size:12px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-option-check{color:var(--lokotro-accent, #3BFBDA);font-weight:700}.lokotro-picker-backdrop{position:fixed;inset:0;z-index:999}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "pipe", type: UpperCasePipe, name: "uppercase" }] }); }
|
|
1809
1873
|
}
|
|
1810
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1874
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroMobileMoneyPhoneInputComponent, decorators: [{
|
|
1811
1875
|
type: Component,
|
|
1812
|
-
args: [{ selector: 'lokotro-mobile-money-phone-input', standalone: true, imports: [
|
|
1876
|
+
args: [{ selector: 'lokotro-mobile-money-phone-input', standalone: true, imports: [FormsModule, ReactiveFormsModule, UpperCasePipe], providers: [
|
|
1813
1877
|
{
|
|
1814
1878
|
provide: NG_VALUE_ACCESSOR,
|
|
1815
1879
|
useExisting: forwardRef(() => LokotroMobileMoneyPhoneInputComponent),
|
|
@@ -1823,26 +1887,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1823
1887
|
], template: `
|
|
1824
1888
|
<div class="lokotro-phone-input-container">
|
|
1825
1889
|
<!-- Label -->
|
|
1826
|
-
|
|
1827
|
-
|
|
1890
|
+
@if (label) {
|
|
1891
|
+
<label class="lokotro-label">{{ label }}</label>
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1828
1894
|
<!-- Input Row -->
|
|
1829
1895
|
<div class="lokotro-phone-input-row">
|
|
1830
1896
|
<!-- Country Selector -->
|
|
1831
|
-
<button
|
|
1897
|
+
<button
|
|
1832
1898
|
type="button"
|
|
1833
1899
|
class="lokotro-country-selector"
|
|
1834
1900
|
[disabled]="disabled || isLoading"
|
|
1835
1901
|
(click)="toggleCountryPicker()">
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1902
|
+
@if (selectedCountry && !isLoading) {
|
|
1903
|
+
<span class="lokotro-flag">
|
|
1904
|
+
{{ getFlag(selectedCountry) }}
|
|
1905
|
+
</span>
|
|
1906
|
+
}
|
|
1907
|
+
@if (isLoading) {
|
|
1908
|
+
<span class="lokotro-loading-spinner"></span>
|
|
1909
|
+
}
|
|
1910
|
+
@if (selectedCountry) {
|
|
1911
|
+
<span class="lokotro-country-code">
|
|
1912
|
+
+{{ getPrimaryCode(selectedCountry) }}
|
|
1913
|
+
</span>
|
|
1914
|
+
}
|
|
1843
1915
|
<span class="lokotro-dropdown-arrow">▼</span>
|
|
1844
1916
|
</button>
|
|
1845
|
-
|
|
1917
|
+
|
|
1846
1918
|
<!-- Phone Input -->
|
|
1847
1919
|
<input
|
|
1848
1920
|
type="tel"
|
|
@@ -1855,56 +1927,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1855
1927
|
(input)="onPhoneInput($event)"
|
|
1856
1928
|
(blur)="onTouched()">
|
|
1857
1929
|
</div>
|
|
1858
|
-
|
|
1930
|
+
|
|
1859
1931
|
<!-- Prefix Error -->
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1932
|
+
@if (prefixError) {
|
|
1933
|
+
<div class="lokotro-prefix-error">
|
|
1934
|
+
{{ prefixError }}
|
|
1935
|
+
</div>
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1864
1938
|
<!-- Valid Prefixes Hint -->
|
|
1865
|
-
|
|
1866
|
-
<
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
<span class="lokotro-picker-title">{{ localization.translate('selectCountry') }}</span>
|
|
1883
|
-
<button type="button" class="lokotro-picker-close" (click)="closeCountryPicker()">×</button>
|
|
1939
|
+
@if (selectedCountry && showPrefixHints) {
|
|
1940
|
+
<div class="lokotro-prefix-hints">
|
|
1941
|
+
<span class="lokotro-hint-label">{{ localization.translate('validPrefixes') }}</span>
|
|
1942
|
+
@for (prefix of getVisiblePrefixes(selectedCountry); track prefix) {
|
|
1943
|
+
<span
|
|
1944
|
+
class="lokotro-prefix-chip"
|
|
1945
|
+
>
|
|
1946
|
+
{{ prefix }}
|
|
1947
|
+
</span>
|
|
1948
|
+
}
|
|
1949
|
+
@if (getValidPrefixes(selectedCountry).length > 6) {
|
|
1950
|
+
<span
|
|
1951
|
+
class="lokotro-more-prefixes"
|
|
1952
|
+
>
|
|
1953
|
+
+{{ getValidPrefixes(selectedCountry).length - 6 }} {{ localization.translate('more') }}
|
|
1954
|
+
</span>
|
|
1955
|
+
}
|
|
1884
1956
|
</div>
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
<
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
<!-- Country Picker Dropdown -->
|
|
1960
|
+
@if (showCountryPicker) {
|
|
1961
|
+
<div class="lokotro-country-picker">
|
|
1962
|
+
<div class="lokotro-picker-header">
|
|
1963
|
+
<span class="lokotro-picker-title">{{ localization.translate('selectCountry') }}</span>
|
|
1964
|
+
<button type="button" class="lokotro-picker-close" (click)="closeCountryPicker()">×</button>
|
|
1965
|
+
</div>
|
|
1966
|
+
<div class="lokotro-picker-list">
|
|
1967
|
+
@for (country of countries; track country) {
|
|
1968
|
+
<button
|
|
1969
|
+
type="button"
|
|
1970
|
+
class="lokotro-country-option"
|
|
1971
|
+
[class.selected]="selectedCountry?.refCountry?.id === country.refCountry.id"
|
|
1972
|
+
(click)="selectCountry(country)">
|
|
1973
|
+
<span class="lokotro-option-flag">{{ getFlag(country) }}</span>
|
|
1974
|
+
<span class="lokotro-option-name">{{ country.refCountry.name | uppercase }}</span>
|
|
1975
|
+
<span class="lokotro-option-code">+{{ getPrimaryCode(country) }}</span>
|
|
1976
|
+
@if (selectedCountry?.refCountry?.id === country.refCountry.id) {
|
|
1977
|
+
<span class="lokotro-option-check">✓</span>
|
|
1978
|
+
}
|
|
1979
|
+
</button>
|
|
1980
|
+
}
|
|
1981
|
+
</div>
|
|
1897
1982
|
</div>
|
|
1898
|
-
|
|
1899
|
-
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1900
1985
|
<!-- Backdrop for picker -->
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1986
|
+
@if (showCountryPicker) {
|
|
1987
|
+
<div
|
|
1988
|
+
class="lokotro-picker-backdrop"
|
|
1989
|
+
(click)="closeCountryPicker()">
|
|
1990
|
+
</div>
|
|
1991
|
+
}
|
|
1906
1992
|
</div>
|
|
1907
|
-
|
|
1993
|
+
`, styles: [".lokotro-phone-input-container{position:relative;width:100%}.lokotro-label{display:block;margin-bottom:8px;font-size:14px;font-weight:500;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-phone-input-row{display:flex;gap:12px;align-items:stretch}.lokotro-country-selector{display:flex;align-items:center;gap:8px;padding:12px 14px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);cursor:pointer;transition:border-color .2s;white-space:nowrap}.lokotro-country-selector:hover:not(:disabled){border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-country-selector:disabled{opacity:.6;cursor:not-allowed}.lokotro-flag{font-size:24px;line-height:1}.lokotro-country-code{font-size:16px;font-weight:600}.lokotro-dropdown-arrow{font-size:10px;opacity:.6}.lokotro-loading-spinner{width:20px;height:20px;border:2px solid var(--lokotro-border, #3A473F);border-top-color:var(--lokotro-accent, #3BFBDA);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.lokotro-phone-input{flex:1;padding:14px 16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);font-size:16px;transition:border-color .2s;min-width:0}.lokotro-phone-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-phone-input.error{border-color:var(--lokotro-error, #D97652)}.lokotro-phone-input::placeholder{color:var(--lokotro-text-secondary, #D5D3B8);opacity:.6}.lokotro-phone-input:disabled{opacity:.6;cursor:not-allowed}.lokotro-prefix-error{margin-top:6px;font-size:12px;color:var(--lokotro-error, #D97652)}.lokotro-prefix-hints{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:8px}.lokotro-hint-label{font-size:12px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-prefix-chip{padding:2px 8px;background:#3bfbda1a;border-radius:4px;font-size:12px;font-weight:600;color:var(--lokotro-accent, #3BFBDA)}.lokotro-more-prefixes{font-size:12px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-country-picker{position:absolute;top:100%;left:0;right:0;max-height:300px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;margin-top:4px;z-index:1000;overflow:hidden;display:flex;flex-direction:column}.lokotro-picker-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--lokotro-border, #3A473F)}.lokotro-picker-title{font-size:16px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-picker-close{background:none;border:none;font-size:24px;color:var(--lokotro-text-secondary, #D5D3B8);cursor:pointer;padding:0;line-height:1}.lokotro-picker-list{overflow-y:auto;max-height:250px}.lokotro-country-option{display:flex;align-items:center;gap:12px;width:100%;padding:12px 16px;background:none;border:none;color:var(--lokotro-text-primary, #F2F0D5);cursor:pointer;text-align:left;transition:background-color .2s}.lokotro-country-option:hover{background:var(--lokotro-surface, #2A3832)}.lokotro-country-option.selected{background:#3bfbda1a}.lokotro-option-flag{font-size:28px}.lokotro-option-name{flex:1;font-size:14px;font-weight:500}.lokotro-option-code{font-size:12px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-option-check{color:var(--lokotro-accent, #3BFBDA);font-weight:700}.lokotro-picker-backdrop{position:fixed;inset:0;z-index:999}\n"] }]
|
|
1908
1994
|
}], ctorParameters: () => [{ type: LokotroCountryService }, { type: LokotroLocalizationService }], propDecorators: { label: [{
|
|
1909
1995
|
type: Input
|
|
1910
1996
|
}], placeholder: [{
|
|
@@ -2049,507 +2135,549 @@ class LokotroPaymentFormComponent {
|
|
|
2049
2135
|
onCancel() {
|
|
2050
2136
|
this.cancel.emit();
|
|
2051
2137
|
}
|
|
2052
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
2053
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
2138
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentFormComponent, deps: [{ token: i1$1.FormBuilder }, { token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2139
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroPaymentFormComponent, isStandalone: true, selector: "lokotro-payment-form", inputs: { channel: "channel", transactionId: "transactionId", showUserInfoForm: "showUserInfoForm" }, outputs: { formSubmitted: "formSubmitted", cancel: "cancel" }, ngImport: i0, template: `
|
|
2054
2140
|
<div class="lokotro-payment-form">
|
|
2055
2141
|
<!-- E-Wallet Form -->
|
|
2056
|
-
|
|
2057
|
-
<
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
</span>
|
|
2069
|
-
</div>
|
|
2070
|
-
|
|
2071
|
-
<div class="lokotro-form-group">
|
|
2072
|
-
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2073
|
-
<input
|
|
2074
|
-
type="password"
|
|
2075
|
-
class="lokotro-input"
|
|
2076
|
-
formControlName="walletPin"
|
|
2077
|
-
placeholder="Enter PIN"
|
|
2078
|
-
maxlength="6">
|
|
2079
|
-
<span class="lokotro-error" *ngIf="ewalletForm.get('walletPin')?.touched && ewalletForm.get('walletPin')?.invalid">
|
|
2080
|
-
{{ localization.translate('required') }}
|
|
2081
|
-
</span>
|
|
2082
|
-
</div>
|
|
2083
|
-
|
|
2084
|
-
<div class="lokotro-form-actions">
|
|
2085
|
-
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2086
|
-
{{ localization.translate('cancel') }}
|
|
2087
|
-
</button>
|
|
2088
|
-
<button type="submit" class="lokotro-btn-primary" [disabled]="ewalletForm.invalid">
|
|
2089
|
-
{{ localization.translate('confirm') }}
|
|
2090
|
-
</button>
|
|
2091
|
-
</div>
|
|
2092
|
-
</form>
|
|
2093
|
-
|
|
2094
|
-
<!-- Mobile Money Form -->
|
|
2095
|
-
<form *ngIf="isMobileMoneyForm" [formGroup]="mobileMoneyForm" (ngSubmit)="submitMobileMoneyForm()">
|
|
2096
|
-
<h3 class="lokotro-form-title">{{ localization.translate('mobileMoneyPayment') }}</h3>
|
|
2097
|
-
|
|
2098
|
-
<!-- Personal Information Section - shown when showUserInfoForm is true -->
|
|
2099
|
-
<div class="lokotro-user-info-section" *ngIf="showUserInfoForm">
|
|
2100
|
-
<h4 class="lokotro-section-subtitle">{{ localization.translate('personalInfo') }}</h4>
|
|
2101
|
-
|
|
2102
|
-
<div class="lokotro-form-row">
|
|
2103
|
-
<div class="lokotro-form-group">
|
|
2104
|
-
<label class="lokotro-label">{{ localization.translate('firstName') }}</label>
|
|
2105
|
-
<input
|
|
2106
|
-
type="text"
|
|
2107
|
-
class="lokotro-input"
|
|
2108
|
-
formControlName="firstName"
|
|
2109
|
-
placeholder="John">
|
|
2110
|
-
<span class="lokotro-error" *ngIf="mobileMoneyForm.get('firstName')?.touched && mobileMoneyForm.get('firstName')?.invalid">
|
|
2142
|
+
@if (isEWalletForm) {
|
|
2143
|
+
<form [formGroup]="ewalletForm" (ngSubmit)="submitEWalletForm()">
|
|
2144
|
+
<h3 class="lokotro-form-title">{{ localization.translate('eWallet') }}</h3>
|
|
2145
|
+
<div class="lokotro-form-group">
|
|
2146
|
+
<label class="lokotro-label">{{ localization.translate('walletNumber') }}</label>
|
|
2147
|
+
<input
|
|
2148
|
+
type="text"
|
|
2149
|
+
class="lokotro-input"
|
|
2150
|
+
formControlName="walletNumber"
|
|
2151
|
+
placeholder="Enter wallet number">
|
|
2152
|
+
@if (ewalletForm.get('walletNumber')?.touched && ewalletForm.get('walletNumber')?.invalid) {
|
|
2153
|
+
<span class="lokotro-error">
|
|
2111
2154
|
{{ localization.translate('required') }}
|
|
2112
2155
|
</span>
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2156
|
+
}
|
|
2157
|
+
</div>
|
|
2158
|
+
<div class="lokotro-form-group">
|
|
2159
|
+
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2160
|
+
<input
|
|
2161
|
+
type="password"
|
|
2162
|
+
class="lokotro-input"
|
|
2163
|
+
formControlName="walletPin"
|
|
2164
|
+
placeholder="Enter PIN"
|
|
2165
|
+
maxlength="6">
|
|
2166
|
+
@if (ewalletForm.get('walletPin')?.touched && ewalletForm.get('walletPin')?.invalid) {
|
|
2167
|
+
<span class="lokotro-error">
|
|
2123
2168
|
{{ localization.translate('required') }}
|
|
2124
2169
|
</span>
|
|
2125
|
-
|
|
2170
|
+
}
|
|
2126
2171
|
</div>
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
placeholder="john.doe@example.com">
|
|
2135
|
-
<span class="lokotro-error" *ngIf="mobileMoneyForm.get('email')?.touched && mobileMoneyForm.get('email')?.invalid">
|
|
2136
|
-
{{ localization.translate('invalidEmail') }}
|
|
2137
|
-
</span>
|
|
2172
|
+
<div class="lokotro-form-actions">
|
|
2173
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2174
|
+
{{ localization.translate('cancel') }}
|
|
2175
|
+
</button>
|
|
2176
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="ewalletForm.invalid">
|
|
2177
|
+
{{ localization.translate('confirm') }}
|
|
2178
|
+
</button>
|
|
2138
2179
|
</div>
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2180
|
+
</form>
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
<!-- Mobile Money Form -->
|
|
2184
|
+
@if (isMobileMoneyForm) {
|
|
2185
|
+
<form [formGroup]="mobileMoneyForm" (ngSubmit)="submitMobileMoneyForm()">
|
|
2186
|
+
<h3 class="lokotro-form-title">{{ localization.translate('mobileMoneyPayment') }}</h3>
|
|
2187
|
+
<!-- Personal Information Section - shown when showUserInfoForm is true -->
|
|
2188
|
+
@if (showUserInfoForm) {
|
|
2189
|
+
<div class="lokotro-user-info-section">
|
|
2190
|
+
<h4 class="lokotro-section-subtitle">{{ localization.translate('personalInfo') }}</h4>
|
|
2191
|
+
<div class="lokotro-form-row">
|
|
2192
|
+
<div class="lokotro-form-group">
|
|
2193
|
+
<label class="lokotro-label">{{ localization.translate('firstName') }}</label>
|
|
2194
|
+
<input
|
|
2195
|
+
type="text"
|
|
2196
|
+
class="lokotro-input"
|
|
2197
|
+
formControlName="firstName"
|
|
2198
|
+
placeholder="John">
|
|
2199
|
+
@if (mobileMoneyForm.get('firstName')?.touched && mobileMoneyForm.get('firstName')?.invalid) {
|
|
2200
|
+
<span class="lokotro-error">
|
|
2201
|
+
{{ localization.translate('required') }}
|
|
2202
|
+
</span>
|
|
2203
|
+
}
|
|
2204
|
+
</div>
|
|
2205
|
+
<div class="lokotro-form-group">
|
|
2206
|
+
<label class="lokotro-label">{{ localization.translate('lastName') }}</label>
|
|
2207
|
+
<input
|
|
2208
|
+
type="text"
|
|
2209
|
+
class="lokotro-input"
|
|
2210
|
+
formControlName="lastName"
|
|
2211
|
+
placeholder="Doe">
|
|
2212
|
+
@if (mobileMoneyForm.get('lastName')?.touched && mobileMoneyForm.get('lastName')?.invalid) {
|
|
2213
|
+
<span class="lokotro-error">
|
|
2214
|
+
{{ localization.translate('required') }}
|
|
2215
|
+
</span>
|
|
2216
|
+
}
|
|
2217
|
+
</div>
|
|
2218
|
+
</div>
|
|
2219
|
+
<div class="lokotro-form-group">
|
|
2220
|
+
<label class="lokotro-label">{{ localization.translate('email') }}</label>
|
|
2221
|
+
<input
|
|
2222
|
+
type="email"
|
|
2223
|
+
class="lokotro-input"
|
|
2224
|
+
formControlName="email"
|
|
2225
|
+
placeholder="john.doe@example.com">
|
|
2226
|
+
@if (mobileMoneyForm.get('email')?.touched && mobileMoneyForm.get('email')?.invalid) {
|
|
2227
|
+
<span class="lokotro-error">
|
|
2228
|
+
{{ localization.translate('invalidEmail') }}
|
|
2229
|
+
</span>
|
|
2230
|
+
}
|
|
2231
|
+
</div>
|
|
2232
|
+
<div class="lokotro-form-group">
|
|
2233
|
+
<label class="lokotro-label">{{ localization.translate('phoneNumber') }} ({{ localization.translate('personalPhone') }})</label>
|
|
2234
|
+
<input
|
|
2235
|
+
type="tel"
|
|
2236
|
+
class="lokotro-input"
|
|
2237
|
+
formControlName="personalPhone"
|
|
2238
|
+
placeholder="+243 XXX XXX XXX">
|
|
2239
|
+
@if (mobileMoneyForm.get('personalPhone')?.touched && mobileMoneyForm.get('personalPhone')?.invalid) {
|
|
2240
|
+
<span class="lokotro-error">
|
|
2241
|
+
{{ localization.translate('invalidPhoneNumber') }}
|
|
2242
|
+
</span>
|
|
2243
|
+
}
|
|
2244
|
+
</div>
|
|
2245
|
+
<hr class="lokotro-divider">
|
|
2246
|
+
</div>
|
|
2247
|
+
}
|
|
2248
|
+
<!-- Mobile Money Phone Input -->
|
|
2249
|
+
@if (showUserInfoForm) {
|
|
2250
|
+
<h4 class="lokotro-section-subtitle">{{ localization.translate('mobileMoneyDetails') }}</h4>
|
|
2251
|
+
}
|
|
2252
|
+
<lokotro-mobile-money-phone-input
|
|
2253
|
+
[label]="localization.translate('mobileMoneyPhone')"
|
|
2254
|
+
[initialCountryCode]="'243'"
|
|
2255
|
+
[showPrefixHints]="true"
|
|
2256
|
+
(countryChanged)="onCountryChanged($event)"
|
|
2257
|
+
(phoneChanged)="onPhoneChanged($event)"
|
|
2258
|
+
formControlName="phoneNumber">
|
|
2259
|
+
</lokotro-mobile-money-phone-input>
|
|
2260
|
+
@if (mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('invalidPrefix')) {
|
|
2261
|
+
<span class="lokotro-error">
|
|
2262
|
+
{{ localization.translate('invalidPhonePrefix') }}
|
|
2149
2263
|
</span>
|
|
2264
|
+
}
|
|
2265
|
+
@if (mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('tooShort')) {
|
|
2266
|
+
<span class="lokotro-error">
|
|
2267
|
+
{{ localization.translate('phoneTooShort') }}
|
|
2268
|
+
</span>
|
|
2269
|
+
}
|
|
2270
|
+
@if (mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('tooLong')) {
|
|
2271
|
+
<span class="lokotro-error">
|
|
2272
|
+
{{ localization.translate('phoneTooLong') }}
|
|
2273
|
+
</span>
|
|
2274
|
+
}
|
|
2275
|
+
<div class="lokotro-form-actions">
|
|
2276
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2277
|
+
{{ localization.translate('cancel') }}
|
|
2278
|
+
</button>
|
|
2279
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="mobileMoneyForm.invalid">
|
|
2280
|
+
{{ localization.translate('confirm') }}
|
|
2281
|
+
</button>
|
|
2150
2282
|
</div>
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
<!-- Mobile Money Phone Input -->
|
|
2156
|
-
<h4 class="lokotro-section-subtitle" *ngIf="showUserInfoForm">{{ localization.translate('mobileMoneyDetails') }}</h4>
|
|
2157
|
-
|
|
2158
|
-
<lokotro-mobile-money-phone-input
|
|
2159
|
-
[label]="localization.translate('mobileMoneyPhone')"
|
|
2160
|
-
[initialCountryCode]="'243'"
|
|
2161
|
-
[showPrefixHints]="true"
|
|
2162
|
-
(countryChanged)="onCountryChanged($event)"
|
|
2163
|
-
(phoneChanged)="onPhoneChanged($event)"
|
|
2164
|
-
formControlName="phoneNumber">
|
|
2165
|
-
</lokotro-mobile-money-phone-input>
|
|
2166
|
-
|
|
2167
|
-
<span class="lokotro-error" *ngIf="mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('invalidPrefix')">
|
|
2168
|
-
{{ localization.translate('invalidPhonePrefix') }}
|
|
2169
|
-
</span>
|
|
2170
|
-
<span class="lokotro-error" *ngIf="mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('tooShort')">
|
|
2171
|
-
{{ localization.translate('phoneTooShort') }}
|
|
2172
|
-
</span>
|
|
2173
|
-
<span class="lokotro-error" *ngIf="mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('tooLong')">
|
|
2174
|
-
{{ localization.translate('phoneTooLong') }}
|
|
2175
|
-
</span>
|
|
2176
|
-
|
|
2177
|
-
<div class="lokotro-form-actions">
|
|
2178
|
-
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2179
|
-
{{ localization.translate('cancel') }}
|
|
2180
|
-
</button>
|
|
2181
|
-
<button type="submit" class="lokotro-btn-primary" [disabled]="mobileMoneyForm.invalid">
|
|
2182
|
-
{{ localization.translate('confirm') }}
|
|
2183
|
-
</button>
|
|
2184
|
-
</div>
|
|
2185
|
-
</form>
|
|
2186
|
-
|
|
2283
|
+
</form>
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2187
2286
|
<!-- Card Form -->
|
|
2188
|
-
|
|
2189
|
-
<
|
|
2190
|
-
|
|
2191
|
-
<div class="lokotro-form-group">
|
|
2192
|
-
<label class="lokotro-label">{{ localization.translate('cardNumber') }}</label>
|
|
2193
|
-
<input
|
|
2194
|
-
type="text"
|
|
2195
|
-
class="lokotro-input"
|
|
2196
|
-
formControlName="cardNumber"
|
|
2197
|
-
placeholder="1234 5678 9012 3456"
|
|
2198
|
-
maxlength="19"
|
|
2199
|
-
(input)="formatCardNumber($event)">
|
|
2200
|
-
<span class="lokotro-error" *ngIf="cardForm.get('cardNumber')?.touched && cardForm.get('cardNumber')?.invalid">
|
|
2201
|
-
{{ localization.translate('invalidCardNumber') }}
|
|
2202
|
-
</span>
|
|
2203
|
-
</div>
|
|
2204
|
-
|
|
2205
|
-
<div class="lokotro-form-group">
|
|
2206
|
-
<label class="lokotro-label">{{ localization.translate('cardHolderName') }}</label>
|
|
2207
|
-
<input
|
|
2208
|
-
type="text"
|
|
2209
|
-
class="lokotro-input"
|
|
2210
|
-
formControlName="cardHolderName"
|
|
2211
|
-
placeholder="John Doe">
|
|
2212
|
-
<span class="lokotro-error" *ngIf="cardForm.get('cardHolderName')?.touched && cardForm.get('cardHolderName')?.invalid">
|
|
2213
|
-
{{ localization.translate('required') }}
|
|
2214
|
-
</span>
|
|
2215
|
-
</div>
|
|
2216
|
-
|
|
2217
|
-
<div class="lokotro-form-row">
|
|
2287
|
+
@if (isCardForm) {
|
|
2288
|
+
<form [formGroup]="cardForm" (ngSubmit)="submitCardForm()">
|
|
2289
|
+
<h3 class="lokotro-form-title">{{ localization.translate('card') }}</h3>
|
|
2218
2290
|
<div class="lokotro-form-group">
|
|
2219
|
-
<label class="lokotro-label">{{ localization.translate('
|
|
2220
|
-
<input
|
|
2221
|
-
type="text"
|
|
2222
|
-
class="lokotro-input"
|
|
2223
|
-
formControlName="
|
|
2224
|
-
placeholder="
|
|
2225
|
-
maxlength="
|
|
2226
|
-
(input)="
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2291
|
+
<label class="lokotro-label">{{ localization.translate('cardNumber') }}</label>
|
|
2292
|
+
<input
|
|
2293
|
+
type="text"
|
|
2294
|
+
class="lokotro-input"
|
|
2295
|
+
formControlName="cardNumber"
|
|
2296
|
+
placeholder="1234 5678 9012 3456"
|
|
2297
|
+
maxlength="19"
|
|
2298
|
+
(input)="formatCardNumber($event)">
|
|
2299
|
+
@if (cardForm.get('cardNumber')?.touched && cardForm.get('cardNumber')?.invalid) {
|
|
2300
|
+
<span class="lokotro-error">
|
|
2301
|
+
{{ localization.translate('invalidCardNumber') }}
|
|
2302
|
+
</span>
|
|
2303
|
+
}
|
|
2230
2304
|
</div>
|
|
2231
|
-
|
|
2232
2305
|
<div class="lokotro-form-group">
|
|
2233
|
-
<label class="lokotro-label">{{ localization.translate('
|
|
2234
|
-
<input
|
|
2235
|
-
type="
|
|
2236
|
-
class="lokotro-input"
|
|
2237
|
-
formControlName="
|
|
2238
|
-
placeholder="
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2306
|
+
<label class="lokotro-label">{{ localization.translate('cardHolderName') }}</label>
|
|
2307
|
+
<input
|
|
2308
|
+
type="text"
|
|
2309
|
+
class="lokotro-input"
|
|
2310
|
+
formControlName="cardHolderName"
|
|
2311
|
+
placeholder="John Doe">
|
|
2312
|
+
@if (cardForm.get('cardHolderName')?.touched && cardForm.get('cardHolderName')?.invalid) {
|
|
2313
|
+
<span class="lokotro-error">
|
|
2314
|
+
{{ localization.translate('required') }}
|
|
2315
|
+
</span>
|
|
2316
|
+
}
|
|
2243
2317
|
</div>
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2318
|
+
<div class="lokotro-form-row">
|
|
2319
|
+
<div class="lokotro-form-group">
|
|
2320
|
+
<label class="lokotro-label">{{ localization.translate('expiryDate') }}</label>
|
|
2321
|
+
<input
|
|
2322
|
+
type="text"
|
|
2323
|
+
class="lokotro-input"
|
|
2324
|
+
formControlName="expiryDate"
|
|
2325
|
+
placeholder="MM/YY"
|
|
2326
|
+
maxlength="5"
|
|
2327
|
+
(input)="formatExpiryDate($event)">
|
|
2328
|
+
@if (cardForm.get('expiryDate')?.touched && cardForm.get('expiryDate')?.invalid) {
|
|
2329
|
+
<span class="lokotro-error">
|
|
2330
|
+
{{ localization.translate('invalidExpiryDate') }}
|
|
2331
|
+
</span>
|
|
2332
|
+
}
|
|
2333
|
+
</div>
|
|
2334
|
+
<div class="lokotro-form-group">
|
|
2335
|
+
<label class="lokotro-label">{{ localization.translate('cvv') }}</label>
|
|
2336
|
+
<input
|
|
2337
|
+
type="password"
|
|
2338
|
+
class="lokotro-input"
|
|
2339
|
+
formControlName="cvv"
|
|
2340
|
+
placeholder="123"
|
|
2341
|
+
maxlength="4">
|
|
2342
|
+
@if (cardForm.get('cvv')?.touched && cardForm.get('cvv')?.invalid) {
|
|
2343
|
+
<span class="lokotro-error">
|
|
2344
|
+
{{ localization.translate('invalidCvv') }}
|
|
2345
|
+
</span>
|
|
2346
|
+
}
|
|
2347
|
+
</div>
|
|
2348
|
+
</div>
|
|
2349
|
+
<div class="lokotro-form-actions">
|
|
2350
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2351
|
+
{{ localization.translate('cancel') }}
|
|
2352
|
+
</button>
|
|
2353
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="cardForm.invalid">
|
|
2354
|
+
{{ localization.translate('confirm') }}
|
|
2355
|
+
</button>
|
|
2356
|
+
</div>
|
|
2357
|
+
</form>
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2256
2360
|
<!-- Flash Form -->
|
|
2257
|
-
|
|
2258
|
-
<
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
<
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2361
|
+
@if (isFlashForm) {
|
|
2362
|
+
<form [formGroup]="flashForm" (ngSubmit)="submitFlashForm()">
|
|
2363
|
+
<h3 class="lokotro-form-title">{{ localization.translate('eFlash') }}</h3>
|
|
2364
|
+
<div class="lokotro-form-group">
|
|
2365
|
+
<label class="lokotro-label">Flash Number</label>
|
|
2366
|
+
<input
|
|
2367
|
+
type="text"
|
|
2368
|
+
class="lokotro-input"
|
|
2369
|
+
formControlName="flashNumber"
|
|
2370
|
+
placeholder="Enter flash number">
|
|
2371
|
+
@if (flashForm.get('flashNumber')?.touched && flashForm.get('flashNumber')?.invalid) {
|
|
2372
|
+
<span class="lokotro-error">
|
|
2373
|
+
{{ localization.translate('required') }}
|
|
2374
|
+
</span>
|
|
2375
|
+
}
|
|
2376
|
+
</div>
|
|
2377
|
+
<div class="lokotro-form-group">
|
|
2378
|
+
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2379
|
+
<input
|
|
2380
|
+
type="password"
|
|
2381
|
+
class="lokotro-input"
|
|
2382
|
+
formControlName="flashPin"
|
|
2383
|
+
placeholder="Enter PIN"
|
|
2384
|
+
maxlength="6">
|
|
2385
|
+
@if (flashForm.get('flashPin')?.touched && flashForm.get('flashPin')?.invalid) {
|
|
2386
|
+
<span class="lokotro-error">
|
|
2387
|
+
{{ localization.translate('required') }}
|
|
2388
|
+
</span>
|
|
2389
|
+
}
|
|
2390
|
+
</div>
|
|
2391
|
+
<div class="lokotro-form-actions">
|
|
2392
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2393
|
+
{{ localization.translate('cancel') }}
|
|
2394
|
+
</button>
|
|
2395
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="flashForm.invalid">
|
|
2396
|
+
{{ localization.translate('confirm') }}
|
|
2397
|
+
</button>
|
|
2398
|
+
</div>
|
|
2399
|
+
</form>
|
|
2400
|
+
}
|
|
2294
2401
|
</div>
|
|
2295
|
-
|
|
2402
|
+
`, isInline: true, styles: [".lokotro-payment-form{width:100%}.lokotro-form-title{font-size:20px;font-weight:600;margin:0 0 24px;color:var(--lokotro-text-primary, #F2F0D5);text-align:center}.lokotro-form-group{margin-bottom:20px}.lokotro-form-row{display:flex;gap:16px}.lokotro-form-row .lokotro-form-group{flex:1}.lokotro-label{display:block;margin-bottom:8px;font-size:14px;font-weight:500;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-input{width:100%;padding:14px 16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);font-size:16px;transition:border-color .2s;box-sizing:border-box}.lokotro-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-input::placeholder{color:var(--lokotro-text-secondary, #D5D3B8);opacity:.6}.lokotro-error{display:block;margin-top:6px;font-size:12px;color:var(--lokotro-error, #D97652)}.lokotro-user-info-section{margin-bottom:24px}.lokotro-section-subtitle{font-size:16px;font-weight:600;margin:0 0 16px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-divider{border:none;border-top:1px solid var(--lokotro-border, #3A473F);margin:24px 0}.lokotro-form-actions{display:flex;gap:12px;margin-top:32px}.lokotro-btn-primary,.lokotro-btn-secondary{flex:1;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-primary:disabled{opacity:.5;cursor:not-allowed}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: LokotroMobileMoneyPhoneInputComponent, selector: "lokotro-mobile-money-phone-input", inputs: ["label", "placeholder", "initialCountryCode", "showPrefixHints", "disabled"], outputs: ["countryChanged", "phoneChanged"] }] }); }
|
|
2296
2403
|
}
|
|
2297
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
2404
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentFormComponent, decorators: [{
|
|
2298
2405
|
type: Component,
|
|
2299
|
-
args: [{ selector: 'lokotro-payment-form', standalone: true, imports: [
|
|
2406
|
+
args: [{ selector: 'lokotro-payment-form', standalone: true, imports: [FormsModule, ReactiveFormsModule, LokotroMobileMoneyPhoneInputComponent], template: `
|
|
2300
2407
|
<div class="lokotro-payment-form">
|
|
2301
2408
|
<!-- E-Wallet Form -->
|
|
2302
|
-
|
|
2303
|
-
<
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
</span>
|
|
2315
|
-
</div>
|
|
2316
|
-
|
|
2317
|
-
<div class="lokotro-form-group">
|
|
2318
|
-
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2319
|
-
<input
|
|
2320
|
-
type="password"
|
|
2321
|
-
class="lokotro-input"
|
|
2322
|
-
formControlName="walletPin"
|
|
2323
|
-
placeholder="Enter PIN"
|
|
2324
|
-
maxlength="6">
|
|
2325
|
-
<span class="lokotro-error" *ngIf="ewalletForm.get('walletPin')?.touched && ewalletForm.get('walletPin')?.invalid">
|
|
2326
|
-
{{ localization.translate('required') }}
|
|
2327
|
-
</span>
|
|
2328
|
-
</div>
|
|
2329
|
-
|
|
2330
|
-
<div class="lokotro-form-actions">
|
|
2331
|
-
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2332
|
-
{{ localization.translate('cancel') }}
|
|
2333
|
-
</button>
|
|
2334
|
-
<button type="submit" class="lokotro-btn-primary" [disabled]="ewalletForm.invalid">
|
|
2335
|
-
{{ localization.translate('confirm') }}
|
|
2336
|
-
</button>
|
|
2337
|
-
</div>
|
|
2338
|
-
</form>
|
|
2339
|
-
|
|
2340
|
-
<!-- Mobile Money Form -->
|
|
2341
|
-
<form *ngIf="isMobileMoneyForm" [formGroup]="mobileMoneyForm" (ngSubmit)="submitMobileMoneyForm()">
|
|
2342
|
-
<h3 class="lokotro-form-title">{{ localization.translate('mobileMoneyPayment') }}</h3>
|
|
2343
|
-
|
|
2344
|
-
<!-- Personal Information Section - shown when showUserInfoForm is true -->
|
|
2345
|
-
<div class="lokotro-user-info-section" *ngIf="showUserInfoForm">
|
|
2346
|
-
<h4 class="lokotro-section-subtitle">{{ localization.translate('personalInfo') }}</h4>
|
|
2347
|
-
|
|
2348
|
-
<div class="lokotro-form-row">
|
|
2349
|
-
<div class="lokotro-form-group">
|
|
2350
|
-
<label class="lokotro-label">{{ localization.translate('firstName') }}</label>
|
|
2351
|
-
<input
|
|
2352
|
-
type="text"
|
|
2353
|
-
class="lokotro-input"
|
|
2354
|
-
formControlName="firstName"
|
|
2355
|
-
placeholder="John">
|
|
2356
|
-
<span class="lokotro-error" *ngIf="mobileMoneyForm.get('firstName')?.touched && mobileMoneyForm.get('firstName')?.invalid">
|
|
2409
|
+
@if (isEWalletForm) {
|
|
2410
|
+
<form [formGroup]="ewalletForm" (ngSubmit)="submitEWalletForm()">
|
|
2411
|
+
<h3 class="lokotro-form-title">{{ localization.translate('eWallet') }}</h3>
|
|
2412
|
+
<div class="lokotro-form-group">
|
|
2413
|
+
<label class="lokotro-label">{{ localization.translate('walletNumber') }}</label>
|
|
2414
|
+
<input
|
|
2415
|
+
type="text"
|
|
2416
|
+
class="lokotro-input"
|
|
2417
|
+
formControlName="walletNumber"
|
|
2418
|
+
placeholder="Enter wallet number">
|
|
2419
|
+
@if (ewalletForm.get('walletNumber')?.touched && ewalletForm.get('walletNumber')?.invalid) {
|
|
2420
|
+
<span class="lokotro-error">
|
|
2357
2421
|
{{ localization.translate('required') }}
|
|
2358
2422
|
</span>
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2423
|
+
}
|
|
2424
|
+
</div>
|
|
2425
|
+
<div class="lokotro-form-group">
|
|
2426
|
+
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2427
|
+
<input
|
|
2428
|
+
type="password"
|
|
2429
|
+
class="lokotro-input"
|
|
2430
|
+
formControlName="walletPin"
|
|
2431
|
+
placeholder="Enter PIN"
|
|
2432
|
+
maxlength="6">
|
|
2433
|
+
@if (ewalletForm.get('walletPin')?.touched && ewalletForm.get('walletPin')?.invalid) {
|
|
2434
|
+
<span class="lokotro-error">
|
|
2369
2435
|
{{ localization.translate('required') }}
|
|
2370
2436
|
</span>
|
|
2437
|
+
}
|
|
2438
|
+
</div>
|
|
2439
|
+
<div class="lokotro-form-actions">
|
|
2440
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2441
|
+
{{ localization.translate('cancel') }}
|
|
2442
|
+
</button>
|
|
2443
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="ewalletForm.invalid">
|
|
2444
|
+
{{ localization.translate('confirm') }}
|
|
2445
|
+
</button>
|
|
2446
|
+
</div>
|
|
2447
|
+
</form>
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
<!-- Mobile Money Form -->
|
|
2451
|
+
@if (isMobileMoneyForm) {
|
|
2452
|
+
<form [formGroup]="mobileMoneyForm" (ngSubmit)="submitMobileMoneyForm()">
|
|
2453
|
+
<h3 class="lokotro-form-title">{{ localization.translate('mobileMoneyPayment') }}</h3>
|
|
2454
|
+
<!-- Personal Information Section - shown when showUserInfoForm is true -->
|
|
2455
|
+
@if (showUserInfoForm) {
|
|
2456
|
+
<div class="lokotro-user-info-section">
|
|
2457
|
+
<h4 class="lokotro-section-subtitle">{{ localization.translate('personalInfo') }}</h4>
|
|
2458
|
+
<div class="lokotro-form-row">
|
|
2459
|
+
<div class="lokotro-form-group">
|
|
2460
|
+
<label class="lokotro-label">{{ localization.translate('firstName') }}</label>
|
|
2461
|
+
<input
|
|
2462
|
+
type="text"
|
|
2463
|
+
class="lokotro-input"
|
|
2464
|
+
formControlName="firstName"
|
|
2465
|
+
placeholder="John">
|
|
2466
|
+
@if (mobileMoneyForm.get('firstName')?.touched && mobileMoneyForm.get('firstName')?.invalid) {
|
|
2467
|
+
<span class="lokotro-error">
|
|
2468
|
+
{{ localization.translate('required') }}
|
|
2469
|
+
</span>
|
|
2470
|
+
}
|
|
2471
|
+
</div>
|
|
2472
|
+
<div class="lokotro-form-group">
|
|
2473
|
+
<label class="lokotro-label">{{ localization.translate('lastName') }}</label>
|
|
2474
|
+
<input
|
|
2475
|
+
type="text"
|
|
2476
|
+
class="lokotro-input"
|
|
2477
|
+
formControlName="lastName"
|
|
2478
|
+
placeholder="Doe">
|
|
2479
|
+
@if (mobileMoneyForm.get('lastName')?.touched && mobileMoneyForm.get('lastName')?.invalid) {
|
|
2480
|
+
<span class="lokotro-error">
|
|
2481
|
+
{{ localization.translate('required') }}
|
|
2482
|
+
</span>
|
|
2483
|
+
}
|
|
2484
|
+
</div>
|
|
2485
|
+
</div>
|
|
2486
|
+
<div class="lokotro-form-group">
|
|
2487
|
+
<label class="lokotro-label">{{ localization.translate('email') }}</label>
|
|
2488
|
+
<input
|
|
2489
|
+
type="email"
|
|
2490
|
+
class="lokotro-input"
|
|
2491
|
+
formControlName="email"
|
|
2492
|
+
placeholder="john.doe@example.com">
|
|
2493
|
+
@if (mobileMoneyForm.get('email')?.touched && mobileMoneyForm.get('email')?.invalid) {
|
|
2494
|
+
<span class="lokotro-error">
|
|
2495
|
+
{{ localization.translate('invalidEmail') }}
|
|
2496
|
+
</span>
|
|
2497
|
+
}
|
|
2498
|
+
</div>
|
|
2499
|
+
<div class="lokotro-form-group">
|
|
2500
|
+
<label class="lokotro-label">{{ localization.translate('phoneNumber') }} ({{ localization.translate('personalPhone') }})</label>
|
|
2501
|
+
<input
|
|
2502
|
+
type="tel"
|
|
2503
|
+
class="lokotro-input"
|
|
2504
|
+
formControlName="personalPhone"
|
|
2505
|
+
placeholder="+243 XXX XXX XXX">
|
|
2506
|
+
@if (mobileMoneyForm.get('personalPhone')?.touched && mobileMoneyForm.get('personalPhone')?.invalid) {
|
|
2507
|
+
<span class="lokotro-error">
|
|
2508
|
+
{{ localization.translate('invalidPhoneNumber') }}
|
|
2509
|
+
</span>
|
|
2510
|
+
}
|
|
2511
|
+
</div>
|
|
2512
|
+
<hr class="lokotro-divider">
|
|
2371
2513
|
</div>
|
|
2514
|
+
}
|
|
2515
|
+
<!-- Mobile Money Phone Input -->
|
|
2516
|
+
@if (showUserInfoForm) {
|
|
2517
|
+
<h4 class="lokotro-section-subtitle">{{ localization.translate('mobileMoneyDetails') }}</h4>
|
|
2518
|
+
}
|
|
2519
|
+
<lokotro-mobile-money-phone-input
|
|
2520
|
+
[label]="localization.translate('mobileMoneyPhone')"
|
|
2521
|
+
[initialCountryCode]="'243'"
|
|
2522
|
+
[showPrefixHints]="true"
|
|
2523
|
+
(countryChanged)="onCountryChanged($event)"
|
|
2524
|
+
(phoneChanged)="onPhoneChanged($event)"
|
|
2525
|
+
formControlName="phoneNumber">
|
|
2526
|
+
</lokotro-mobile-money-phone-input>
|
|
2527
|
+
@if (mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('invalidPrefix')) {
|
|
2528
|
+
<span class="lokotro-error">
|
|
2529
|
+
{{ localization.translate('invalidPhonePrefix') }}
|
|
2530
|
+
</span>
|
|
2531
|
+
}
|
|
2532
|
+
@if (mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('tooShort')) {
|
|
2533
|
+
<span class="lokotro-error">
|
|
2534
|
+
{{ localization.translate('phoneTooShort') }}
|
|
2535
|
+
</span>
|
|
2536
|
+
}
|
|
2537
|
+
@if (mobileMoneyForm.get('phoneNumber')?.touched && mobileMoneyForm.get('phoneNumber')?.hasError('tooLong')) {
|
|
2538
|
+
<span class="lokotro-error">
|
|
2539
|
+
{{ localization.translate('phoneTooLong') }}
|
|
2540
|
+
</span>
|
|
2541
|
+
}
|
|
2542
|
+
<div class="lokotro-form-actions">
|
|
2543
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2544
|
+
{{ localization.translate('cancel') }}
|
|
2545
|
+
</button>
|
|
2546
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="mobileMoneyForm.invalid">
|
|
2547
|
+
{{ localization.translate('confirm') }}
|
|
2548
|
+
</button>
|
|
2372
2549
|
</div>
|
|
2373
|
-
|
|
2550
|
+
</form>
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
<!-- Card Form -->
|
|
2554
|
+
@if (isCardForm) {
|
|
2555
|
+
<form [formGroup]="cardForm" (ngSubmit)="submitCardForm()">
|
|
2556
|
+
<h3 class="lokotro-form-title">{{ localization.translate('card') }}</h3>
|
|
2374
2557
|
<div class="lokotro-form-group">
|
|
2375
|
-
<label class="lokotro-label">{{ localization.translate('
|
|
2376
|
-
<input
|
|
2377
|
-
type="
|
|
2378
|
-
class="lokotro-input"
|
|
2379
|
-
formControlName="
|
|
2380
|
-
placeholder="
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2558
|
+
<label class="lokotro-label">{{ localization.translate('cardNumber') }}</label>
|
|
2559
|
+
<input
|
|
2560
|
+
type="text"
|
|
2561
|
+
class="lokotro-input"
|
|
2562
|
+
formControlName="cardNumber"
|
|
2563
|
+
placeholder="1234 5678 9012 3456"
|
|
2564
|
+
maxlength="19"
|
|
2565
|
+
(input)="formatCardNumber($event)">
|
|
2566
|
+
@if (cardForm.get('cardNumber')?.touched && cardForm.get('cardNumber')?.invalid) {
|
|
2567
|
+
<span class="lokotro-error">
|
|
2568
|
+
{{ localization.translate('invalidCardNumber') }}
|
|
2569
|
+
</span>
|
|
2570
|
+
}
|
|
2384
2571
|
</div>
|
|
2385
|
-
|
|
2386
2572
|
<div class="lokotro-form-group">
|
|
2387
|
-
<label class="lokotro-label">{{ localization.translate('
|
|
2388
|
-
<input
|
|
2389
|
-
type="
|
|
2390
|
-
class="lokotro-input"
|
|
2391
|
-
formControlName="
|
|
2392
|
-
placeholder="
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2573
|
+
<label class="lokotro-label">{{ localization.translate('cardHolderName') }}</label>
|
|
2574
|
+
<input
|
|
2575
|
+
type="text"
|
|
2576
|
+
class="lokotro-input"
|
|
2577
|
+
formControlName="cardHolderName"
|
|
2578
|
+
placeholder="John Doe">
|
|
2579
|
+
@if (cardForm.get('cardHolderName')?.touched && cardForm.get('cardHolderName')?.invalid) {
|
|
2580
|
+
<span class="lokotro-error">
|
|
2581
|
+
{{ localization.translate('required') }}
|
|
2582
|
+
</span>
|
|
2583
|
+
}
|
|
2396
2584
|
</div>
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
placeholder="1234 5678 9012 3456"
|
|
2444
|
-
maxlength="19"
|
|
2445
|
-
(input)="formatCardNumber($event)">
|
|
2446
|
-
<span class="lokotro-error" *ngIf="cardForm.get('cardNumber')?.touched && cardForm.get('cardNumber')?.invalid">
|
|
2447
|
-
{{ localization.translate('invalidCardNumber') }}
|
|
2448
|
-
</span>
|
|
2449
|
-
</div>
|
|
2450
|
-
|
|
2451
|
-
<div class="lokotro-form-group">
|
|
2452
|
-
<label class="lokotro-label">{{ localization.translate('cardHolderName') }}</label>
|
|
2453
|
-
<input
|
|
2454
|
-
type="text"
|
|
2455
|
-
class="lokotro-input"
|
|
2456
|
-
formControlName="cardHolderName"
|
|
2457
|
-
placeholder="John Doe">
|
|
2458
|
-
<span class="lokotro-error" *ngIf="cardForm.get('cardHolderName')?.touched && cardForm.get('cardHolderName')?.invalid">
|
|
2459
|
-
{{ localization.translate('required') }}
|
|
2460
|
-
</span>
|
|
2461
|
-
</div>
|
|
2462
|
-
|
|
2463
|
-
<div class="lokotro-form-row">
|
|
2585
|
+
<div class="lokotro-form-row">
|
|
2586
|
+
<div class="lokotro-form-group">
|
|
2587
|
+
<label class="lokotro-label">{{ localization.translate('expiryDate') }}</label>
|
|
2588
|
+
<input
|
|
2589
|
+
type="text"
|
|
2590
|
+
class="lokotro-input"
|
|
2591
|
+
formControlName="expiryDate"
|
|
2592
|
+
placeholder="MM/YY"
|
|
2593
|
+
maxlength="5"
|
|
2594
|
+
(input)="formatExpiryDate($event)">
|
|
2595
|
+
@if (cardForm.get('expiryDate')?.touched && cardForm.get('expiryDate')?.invalid) {
|
|
2596
|
+
<span class="lokotro-error">
|
|
2597
|
+
{{ localization.translate('invalidExpiryDate') }}
|
|
2598
|
+
</span>
|
|
2599
|
+
}
|
|
2600
|
+
</div>
|
|
2601
|
+
<div class="lokotro-form-group">
|
|
2602
|
+
<label class="lokotro-label">{{ localization.translate('cvv') }}</label>
|
|
2603
|
+
<input
|
|
2604
|
+
type="password"
|
|
2605
|
+
class="lokotro-input"
|
|
2606
|
+
formControlName="cvv"
|
|
2607
|
+
placeholder="123"
|
|
2608
|
+
maxlength="4">
|
|
2609
|
+
@if (cardForm.get('cvv')?.touched && cardForm.get('cvv')?.invalid) {
|
|
2610
|
+
<span class="lokotro-error">
|
|
2611
|
+
{{ localization.translate('invalidCvv') }}
|
|
2612
|
+
</span>
|
|
2613
|
+
}
|
|
2614
|
+
</div>
|
|
2615
|
+
</div>
|
|
2616
|
+
<div class="lokotro-form-actions">
|
|
2617
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2618
|
+
{{ localization.translate('cancel') }}
|
|
2619
|
+
</button>
|
|
2620
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="cardForm.invalid">
|
|
2621
|
+
{{ localization.translate('confirm') }}
|
|
2622
|
+
</button>
|
|
2623
|
+
</div>
|
|
2624
|
+
</form>
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
<!-- Flash Form -->
|
|
2628
|
+
@if (isFlashForm) {
|
|
2629
|
+
<form [formGroup]="flashForm" (ngSubmit)="submitFlashForm()">
|
|
2630
|
+
<h3 class="lokotro-form-title">{{ localization.translate('eFlash') }}</h3>
|
|
2464
2631
|
<div class="lokotro-form-group">
|
|
2465
|
-
<label class="lokotro-label">
|
|
2466
|
-
<input
|
|
2467
|
-
type="text"
|
|
2468
|
-
class="lokotro-input"
|
|
2469
|
-
formControlName="
|
|
2470
|
-
placeholder="
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2632
|
+
<label class="lokotro-label">Flash Number</label>
|
|
2633
|
+
<input
|
|
2634
|
+
type="text"
|
|
2635
|
+
class="lokotro-input"
|
|
2636
|
+
formControlName="flashNumber"
|
|
2637
|
+
placeholder="Enter flash number">
|
|
2638
|
+
@if (flashForm.get('flashNumber')?.touched && flashForm.get('flashNumber')?.invalid) {
|
|
2639
|
+
<span class="lokotro-error">
|
|
2640
|
+
{{ localization.translate('required') }}
|
|
2641
|
+
</span>
|
|
2642
|
+
}
|
|
2476
2643
|
</div>
|
|
2477
|
-
|
|
2478
2644
|
<div class="lokotro-form-group">
|
|
2479
|
-
<label class="lokotro-label">{{ localization.translate('
|
|
2480
|
-
<input
|
|
2481
|
-
type="password"
|
|
2482
|
-
class="lokotro-input"
|
|
2483
|
-
formControlName="
|
|
2484
|
-
placeholder="
|
|
2485
|
-
maxlength="
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2645
|
+
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2646
|
+
<input
|
|
2647
|
+
type="password"
|
|
2648
|
+
class="lokotro-input"
|
|
2649
|
+
formControlName="flashPin"
|
|
2650
|
+
placeholder="Enter PIN"
|
|
2651
|
+
maxlength="6">
|
|
2652
|
+
@if (flashForm.get('flashPin')?.touched && flashForm.get('flashPin')?.invalid) {
|
|
2653
|
+
<span class="lokotro-error">
|
|
2654
|
+
{{ localization.translate('required') }}
|
|
2655
|
+
</span>
|
|
2656
|
+
}
|
|
2489
2657
|
</div>
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
<span class="lokotro-error" *ngIf="flashForm.get('flashNumber')?.touched && flashForm.get('flashNumber')?.invalid">
|
|
2514
|
-
{{ localization.translate('required') }}
|
|
2515
|
-
</span>
|
|
2516
|
-
</div>
|
|
2517
|
-
|
|
2518
|
-
<div class="lokotro-form-group">
|
|
2519
|
-
<label class="lokotro-label">{{ localization.translate('pin') }}</label>
|
|
2520
|
-
<input
|
|
2521
|
-
type="password"
|
|
2522
|
-
class="lokotro-input"
|
|
2523
|
-
formControlName="flashPin"
|
|
2524
|
-
placeholder="Enter PIN"
|
|
2525
|
-
maxlength="6">
|
|
2526
|
-
<span class="lokotro-error" *ngIf="flashForm.get('flashPin')?.touched && flashForm.get('flashPin')?.invalid">
|
|
2527
|
-
{{ localization.translate('required') }}
|
|
2528
|
-
</span>
|
|
2529
|
-
</div>
|
|
2530
|
-
|
|
2531
|
-
<div class="lokotro-form-actions">
|
|
2532
|
-
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2533
|
-
{{ localization.translate('cancel') }}
|
|
2534
|
-
</button>
|
|
2535
|
-
<button type="submit" class="lokotro-btn-primary" [disabled]="flashForm.invalid">
|
|
2536
|
-
{{ localization.translate('confirm') }}
|
|
2537
|
-
</button>
|
|
2538
|
-
</div>
|
|
2539
|
-
</form>
|
|
2540
|
-
</div>
|
|
2541
|
-
`, styles: [".lokotro-payment-form{width:100%}.lokotro-form-title{font-size:20px;font-weight:600;margin:0 0 24px;color:var(--lokotro-text-primary, #F2F0D5);text-align:center}.lokotro-form-group{margin-bottom:20px}.lokotro-form-row{display:flex;gap:16px}.lokotro-form-row .lokotro-form-group{flex:1}.lokotro-label{display:block;margin-bottom:8px;font-size:14px;font-weight:500;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-input{width:100%;padding:14px 16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);font-size:16px;transition:border-color .2s;box-sizing:border-box}.lokotro-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-input::placeholder{color:var(--lokotro-text-secondary, #D5D3B8);opacity:.6}.lokotro-error{display:block;margin-top:6px;font-size:12px;color:var(--lokotro-error, #D97652)}.lokotro-user-info-section{margin-bottom:24px}.lokotro-section-subtitle{font-size:16px;font-weight:600;margin:0 0 16px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-divider{border:none;border-top:1px solid var(--lokotro-border, #3A473F);margin:24px 0}.lokotro-form-actions{display:flex;gap:12px;margin-top:32px}.lokotro-btn-primary,.lokotro-btn-secondary{flex:1;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-primary:disabled{opacity:.5;cursor:not-allowed}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}\n"] }]
|
|
2542
|
-
}], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: LokotroLocalizationService }], propDecorators: { channel: [{
|
|
2543
|
-
type: Input
|
|
2544
|
-
}], transactionId: [{
|
|
2545
|
-
type: Input
|
|
2546
|
-
}], showUserInfoForm: [{
|
|
2547
|
-
type: Input
|
|
2548
|
-
}], formSubmitted: [{
|
|
2549
|
-
type: Output
|
|
2550
|
-
}], cancel: [{
|
|
2551
|
-
type: Output
|
|
2552
|
-
}] } });
|
|
2658
|
+
<div class="lokotro-form-actions">
|
|
2659
|
+
<button type="button" class="lokotro-btn-secondary" (click)="onCancel()">
|
|
2660
|
+
{{ localization.translate('cancel') }}
|
|
2661
|
+
</button>
|
|
2662
|
+
<button type="submit" class="lokotro-btn-primary" [disabled]="flashForm.invalid">
|
|
2663
|
+
{{ localization.translate('confirm') }}
|
|
2664
|
+
</button>
|
|
2665
|
+
</div>
|
|
2666
|
+
</form>
|
|
2667
|
+
}
|
|
2668
|
+
</div>
|
|
2669
|
+
`, styles: [".lokotro-payment-form{width:100%}.lokotro-form-title{font-size:20px;font-weight:600;margin:0 0 24px;color:var(--lokotro-text-primary, #F2F0D5);text-align:center}.lokotro-form-group{margin-bottom:20px}.lokotro-form-row{display:flex;gap:16px}.lokotro-form-row .lokotro-form-group{flex:1}.lokotro-label{display:block;margin-bottom:8px;font-size:14px;font-weight:500;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-input{width:100%;padding:14px 16px;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);font-size:16px;transition:border-color .2s;box-sizing:border-box}.lokotro-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-input::placeholder{color:var(--lokotro-text-secondary, #D5D3B8);opacity:.6}.lokotro-error{display:block;margin-top:6px;font-size:12px;color:var(--lokotro-error, #D97652)}.lokotro-user-info-section{margin-bottom:24px}.lokotro-section-subtitle{font-size:16px;font-weight:600;margin:0 0 16px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-divider{border:none;border-top:1px solid var(--lokotro-border, #3A473F);margin:24px 0}.lokotro-form-actions{display:flex;gap:12px;margin-top:32px}.lokotro-btn-primary,.lokotro-btn-secondary{flex:1;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-primary:disabled{opacity:.5;cursor:not-allowed}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}\n"] }]
|
|
2670
|
+
}], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: LokotroLocalizationService }], propDecorators: { channel: [{
|
|
2671
|
+
type: Input
|
|
2672
|
+
}], transactionId: [{
|
|
2673
|
+
type: Input
|
|
2674
|
+
}], showUserInfoForm: [{
|
|
2675
|
+
type: Input
|
|
2676
|
+
}], formSubmitted: [{
|
|
2677
|
+
type: Output
|
|
2678
|
+
}], cancel: [{
|
|
2679
|
+
type: Output
|
|
2680
|
+
}] } });
|
|
2553
2681
|
|
|
2554
2682
|
/**
|
|
2555
2683
|
* Lokotro Pay - OTP Verification Component
|
|
@@ -2639,8 +2767,8 @@ class LokotroOtpVerificationComponent {
|
|
|
2639
2767
|
onCancelClick() {
|
|
2640
2768
|
this.cancel.emit();
|
|
2641
2769
|
}
|
|
2642
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
2643
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
2770
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroOtpVerificationComponent, deps: [{ token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2771
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroOtpVerificationComponent, isStandalone: true, selector: "lokotro-otp-verification", inputs: { transactionId: "transactionId", otpDestination: "otpDestination", otpLength: "otpLength" }, outputs: { otpVerified: "otpVerified", resendOtp: "resendOtp", cancel: "cancel" }, ngImport: i0, template: `
|
|
2644
2772
|
<div class="lokotro-otp-verification">
|
|
2645
2773
|
<div class="lokotro-otp-icon">
|
|
2646
2774
|
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
@@ -2648,54 +2776,60 @@ class LokotroOtpVerificationComponent {
|
|
|
2648
2776
|
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
|
2649
2777
|
</svg>
|
|
2650
2778
|
</div>
|
|
2651
|
-
|
|
2779
|
+
|
|
2652
2780
|
<h3 class="lokotro-otp-title">{{ localization.translate('enterOtp') }}</h3>
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2781
|
+
@if (otpDestination) {
|
|
2782
|
+
<p class="lokotro-otp-subtitle">
|
|
2783
|
+
{{ localization.translate('otpSentTo') }} {{ otpDestination }}
|
|
2784
|
+
</p>
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2657
2787
|
<div class="lokotro-otp-inputs">
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
<div class="lokotro-otp-timer" *ngIf="resendTimer > 0">
|
|
2671
|
-
Resend OTP in {{ resendTimer }}s
|
|
2788
|
+
@for (digit of otpDigits; track digit; let i = $index) {
|
|
2789
|
+
<input
|
|
2790
|
+
type="text"
|
|
2791
|
+
class="lokotro-otp-input"
|
|
2792
|
+
maxlength="1"
|
|
2793
|
+
[value]="otpDigits[i]"
|
|
2794
|
+
(input)="onOtpInput($event, i)"
|
|
2795
|
+
(keydown)="onOtpKeydown($event, i)"
|
|
2796
|
+
(paste)="onOtpPaste($event)"
|
|
2797
|
+
#otpInput>
|
|
2798
|
+
}
|
|
2672
2799
|
</div>
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
class="lokotro-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2800
|
+
|
|
2801
|
+
@if (resendTimer > 0) {
|
|
2802
|
+
<div class="lokotro-otp-timer">
|
|
2803
|
+
Resend OTP in {{ resendTimer }}s
|
|
2804
|
+
</div>
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
@if (resendTimer === 0) {
|
|
2808
|
+
<button
|
|
2809
|
+
class="lokotro-resend-btn"
|
|
2810
|
+
(click)="onResend()">
|
|
2811
|
+
{{ localization.translate('resendOtp') }}
|
|
2812
|
+
</button>
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2681
2815
|
<div class="lokotro-form-actions">
|
|
2682
2816
|
<button type="button" class="lokotro-btn-secondary" (click)="onCancelClick()">
|
|
2683
2817
|
{{ localization.translate('cancel') }}
|
|
2684
2818
|
</button>
|
|
2685
|
-
<button
|
|
2686
|
-
type="button"
|
|
2687
|
-
class="lokotro-btn-primary"
|
|
2819
|
+
<button
|
|
2820
|
+
type="button"
|
|
2821
|
+
class="lokotro-btn-primary"
|
|
2688
2822
|
[disabled]="!isOtpComplete"
|
|
2689
2823
|
(click)="onVerify()">
|
|
2690
2824
|
{{ localization.translate('verifyOtp') }}
|
|
2691
2825
|
</button>
|
|
2692
2826
|
</div>
|
|
2693
2827
|
</div>
|
|
2694
|
-
|
|
2828
|
+
`, isInline: true, styles: [".lokotro-otp-verification{display:flex;flex-direction:column;align-items:center;text-align:center;padding:24px 0}.lokotro-otp-icon{width:80px;height:80px;display:flex;align-items:center;justify-content:center;background:var(--lokotro-card, #3A4840);border-radius:50%;margin-bottom:24px;color:var(--lokotro-accent, #3BFBDA)}.lokotro-otp-title{font-size:24px;font-weight:600;margin:0 0 8px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-otp-subtitle{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0 0 32px}.lokotro-otp-inputs{display:flex;gap:12px;margin-bottom:24px}.lokotro-otp-input{width:50px;height:56px;text-align:center;font-size:24px;font-weight:600;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);transition:border-color .2s}.lokotro-otp-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-otp-timer{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin-bottom:24px}.lokotro-resend-btn{background:none;border:none;color:var(--lokotro-accent, #3BFBDA);font-size:14px;font-weight:600;cursor:pointer;margin-bottom:24px;text-decoration:underline}.lokotro-resend-btn:hover{opacity:.8}.lokotro-form-actions{display:flex;gap:12px;width:100%}.lokotro-btn-primary,.lokotro-btn-secondary{flex:1;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-primary:disabled{opacity:.5;cursor:not-allowed}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }] }); }
|
|
2695
2829
|
}
|
|
2696
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
2830
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroOtpVerificationComponent, decorators: [{
|
|
2697
2831
|
type: Component,
|
|
2698
|
-
args: [{ selector: 'lokotro-otp-verification', standalone: true, imports: [
|
|
2832
|
+
args: [{ selector: 'lokotro-otp-verification', standalone: true, imports: [FormsModule], template: `
|
|
2699
2833
|
<div class="lokotro-otp-verification">
|
|
2700
2834
|
<div class="lokotro-otp-icon">
|
|
2701
2835
|
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
@@ -2703,50 +2837,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
2703
2837
|
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
|
2704
2838
|
</svg>
|
|
2705
2839
|
</div>
|
|
2706
|
-
|
|
2840
|
+
|
|
2707
2841
|
<h3 class="lokotro-otp-title">{{ localization.translate('enterOtp') }}</h3>
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2842
|
+
@if (otpDestination) {
|
|
2843
|
+
<p class="lokotro-otp-subtitle">
|
|
2844
|
+
{{ localization.translate('otpSentTo') }} {{ otpDestination }}
|
|
2845
|
+
</p>
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2712
2848
|
<div class="lokotro-otp-inputs">
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
<div class="lokotro-otp-timer" *ngIf="resendTimer > 0">
|
|
2726
|
-
Resend OTP in {{ resendTimer }}s
|
|
2849
|
+
@for (digit of otpDigits; track digit; let i = $index) {
|
|
2850
|
+
<input
|
|
2851
|
+
type="text"
|
|
2852
|
+
class="lokotro-otp-input"
|
|
2853
|
+
maxlength="1"
|
|
2854
|
+
[value]="otpDigits[i]"
|
|
2855
|
+
(input)="onOtpInput($event, i)"
|
|
2856
|
+
(keydown)="onOtpKeydown($event, i)"
|
|
2857
|
+
(paste)="onOtpPaste($event)"
|
|
2858
|
+
#otpInput>
|
|
2859
|
+
}
|
|
2727
2860
|
</div>
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
class="lokotro-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2861
|
+
|
|
2862
|
+
@if (resendTimer > 0) {
|
|
2863
|
+
<div class="lokotro-otp-timer">
|
|
2864
|
+
Resend OTP in {{ resendTimer }}s
|
|
2865
|
+
</div>
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
@if (resendTimer === 0) {
|
|
2869
|
+
<button
|
|
2870
|
+
class="lokotro-resend-btn"
|
|
2871
|
+
(click)="onResend()">
|
|
2872
|
+
{{ localization.translate('resendOtp') }}
|
|
2873
|
+
</button>
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2736
2876
|
<div class="lokotro-form-actions">
|
|
2737
2877
|
<button type="button" class="lokotro-btn-secondary" (click)="onCancelClick()">
|
|
2738
2878
|
{{ localization.translate('cancel') }}
|
|
2739
2879
|
</button>
|
|
2740
|
-
<button
|
|
2741
|
-
type="button"
|
|
2742
|
-
class="lokotro-btn-primary"
|
|
2880
|
+
<button
|
|
2881
|
+
type="button"
|
|
2882
|
+
class="lokotro-btn-primary"
|
|
2743
2883
|
[disabled]="!isOtpComplete"
|
|
2744
2884
|
(click)="onVerify()">
|
|
2745
2885
|
{{ localization.translate('verifyOtp') }}
|
|
2746
2886
|
</button>
|
|
2747
2887
|
</div>
|
|
2748
2888
|
</div>
|
|
2749
|
-
|
|
2889
|
+
`, styles: [".lokotro-otp-verification{display:flex;flex-direction:column;align-items:center;text-align:center;padding:24px 0}.lokotro-otp-icon{width:80px;height:80px;display:flex;align-items:center;justify-content:center;background:var(--lokotro-card, #3A4840);border-radius:50%;margin-bottom:24px;color:var(--lokotro-accent, #3BFBDA)}.lokotro-otp-title{font-size:24px;font-weight:600;margin:0 0 8px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-otp-subtitle{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0 0 32px}.lokotro-otp-inputs{display:flex;gap:12px;margin-bottom:24px}.lokotro-otp-input{width:50px;height:56px;text-align:center;font-size:24px;font-weight:600;background:var(--lokotro-card, #3A4840);border:2px solid var(--lokotro-border, #3A473F);border-radius:12px;color:var(--lokotro-text-primary, #F2F0D5);transition:border-color .2s}.lokotro-otp-input:focus{outline:none;border-color:var(--lokotro-accent, #3BFBDA)}.lokotro-otp-timer{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin-bottom:24px}.lokotro-resend-btn{background:none;border:none;color:var(--lokotro-accent, #3BFBDA);font-size:14px;font-weight:600;cursor:pointer;margin-bottom:24px;text-decoration:underline}.lokotro-resend-btn:hover{opacity:.8}.lokotro-form-actions{display:flex;gap:12px;width:100%}.lokotro-btn-primary,.lokotro-btn-secondary{flex:1;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-btn-primary:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-primary:disabled{opacity:.5;cursor:not-allowed}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}\n"] }]
|
|
2750
2890
|
}], ctorParameters: () => [{ type: LokotroLocalizationService }], propDecorators: { transactionId: [{
|
|
2751
2891
|
type: Input
|
|
2752
2892
|
}], otpDestination: [{
|
|
@@ -2775,70 +2915,78 @@ class LokotroProcessingComponent {
|
|
|
2775
2915
|
setTimeout(() => this.currentStep = 3, 6000);
|
|
2776
2916
|
}
|
|
2777
2917
|
}
|
|
2778
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
2779
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
2918
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroProcessingComponent, deps: [{ token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2919
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroProcessingComponent, isStandalone: true, selector: "lokotro-processing", inputs: { type: "type", message: "message" }, ngImport: i0, template: `
|
|
2780
2920
|
<div class="lokotro-processing">
|
|
2781
2921
|
<div class="lokotro-processing-spinner">
|
|
2782
2922
|
<div class="lokotro-spinner-ring"></div>
|
|
2783
2923
|
<div class="lokotro-spinner-ring"></div>
|
|
2784
2924
|
<div class="lokotro-spinner-ring"></div>
|
|
2785
2925
|
</div>
|
|
2786
|
-
|
|
2926
|
+
|
|
2787
2927
|
<h3 class="lokotro-processing-title">{{ message || localization.translate('processing') }}</h3>
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2928
|
+
|
|
2929
|
+
@if (type === 'mobileMoney') {
|
|
2930
|
+
<p class="lokotro-processing-subtitle">
|
|
2931
|
+
Please confirm the payment on your mobile device
|
|
2932
|
+
</p>
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
@if (type === 'mobileMoney') {
|
|
2936
|
+
<div class="lokotro-processing-steps">
|
|
2937
|
+
<div class="lokotro-step" [class.active]="currentStep >= 1">
|
|
2938
|
+
<div class="lokotro-step-icon">📱</div>
|
|
2939
|
+
<span>Check your phone</span>
|
|
2940
|
+
</div>
|
|
2941
|
+
<div class="lokotro-step" [class.active]="currentStep >= 2">
|
|
2942
|
+
<div class="lokotro-step-icon">🔐</div>
|
|
2943
|
+
<span>Enter your PIN</span>
|
|
2944
|
+
</div>
|
|
2945
|
+
<div class="lokotro-step" [class.active]="currentStep >= 3">
|
|
2946
|
+
<div class="lokotro-step-icon">✅</div>
|
|
2947
|
+
<span>Confirm payment</span>
|
|
2948
|
+
</div>
|
|
2805
2949
|
</div>
|
|
2806
|
-
|
|
2950
|
+
}
|
|
2807
2951
|
</div>
|
|
2808
|
-
|
|
2952
|
+
`, isInline: true, styles: [".lokotro-processing{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:48px 24px;min-height:300px}.lokotro-processing-spinner{position:relative;width:80px;height:80px;margin-bottom:32px}.lokotro-spinner-ring{position:absolute;width:100%;height:100%;border:3px solid transparent;border-radius:50%;animation:lokotro-spin 1.5s linear infinite}.lokotro-spinner-ring:nth-child(1){border-top-color:var(--lokotro-accent, #3BFBDA);animation-delay:0s}.lokotro-spinner-ring:nth-child(2){border-right-color:var(--lokotro-primary, #5A5E39);animation-delay:.15s;width:70%;height:70%;top:15%;left:15%}.lokotro-spinner-ring:nth-child(3){border-bottom-color:var(--lokotro-secondary, #6E7346);animation-delay:.3s;width:50%;height:50%;top:25%;left:25%}@keyframes lokotro-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.lokotro-processing-title{font-size:20px;font-weight:600;margin:0 0 8px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-processing-subtitle{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0 0 32px}.lokotro-processing-steps{display:flex;flex-direction:column;gap:16px;width:100%;max-width:280px}.lokotro-step{display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--lokotro-card, #3A4840);border-radius:12px;opacity:.5;transition:opacity .3s}.lokotro-step.active{opacity:1}.lokotro-step-icon{font-size:20px}.lokotro-step span{font-size:14px;color:var(--lokotro-text-primary, #F2F0D5)}\n"] }); }
|
|
2809
2953
|
}
|
|
2810
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
2954
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroProcessingComponent, decorators: [{
|
|
2811
2955
|
type: Component,
|
|
2812
|
-
args: [{ selector: 'lokotro-processing', standalone: true, imports: [
|
|
2956
|
+
args: [{ selector: 'lokotro-processing', standalone: true, imports: [], template: `
|
|
2813
2957
|
<div class="lokotro-processing">
|
|
2814
2958
|
<div class="lokotro-processing-spinner">
|
|
2815
2959
|
<div class="lokotro-spinner-ring"></div>
|
|
2816
2960
|
<div class="lokotro-spinner-ring"></div>
|
|
2817
2961
|
<div class="lokotro-spinner-ring"></div>
|
|
2818
2962
|
</div>
|
|
2819
|
-
|
|
2963
|
+
|
|
2820
2964
|
<h3 class="lokotro-processing-title">{{ message || localization.translate('processing') }}</h3>
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2965
|
+
|
|
2966
|
+
@if (type === 'mobileMoney') {
|
|
2967
|
+
<p class="lokotro-processing-subtitle">
|
|
2968
|
+
Please confirm the payment on your mobile device
|
|
2969
|
+
</p>
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
@if (type === 'mobileMoney') {
|
|
2973
|
+
<div class="lokotro-processing-steps">
|
|
2974
|
+
<div class="lokotro-step" [class.active]="currentStep >= 1">
|
|
2975
|
+
<div class="lokotro-step-icon">📱</div>
|
|
2976
|
+
<span>Check your phone</span>
|
|
2977
|
+
</div>
|
|
2978
|
+
<div class="lokotro-step" [class.active]="currentStep >= 2">
|
|
2979
|
+
<div class="lokotro-step-icon">🔐</div>
|
|
2980
|
+
<span>Enter your PIN</span>
|
|
2981
|
+
</div>
|
|
2982
|
+
<div class="lokotro-step" [class.active]="currentStep >= 3">
|
|
2983
|
+
<div class="lokotro-step-icon">✅</div>
|
|
2984
|
+
<span>Confirm payment</span>
|
|
2985
|
+
</div>
|
|
2838
2986
|
</div>
|
|
2839
|
-
|
|
2987
|
+
}
|
|
2840
2988
|
</div>
|
|
2841
|
-
|
|
2989
|
+
`, styles: [".lokotro-processing{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:48px 24px;min-height:300px}.lokotro-processing-spinner{position:relative;width:80px;height:80px;margin-bottom:32px}.lokotro-spinner-ring{position:absolute;width:100%;height:100%;border:3px solid transparent;border-radius:50%;animation:lokotro-spin 1.5s linear infinite}.lokotro-spinner-ring:nth-child(1){border-top-color:var(--lokotro-accent, #3BFBDA);animation-delay:0s}.lokotro-spinner-ring:nth-child(2){border-right-color:var(--lokotro-primary, #5A5E39);animation-delay:.15s;width:70%;height:70%;top:15%;left:15%}.lokotro-spinner-ring:nth-child(3){border-bottom-color:var(--lokotro-secondary, #6E7346);animation-delay:.3s;width:50%;height:50%;top:25%;left:25%}@keyframes lokotro-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.lokotro-processing-title{font-size:20px;font-weight:600;margin:0 0 8px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-processing-subtitle{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0 0 32px}.lokotro-processing-steps{display:flex;flex-direction:column;gap:16px;width:100%;max-width:280px}.lokotro-step{display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--lokotro-card, #3A4840);border-radius:12px;opacity:.5;transition:opacity .3s}.lokotro-step.active{opacity:1}.lokotro-step-icon{font-size:20px}.lokotro-step span{font-size:14px;color:var(--lokotro-text-primary, #F2F0D5)}\n"] }]
|
|
2842
2990
|
}], ctorParameters: () => [{ type: LokotroLocalizationService }], propDecorators: { type: [{
|
|
2843
2991
|
type: Input
|
|
2844
2992
|
}], message: [{
|
|
@@ -2854,8 +3002,59 @@ class LokotroResultComponent {
|
|
|
2854
3002
|
this.localization = localization;
|
|
2855
3003
|
this.type = 'success';
|
|
2856
3004
|
this.title = '';
|
|
3005
|
+
/** Auto-redirect duration in seconds. If > 0, will auto-call onAutoRedirect after countdown. */
|
|
3006
|
+
this.autoRedirectSeconds = 0;
|
|
2857
3007
|
this.primaryAction = new EventEmitter();
|
|
2858
3008
|
this.secondaryAction = new EventEmitter();
|
|
3009
|
+
/** Emitted when auto-redirect triggers after countdown completes. */
|
|
3010
|
+
this.autoRedirect = new EventEmitter();
|
|
3011
|
+
// Countdown state
|
|
3012
|
+
this.countdownSeconds = 0;
|
|
3013
|
+
this.isCountdownCancelled = false;
|
|
3014
|
+
}
|
|
3015
|
+
ngOnInit() {
|
|
3016
|
+
this.startAutoRedirectCountdown();
|
|
3017
|
+
}
|
|
3018
|
+
ngOnDestroy() {
|
|
3019
|
+
this.clearCountdown();
|
|
3020
|
+
}
|
|
3021
|
+
startAutoRedirectCountdown() {
|
|
3022
|
+
if (this.autoRedirectSeconds <= 0)
|
|
3023
|
+
return;
|
|
3024
|
+
this.countdownSeconds = this.autoRedirectSeconds;
|
|
3025
|
+
this.countdownInterval = setInterval(() => {
|
|
3026
|
+
if (this.isCountdownCancelled) {
|
|
3027
|
+
this.clearCountdown();
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
this.countdownSeconds--;
|
|
3031
|
+
if (this.countdownSeconds <= 0) {
|
|
3032
|
+
this.clearCountdown();
|
|
3033
|
+
this.triggerAutoRedirect();
|
|
3034
|
+
}
|
|
3035
|
+
}, 1000);
|
|
3036
|
+
}
|
|
3037
|
+
cancelCountdown() {
|
|
3038
|
+
if (this.countdownInterval) {
|
|
3039
|
+
this.isCountdownCancelled = true;
|
|
3040
|
+
this.clearCountdown();
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
clearCountdown() {
|
|
3044
|
+
if (this.countdownInterval) {
|
|
3045
|
+
clearInterval(this.countdownInterval);
|
|
3046
|
+
this.countdownInterval = undefined;
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
triggerAutoRedirect() {
|
|
3050
|
+
if (this.isCountdownCancelled)
|
|
3051
|
+
return;
|
|
3052
|
+
this.autoRedirect.emit();
|
|
3053
|
+
}
|
|
3054
|
+
getCountdownProgress() {
|
|
3055
|
+
if (this.autoRedirectSeconds <= 0)
|
|
3056
|
+
return 0;
|
|
3057
|
+
return (this.countdownSeconds / this.autoRedirectSeconds) * 100;
|
|
2859
3058
|
}
|
|
2860
3059
|
formatAmount(amount, currency) {
|
|
2861
3060
|
const formatter = new Intl.NumberFormat('en-US', {
|
|
@@ -2866,143 +3065,237 @@ class LokotroResultComponent {
|
|
|
2866
3065
|
return formatter.format(amount);
|
|
2867
3066
|
}
|
|
2868
3067
|
onPrimaryClick() {
|
|
3068
|
+
this.cancelCountdown();
|
|
2869
3069
|
this.primaryAction.emit();
|
|
2870
3070
|
}
|
|
2871
3071
|
onSecondaryClick() {
|
|
3072
|
+
this.cancelCountdown();
|
|
2872
3073
|
this.secondaryAction.emit();
|
|
2873
3074
|
}
|
|
2874
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
2875
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
3075
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroResultComponent, deps: [{ token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3076
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroResultComponent, isStandalone: true, selector: "lokotro-result", inputs: { type: "type", title: "title", message: "message", amount: "amount", currency: "currency", transactionId: "transactionId", primaryActionLabel: "primaryActionLabel", secondaryActionLabel: "secondaryActionLabel", autoRedirectSeconds: "autoRedirectSeconds" }, outputs: { primaryAction: "primaryAction", secondaryAction: "secondaryAction", autoRedirect: "autoRedirect" }, ngImport: i0, template: `
|
|
2876
3077
|
<div class="lokotro-result" [class]="'lokotro-result-' + type">
|
|
2877
3078
|
<!-- Animated Icon -->
|
|
2878
3079
|
<div class="lokotro-result-icon" [class]="'lokotro-icon-' + type">
|
|
2879
3080
|
<!-- Success Icon -->
|
|
2880
|
-
|
|
2881
|
-
<
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
3081
|
+
@if (type === 'success') {
|
|
3082
|
+
<svg class="lokotro-checkmark" viewBox="0 0 52 52">
|
|
3083
|
+
<circle class="lokotro-checkmark-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3084
|
+
<path class="lokotro-checkmark-check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/>
|
|
3085
|
+
</svg>
|
|
3086
|
+
}
|
|
3087
|
+
|
|
2885
3088
|
<!-- Error Icon -->
|
|
2886
|
-
|
|
2887
|
-
<
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
3089
|
+
@if (type === 'error') {
|
|
3090
|
+
<svg class="lokotro-error-icon" viewBox="0 0 52 52">
|
|
3091
|
+
<circle class="lokotro-error-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3092
|
+
<path class="lokotro-error-x" fill="none" d="M16 16l20 20M36 16l-20 20"/>
|
|
3093
|
+
</svg>
|
|
3094
|
+
}
|
|
3095
|
+
|
|
2891
3096
|
<!-- Warning Icon -->
|
|
2892
|
-
|
|
2893
|
-
<
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3097
|
+
@if (type === 'warning') {
|
|
3098
|
+
<svg class="lokotro-warning-icon" viewBox="0 0 52 52">
|
|
3099
|
+
<circle class="lokotro-warning-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3100
|
+
<path class="lokotro-warning-exclaim" fill="none" d="M26 15v15M26 37v1"/>
|
|
3101
|
+
</svg>
|
|
3102
|
+
}
|
|
3103
|
+
|
|
2897
3104
|
<!-- Info Icon -->
|
|
2898
|
-
|
|
2899
|
-
<
|
|
2900
|
-
|
|
2901
|
-
|
|
3105
|
+
@if (type === 'info') {
|
|
3106
|
+
<svg class="lokotro-info-icon" viewBox="0 0 52 52">
|
|
3107
|
+
<circle class="lokotro-info-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3108
|
+
<path class="lokotro-info-i" fill="none" d="M26 22v15M26 15v1"/>
|
|
3109
|
+
</svg>
|
|
3110
|
+
}
|
|
2902
3111
|
</div>
|
|
2903
|
-
|
|
3112
|
+
|
|
2904
3113
|
<!-- Title -->
|
|
2905
3114
|
<h2 class="lokotro-result-title">{{ title }}</h2>
|
|
2906
|
-
|
|
3115
|
+
|
|
2907
3116
|
<!-- Message -->
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3117
|
+
@if (message) {
|
|
3118
|
+
<p class="lokotro-result-message">{{ message }}</p>
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
<!-- Countdown Indicator -->
|
|
3122
|
+
@if (autoRedirectSeconds > 0 && countdownSeconds > 0 && !isCountdownCancelled) {
|
|
3123
|
+
<div class="lokotro-countdown-indicator"
|
|
3124
|
+
(click)="cancelCountdown()">
|
|
3125
|
+
<div class="lokotro-countdown-progress">
|
|
3126
|
+
<svg viewBox="0 0 36 36" class="lokotro-countdown-circle">
|
|
3127
|
+
<path class="lokotro-countdown-bg"
|
|
3128
|
+
d="M18 2.0845
|
|
3129
|
+
a 15.9155 15.9155 0 0 1 0 31.831
|
|
3130
|
+
a 15.9155 15.9155 0 0 1 0 -31.831"
|
|
3131
|
+
/>
|
|
3132
|
+
<path class="lokotro-countdown-fill" [class]="'lokotro-countdown-' + type"
|
|
3133
|
+
[attr.stroke-dasharray]="getCountdownProgress() + ', 100'"
|
|
3134
|
+
d="M18 2.0845
|
|
3135
|
+
a 15.9155 15.9155 0 0 1 0 31.831
|
|
3136
|
+
a 15.9155 15.9155 0 0 1 0 -31.831"
|
|
3137
|
+
/>
|
|
3138
|
+
</svg>
|
|
3139
|
+
</div>
|
|
3140
|
+
<span class="lokotro-countdown-text" [class]="'lokotro-text-' + type">
|
|
3141
|
+
{{ localization.translate('redirectingIn', { seconds: countdownSeconds }) }}
|
|
3142
|
+
</span>
|
|
3143
|
+
<svg class="lokotro-countdown-cancel" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
3144
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
3145
|
+
</svg>
|
|
2915
3146
|
</div>
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
<!-- Transaction Details -->
|
|
3150
|
+
@if (type === 'success' && (amount || transactionId)) {
|
|
3151
|
+
<div class="lokotro-result-details">
|
|
3152
|
+
@if (amount) {
|
|
3153
|
+
<div class="lokotro-detail-row">
|
|
3154
|
+
<span class="lokotro-detail-label">{{ localization.translate('amount') }}</span>
|
|
3155
|
+
<span class="lokotro-detail-value">{{ formatAmount(amount, currency) }}</span>
|
|
3156
|
+
</div>
|
|
3157
|
+
}
|
|
3158
|
+
@if (transactionId) {
|
|
3159
|
+
<div class="lokotro-detail-row">
|
|
3160
|
+
<span class="lokotro-detail-label">Transaction ID</span>
|
|
3161
|
+
<span class="lokotro-detail-value lokotro-mono">{{ transactionId }}</span>
|
|
3162
|
+
</div>
|
|
3163
|
+
}
|
|
2919
3164
|
</div>
|
|
2920
|
-
|
|
2921
|
-
|
|
3165
|
+
}
|
|
3166
|
+
|
|
2922
3167
|
<!-- Actions -->
|
|
2923
3168
|
<div class="lokotro-result-actions">
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
3169
|
+
@if (primaryActionLabel) {
|
|
3170
|
+
<button
|
|
3171
|
+
class="lokotro-btn-primary"
|
|
3172
|
+
(click)="onPrimaryClick()">
|
|
3173
|
+
{{ primaryActionLabel }}
|
|
3174
|
+
</button>
|
|
3175
|
+
}
|
|
3176
|
+
@if (secondaryActionLabel) {
|
|
3177
|
+
<button
|
|
3178
|
+
class="lokotro-btn-secondary"
|
|
3179
|
+
(click)="onSecondaryClick()">
|
|
3180
|
+
{{ secondaryActionLabel }}
|
|
3181
|
+
</button>
|
|
3182
|
+
}
|
|
2936
3183
|
</div>
|
|
2937
3184
|
</div>
|
|
2938
|
-
|
|
3185
|
+
`, isInline: true, styles: [".lokotro-result{display:flex;flex-direction:column;align-items:center;text-align:center;padding:48px 24px}.lokotro-result-icon{width:80px;height:80px;margin-bottom:24px}.lokotro-checkmark{width:100%;height:100%;stroke-width:3}.lokotro-checkmark-circle{stroke:var(--lokotro-success, #3BFBDA);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-checkmark-check{stroke:var(--lokotro-success, #3BFBDA);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:48;stroke-dashoffset:48;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}.lokotro-error-icon{width:100%;height:100%;stroke-width:3}.lokotro-error-circle{stroke:var(--lokotro-error, #D97652);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-error-x{stroke:var(--lokotro-error, #D97652);stroke-width:3;stroke-linecap:round;stroke-dasharray:28;stroke-dashoffset:28;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}.lokotro-warning-icon{width:100%;height:100%;stroke-width:3}.lokotro-warning-circle{stroke:var(--lokotro-warning, #D97652);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-warning-exclaim{stroke:var(--lokotro-warning, #D97652);stroke-width:3;stroke-linecap:round;stroke-dasharray:20;stroke-dashoffset:20;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}.lokotro-info-icon{width:100%;height:100%;stroke-width:3}.lokotro-info-circle{stroke:var(--lokotro-info, #3B82F6);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-info-i{stroke:var(--lokotro-info, #3B82F6);stroke-width:3;stroke-linecap:round;stroke-dasharray:20;stroke-dashoffset:20;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}@keyframes lokotro-stroke{to{stroke-dashoffset:0}}.lokotro-result-title{font-size:24px;font-weight:700;margin:0 0 12px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-result-success .lokotro-result-title{color:var(--lokotro-success, #3BFBDA)}.lokotro-result-error .lokotro-result-title{color:var(--lokotro-error, #D97652)}.lokotro-result-message{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0 0 24px;line-height:1.5}.lokotro-result-details{width:100%;max-width:320px;background:var(--lokotro-card, #3A4840);border-radius:16px;padding:16px;margin-bottom:32px}.lokotro-detail-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0}.lokotro-detail-row:not(:last-child){border-bottom:1px solid var(--lokotro-border, #3A473F)}.lokotro-detail-label{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-detail-value{font-size:14px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-mono{font-family:Courier New,monospace;font-size:12px}.lokotro-result-actions{display:flex;flex-direction:column;gap:12px;width:100%;max-width:320px}.lokotro-btn-primary,.lokotro-btn-secondary{width:100%;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-result-success .lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-success, #3BFBDA),var(--lokotro-success-dark, #27D4B6));color:var(--lokotro-background-dark, #1C2621)}.lokotro-btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-countdown-indicator{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--lokotro-primary-light, rgba(90, 94, 57, .1));border:1px solid var(--lokotro-primary-border, rgba(90, 94, 57, .3));border-radius:20px;cursor:pointer;margin-bottom:16px;transition:all .2s ease}.lokotro-countdown-indicator:hover{background:var(--lokotro-primary-light, rgba(90, 94, 57, .2))}.lokotro-result-error .lokotro-countdown-indicator{background:var(--lokotro-error-light, rgba(217, 118, 82, .1));border-color:var(--lokotro-error-border, rgba(217, 118, 82, .3))}.lokotro-countdown-progress{width:16px;height:16px}.lokotro-countdown-circle{width:100%;height:100%;transform:rotate(-90deg)}.lokotro-countdown-bg{fill:none;stroke:var(--lokotro-border, #3A473F);stroke-width:3}.lokotro-countdown-fill{fill:none;stroke-width:3;stroke-linecap:round;transition:stroke-dasharray .3s ease}.lokotro-countdown-success{stroke:var(--lokotro-success, #3BFBDA)}.lokotro-countdown-error{stroke:var(--lokotro-error, #D97652)}.lokotro-countdown-warning{stroke:var(--lokotro-warning, #D97652)}.lokotro-countdown-info{stroke:var(--lokotro-info, #3B82F6)}.lokotro-countdown-text{font-size:12px;font-weight:500}.lokotro-text-success{color:var(--lokotro-success, #3BFBDA)}.lokotro-text-error{color:var(--lokotro-error, #D97652)}.lokotro-text-warning{color:var(--lokotro-warning, #D97652)}.lokotro-text-info{color:var(--lokotro-info, #3B82F6)}.lokotro-countdown-cancel{color:var(--lokotro-text-secondary, #D5D3B8)}\n"] }); }
|
|
2939
3186
|
}
|
|
2940
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
3187
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroResultComponent, decorators: [{
|
|
2941
3188
|
type: Component,
|
|
2942
|
-
args: [{ selector: 'lokotro-result', standalone: true, imports: [
|
|
3189
|
+
args: [{ selector: 'lokotro-result', standalone: true, imports: [], template: `
|
|
2943
3190
|
<div class="lokotro-result" [class]="'lokotro-result-' + type">
|
|
2944
3191
|
<!-- Animated Icon -->
|
|
2945
3192
|
<div class="lokotro-result-icon" [class]="'lokotro-icon-' + type">
|
|
2946
3193
|
<!-- Success Icon -->
|
|
2947
|
-
|
|
2948
|
-
<
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
3194
|
+
@if (type === 'success') {
|
|
3195
|
+
<svg class="lokotro-checkmark" viewBox="0 0 52 52">
|
|
3196
|
+
<circle class="lokotro-checkmark-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3197
|
+
<path class="lokotro-checkmark-check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/>
|
|
3198
|
+
</svg>
|
|
3199
|
+
}
|
|
3200
|
+
|
|
2952
3201
|
<!-- Error Icon -->
|
|
2953
|
-
|
|
2954
|
-
<
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
3202
|
+
@if (type === 'error') {
|
|
3203
|
+
<svg class="lokotro-error-icon" viewBox="0 0 52 52">
|
|
3204
|
+
<circle class="lokotro-error-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3205
|
+
<path class="lokotro-error-x" fill="none" d="M16 16l20 20M36 16l-20 20"/>
|
|
3206
|
+
</svg>
|
|
3207
|
+
}
|
|
3208
|
+
|
|
2958
3209
|
<!-- Warning Icon -->
|
|
2959
|
-
|
|
2960
|
-
<
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
3210
|
+
@if (type === 'warning') {
|
|
3211
|
+
<svg class="lokotro-warning-icon" viewBox="0 0 52 52">
|
|
3212
|
+
<circle class="lokotro-warning-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3213
|
+
<path class="lokotro-warning-exclaim" fill="none" d="M26 15v15M26 37v1"/>
|
|
3214
|
+
</svg>
|
|
3215
|
+
}
|
|
3216
|
+
|
|
2964
3217
|
<!-- Info Icon -->
|
|
2965
|
-
|
|
2966
|
-
<
|
|
2967
|
-
|
|
2968
|
-
|
|
3218
|
+
@if (type === 'info') {
|
|
3219
|
+
<svg class="lokotro-info-icon" viewBox="0 0 52 52">
|
|
3220
|
+
<circle class="lokotro-info-circle" cx="26" cy="26" r="25" fill="none"/>
|
|
3221
|
+
<path class="lokotro-info-i" fill="none" d="M26 22v15M26 15v1"/>
|
|
3222
|
+
</svg>
|
|
3223
|
+
}
|
|
2969
3224
|
</div>
|
|
2970
|
-
|
|
3225
|
+
|
|
2971
3226
|
<!-- Title -->
|
|
2972
3227
|
<h2 class="lokotro-result-title">{{ title }}</h2>
|
|
2973
|
-
|
|
3228
|
+
|
|
2974
3229
|
<!-- Message -->
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
3230
|
+
@if (message) {
|
|
3231
|
+
<p class="lokotro-result-message">{{ message }}</p>
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
<!-- Countdown Indicator -->
|
|
3235
|
+
@if (autoRedirectSeconds > 0 && countdownSeconds > 0 && !isCountdownCancelled) {
|
|
3236
|
+
<div class="lokotro-countdown-indicator"
|
|
3237
|
+
(click)="cancelCountdown()">
|
|
3238
|
+
<div class="lokotro-countdown-progress">
|
|
3239
|
+
<svg viewBox="0 0 36 36" class="lokotro-countdown-circle">
|
|
3240
|
+
<path class="lokotro-countdown-bg"
|
|
3241
|
+
d="M18 2.0845
|
|
3242
|
+
a 15.9155 15.9155 0 0 1 0 31.831
|
|
3243
|
+
a 15.9155 15.9155 0 0 1 0 -31.831"
|
|
3244
|
+
/>
|
|
3245
|
+
<path class="lokotro-countdown-fill" [class]="'lokotro-countdown-' + type"
|
|
3246
|
+
[attr.stroke-dasharray]="getCountdownProgress() + ', 100'"
|
|
3247
|
+
d="M18 2.0845
|
|
3248
|
+
a 15.9155 15.9155 0 0 1 0 31.831
|
|
3249
|
+
a 15.9155 15.9155 0 0 1 0 -31.831"
|
|
3250
|
+
/>
|
|
3251
|
+
</svg>
|
|
3252
|
+
</div>
|
|
3253
|
+
<span class="lokotro-countdown-text" [class]="'lokotro-text-' + type">
|
|
3254
|
+
{{ localization.translate('redirectingIn', { seconds: countdownSeconds }) }}
|
|
3255
|
+
</span>
|
|
3256
|
+
<svg class="lokotro-countdown-cancel" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
3257
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
3258
|
+
</svg>
|
|
2982
3259
|
</div>
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
<!-- Transaction Details -->
|
|
3263
|
+
@if (type === 'success' && (amount || transactionId)) {
|
|
3264
|
+
<div class="lokotro-result-details">
|
|
3265
|
+
@if (amount) {
|
|
3266
|
+
<div class="lokotro-detail-row">
|
|
3267
|
+
<span class="lokotro-detail-label">{{ localization.translate('amount') }}</span>
|
|
3268
|
+
<span class="lokotro-detail-value">{{ formatAmount(amount, currency) }}</span>
|
|
3269
|
+
</div>
|
|
3270
|
+
}
|
|
3271
|
+
@if (transactionId) {
|
|
3272
|
+
<div class="lokotro-detail-row">
|
|
3273
|
+
<span class="lokotro-detail-label">Transaction ID</span>
|
|
3274
|
+
<span class="lokotro-detail-value lokotro-mono">{{ transactionId }}</span>
|
|
3275
|
+
</div>
|
|
3276
|
+
}
|
|
2986
3277
|
</div>
|
|
2987
|
-
|
|
2988
|
-
|
|
3278
|
+
}
|
|
3279
|
+
|
|
2989
3280
|
<!-- Actions -->
|
|
2990
3281
|
<div class="lokotro-result-actions">
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3282
|
+
@if (primaryActionLabel) {
|
|
3283
|
+
<button
|
|
3284
|
+
class="lokotro-btn-primary"
|
|
3285
|
+
(click)="onPrimaryClick()">
|
|
3286
|
+
{{ primaryActionLabel }}
|
|
3287
|
+
</button>
|
|
3288
|
+
}
|
|
3289
|
+
@if (secondaryActionLabel) {
|
|
3290
|
+
<button
|
|
3291
|
+
class="lokotro-btn-secondary"
|
|
3292
|
+
(click)="onSecondaryClick()">
|
|
3293
|
+
{{ secondaryActionLabel }}
|
|
3294
|
+
</button>
|
|
3295
|
+
}
|
|
3003
3296
|
</div>
|
|
3004
3297
|
</div>
|
|
3005
|
-
|
|
3298
|
+
`, styles: [".lokotro-result{display:flex;flex-direction:column;align-items:center;text-align:center;padding:48px 24px}.lokotro-result-icon{width:80px;height:80px;margin-bottom:24px}.lokotro-checkmark{width:100%;height:100%;stroke-width:3}.lokotro-checkmark-circle{stroke:var(--lokotro-success, #3BFBDA);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-checkmark-check{stroke:var(--lokotro-success, #3BFBDA);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:48;stroke-dashoffset:48;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}.lokotro-error-icon{width:100%;height:100%;stroke-width:3}.lokotro-error-circle{stroke:var(--lokotro-error, #D97652);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-error-x{stroke:var(--lokotro-error, #D97652);stroke-width:3;stroke-linecap:round;stroke-dasharray:28;stroke-dashoffset:28;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}.lokotro-warning-icon{width:100%;height:100%;stroke-width:3}.lokotro-warning-circle{stroke:var(--lokotro-warning, #D97652);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-warning-exclaim{stroke:var(--lokotro-warning, #D97652);stroke-width:3;stroke-linecap:round;stroke-dasharray:20;stroke-dashoffset:20;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}.lokotro-info-icon{width:100%;height:100%;stroke-width:3}.lokotro-info-circle{stroke:var(--lokotro-info, #3B82F6);stroke-dasharray:166;stroke-dashoffset:166;animation:lokotro-stroke .6s cubic-bezier(.65,0,.45,1) forwards}.lokotro-info-i{stroke:var(--lokotro-info, #3B82F6);stroke-width:3;stroke-linecap:round;stroke-dasharray:20;stroke-dashoffset:20;animation:lokotro-stroke .3s cubic-bezier(.65,0,.45,1) .6s forwards}@keyframes lokotro-stroke{to{stroke-dashoffset:0}}.lokotro-result-title{font-size:24px;font-weight:700;margin:0 0 12px;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-result-success .lokotro-result-title{color:var(--lokotro-success, #3BFBDA)}.lokotro-result-error .lokotro-result-title{color:var(--lokotro-error, #D97652)}.lokotro-result-message{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0 0 24px;line-height:1.5}.lokotro-result-details{width:100%;max-width:320px;background:var(--lokotro-card, #3A4840);border-radius:16px;padding:16px;margin-bottom:32px}.lokotro-detail-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0}.lokotro-detail-row:not(:last-child){border-bottom:1px solid var(--lokotro-border, #3A473F)}.lokotro-detail-label{font-size:14px;color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-detail-value{font-size:14px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-mono{font-family:Courier New,monospace;font-size:12px}.lokotro-result-actions{display:flex;flex-direction:column;gap:12px;width:100%;max-width:320px}.lokotro-btn-primary,.lokotro-btn-secondary{width:100%;padding:14px 24px;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s ease}.lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-primary, #5A5E39),var(--lokotro-secondary, #6E7346));color:var(--lokotro-text-primary, #F2F0D5);border:none}.lokotro-result-success .lokotro-btn-primary{background:linear-gradient(135deg,var(--lokotro-success, #3BFBDA),var(--lokotro-success-dark, #27D4B6));color:var(--lokotro-background-dark, #1C2621)}.lokotro-btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 16px #0003}.lokotro-btn-secondary{background:transparent;color:var(--lokotro-text-primary, #F2F0D5);border:2px solid var(--lokotro-border, #3A473F)}.lokotro-btn-secondary:hover{border-color:var(--lokotro-text-secondary, #D5D3B8)}.lokotro-countdown-indicator{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--lokotro-primary-light, rgba(90, 94, 57, .1));border:1px solid var(--lokotro-primary-border, rgba(90, 94, 57, .3));border-radius:20px;cursor:pointer;margin-bottom:16px;transition:all .2s ease}.lokotro-countdown-indicator:hover{background:var(--lokotro-primary-light, rgba(90, 94, 57, .2))}.lokotro-result-error .lokotro-countdown-indicator{background:var(--lokotro-error-light, rgba(217, 118, 82, .1));border-color:var(--lokotro-error-border, rgba(217, 118, 82, .3))}.lokotro-countdown-progress{width:16px;height:16px}.lokotro-countdown-circle{width:100%;height:100%;transform:rotate(-90deg)}.lokotro-countdown-bg{fill:none;stroke:var(--lokotro-border, #3A473F);stroke-width:3}.lokotro-countdown-fill{fill:none;stroke-width:3;stroke-linecap:round;transition:stroke-dasharray .3s ease}.lokotro-countdown-success{stroke:var(--lokotro-success, #3BFBDA)}.lokotro-countdown-error{stroke:var(--lokotro-error, #D97652)}.lokotro-countdown-warning{stroke:var(--lokotro-warning, #D97652)}.lokotro-countdown-info{stroke:var(--lokotro-info, #3B82F6)}.lokotro-countdown-text{font-size:12px;font-weight:500}.lokotro-text-success{color:var(--lokotro-success, #3BFBDA)}.lokotro-text-error{color:var(--lokotro-error, #D97652)}.lokotro-text-warning{color:var(--lokotro-warning, #D97652)}.lokotro-text-info{color:var(--lokotro-info, #3B82F6)}.lokotro-countdown-cancel{color:var(--lokotro-text-secondary, #D5D3B8)}\n"] }]
|
|
3006
3299
|
}], ctorParameters: () => [{ type: LokotroLocalizationService }], propDecorators: { type: [{
|
|
3007
3300
|
type: Input
|
|
3008
3301
|
}], title: [{
|
|
@@ -3019,40 +3312,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
3019
3312
|
type: Input
|
|
3020
3313
|
}], secondaryActionLabel: [{
|
|
3021
3314
|
type: Input
|
|
3315
|
+
}], autoRedirectSeconds: [{
|
|
3316
|
+
type: Input
|
|
3022
3317
|
}], primaryAction: [{
|
|
3023
3318
|
type: Output
|
|
3024
3319
|
}], secondaryAction: [{
|
|
3025
3320
|
type: Output
|
|
3321
|
+
}], autoRedirect: [{
|
|
3322
|
+
type: Output
|
|
3026
3323
|
}] } });
|
|
3027
3324
|
|
|
3028
3325
|
/**
|
|
3029
3326
|
* Lokotro Pay - Loading Component
|
|
3030
3327
|
*/
|
|
3031
3328
|
class LokotroLoadingComponent {
|
|
3032
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
3033
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
3329
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3330
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroLoadingComponent, isStandalone: true, selector: "lokotro-loading", inputs: { message: "message" }, ngImport: i0, template: `
|
|
3034
3331
|
<div class="lokotro-loading">
|
|
3035
3332
|
<div class="lokotro-loading-spinner">
|
|
3036
3333
|
<div class="lokotro-pulse-ring"></div>
|
|
3037
3334
|
<div class="lokotro-pulse-ring"></div>
|
|
3038
3335
|
<div class="lokotro-pulse-dot"></div>
|
|
3039
3336
|
</div>
|
|
3040
|
-
|
|
3337
|
+
@if (message) {
|
|
3338
|
+
<p class="lokotro-loading-message">{{ message }}</p>
|
|
3339
|
+
}
|
|
3041
3340
|
</div>
|
|
3042
|
-
|
|
3341
|
+
`, isInline: true, styles: [".lokotro-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px;padding:24px}.lokotro-loading-spinner{position:relative;width:60px;height:60px;margin-bottom:24px}.lokotro-pulse-ring{position:absolute;width:100%;height:100%;border:3px solid var(--lokotro-accent, #3BFBDA);border-radius:50%;opacity:0;animation:lokotro-pulse 2s cubic-bezier(.215,.61,.355,1) infinite}.lokotro-pulse-ring:nth-child(2){animation-delay:.5s}.lokotro-pulse-dot{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:16px;height:16px;background:var(--lokotro-accent, #3BFBDA);border-radius:50%;animation:lokotro-dot-pulse 2s ease-in-out infinite}@keyframes lokotro-pulse{0%{transform:scale(.5);opacity:.8}to{transform:scale(1.5);opacity:0}}@keyframes lokotro-dot-pulse{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.2)}}.lokotro-loading-message{font-size:16px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0}\n"] }); }
|
|
3043
3342
|
}
|
|
3044
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
3343
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroLoadingComponent, decorators: [{
|
|
3045
3344
|
type: Component,
|
|
3046
|
-
args: [{ selector: 'lokotro-loading', standalone: true, imports: [
|
|
3345
|
+
args: [{ selector: 'lokotro-loading', standalone: true, imports: [], template: `
|
|
3047
3346
|
<div class="lokotro-loading">
|
|
3048
3347
|
<div class="lokotro-loading-spinner">
|
|
3049
3348
|
<div class="lokotro-pulse-ring"></div>
|
|
3050
3349
|
<div class="lokotro-pulse-ring"></div>
|
|
3051
3350
|
<div class="lokotro-pulse-dot"></div>
|
|
3052
3351
|
</div>
|
|
3053
|
-
|
|
3352
|
+
@if (message) {
|
|
3353
|
+
<p class="lokotro-loading-message">{{ message }}</p>
|
|
3354
|
+
}
|
|
3054
3355
|
</div>
|
|
3055
|
-
|
|
3356
|
+
`, styles: [".lokotro-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px;padding:24px}.lokotro-loading-spinner{position:relative;width:60px;height:60px;margin-bottom:24px}.lokotro-pulse-ring{position:absolute;width:100%;height:100%;border:3px solid var(--lokotro-accent, #3BFBDA);border-radius:50%;opacity:0;animation:lokotro-pulse 2s cubic-bezier(.215,.61,.355,1) infinite}.lokotro-pulse-ring:nth-child(2){animation-delay:.5s}.lokotro-pulse-dot{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:16px;height:16px;background:var(--lokotro-accent, #3BFBDA);border-radius:50%;animation:lokotro-dot-pulse 2s ease-in-out infinite}@keyframes lokotro-pulse{0%{transform:scale(.5);opacity:.8}to{transform:scale(1.5);opacity:0}}@keyframes lokotro-dot-pulse{0%,to{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.2)}}.lokotro-loading-message{font-size:16px;color:var(--lokotro-text-secondary, #D5D3B8);margin:0}\n"] }]
|
|
3056
3357
|
}], propDecorators: { message: [{
|
|
3057
3358
|
type: Input
|
|
3058
3359
|
}] } });
|
|
@@ -3069,10 +3370,13 @@ const initialState = {
|
|
|
3069
3370
|
currentScreen: LokotroPayScreenNavigation.LoadingScreen
|
|
3070
3371
|
};
|
|
3071
3372
|
class LokotroPaymentService {
|
|
3373
|
+
static { this.MOBILE_MONEY_POLL_INTERVAL = 5000; }
|
|
3374
|
+
static { this.MOBILE_MONEY_MAX_ATTEMPTS = 60; }
|
|
3072
3375
|
constructor(httpClient) {
|
|
3073
3376
|
this.httpClient = httpClient;
|
|
3074
3377
|
this.stateSubject = new BehaviorSubject(initialState);
|
|
3075
3378
|
this.state$ = this.stateSubject.asObservable();
|
|
3379
|
+
this.mobileMoneyPollingAttempts = 0;
|
|
3076
3380
|
}
|
|
3077
3381
|
/**
|
|
3078
3382
|
* Get current state
|
|
@@ -3093,6 +3397,8 @@ class LokotroPaymentService {
|
|
|
3093
3397
|
* Reset state to initial
|
|
3094
3398
|
*/
|
|
3095
3399
|
resetState() {
|
|
3400
|
+
this.stopMobileMoneyPolling();
|
|
3401
|
+
this.currentPaymentBody = undefined;
|
|
3096
3402
|
this.stateSubject.next(initialState);
|
|
3097
3403
|
}
|
|
3098
3404
|
/**
|
|
@@ -3112,32 +3418,26 @@ class LokotroPaymentService {
|
|
|
3112
3418
|
* POST /payments/collect
|
|
3113
3419
|
*/
|
|
3114
3420
|
createPayment(paymentBody) {
|
|
3421
|
+
this.currentPaymentBody = paymentBody;
|
|
3115
3422
|
this.updateState({ isLoading: true });
|
|
3116
3423
|
const requestData = this.convertPaymentBodyToRequest(paymentBody);
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
isLoading: false,
|
|
3122
|
-
transactionId: response.data.transaction_id,
|
|
3123
|
-
paymentInfo,
|
|
3124
|
-
currentScreen: paymentInfo.showPaymentMethodForm
|
|
3125
|
-
? LokotroPayScreenNavigation.PaymentMethodSelectionScreen
|
|
3126
|
-
: LokotroPayScreenNavigation.PaymentFormScreen
|
|
3127
|
-
});
|
|
3128
|
-
}
|
|
3129
|
-
else {
|
|
3424
|
+
console.log('[Lokotro Payment] Creating payment with body:', requestData);
|
|
3425
|
+
return this.httpClient.post(LokotroPayEnv.endpoints.collect, requestData).pipe(switchMap(response => {
|
|
3426
|
+
console.log('[Lokotro Payment] Create payment response:', response);
|
|
3427
|
+
if (!response.isSuccess || !response.data) {
|
|
3130
3428
|
this.updateState({
|
|
3131
3429
|
isLoading: false,
|
|
3132
3430
|
error: {
|
|
3133
|
-
message: response.message,
|
|
3431
|
+
message: response.message || 'Failed to create payment',
|
|
3134
3432
|
title: 'Payment Creation Failed',
|
|
3135
3433
|
errorCode: response.apiResponseCode,
|
|
3136
3434
|
timestamp: new Date()
|
|
3137
3435
|
},
|
|
3138
3436
|
currentScreen: LokotroPayScreenNavigation.ErrorScreen
|
|
3139
3437
|
});
|
|
3438
|
+
return of(response);
|
|
3140
3439
|
}
|
|
3440
|
+
return this.resolveCollectResponse(this.unwrapPayload(response.data), paymentBody).pipe(map(() => response));
|
|
3141
3441
|
}), catchError(error => {
|
|
3142
3442
|
this.updateState({
|
|
3143
3443
|
isLoading: false,
|
|
@@ -3156,7 +3456,7 @@ class LokotroPaymentService {
|
|
|
3156
3456
|
* GET /payments/transaction/{transaction_id}
|
|
3157
3457
|
*/
|
|
3158
3458
|
getTransactionDetails(transactionId) {
|
|
3159
|
-
return this.httpClient.get(`${LokotroPayEnv.endpoints.transaction}/${transactionId}`)
|
|
3459
|
+
return this.httpClient.get(`${LokotroPayEnv.endpoints.transaction}/${transactionId}`);
|
|
3160
3460
|
}
|
|
3161
3461
|
/**
|
|
3162
3462
|
* Step 3: Submit payment details
|
|
@@ -3170,29 +3470,43 @@ class LokotroPaymentService {
|
|
|
3170
3470
|
const requestData = this.convertSubmitRequestToData(request);
|
|
3171
3471
|
return this.httpClient.post(LokotroPayEnv.endpoints.submit, requestData).pipe(tap(response => {
|
|
3172
3472
|
if (response.isSuccess && response.data) {
|
|
3173
|
-
const
|
|
3473
|
+
const responseData = this.unwrapPayload(response.data);
|
|
3474
|
+
const submitResponse = this.parseSubmitResponse(responseData);
|
|
3174
3475
|
if (submitResponse.requiresOtp) {
|
|
3175
3476
|
this.updateState({
|
|
3176
3477
|
isLoading: false,
|
|
3478
|
+
transactionId: submitResponse.transactionId || this.resolvePaymentId(request),
|
|
3177
3479
|
currentScreen: LokotroPayScreenNavigation.EWalletOtpScreen
|
|
3178
3480
|
});
|
|
3481
|
+
return;
|
|
3179
3482
|
}
|
|
3180
|
-
|
|
3181
|
-
|
|
3483
|
+
if (submitResponse.redirectUrl) {
|
|
3484
|
+
this.updateState({
|
|
3485
|
+
isLoading: false,
|
|
3486
|
+
transactionId: submitResponse.transactionId || this.resolvePaymentId(request)
|
|
3487
|
+
});
|
|
3182
3488
|
window.location.href = submitResponse.redirectUrl;
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
if (submitResponse.status === LokotroPaymentStatus.PendingBankProofUpload) {
|
|
3492
|
+
this.handlePaymentSuccess(responseData, LokotroPaymentStatus.PendingBankProofUpload, 'Upload Proof Required');
|
|
3493
|
+
return;
|
|
3183
3494
|
}
|
|
3184
|
-
|
|
3185
|
-
this.handlePaymentSuccess(
|
|
3495
|
+
if (LokotroPaymentStatusInfo.isSuccess(submitResponse.status)) {
|
|
3496
|
+
this.handlePaymentSuccess(responseData);
|
|
3497
|
+
return;
|
|
3186
3498
|
}
|
|
3187
|
-
|
|
3499
|
+
if (LokotroPaymentStatusInfo.isPending(submitResponse.status)) {
|
|
3500
|
+
const txId = submitResponse.transactionId || this.resolvePaymentId(request);
|
|
3188
3501
|
this.updateState({
|
|
3189
3502
|
isLoading: false,
|
|
3503
|
+
transactionId: txId,
|
|
3190
3504
|
currentScreen: LokotroPayScreenNavigation.MobileMoneyProcessingScreen
|
|
3191
3505
|
});
|
|
3506
|
+
this.startMobileMoneyPolling(txId);
|
|
3507
|
+
return;
|
|
3192
3508
|
}
|
|
3193
|
-
|
|
3194
|
-
this.handlePaymentFailure(response.message, response.apiResponseCode);
|
|
3195
|
-
}
|
|
3509
|
+
this.handlePaymentFailure(this.getString(responseData['message']) || response.message, response.apiResponseCode);
|
|
3196
3510
|
}
|
|
3197
3511
|
else {
|
|
3198
3512
|
this.handlePaymentFailure(response.message, response.apiResponseCode);
|
|
@@ -3209,16 +3523,17 @@ class LokotroPaymentService {
|
|
|
3209
3523
|
verifyOtp(request) {
|
|
3210
3524
|
this.updateState({ isLoading: true });
|
|
3211
3525
|
return this.httpClient.post(LokotroPayEnv.endpoints.verifyOtp, {
|
|
3212
|
-
|
|
3213
|
-
|
|
3526
|
+
payment_id: request.paymentId || request.transactionId || this.currentState.transactionId,
|
|
3527
|
+
otp_code: request.otpCode || request.otp
|
|
3214
3528
|
}).pipe(tap(response => {
|
|
3215
3529
|
if (response.isSuccess && response.data) {
|
|
3216
|
-
const
|
|
3530
|
+
const responseData = this.unwrapPayload(response.data);
|
|
3531
|
+
const status = LokotroPaymentStatusInfo.fromString(this.getString(responseData['status']));
|
|
3217
3532
|
if (LokotroPaymentStatusInfo.isSuccess(status)) {
|
|
3218
|
-
this.handlePaymentSuccess(
|
|
3533
|
+
this.handlePaymentSuccess(responseData);
|
|
3219
3534
|
}
|
|
3220
3535
|
else {
|
|
3221
|
-
this.handlePaymentFailure(response.message, response.apiResponseCode);
|
|
3536
|
+
this.handlePaymentFailure(this.getString(responseData['message']) || response.message, response.apiResponseCode);
|
|
3222
3537
|
}
|
|
3223
3538
|
}
|
|
3224
3539
|
else {
|
|
@@ -3229,7 +3544,8 @@ class LokotroPaymentService {
|
|
|
3229
3544
|
title: 'Verification Failed',
|
|
3230
3545
|
errorCode: response.apiResponseCode,
|
|
3231
3546
|
timestamp: new Date()
|
|
3232
|
-
}
|
|
3547
|
+
},
|
|
3548
|
+
currentScreen: LokotroPayScreenNavigation.ErrorScreen
|
|
3233
3549
|
});
|
|
3234
3550
|
}
|
|
3235
3551
|
}), catchError(error => {
|
|
@@ -3239,7 +3555,8 @@ class LokotroPaymentService {
|
|
|
3239
3555
|
message: error.message || 'OTP verification failed',
|
|
3240
3556
|
title: 'Error',
|
|
3241
3557
|
timestamp: new Date()
|
|
3242
|
-
}
|
|
3558
|
+
},
|
|
3559
|
+
currentScreen: LokotroPayScreenNavigation.ErrorScreen
|
|
3243
3560
|
});
|
|
3244
3561
|
return throwError(() => error);
|
|
3245
3562
|
}));
|
|
@@ -3249,7 +3566,9 @@ class LokotroPaymentService {
|
|
|
3249
3566
|
* POST /payments/resend-otp
|
|
3250
3567
|
*/
|
|
3251
3568
|
resendOtp(request) {
|
|
3252
|
-
return this.httpClient.post(LokotroPayEnv.endpoints.resendOtp, {
|
|
3569
|
+
return this.httpClient.post(LokotroPayEnv.endpoints.resendOtp, {
|
|
3570
|
+
payment_id: request.paymentId || request.transactionId || this.currentState.transactionId
|
|
3571
|
+
});
|
|
3253
3572
|
}
|
|
3254
3573
|
/**
|
|
3255
3574
|
* Select payment method
|
|
@@ -3266,20 +3585,71 @@ class LokotroPaymentService {
|
|
|
3266
3585
|
navigateToScreen(screen) {
|
|
3267
3586
|
this.updateState({ currentScreen: screen });
|
|
3268
3587
|
}
|
|
3588
|
+
/**
|
|
3589
|
+
* Start polling for mobile money payment status
|
|
3590
|
+
*/
|
|
3591
|
+
startMobileMoneyPolling(transactionId) {
|
|
3592
|
+
this.stopMobileMoneyPolling();
|
|
3593
|
+
this.mobileMoneyPollingAttempts = 0;
|
|
3594
|
+
console.log('[Lokotro Payment] Starting mobile money status polling for:', transactionId);
|
|
3595
|
+
this.mobileMoneyPollingTimer = setInterval(() => {
|
|
3596
|
+
this.mobileMoneyPollingAttempts++;
|
|
3597
|
+
if (this.mobileMoneyPollingAttempts > LokotroPaymentService.MOBILE_MONEY_MAX_ATTEMPTS) {
|
|
3598
|
+
console.warn('[Lokotro Payment] Mobile money polling max attempts reached');
|
|
3599
|
+
this.stopMobileMoneyPolling();
|
|
3600
|
+
this.handlePaymentFailure('Payment took too long. Please try again or contact support.');
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
const endpoint = `${LokotroPayEnv.endpoints.mobileMoneyStatus}/${transactionId}`;
|
|
3604
|
+
this.httpClient.get(endpoint).subscribe({
|
|
3605
|
+
next: (response) => {
|
|
3606
|
+
if (!response.isSuccess || !response.data)
|
|
3607
|
+
return;
|
|
3608
|
+
const data = this.unwrapPayload(response.data);
|
|
3609
|
+
const status = this.getString(data['status']).toLowerCase();
|
|
3610
|
+
console.log(`[Lokotro Payment] Mobile money poll #${this.mobileMoneyPollingAttempts}: status=${status}`);
|
|
3611
|
+
if (status === 'completed' || status === 'success' || status === 'approved') {
|
|
3612
|
+
this.stopMobileMoneyPolling();
|
|
3613
|
+
this.handlePaymentSuccess(data);
|
|
3614
|
+
}
|
|
3615
|
+
else if (status === 'failed' || status === 'error' || status === 'cancelled' || status === 'declined') {
|
|
3616
|
+
this.stopMobileMoneyPolling();
|
|
3617
|
+
this.handlePaymentFailure(this.getString(data['message']) || 'Payment failed or was declined');
|
|
3618
|
+
}
|
|
3619
|
+
},
|
|
3620
|
+
error: (err) => {
|
|
3621
|
+
console.error('[Lokotro Payment] Mobile money polling error:', err);
|
|
3622
|
+
}
|
|
3623
|
+
});
|
|
3624
|
+
}, LokotroPaymentService.MOBILE_MONEY_POLL_INTERVAL);
|
|
3625
|
+
}
|
|
3626
|
+
/**
|
|
3627
|
+
* Stop mobile money status polling
|
|
3628
|
+
*/
|
|
3629
|
+
stopMobileMoneyPolling() {
|
|
3630
|
+
if (this.mobileMoneyPollingTimer) {
|
|
3631
|
+
clearInterval(this.mobileMoneyPollingTimer);
|
|
3632
|
+
this.mobileMoneyPollingTimer = undefined;
|
|
3633
|
+
this.mobileMoneyPollingAttempts = 0;
|
|
3634
|
+
console.log('[Lokotro Payment] Mobile money polling stopped');
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3269
3637
|
/**
|
|
3270
3638
|
* Handle payment success
|
|
3271
3639
|
*/
|
|
3272
|
-
handlePaymentSuccess(data) {
|
|
3640
|
+
handlePaymentSuccess(data, paymentStatus = LokotroPaymentStatus.Approved, defaultTitle = 'Success') {
|
|
3641
|
+
this.stopMobileMoneyPolling();
|
|
3642
|
+
const transactionId = this.getString(data['transaction_id']) || this.getString(data['payment_id']);
|
|
3273
3643
|
const response = {
|
|
3274
|
-
message: data['message'] || 'Payment successful',
|
|
3275
|
-
title: data['title'] ||
|
|
3276
|
-
customRef: data['custom_ref'] || data['customer_reference']
|
|
3277
|
-
amount:
|
|
3644
|
+
message: this.getString(data['message']) || 'Payment successful',
|
|
3645
|
+
title: this.getString(data['title']) || defaultTitle,
|
|
3646
|
+
customRef: this.getString(data['custom_ref']) || this.getString(data['customer_reference']),
|
|
3647
|
+
amount: this.getNumber(data['amount']),
|
|
3278
3648
|
apiResponseCode: LokotroPayApiResponseCode.LOK000,
|
|
3279
|
-
currency: data['currency'] || '',
|
|
3280
|
-
paymentStatus
|
|
3281
|
-
systemRef: data['
|
|
3282
|
-
transactionId
|
|
3649
|
+
currency: this.getString(data['currency']) || this.getString(data['currency_str']),
|
|
3650
|
+
paymentStatus,
|
|
3651
|
+
systemRef: this.getString(data['system_reference']) || this.getString(data['system_ref']) || transactionId,
|
|
3652
|
+
transactionId,
|
|
3283
3653
|
timestamp: new Date()
|
|
3284
3654
|
};
|
|
3285
3655
|
this.updateState({
|
|
@@ -3292,6 +3662,7 @@ class LokotroPaymentService {
|
|
|
3292
3662
|
* Handle payment failure
|
|
3293
3663
|
*/
|
|
3294
3664
|
handlePaymentFailure(message, errorCode) {
|
|
3665
|
+
this.stopMobileMoneyPolling();
|
|
3295
3666
|
this.updateState({
|
|
3296
3667
|
isLoading: false,
|
|
3297
3668
|
error: {
|
|
@@ -3303,6 +3674,115 @@ class LokotroPaymentService {
|
|
|
3303
3674
|
currentScreen: LokotroPayScreenNavigation.ErrorScreen
|
|
3304
3675
|
});
|
|
3305
3676
|
}
|
|
3677
|
+
/**
|
|
3678
|
+
* Resolve the collect response into the same flow the Flutter SDK uses.
|
|
3679
|
+
*/
|
|
3680
|
+
resolveCollectResponse(collectData, paymentBody) {
|
|
3681
|
+
const paymentId = this.resolvePaymentId(collectData);
|
|
3682
|
+
const paymentStatus = this.getString(collectData['status']).toLowerCase();
|
|
3683
|
+
const paymentInfo = this.parsePaymentInfo(collectData);
|
|
3684
|
+
const additionalData = this.asRecord(collectData['additional_data']);
|
|
3685
|
+
if (paymentStatus === 'pending_otp' || paymentStatus === 'pending_otp_verification') {
|
|
3686
|
+
this.updateState({
|
|
3687
|
+
isLoading: false,
|
|
3688
|
+
transactionId: paymentId,
|
|
3689
|
+
paymentInfo,
|
|
3690
|
+
currentScreen: LokotroPayScreenNavigation.EWalletOtpScreen
|
|
3691
|
+
});
|
|
3692
|
+
return of(void 0);
|
|
3693
|
+
}
|
|
3694
|
+
if (paymentStatus === 'pending_bank_proof_upload') {
|
|
3695
|
+
this.handlePaymentSuccess(collectData, LokotroPaymentStatus.PendingBankProofUpload, 'Upload Proof Required');
|
|
3696
|
+
return of(void 0);
|
|
3697
|
+
}
|
|
3698
|
+
if (paymentStatus === 'completed' || paymentStatus === 'approved' || paymentStatus === 'success') {
|
|
3699
|
+
this.handlePaymentSuccess(collectData);
|
|
3700
|
+
return of(void 0);
|
|
3701
|
+
}
|
|
3702
|
+
if (paymentStatus === 'session_created') {
|
|
3703
|
+
const redirectUrl = this.getString(collectData['mastercardUrl']) ||
|
|
3704
|
+
this.getString(collectData['redirect_url']) ||
|
|
3705
|
+
this.getString(collectData['payment_url']);
|
|
3706
|
+
if (!redirectUrl) {
|
|
3707
|
+
this.handlePaymentFailure('Hosted session created but no checkout URL was provided');
|
|
3708
|
+
return of(void 0);
|
|
3709
|
+
}
|
|
3710
|
+
this.updateState({
|
|
3711
|
+
isLoading: false,
|
|
3712
|
+
transactionId: paymentId
|
|
3713
|
+
});
|
|
3714
|
+
window.location.href = redirectUrl;
|
|
3715
|
+
return of(void 0);
|
|
3716
|
+
}
|
|
3717
|
+
if (this.getString(additionalData?.['action']) === 'select_payment_method') {
|
|
3718
|
+
this.updateState({
|
|
3719
|
+
isLoading: false,
|
|
3720
|
+
transactionId: paymentId,
|
|
3721
|
+
paymentInfo,
|
|
3722
|
+
currentScreen: LokotroPayScreenNavigation.PaymentMethodSelectionScreen
|
|
3723
|
+
});
|
|
3724
|
+
return of(void 0);
|
|
3725
|
+
}
|
|
3726
|
+
if (paymentStatus === 'failed' || paymentStatus === 'rejected' || paymentStatus === 'declined') {
|
|
3727
|
+
this.handlePaymentFailure(this.getString(collectData['message']) || 'Payment failed');
|
|
3728
|
+
return of(void 0);
|
|
3729
|
+
}
|
|
3730
|
+
if (!paymentId) {
|
|
3731
|
+
this.handlePaymentFailure('Transaction ID not received from payment collection');
|
|
3732
|
+
return of(void 0);
|
|
3733
|
+
}
|
|
3734
|
+
return this.getTransactionDetails(paymentId).pipe(switchMap(response => this.resolveTransactionResponse(response, paymentBody)));
|
|
3735
|
+
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Resolve transaction details into the correct screen or auto-submit flow.
|
|
3738
|
+
*/
|
|
3739
|
+
resolveTransactionResponse(response, paymentBody) {
|
|
3740
|
+
if (!response.isSuccess || !response.data) {
|
|
3741
|
+
this.handlePaymentFailure(response.message || 'Failed to load transaction details', response.apiResponseCode);
|
|
3742
|
+
return of(void 0);
|
|
3743
|
+
}
|
|
3744
|
+
const transactionData = this.unwrapPayload(response.data);
|
|
3745
|
+
const paymentId = this.resolvePaymentId(transactionData);
|
|
3746
|
+
if (!paymentId) {
|
|
3747
|
+
this.handlePaymentFailure('Transaction ID not found in transaction details');
|
|
3748
|
+
return of(void 0);
|
|
3749
|
+
}
|
|
3750
|
+
const paymentInfo = this.parseTransactionPaymentInfo(transactionData);
|
|
3751
|
+
const selectedPaymentMethod = this.resolveSelectedPaymentMethod(transactionData, paymentInfo);
|
|
3752
|
+
if (!paymentInfo.showUserInfoForm && !paymentInfo.showPaymentMethodForm) {
|
|
3753
|
+
this.updateState({
|
|
3754
|
+
transactionId: paymentId,
|
|
3755
|
+
paymentInfo,
|
|
3756
|
+
selectedPaymentMethod
|
|
3757
|
+
});
|
|
3758
|
+
if (selectedPaymentMethod?.channel === LokotroPayChannel.Card) {
|
|
3759
|
+
const hostedCheckoutUrl = this.getString(transactionData['mastercardUrl']) ||
|
|
3760
|
+
this.getString(transactionData['redirect_url']);
|
|
3761
|
+
if (hostedCheckoutUrl) {
|
|
3762
|
+
this.updateState({ isLoading: false });
|
|
3763
|
+
window.location.href = hostedCheckoutUrl;
|
|
3764
|
+
return of(void 0);
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
const paymentMethodId = selectedPaymentMethod?.id || this.getString(transactionData['payment_method_id']);
|
|
3768
|
+
if (!paymentMethodId) {
|
|
3769
|
+
this.handlePaymentFailure('Payment method not found for auto-processing');
|
|
3770
|
+
return of(void 0);
|
|
3771
|
+
}
|
|
3772
|
+
return this.submitPaymentDetails(this.buildAutoSubmitRequest(paymentId, paymentMethodId, paymentBody)).pipe(map(() => void 0));
|
|
3773
|
+
}
|
|
3774
|
+
const nextScreen = paymentInfo.showPaymentMethodForm
|
|
3775
|
+
? LokotroPayScreenNavigation.PaymentMethodSelectionScreen
|
|
3776
|
+
: this.getFormScreenForChannel(selectedPaymentMethod?.channel || this.parseChannel(this.getString(transactionData['channel'])));
|
|
3777
|
+
this.updateState({
|
|
3778
|
+
isLoading: false,
|
|
3779
|
+
transactionId: paymentId,
|
|
3780
|
+
paymentInfo,
|
|
3781
|
+
selectedPaymentMethod,
|
|
3782
|
+
currentScreen: nextScreen
|
|
3783
|
+
});
|
|
3784
|
+
return of(void 0);
|
|
3785
|
+
}
|
|
3306
3786
|
/**
|
|
3307
3787
|
* Get form screen for payment channel
|
|
3308
3788
|
*/
|
|
@@ -3336,14 +3816,12 @@ class LokotroPaymentService {
|
|
|
3336
3816
|
fee_covered_by: body.feeCoveredBy || 'buyer',
|
|
3337
3817
|
delivery_behaviour: body.deliveryBehaviour || 'direct_delivery'
|
|
3338
3818
|
};
|
|
3339
|
-
// Add optional URLs
|
|
3340
3819
|
if (body.notifyUrl)
|
|
3341
3820
|
request['notify_url'] = body.notifyUrl;
|
|
3342
3821
|
if (body.successRedirectUrl)
|
|
3343
3822
|
request['success_redirect_url'] = body.successRedirectUrl;
|
|
3344
3823
|
if (body.failRedirectUrl)
|
|
3345
3824
|
request['fail_redirect_url'] = body.failRedirectUrl;
|
|
3346
|
-
// Add user information
|
|
3347
3825
|
if (body.userInfo === 'full') {
|
|
3348
3826
|
if (body.firstName)
|
|
3349
3827
|
request['first_name'] = body.firstName;
|
|
@@ -3354,7 +3832,6 @@ class LokotroPaymentService {
|
|
|
3354
3832
|
if (body.email)
|
|
3355
3833
|
request['email'] = body.email;
|
|
3356
3834
|
}
|
|
3357
|
-
// Add payment method specific fields
|
|
3358
3835
|
if (body.paymentMethodInfo === 'full') {
|
|
3359
3836
|
if (body.walletNumber)
|
|
3360
3837
|
request['wallet_number'] = body.walletNumber;
|
|
@@ -3375,21 +3852,16 @@ class LokotroPaymentService {
|
|
|
3375
3852
|
if (body.cardHolderName)
|
|
3376
3853
|
request['card_holder_name'] = body.cardHolderName;
|
|
3377
3854
|
}
|
|
3378
|
-
// Add merchant information
|
|
3379
3855
|
if (body.merchant) {
|
|
3380
3856
|
request['merchant'] = {
|
|
3381
|
-
id: body.merchant.id,
|
|
3382
3857
|
name: body.merchant.name,
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
description: body.merchant.description
|
|
3858
|
+
url: body.merchant.website,
|
|
3859
|
+
logo: body.merchant.logoUrl
|
|
3386
3860
|
};
|
|
3387
3861
|
}
|
|
3388
|
-
// Add mastercard payment method
|
|
3389
3862
|
if (body.mastercardPaymentMethod) {
|
|
3390
3863
|
request['mastercard_payment_method'] = body.mastercardPaymentMethod;
|
|
3391
3864
|
}
|
|
3392
|
-
// Add metadata
|
|
3393
3865
|
if (body.metadata) {
|
|
3394
3866
|
request['metadata'] = body.metadata;
|
|
3395
3867
|
}
|
|
@@ -3400,13 +3872,21 @@ class LokotroPaymentService {
|
|
|
3400
3872
|
*/
|
|
3401
3873
|
convertSubmitRequestToData(request) {
|
|
3402
3874
|
const data = {
|
|
3403
|
-
|
|
3404
|
-
|
|
3875
|
+
payment_id: this.resolvePaymentId(request),
|
|
3876
|
+
payment_method_id: request.paymentMethodId || request.paymentMethod || ''
|
|
3405
3877
|
};
|
|
3878
|
+
if (request.firstName)
|
|
3879
|
+
data['first_name'] = request.firstName;
|
|
3880
|
+
if (request.lastName)
|
|
3881
|
+
data['last_name'] = request.lastName;
|
|
3882
|
+
if (request.email)
|
|
3883
|
+
data['email'] = request.email;
|
|
3884
|
+
if (request.phoneNumber)
|
|
3885
|
+
data['phone_number'] = request.phoneNumber;
|
|
3406
3886
|
if (request.walletNumber)
|
|
3407
|
-
data['
|
|
3887
|
+
data['ewallet_number'] = request.walletNumber;
|
|
3408
3888
|
if (request.walletPin)
|
|
3409
|
-
data['
|
|
3889
|
+
data['ewallet_pin'] = request.walletPin;
|
|
3410
3890
|
if (request.mobileMoneyPhoneNumber)
|
|
3411
3891
|
data['mobile_money_phone_number'] = request.mobileMoneyPhoneNumber;
|
|
3412
3892
|
if (request.flashNumber)
|
|
@@ -3421,61 +3901,238 @@ class LokotroPaymentService {
|
|
|
3421
3901
|
data['card_cvv'] = request.cardCvv;
|
|
3422
3902
|
if (request.cardHolderName)
|
|
3423
3903
|
data['card_holder_name'] = request.cardHolderName;
|
|
3904
|
+
if (request.bankTransferAccountId)
|
|
3905
|
+
data['bank_account_id'] = request.bankTransferAccountId;
|
|
3906
|
+
if (request.bankAccountId)
|
|
3907
|
+
data['bank_account_id'] = request.bankAccountId;
|
|
3908
|
+
if (request.bankAccountNumber)
|
|
3909
|
+
data['bank_account_number'] = request.bankAccountNumber;
|
|
3910
|
+
if (request.bankAccountLabel)
|
|
3911
|
+
data['bank_account_label'] = request.bankAccountLabel;
|
|
3912
|
+
if (request.bankId)
|
|
3913
|
+
data['bank_id'] = request.bankId;
|
|
3914
|
+
if (request.bankEntityId)
|
|
3915
|
+
data['bank_entity_id'] = request.bankEntityId;
|
|
3916
|
+
if (request.mastercardPaymentMethod)
|
|
3917
|
+
data['mastercard_payment_method'] = request.mastercardPaymentMethod;
|
|
3918
|
+
if (request.sessionId)
|
|
3919
|
+
data['session_id'] = request.sessionId;
|
|
3920
|
+
if (request.cardData)
|
|
3921
|
+
data['card_data'] = request.cardData;
|
|
3922
|
+
if (typeof request.savePaymentMethod === 'boolean')
|
|
3923
|
+
data['save_payment_method'] = request.savePaymentMethod;
|
|
3424
3924
|
return data;
|
|
3425
3925
|
}
|
|
3426
3926
|
/**
|
|
3427
|
-
* Parse payment info from
|
|
3927
|
+
* Parse payment info from collect response.
|
|
3428
3928
|
*/
|
|
3429
3929
|
parsePaymentInfo(data) {
|
|
3930
|
+
const additionalData = this.asRecord(data['additional_data']);
|
|
3931
|
+
const availablePaymentMethods = this.getRecordArray(data['available_payment_methods'] || additionalData?.['payment_methods'])
|
|
3932
|
+
.map(method => this.parsePaymentMethod(method));
|
|
3933
|
+
const action = this.getString(additionalData?.['action']);
|
|
3934
|
+
return {
|
|
3935
|
+
id: this.resolvePaymentId(data),
|
|
3936
|
+
amount: this.getNumber(data['amount']),
|
|
3937
|
+
currency: this.getString(data['currency']) || 'USD',
|
|
3938
|
+
description: this.getString(data['description']),
|
|
3939
|
+
merchantName: this.getString(data['merchant_name']),
|
|
3940
|
+
merchantId: this.getString(data['merchant_id']),
|
|
3941
|
+
availablePaymentMethods,
|
|
3942
|
+
createdAt: new Date(this.getString(data['created_at']) || Date.now()),
|
|
3943
|
+
expiresAt: this.getString(data['expires_at']) ? new Date(this.getString(data['expires_at'])) : undefined,
|
|
3944
|
+
metadata: this.asRecord(data['metadata']),
|
|
3945
|
+
paymentUrl: this.getString(data['payment_url']) || undefined,
|
|
3946
|
+
showUserInfoForm: this.getBoolean(data['show_user_info_form']) || action === 'select_payment_method',
|
|
3947
|
+
showPaymentMethodForm: this.getBoolean(data['show_payment_method_form']) || action === 'select_payment_method'
|
|
3948
|
+
};
|
|
3949
|
+
}
|
|
3950
|
+
/**
|
|
3951
|
+
* Parse payment info from transaction details response.
|
|
3952
|
+
*/
|
|
3953
|
+
parseTransactionPaymentInfo(data) {
|
|
3954
|
+
const fillingInfo = this.getString(data['filling_info']) || 'none';
|
|
3955
|
+
const channelInfo = this.getString(data['channel_info']) || 'none';
|
|
3430
3956
|
return {
|
|
3431
|
-
id: data
|
|
3432
|
-
amount:
|
|
3433
|
-
currency: data.
|
|
3434
|
-
description: data
|
|
3435
|
-
merchantName: data
|
|
3436
|
-
merchantId: data
|
|
3437
|
-
availablePaymentMethods: (data
|
|
3438
|
-
createdAt: new Date(data
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3957
|
+
id: this.resolvePaymentId(data),
|
|
3958
|
+
amount: this.getNumber(data['transactional_amount'] ?? data['amount']),
|
|
3959
|
+
currency: this.getString(data['transactional_currency']) || this.getString(data['currency_str']) || 'USD',
|
|
3960
|
+
description: this.getString(data['description']),
|
|
3961
|
+
merchantName: this.getString(data['merchant_name']),
|
|
3962
|
+
merchantId: this.getString(data['merchant_id']),
|
|
3963
|
+
availablePaymentMethods: this.getRecordArray(data['payment_methods']).map(method => this.parsePaymentMethod(method)),
|
|
3964
|
+
createdAt: new Date(this.getString(data['created_at']) || Date.now()),
|
|
3965
|
+
metadata: this.asRecord(data['metadata']),
|
|
3966
|
+
paymentUrl: this.getString(data['payment_url']) || undefined,
|
|
3967
|
+
showUserInfoForm: fillingInfo === 'none',
|
|
3968
|
+
showPaymentMethodForm: channelInfo === 'none',
|
|
3969
|
+
fillingInfo,
|
|
3970
|
+
channelInfo
|
|
3444
3971
|
};
|
|
3445
3972
|
}
|
|
3446
3973
|
/**
|
|
3447
|
-
* Parse payment method from API response
|
|
3974
|
+
* Parse payment method from API response.
|
|
3448
3975
|
*/
|
|
3449
3976
|
parsePaymentMethod(data) {
|
|
3977
|
+
const nestedChannel = this.asRecord(data['channel']);
|
|
3978
|
+
const rawChannel = this.getString(nestedChannel?.['name']) ||
|
|
3979
|
+
this.getString(data['group']) ||
|
|
3980
|
+
this.getString(data['method']) ||
|
|
3981
|
+
this.getString(data['channel']) ||
|
|
3982
|
+
this.getString(data['name']);
|
|
3983
|
+
const name = this.getString(data['name']) || this.getString(data['method']) || rawChannel;
|
|
3450
3984
|
return {
|
|
3451
|
-
id: data['id'] || '',
|
|
3452
|
-
name
|
|
3453
|
-
displayName: data['display_name'] ||
|
|
3454
|
-
channel:
|
|
3455
|
-
iconUrl: data['icon_url'] || data['icon']
|
|
3456
|
-
isEnabled: data['is_enabled']
|
|
3457
|
-
configuration: data['configuration'],
|
|
3458
|
-
supportedCurrencies: data['supported_currencies']
|
|
3985
|
+
id: this.getString(data['id']) || this.getString(data['payment_method_id']) || name,
|
|
3986
|
+
name,
|
|
3987
|
+
displayName: this.getString(data['display_name']) || name,
|
|
3988
|
+
channel: this.parseChannel(rawChannel),
|
|
3989
|
+
iconUrl: this.getString(data['icon_url']) || this.getString(data['icon']),
|
|
3990
|
+
isEnabled: this.getBoolean(data['is_enabled'], this.getBoolean(data['available'], true)),
|
|
3991
|
+
configuration: this.asRecord(data['configuration']),
|
|
3992
|
+
supportedCurrencies: Array.isArray(data['supported_currencies'])
|
|
3993
|
+
? data['supported_currencies']
|
|
3994
|
+
: undefined
|
|
3459
3995
|
};
|
|
3460
3996
|
}
|
|
3461
3997
|
/**
|
|
3462
|
-
* Parse submit response from API
|
|
3998
|
+
* Parse submit response from API.
|
|
3463
3999
|
*/
|
|
3464
4000
|
parseSubmitResponse(data) {
|
|
4001
|
+
const rawStatus = this.getString(data['status']);
|
|
3465
4002
|
return {
|
|
3466
|
-
success: data
|
|
3467
|
-
message: data
|
|
3468
|
-
transactionId: data
|
|
3469
|
-
status: LokotroPaymentStatusInfo.fromString(
|
|
3470
|
-
requiresOtp: data
|
|
3471
|
-
otpDestination: data.
|
|
3472
|
-
redirectUrl: data.
|
|
4003
|
+
success: this.getBoolean(data['success']),
|
|
4004
|
+
message: this.getString(data['message']),
|
|
4005
|
+
transactionId: this.resolvePaymentId(data),
|
|
4006
|
+
status: LokotroPaymentStatusInfo.fromString(rawStatus),
|
|
4007
|
+
requiresOtp: this.getBoolean(data['requires_otp']) || rawStatus === 'pending_otp' || rawStatus === 'pending_otp_verification',
|
|
4008
|
+
otpDestination: this.getString(data['otp_destination']) || this.getString(data['otp_sent_to']) || undefined,
|
|
4009
|
+
redirectUrl: this.getString(data['redirect_url']) || this.getString(data['mastercardUrl']) || undefined
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
/**
|
|
4013
|
+
* Build an auto-submit request using the original payment body.
|
|
4014
|
+
*/
|
|
4015
|
+
buildAutoSubmitRequest(paymentId, paymentMethodId, paymentBody) {
|
|
4016
|
+
return {
|
|
4017
|
+
paymentId,
|
|
4018
|
+
paymentMethodId,
|
|
4019
|
+
paymentMethod: paymentBody.paymentMethod,
|
|
4020
|
+
firstName: paymentBody.firstName,
|
|
4021
|
+
lastName: paymentBody.lastName,
|
|
4022
|
+
email: paymentBody.email,
|
|
4023
|
+
phoneNumber: paymentBody.phoneNumber,
|
|
4024
|
+
walletNumber: paymentBody.walletNumber,
|
|
4025
|
+
walletPin: paymentBody.walletPin,
|
|
4026
|
+
mobileMoneyPhoneNumber: paymentBody.mobileMoneyPhoneNumber,
|
|
4027
|
+
flashNumber: paymentBody.flashNumber,
|
|
4028
|
+
flashPin: paymentBody.flashPin,
|
|
4029
|
+
cardNumber: paymentBody.cardNumber,
|
|
4030
|
+
cardExpiryDate: paymentBody.cardExpiryDate,
|
|
4031
|
+
cardCvv: paymentBody.cardCvv,
|
|
4032
|
+
cardHolderName: paymentBody.cardHolderName,
|
|
4033
|
+
mastercardPaymentMethod: paymentBody.mastercardPaymentMethod
|
|
3473
4034
|
};
|
|
3474
4035
|
}
|
|
3475
|
-
|
|
3476
|
-
|
|
4036
|
+
/**
|
|
4037
|
+
* Resolve the selected payment method from transaction details.
|
|
4038
|
+
*/
|
|
4039
|
+
resolveSelectedPaymentMethod(transactionData, paymentInfo) {
|
|
4040
|
+
const paymentMethodId = this.getString(transactionData['payment_method_id']);
|
|
4041
|
+
const paymentMethodName = this.getString(transactionData['payment_method_str']) || this.getString(transactionData['payment_method']);
|
|
4042
|
+
const normalizedName = this.normalizeMethodKey(paymentMethodName);
|
|
4043
|
+
const exactMatch = paymentInfo.availablePaymentMethods.find(method => method.id === paymentMethodId ||
|
|
4044
|
+
this.normalizeMethodKey(method.name) === normalizedName ||
|
|
4045
|
+
this.normalizeMethodKey(method.displayName) === normalizedName);
|
|
4046
|
+
if (exactMatch) {
|
|
4047
|
+
return exactMatch;
|
|
4048
|
+
}
|
|
4049
|
+
const channel = this.parseChannel(this.getString(transactionData['channel']) || paymentMethodName);
|
|
4050
|
+
if (!paymentMethodId && !paymentMethodName && channel === LokotroPayChannel.None) {
|
|
4051
|
+
return paymentInfo.availablePaymentMethods[0];
|
|
4052
|
+
}
|
|
4053
|
+
return {
|
|
4054
|
+
id: paymentMethodId || paymentMethodName || channel,
|
|
4055
|
+
name: paymentMethodName || paymentMethodId || channel,
|
|
4056
|
+
displayName: paymentMethodName || paymentMethodId || channel,
|
|
4057
|
+
channel,
|
|
4058
|
+
iconUrl: '',
|
|
4059
|
+
isEnabled: true
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
/**
|
|
4063
|
+
* Normalize payloads that sometimes return data nested inside data.
|
|
4064
|
+
*/
|
|
4065
|
+
unwrapPayload(payload) {
|
|
4066
|
+
const record = this.asRecord(payload);
|
|
4067
|
+
if (!record) {
|
|
4068
|
+
return {};
|
|
4069
|
+
}
|
|
4070
|
+
const nestedData = this.asRecord(record['data']);
|
|
4071
|
+
return nestedData || record;
|
|
4072
|
+
}
|
|
4073
|
+
resolvePaymentId(source) {
|
|
4074
|
+
return this.getString(source['payment_id']) ||
|
|
4075
|
+
this.getString(source['transaction_id']) ||
|
|
4076
|
+
this.getString(source['paymentId']) ||
|
|
4077
|
+
this.getString(source['transactionId']) ||
|
|
4078
|
+
this.currentState.transactionId ||
|
|
4079
|
+
'';
|
|
4080
|
+
}
|
|
4081
|
+
parseChannel(channel) {
|
|
4082
|
+
switch (this.normalizeMethodKey(channel)) {
|
|
4083
|
+
case 'card':
|
|
4084
|
+
return LokotroPayChannel.Card;
|
|
4085
|
+
case 'mobilemoney':
|
|
4086
|
+
return LokotroPayChannel.MobileMoney;
|
|
4087
|
+
case 'wallet':
|
|
4088
|
+
case 'ewallet':
|
|
4089
|
+
case 'lokotrowallet':
|
|
4090
|
+
return LokotroPayChannel.EWallet;
|
|
4091
|
+
case 'flash':
|
|
4092
|
+
case 'eflash':
|
|
4093
|
+
return LokotroPayChannel.EFlash;
|
|
4094
|
+
case 'banktransfer':
|
|
4095
|
+
return LokotroPayChannel.BankTransfer;
|
|
4096
|
+
default:
|
|
4097
|
+
return LokotroPayChannel.None;
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
normalizeMethodKey(value) {
|
|
4101
|
+
return value.toLowerCase().replace(/[_\s-]/g, '');
|
|
4102
|
+
}
|
|
4103
|
+
getNumber(value, fallback = 0) {
|
|
4104
|
+
if (typeof value === 'number') {
|
|
4105
|
+
return Number.isFinite(value) ? value : fallback;
|
|
4106
|
+
}
|
|
4107
|
+
if (typeof value === 'string') {
|
|
4108
|
+
const parsedValue = parseFloat(value);
|
|
4109
|
+
return Number.isFinite(parsedValue) ? parsedValue : fallback;
|
|
4110
|
+
}
|
|
4111
|
+
return fallback;
|
|
4112
|
+
}
|
|
4113
|
+
getString(value) {
|
|
4114
|
+
return typeof value === 'string' ? value : '';
|
|
4115
|
+
}
|
|
4116
|
+
getBoolean(value, fallback = false) {
|
|
4117
|
+
return typeof value === 'boolean' ? value : fallback;
|
|
4118
|
+
}
|
|
4119
|
+
asRecord(value) {
|
|
4120
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
4121
|
+
? value
|
|
4122
|
+
: undefined;
|
|
4123
|
+
}
|
|
4124
|
+
getRecordArray(value) {
|
|
4125
|
+
if (!Array.isArray(value)) {
|
|
4126
|
+
return [];
|
|
4127
|
+
}
|
|
4128
|
+
return value
|
|
4129
|
+
.map(item => this.asRecord(item))
|
|
4130
|
+
.filter((item) => Boolean(item));
|
|
4131
|
+
}
|
|
4132
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentService, deps: [{ token: LokotroHttpClientService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4133
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentService, providedIn: 'root' }); }
|
|
3477
4134
|
}
|
|
3478
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
4135
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentService, decorators: [{
|
|
3479
4136
|
type: Injectable,
|
|
3480
4137
|
args: [{
|
|
3481
4138
|
providedIn: 'root'
|
|
@@ -3487,6 +4144,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
3487
4144
|
* Main checkout widget with clean, theme-based design
|
|
3488
4145
|
*/
|
|
3489
4146
|
class LokotroPayCheckoutComponent {
|
|
4147
|
+
// Retry attempts tracking
|
|
4148
|
+
static { this.MAX_RETRY_ATTEMPTS = 3; }
|
|
3490
4149
|
constructor(paymentService, localization) {
|
|
3491
4150
|
this.paymentService = paymentService;
|
|
3492
4151
|
this.localization = localization;
|
|
@@ -3495,6 +4154,11 @@ class LokotroPayCheckoutComponent {
|
|
|
3495
4154
|
this.error = new EventEmitter();
|
|
3496
4155
|
this.closed = new EventEmitter();
|
|
3497
4156
|
this.isDarkTheme = true;
|
|
4157
|
+
this.retryAttempts = 0;
|
|
4158
|
+
}
|
|
4159
|
+
/** Check if user has retries left */
|
|
4160
|
+
get hasRetriesLeft() {
|
|
4161
|
+
return this.retryAttempts < LokotroPayCheckoutComponent.MAX_RETRY_ATTEMPTS;
|
|
3498
4162
|
}
|
|
3499
4163
|
ngOnInit() {
|
|
3500
4164
|
this.initializeEnvironment();
|
|
@@ -3507,11 +4171,18 @@ class LokotroPayCheckoutComponent {
|
|
|
3507
4171
|
this.paymentService.resetState();
|
|
3508
4172
|
}
|
|
3509
4173
|
initializeEnvironment() {
|
|
4174
|
+
console.log('[Lokotro Checkout] initializeEnvironment - configs:', {
|
|
4175
|
+
token: this.configs.token?.substring(0, 20) + '...',
|
|
4176
|
+
isProduction: this.configs.isProduction,
|
|
4177
|
+
customApiUrl: this.configs.customApiUrl
|
|
4178
|
+
});
|
|
3510
4179
|
LokotroPayEnv.initialize(this.configs.isProduction ?? false, this.configs.customApiUrl);
|
|
4180
|
+
console.log('[Lokotro Checkout] Calling setAppKey with token');
|
|
3511
4181
|
this.paymentService.setAppKey(this.configs.token);
|
|
3512
4182
|
if (this.configs.acceptLanguage) {
|
|
3513
4183
|
this.paymentService.setAcceptLanguage(this.configs.acceptLanguage);
|
|
3514
4184
|
}
|
|
4185
|
+
console.log('[Lokotro Checkout] Environment initialized');
|
|
3515
4186
|
}
|
|
3516
4187
|
initializeLocalization() {
|
|
3517
4188
|
if (this.language) {
|
|
@@ -3613,6 +4284,8 @@ class LokotroPayCheckoutComponent {
|
|
|
3613
4284
|
onFormSubmitted(formData) {
|
|
3614
4285
|
const submitRequest = {
|
|
3615
4286
|
transactionId: this.state?.transactionId || '',
|
|
4287
|
+
paymentId: this.state?.transactionId || '',
|
|
4288
|
+
paymentMethodId: this.state?.selectedPaymentMethod?.id || '',
|
|
3616
4289
|
paymentMethod: this.state?.selectedPaymentMethod?.name || '',
|
|
3617
4290
|
...formData
|
|
3618
4291
|
};
|
|
@@ -3626,8 +4299,8 @@ class LokotroPayCheckoutComponent {
|
|
|
3626
4299
|
if (!this.state?.transactionId)
|
|
3627
4300
|
return;
|
|
3628
4301
|
this.paymentService.verifyOtp({
|
|
3629
|
-
|
|
3630
|
-
otp
|
|
4302
|
+
paymentId: this.state.transactionId,
|
|
4303
|
+
otpCode: otp
|
|
3631
4304
|
}).subscribe({
|
|
3632
4305
|
error: (err) => {
|
|
3633
4306
|
console.error('[Lokotro Pay] OTP verification error:', err);
|
|
@@ -3638,7 +4311,7 @@ class LokotroPayCheckoutComponent {
|
|
|
3638
4311
|
if (!this.state?.transactionId)
|
|
3639
4312
|
return;
|
|
3640
4313
|
this.paymentService.resendOtp({
|
|
3641
|
-
|
|
4314
|
+
paymentId: this.state.transactionId
|
|
3642
4315
|
}).subscribe({
|
|
3643
4316
|
error: (err) => {
|
|
3644
4317
|
console.error('[Lokotro Pay] OTP resend error:', err);
|
|
@@ -3662,127 +4335,195 @@ class LokotroPayCheckoutComponent {
|
|
|
3662
4335
|
this.closed.emit();
|
|
3663
4336
|
}
|
|
3664
4337
|
onRetry() {
|
|
4338
|
+
if (!this.hasRetriesLeft) {
|
|
4339
|
+
// No retries left, emit error and close
|
|
4340
|
+
this.onErrorAutoRedirect();
|
|
4341
|
+
return;
|
|
4342
|
+
}
|
|
4343
|
+
this.retryAttempts++;
|
|
3665
4344
|
this.paymentService.resetState();
|
|
3666
4345
|
this.initializePayment();
|
|
3667
4346
|
}
|
|
3668
4347
|
onDone() {
|
|
4348
|
+
// Emit response callback before closing
|
|
4349
|
+
if (this.state?.response) {
|
|
4350
|
+
this.response.emit({
|
|
4351
|
+
message: this.state.response.message,
|
|
4352
|
+
title: this.state.response.title,
|
|
4353
|
+
customRef: this.state.response.customRef,
|
|
4354
|
+
amount: this.state.response.amount,
|
|
4355
|
+
apiResponseCode: this.state.response.apiResponseCode,
|
|
4356
|
+
currency: this.state.response.currency,
|
|
4357
|
+
paymentStatus: this.state.response.paymentStatus,
|
|
4358
|
+
systemRef: this.state.response.systemRef,
|
|
4359
|
+
transactionId: this.state.response.transactionId,
|
|
4360
|
+
timestamp: this.state.response.timestamp || new Date()
|
|
4361
|
+
});
|
|
4362
|
+
}
|
|
3669
4363
|
this.closed.emit();
|
|
3670
4364
|
}
|
|
3671
4365
|
onContinue() {
|
|
3672
4366
|
// Continue from warning screen
|
|
3673
4367
|
this.paymentService.navigateToScreen(LokotroPayScreenNavigation.PaymentMethodSelectionScreen);
|
|
3674
4368
|
}
|
|
3675
|
-
|
|
3676
|
-
|
|
4369
|
+
/** Handle auto-redirect from success screen */
|
|
4370
|
+
onSuccessAutoRedirect() {
|
|
4371
|
+
if (this.state?.response) {
|
|
4372
|
+
this.response.emit({
|
|
4373
|
+
message: this.state.response.message,
|
|
4374
|
+
title: this.state.response.title,
|
|
4375
|
+
customRef: this.state.response.customRef,
|
|
4376
|
+
amount: this.state.response.amount,
|
|
4377
|
+
apiResponseCode: this.state.response.apiResponseCode,
|
|
4378
|
+
currency: this.state.response.currency,
|
|
4379
|
+
paymentStatus: this.state.response.paymentStatus,
|
|
4380
|
+
systemRef: this.state.response.systemRef,
|
|
4381
|
+
transactionId: this.state.response.transactionId,
|
|
4382
|
+
timestamp: this.state.response.timestamp || new Date()
|
|
4383
|
+
});
|
|
4384
|
+
}
|
|
4385
|
+
this.closed.emit();
|
|
4386
|
+
}
|
|
4387
|
+
/** Handle auto-redirect from error screen (after retries exhausted) */
|
|
4388
|
+
onErrorAutoRedirect() {
|
|
4389
|
+
if (this.state?.error) {
|
|
4390
|
+
this.error.emit({
|
|
4391
|
+
message: this.state.error.message,
|
|
4392
|
+
title: this.state.error.title,
|
|
4393
|
+
errorCode: this.state.error.errorCode,
|
|
4394
|
+
timestamp: this.state.error.timestamp
|
|
4395
|
+
});
|
|
4396
|
+
}
|
|
4397
|
+
this.closed.emit();
|
|
4398
|
+
}
|
|
4399
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPayCheckoutComponent, deps: [{ token: LokotroPaymentService }, { token: LokotroLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4400
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroPayCheckoutComponent, isStandalone: true, selector: "lokotro-pay-checkout", inputs: { title: "title", titleStyle: "titleStyle", titleBackgroundColor: "titleBackgroundColor", configs: "configs", paymentBody: "paymentBody", enableHapticFeedback: "enableHapticFeedback", backgroundColor: "backgroundColor", padding: "padding", themeConfig: "themeConfig", language: "language" }, outputs: { response: "response", error: "error", closed: "closed" }, ngImport: i0, template: `
|
|
3677
4401
|
<div class="lokotro-checkout" [class.lokotro-dark]="isDarkTheme" [style]="containerStyle">
|
|
3678
4402
|
<!-- Header -->
|
|
3679
|
-
|
|
3680
|
-
<
|
|
3681
|
-
|
|
3682
|
-
<
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
4403
|
+
@if (title) {
|
|
4404
|
+
<div class="lokotro-checkout-header" [style.background-color]="titleBackgroundColor">
|
|
4405
|
+
@if (canGoBack) {
|
|
4406
|
+
<button class="lokotro-back-btn" (click)="onBack()">
|
|
4407
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
4408
|
+
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
4409
|
+
</svg>
|
|
4410
|
+
</button>
|
|
4411
|
+
}
|
|
4412
|
+
<h2 class="lokotro-title" [style]="titleStyleString">{{ title }}</h2>
|
|
4413
|
+
<button class="lokotro-close-btn" (click)="onClose()">
|
|
4414
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
4415
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
4416
|
+
</svg>
|
|
4417
|
+
</button>
|
|
4418
|
+
</div>
|
|
4419
|
+
}
|
|
4420
|
+
|
|
3693
4421
|
<!-- Content -->
|
|
3694
4422
|
<div class="lokotro-checkout-content">
|
|
3695
4423
|
<!-- Loading Screen -->
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
4424
|
+
@if (currentScreen === 'loadingScreen') {
|
|
4425
|
+
<lokotro-loading
|
|
4426
|
+
[message]="localization.translate('loading')">
|
|
4427
|
+
</lokotro-loading>
|
|
4428
|
+
}
|
|
4429
|
+
|
|
3701
4430
|
<!-- Payment Method Selection Screen -->
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
4431
|
+
@if (currentScreen === 'paymentMethodSelectionScreen') {
|
|
4432
|
+
<lokotro-payment-method-selection
|
|
4433
|
+
[paymentMethods]="state?.paymentInfo?.availablePaymentMethods || []"
|
|
4434
|
+
[selectedMethod]="state?.selectedPaymentMethod"
|
|
4435
|
+
(methodSelected)="onPaymentMethodSelected($event)">
|
|
4436
|
+
</lokotro-payment-method-selection>
|
|
4437
|
+
}
|
|
4438
|
+
|
|
3709
4439
|
<!-- Payment Form Screens -->
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
4440
|
+
@if (isPaymentFormScreen) {
|
|
4441
|
+
<lokotro-payment-form
|
|
4442
|
+
[channel]="state?.selectedPaymentMethod?.channel"
|
|
4443
|
+
[transactionId]="state?.transactionId"
|
|
4444
|
+
[showUserInfoForm]="state?.paymentInfo?.showUserInfoForm || false"
|
|
4445
|
+
(formSubmitted)="onFormSubmitted($event)"
|
|
4446
|
+
(cancel)="onCancel()">
|
|
4447
|
+
</lokotro-payment-form>
|
|
4448
|
+
}
|
|
4449
|
+
|
|
3718
4450
|
<!-- OTP Verification Screen -->
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
4451
|
+
@if (currentScreen === 'ewalletOtpScreen') {
|
|
4452
|
+
<lokotro-otp-verification
|
|
4453
|
+
[transactionId]="state?.transactionId"
|
|
4454
|
+
(otpVerified)="onOtpVerified($event)"
|
|
4455
|
+
(resendOtp)="onResendOtp()"
|
|
4456
|
+
(cancel)="onCancel()">
|
|
4457
|
+
</lokotro-otp-verification>
|
|
4458
|
+
}
|
|
4459
|
+
|
|
3727
4460
|
<!-- Processing Screens -->
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
4461
|
+
@if (isProcessingScreen) {
|
|
4462
|
+
<lokotro-processing
|
|
4463
|
+
[type]="currentScreen === 'mobileMoneyProcessingScreen' ? 'mobileMoney' : 'default'"
|
|
4464
|
+
[message]="localization.translate('processing')">
|
|
4465
|
+
</lokotro-processing>
|
|
4466
|
+
}
|
|
4467
|
+
|
|
3734
4468
|
<!-- Success Screen -->
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
4469
|
+
@if (currentScreen === 'successScreen') {
|
|
4470
|
+
<lokotro-result
|
|
4471
|
+
type="success"
|
|
4472
|
+
[title]="state?.response?.title || localization.translate('paymentSuccessful')"
|
|
4473
|
+
[message]="state?.response?.message || ''"
|
|
4474
|
+
[amount]="state?.response?.amount"
|
|
4475
|
+
[currency]="state?.response?.currency"
|
|
4476
|
+
[transactionId]="state?.response?.transactionId"
|
|
4477
|
+
[autoRedirectSeconds]="3"
|
|
4478
|
+
(autoRedirect)="onSuccessAutoRedirect()"
|
|
4479
|
+
(primaryAction)="onDone()"
|
|
4480
|
+
[primaryActionLabel]="localization.translate('done')">
|
|
4481
|
+
</lokotro-result>
|
|
4482
|
+
}
|
|
4483
|
+
|
|
3747
4484
|
<!-- Error Screen -->
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
4485
|
+
@if (currentScreen === 'errorScreen') {
|
|
4486
|
+
<lokotro-result
|
|
4487
|
+
type="error"
|
|
4488
|
+
[title]="state?.error?.title || localization.translate('paymentFailed')"
|
|
4489
|
+
[message]="state?.error?.message || ''"
|
|
4490
|
+
[autoRedirectSeconds]="hasRetriesLeft ? 0 : 3"
|
|
4491
|
+
(autoRedirect)="onErrorAutoRedirect()"
|
|
4492
|
+
(primaryAction)="onRetry()"
|
|
4493
|
+
[primaryActionLabel]="hasRetriesLeft ? localization.translate('retry') : undefined"
|
|
4494
|
+
(secondaryAction)="onClose()"
|
|
4495
|
+
[secondaryActionLabel]="localization.translate('close')">
|
|
4496
|
+
</lokotro-result>
|
|
4497
|
+
}
|
|
4498
|
+
|
|
3759
4499
|
<!-- Warning Screen -->
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
4500
|
+
@if (currentScreen === 'warningScreen') {
|
|
4501
|
+
<lokotro-result
|
|
4502
|
+
type="warning"
|
|
4503
|
+
[title]="'Warning'"
|
|
4504
|
+
[message]="state?.error?.message || ''"
|
|
4505
|
+
(primaryAction)="onContinue()"
|
|
4506
|
+
[primaryActionLabel]="localization.translate('continue')">
|
|
4507
|
+
</lokotro-result>
|
|
4508
|
+
}
|
|
4509
|
+
|
|
3769
4510
|
<!-- Info Screen -->
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
4511
|
+
@if (currentScreen === 'infoScreen') {
|
|
4512
|
+
<lokotro-result
|
|
4513
|
+
type="info"
|
|
4514
|
+
[title]="'Information'"
|
|
4515
|
+
[message]="state?.error?.message || ''"
|
|
4516
|
+
(primaryAction)="onClose()"
|
|
4517
|
+
[primaryActionLabel]="localization.translate('close')">
|
|
4518
|
+
</lokotro-result>
|
|
4519
|
+
}
|
|
3778
4520
|
</div>
|
|
3779
4521
|
</div>
|
|
3780
|
-
|
|
4522
|
+
`, isInline: true, styles: [".lokotro-checkout{display:flex;flex-direction:column;min-height:100%;background:var(--lokotro-background, #1C2621);color:var(--lokotro-text-primary, #F2F0D5);font-family:var(--lokotro-font-family, \"Comfortaa\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif)}.lokotro-checkout-header{display:flex;align-items:center;justify-content:space-between;padding:16px;background:var(--lokotro-surface, #2A3832);border-bottom:1px solid var(--lokotro-border, #3A473F)}.lokotro-title{flex:1;text-align:center;font-size:18px;font-weight:600;margin:0;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-back-btn,.lokotro-close-btn{background:none;border:none;padding:8px;cursor:pointer;color:var(--lokotro-text-primary, #F2F0D5);border-radius:8px;transition:background-color .2s}.lokotro-back-btn:hover,.lokotro-close-btn:hover{background:var(--lokotro-glass-light, rgba(255, 255, 255, .1))}.lokotro-checkout-content{flex:1;padding:16px;overflow-y:auto}.lokotro-dark{--lokotro-background: #1C2621;--lokotro-surface: #2A3832;--lokotro-text-primary: #F2F0D5;--lokotro-text-secondary: #D5D3B8}\n"], dependencies: [{ kind: "component", type: LokotroPaymentMethodSelectionComponent, selector: "lokotro-payment-method-selection", inputs: ["paymentMethods", "selectedMethod"], outputs: ["methodSelected"] }, { kind: "component", type: LokotroPaymentFormComponent, selector: "lokotro-payment-form", inputs: ["channel", "transactionId", "showUserInfoForm"], outputs: ["formSubmitted", "cancel"] }, { kind: "component", type: LokotroOtpVerificationComponent, selector: "lokotro-otp-verification", inputs: ["transactionId", "otpDestination", "otpLength"], outputs: ["otpVerified", "resendOtp", "cancel"] }, { kind: "component", type: LokotroProcessingComponent, selector: "lokotro-processing", inputs: ["type", "message"] }, { kind: "component", type: LokotroResultComponent, selector: "lokotro-result", inputs: ["type", "title", "message", "amount", "currency", "transactionId", "primaryActionLabel", "secondaryActionLabel", "autoRedirectSeconds"], outputs: ["primaryAction", "secondaryAction", "autoRedirect"] }, { kind: "component", type: LokotroLoadingComponent, selector: "lokotro-loading", inputs: ["message"] }] }); }
|
|
3781
4523
|
}
|
|
3782
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
4524
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPayCheckoutComponent, decorators: [{
|
|
3783
4525
|
type: Component,
|
|
3784
4526
|
args: [{ selector: 'lokotro-pay-checkout', standalone: true, imports: [
|
|
3785
|
-
CommonModule,
|
|
3786
4527
|
LokotroPaymentMethodSelectionComponent,
|
|
3787
4528
|
LokotroPaymentFormComponent,
|
|
3788
4529
|
LokotroOtpVerificationComponent,
|
|
@@ -3792,108 +4533,126 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
3792
4533
|
], template: `
|
|
3793
4534
|
<div class="lokotro-checkout" [class.lokotro-dark]="isDarkTheme" [style]="containerStyle">
|
|
3794
4535
|
<!-- Header -->
|
|
3795
|
-
|
|
3796
|
-
<
|
|
3797
|
-
|
|
3798
|
-
<
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
4536
|
+
@if (title) {
|
|
4537
|
+
<div class="lokotro-checkout-header" [style.background-color]="titleBackgroundColor">
|
|
4538
|
+
@if (canGoBack) {
|
|
4539
|
+
<button class="lokotro-back-btn" (click)="onBack()">
|
|
4540
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
4541
|
+
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
4542
|
+
</svg>
|
|
4543
|
+
</button>
|
|
4544
|
+
}
|
|
4545
|
+
<h2 class="lokotro-title" [style]="titleStyleString">{{ title }}</h2>
|
|
4546
|
+
<button class="lokotro-close-btn" (click)="onClose()">
|
|
4547
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
4548
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
4549
|
+
</svg>
|
|
4550
|
+
</button>
|
|
4551
|
+
</div>
|
|
4552
|
+
}
|
|
4553
|
+
|
|
3809
4554
|
<!-- Content -->
|
|
3810
4555
|
<div class="lokotro-checkout-content">
|
|
3811
4556
|
<!-- Loading Screen -->
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
4557
|
+
@if (currentScreen === 'loadingScreen') {
|
|
4558
|
+
<lokotro-loading
|
|
4559
|
+
[message]="localization.translate('loading')">
|
|
4560
|
+
</lokotro-loading>
|
|
4561
|
+
}
|
|
4562
|
+
|
|
3817
4563
|
<!-- Payment Method Selection Screen -->
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
4564
|
+
@if (currentScreen === 'paymentMethodSelectionScreen') {
|
|
4565
|
+
<lokotro-payment-method-selection
|
|
4566
|
+
[paymentMethods]="state?.paymentInfo?.availablePaymentMethods || []"
|
|
4567
|
+
[selectedMethod]="state?.selectedPaymentMethod"
|
|
4568
|
+
(methodSelected)="onPaymentMethodSelected($event)">
|
|
4569
|
+
</lokotro-payment-method-selection>
|
|
4570
|
+
}
|
|
4571
|
+
|
|
3825
4572
|
<!-- Payment Form Screens -->
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
4573
|
+
@if (isPaymentFormScreen) {
|
|
4574
|
+
<lokotro-payment-form
|
|
4575
|
+
[channel]="state?.selectedPaymentMethod?.channel"
|
|
4576
|
+
[transactionId]="state?.transactionId"
|
|
4577
|
+
[showUserInfoForm]="state?.paymentInfo?.showUserInfoForm || false"
|
|
4578
|
+
(formSubmitted)="onFormSubmitted($event)"
|
|
4579
|
+
(cancel)="onCancel()">
|
|
4580
|
+
</lokotro-payment-form>
|
|
4581
|
+
}
|
|
4582
|
+
|
|
3834
4583
|
<!-- OTP Verification Screen -->
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
4584
|
+
@if (currentScreen === 'ewalletOtpScreen') {
|
|
4585
|
+
<lokotro-otp-verification
|
|
4586
|
+
[transactionId]="state?.transactionId"
|
|
4587
|
+
(otpVerified)="onOtpVerified($event)"
|
|
4588
|
+
(resendOtp)="onResendOtp()"
|
|
4589
|
+
(cancel)="onCancel()">
|
|
4590
|
+
</lokotro-otp-verification>
|
|
4591
|
+
}
|
|
4592
|
+
|
|
3843
4593
|
<!-- Processing Screens -->
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
4594
|
+
@if (isProcessingScreen) {
|
|
4595
|
+
<lokotro-processing
|
|
4596
|
+
[type]="currentScreen === 'mobileMoneyProcessingScreen' ? 'mobileMoney' : 'default'"
|
|
4597
|
+
[message]="localization.translate('processing')">
|
|
4598
|
+
</lokotro-processing>
|
|
4599
|
+
}
|
|
4600
|
+
|
|
3850
4601
|
<!-- Success Screen -->
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
4602
|
+
@if (currentScreen === 'successScreen') {
|
|
4603
|
+
<lokotro-result
|
|
4604
|
+
type="success"
|
|
4605
|
+
[title]="state?.response?.title || localization.translate('paymentSuccessful')"
|
|
4606
|
+
[message]="state?.response?.message || ''"
|
|
4607
|
+
[amount]="state?.response?.amount"
|
|
4608
|
+
[currency]="state?.response?.currency"
|
|
4609
|
+
[transactionId]="state?.response?.transactionId"
|
|
4610
|
+
[autoRedirectSeconds]="3"
|
|
4611
|
+
(autoRedirect)="onSuccessAutoRedirect()"
|
|
4612
|
+
(primaryAction)="onDone()"
|
|
4613
|
+
[primaryActionLabel]="localization.translate('done')">
|
|
4614
|
+
</lokotro-result>
|
|
4615
|
+
}
|
|
4616
|
+
|
|
3863
4617
|
<!-- Error Screen -->
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
4618
|
+
@if (currentScreen === 'errorScreen') {
|
|
4619
|
+
<lokotro-result
|
|
4620
|
+
type="error"
|
|
4621
|
+
[title]="state?.error?.title || localization.translate('paymentFailed')"
|
|
4622
|
+
[message]="state?.error?.message || ''"
|
|
4623
|
+
[autoRedirectSeconds]="hasRetriesLeft ? 0 : 3"
|
|
4624
|
+
(autoRedirect)="onErrorAutoRedirect()"
|
|
4625
|
+
(primaryAction)="onRetry()"
|
|
4626
|
+
[primaryActionLabel]="hasRetriesLeft ? localization.translate('retry') : undefined"
|
|
4627
|
+
(secondaryAction)="onClose()"
|
|
4628
|
+
[secondaryActionLabel]="localization.translate('close')">
|
|
4629
|
+
</lokotro-result>
|
|
4630
|
+
}
|
|
4631
|
+
|
|
3875
4632
|
<!-- Warning Screen -->
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
4633
|
+
@if (currentScreen === 'warningScreen') {
|
|
4634
|
+
<lokotro-result
|
|
4635
|
+
type="warning"
|
|
4636
|
+
[title]="'Warning'"
|
|
4637
|
+
[message]="state?.error?.message || ''"
|
|
4638
|
+
(primaryAction)="onContinue()"
|
|
4639
|
+
[primaryActionLabel]="localization.translate('continue')">
|
|
4640
|
+
</lokotro-result>
|
|
4641
|
+
}
|
|
4642
|
+
|
|
3885
4643
|
<!-- Info Screen -->
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
4644
|
+
@if (currentScreen === 'infoScreen') {
|
|
4645
|
+
<lokotro-result
|
|
4646
|
+
type="info"
|
|
4647
|
+
[title]="'Information'"
|
|
4648
|
+
[message]="state?.error?.message || ''"
|
|
4649
|
+
(primaryAction)="onClose()"
|
|
4650
|
+
[primaryActionLabel]="localization.translate('close')">
|
|
4651
|
+
</lokotro-result>
|
|
4652
|
+
}
|
|
3894
4653
|
</div>
|
|
3895
4654
|
</div>
|
|
3896
|
-
|
|
4655
|
+
`, styles: [".lokotro-checkout{display:flex;flex-direction:column;min-height:100%;background:var(--lokotro-background, #1C2621);color:var(--lokotro-text-primary, #F2F0D5);font-family:var(--lokotro-font-family, \"Comfortaa\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif)}.lokotro-checkout-header{display:flex;align-items:center;justify-content:space-between;padding:16px;background:var(--lokotro-surface, #2A3832);border-bottom:1px solid var(--lokotro-border, #3A473F)}.lokotro-title{flex:1;text-align:center;font-size:18px;font-weight:600;margin:0;color:var(--lokotro-text-primary, #F2F0D5)}.lokotro-back-btn,.lokotro-close-btn{background:none;border:none;padding:8px;cursor:pointer;color:var(--lokotro-text-primary, #F2F0D5);border-radius:8px;transition:background-color .2s}.lokotro-back-btn:hover,.lokotro-close-btn:hover{background:var(--lokotro-glass-light, rgba(255, 255, 255, .1))}.lokotro-checkout-content{flex:1;padding:16px;overflow-y:auto}.lokotro-dark{--lokotro-background: #1C2621;--lokotro-surface: #2A3832;--lokotro-text-primary: #F2F0D5;--lokotro-text-secondary: #D5D3B8}\n"] }]
|
|
3897
4656
|
}], ctorParameters: () => [{ type: LokotroPaymentService }, { type: LokotroLocalizationService }], propDecorators: { title: [{
|
|
3898
4657
|
type: Input
|
|
3899
4658
|
}], titleStyle: [{
|
|
@@ -3982,10 +4741,8 @@ class LokotroPayModule {
|
|
|
3982
4741
|
],
|
|
3983
4742
|
};
|
|
3984
4743
|
}
|
|
3985
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
3986
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.
|
|
3987
|
-
HttpClientModule,
|
|
3988
|
-
ReactiveFormsModule,
|
|
4744
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPayModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
4745
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.18", ngImport: i0, type: LokotroPayModule, imports: [ReactiveFormsModule,
|
|
3989
4746
|
FormsModule,
|
|
3990
4747
|
// Standalone components
|
|
3991
4748
|
LokotroPayCheckoutComponent,
|
|
@@ -4001,25 +4758,17 @@ class LokotroPayModule {
|
|
|
4001
4758
|
LokotroProcessingComponent,
|
|
4002
4759
|
LokotroResultComponent,
|
|
4003
4760
|
LokotroLoadingComponent] }); }
|
|
4004
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.
|
|
4005
|
-
HttpClientModule,
|
|
4006
|
-
ReactiveFormsModule,
|
|
4761
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPayModule, imports: [ReactiveFormsModule,
|
|
4007
4762
|
FormsModule,
|
|
4008
4763
|
// Standalone components
|
|
4009
4764
|
LokotroPayCheckoutComponent,
|
|
4010
|
-
LokotroPaymentMethodSelectionComponent,
|
|
4011
4765
|
LokotroPaymentFormComponent,
|
|
4012
|
-
LokotroOtpVerificationComponent
|
|
4013
|
-
LokotroProcessingComponent,
|
|
4014
|
-
LokotroResultComponent,
|
|
4015
|
-
LokotroLoadingComponent] }); }
|
|
4766
|
+
LokotroOtpVerificationComponent] }); }
|
|
4016
4767
|
}
|
|
4017
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
4768
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPayModule, decorators: [{
|
|
4018
4769
|
type: NgModule,
|
|
4019
4770
|
args: [{
|
|
4020
4771
|
imports: [
|
|
4021
|
-
CommonModule,
|
|
4022
|
-
HttpClientModule,
|
|
4023
4772
|
ReactiveFormsModule,
|
|
4024
4773
|
FormsModule,
|
|
4025
4774
|
// Standalone components
|
|
@@ -4477,210 +5226,242 @@ class LokotroPaymentStatusComponent {
|
|
|
4477
5226
|
}
|
|
4478
5227
|
this.onClose.emit();
|
|
4479
5228
|
}
|
|
4480
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
4481
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
5229
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentStatusComponent, deps: [{ token: LokotroPaymentService }, { token: LokotroLocalizationService }, { token: LokotroHttpClientService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5230
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LokotroPaymentStatusComponent, isStandalone: true, selector: "lokotro-payment-status", inputs: { statusConfig: "statusConfig", showHeader: "showHeader", showCloseButton: "showCloseButton" }, outputs: { statusChange: "statusChange", paymentComplete: "paymentComplete", paymentFailed: "paymentFailed", onClose: "onClose", onDoneEvent: "onDoneEvent" }, ngImport: i0, template: `
|
|
4482
5231
|
<div class="lokotro-payment-status-container">
|
|
4483
5232
|
<!-- Header -->
|
|
4484
|
-
|
|
4485
|
-
<
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
<
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
5233
|
+
@if (showHeader) {
|
|
5234
|
+
<div class="lokotro-status-header">
|
|
5235
|
+
<h2 class="lokotro-status-title">{{ localization.translate('paymentStatus') }}</h2>
|
|
5236
|
+
@if (showCloseButton) {
|
|
5237
|
+
<button class="lokotro-close-btn" (click)="onClose.emit()">
|
|
5238
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
5239
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
5240
|
+
</svg>
|
|
5241
|
+
</button>
|
|
5242
|
+
}
|
|
5243
|
+
</div>
|
|
5244
|
+
}
|
|
5245
|
+
|
|
4493
5246
|
<!-- Content -->
|
|
4494
5247
|
<div class="lokotro-status-content">
|
|
4495
5248
|
<!-- Loading State -->
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
5249
|
+
@if (currentScreen === 'loading') {
|
|
5250
|
+
<lokotro-loading
|
|
5251
|
+
[message]="localization.translate('checkingPaymentStatus')">
|
|
5252
|
+
</lokotro-loading>
|
|
5253
|
+
}
|
|
5254
|
+
|
|
4501
5255
|
<!-- Pending State -->
|
|
4502
|
-
|
|
4503
|
-
<div class="status-
|
|
4504
|
-
<
|
|
4505
|
-
<
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
<h3 class="status-title">{{ localization.translate('paymentPending') }}</h3>
|
|
4510
|
-
<p class="status-message">{{ localization.translate('paymentPendingMessage') }}</p>
|
|
4511
|
-
<div class="payment-info" *ngIf="paymentDetails">
|
|
4512
|
-
<div class="info-row">
|
|
4513
|
-
<span class="info-label">{{ localization.translate('paymentId') }}:</span>
|
|
4514
|
-
<span class="info-value">{{ paymentDetails.paymentId }}</span>
|
|
5256
|
+
@if (currentScreen === 'pending') {
|
|
5257
|
+
<div class="status-section pending">
|
|
5258
|
+
<div class="status-icon pending-icon">
|
|
5259
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
5260
|
+
<circle cx="12" cy="12" r="10"/>
|
|
5261
|
+
<polyline points="12 6 12 12 16 14"/>
|
|
5262
|
+
</svg>
|
|
4515
5263
|
</div>
|
|
4516
|
-
<
|
|
4517
|
-
|
|
4518
|
-
|
|
5264
|
+
<h3 class="status-title">{{ localization.translate('paymentPending') }}</h3>
|
|
5265
|
+
<p class="status-message">{{ localization.translate('paymentPendingMessage') }}</p>
|
|
5266
|
+
@if (paymentDetails) {
|
|
5267
|
+
<div class="payment-info">
|
|
5268
|
+
<div class="info-row">
|
|
5269
|
+
<span class="info-label">{{ localization.translate('paymentId') }}:</span>
|
|
5270
|
+
<span class="info-value">{{ paymentDetails.paymentId }}</span>
|
|
5271
|
+
</div>
|
|
5272
|
+
@if (paymentDetails.amount) {
|
|
5273
|
+
<div class="info-row">
|
|
5274
|
+
<span class="info-label">{{ localization.translate('amount') }}:</span>
|
|
5275
|
+
<span class="info-value">{{ paymentDetails.amount }} {{ paymentDetails.currency }}</span>
|
|
5276
|
+
</div>
|
|
5277
|
+
}
|
|
5278
|
+
</div>
|
|
5279
|
+
}
|
|
5280
|
+
<div class="polling-indicator">
|
|
5281
|
+
<span class="pulse"></span>
|
|
5282
|
+
<span>{{ localization.translate('checkingForUpdates') }}</span>
|
|
4519
5283
|
</div>
|
|
4520
5284
|
</div>
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
<span>{{ localization.translate('checkingForUpdates') }}</span>
|
|
4524
|
-
</div>
|
|
4525
|
-
</div>
|
|
4526
|
-
|
|
5285
|
+
}
|
|
5286
|
+
|
|
4527
5287
|
<!-- Processing State -->
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
5288
|
+
@if (currentScreen === 'processing') {
|
|
5289
|
+
<lokotro-processing
|
|
5290
|
+
type="default"
|
|
5291
|
+
[message]="localization.translate('paymentProcessing')">
|
|
5292
|
+
</lokotro-processing>
|
|
5293
|
+
}
|
|
5294
|
+
|
|
4534
5295
|
<!-- Success State -->
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
5296
|
+
@if (currentScreen === 'success') {
|
|
5297
|
+
<lokotro-result
|
|
5298
|
+
type="success"
|
|
5299
|
+
[title]="localization.translate('paymentSuccessful')"
|
|
5300
|
+
[message]="paymentDetails?.message || localization.translate('paymentSuccessMessage')"
|
|
5301
|
+
[amount]="paymentDetails?.amount"
|
|
5302
|
+
[currency]="paymentDetails?.currency"
|
|
5303
|
+
[transactionId]="paymentDetails?.transactionId"
|
|
5304
|
+
(primaryAction)="onDone()"
|
|
5305
|
+
[primaryActionLabel]="localization.translate('done')">
|
|
5306
|
+
</lokotro-result>
|
|
5307
|
+
}
|
|
5308
|
+
|
|
4547
5309
|
<!-- Error State -->
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
5310
|
+
@if (currentScreen === 'error') {
|
|
5311
|
+
<lokotro-result
|
|
5312
|
+
type="error"
|
|
5313
|
+
[title]="localization.translate('paymentFailed')"
|
|
5314
|
+
[message]="errorMessage || localization.translate('paymentFailedMessage')"
|
|
5315
|
+
(primaryAction)="retryCheck()"
|
|
5316
|
+
[primaryActionLabel]="localization.translate('retry')"
|
|
5317
|
+
(secondaryAction)="onClose.emit()"
|
|
5318
|
+
[secondaryActionLabel]="localization.translate('close')">
|
|
5319
|
+
</lokotro-result>
|
|
5320
|
+
}
|
|
5321
|
+
|
|
4559
5322
|
<!-- Cancelled State -->
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
5323
|
+
@if (currentScreen === 'cancelled') {
|
|
5324
|
+
<lokotro-result
|
|
5325
|
+
type="error"
|
|
5326
|
+
[title]="localization.translate('paymentCancelled')"
|
|
5327
|
+
[message]="localization.translate('paymentCancelledMessage')"
|
|
5328
|
+
(primaryAction)="onClose.emit()"
|
|
5329
|
+
[primaryActionLabel]="localization.translate('close')">
|
|
5330
|
+
</lokotro-result>
|
|
5331
|
+
}
|
|
5332
|
+
|
|
4569
5333
|
<!-- Expired State -->
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
5334
|
+
@if (currentScreen === 'expired') {
|
|
5335
|
+
<lokotro-result
|
|
5336
|
+
type="warning"
|
|
5337
|
+
[title]="localization.translate('paymentExpired')"
|
|
5338
|
+
[message]="localization.translate('paymentExpiredMessage')"
|
|
5339
|
+
(primaryAction)="onClose.emit()"
|
|
5340
|
+
[primaryActionLabel]="localization.translate('close')">
|
|
5341
|
+
</lokotro-result>
|
|
5342
|
+
}
|
|
4578
5343
|
</div>
|
|
4579
5344
|
</div>
|
|
4580
|
-
|
|
5345
|
+
`, isInline: true, styles: [".lokotro-payment-status-container{min-height:300px;display:flex;flex-direction:column;background:var(--lokotro-background, #1C2621);border-radius:16px;border:1px solid var(--lokotro-border, rgba(59, 251, 218, .1));overflow:hidden;font-family:var(--lokotro-font-family, \"Comfortaa\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif)}.lokotro-status-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:var(--lokotro-surface, #2A3832);border-bottom:1px solid var(--lokotro-border, rgba(59, 251, 218, .1))}.lokotro-status-title{font-size:18px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5);margin:0}.lokotro-close-btn{background:none;border:none;padding:8px;cursor:pointer;color:var(--lokotro-text-primary, #F2F0D5);border-radius:8px;transition:background-color .2s}.lokotro-close-btn:hover{background:#ffffff1a}.lokotro-status-content{flex:1;padding:24px;display:flex;flex-direction:column;align-items:center;justify-content:center}.status-section{text-align:center;width:100%;max-width:400px}.status-icon{width:80px;height:80px;margin:0 auto 24px;display:flex;align-items:center;justify-content:center;border-radius:50%}.pending-icon{background:#fbbf241a;color:#fbbf24}.status-title{font-size:22px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5);margin:0 0 12px}.status-message{font-size:14px;color:var(--lokotro-text-secondary, rgba(242, 240, 213, .7));margin:0 0 24px;line-height:1.5}.payment-info{background:#5a5e3933;border-radius:12px;padding:16px;margin-bottom:24px}.info-row{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(242,240,213,.1)}.info-row:last-child{border-bottom:none}.info-label{color:var(--lokotro-text-secondary, rgba(242, 240, 213, .6));font-size:14px}.info-value{color:var(--lokotro-text-primary, #F2F0D5);font-size:14px;font-weight:500}.polling-indicator{display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;color:var(--lokotro-text-secondary, rgba(242, 240, 213, .5))}.pulse{width:8px;height:8px;background:var(--lokotro-primary, #3BFBDA);border-radius:50%;animation:pulse 1.5s ease-in-out infinite}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.2)}}\n"], dependencies: [{ kind: "component", type: LokotroLoadingComponent, selector: "lokotro-loading", inputs: ["message"] }, { kind: "component", type: LokotroResultComponent, selector: "lokotro-result", inputs: ["type", "title", "message", "amount", "currency", "transactionId", "primaryActionLabel", "secondaryActionLabel", "autoRedirectSeconds"], outputs: ["primaryAction", "secondaryAction", "autoRedirect"] }, { kind: "component", type: LokotroProcessingComponent, selector: "lokotro-processing", inputs: ["type", "message"] }] }); }
|
|
4581
5346
|
}
|
|
4582
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
5347
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LokotroPaymentStatusComponent, decorators: [{
|
|
4583
5348
|
type: Component,
|
|
4584
|
-
args: [{ selector: 'lokotro-payment-status', standalone: true, imports: [
|
|
5349
|
+
args: [{ selector: 'lokotro-payment-status', standalone: true, imports: [LokotroLoadingComponent, LokotroResultComponent, LokotroProcessingComponent], template: `
|
|
4585
5350
|
<div class="lokotro-payment-status-container">
|
|
4586
5351
|
<!-- Header -->
|
|
4587
|
-
|
|
4588
|
-
<
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
<
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
5352
|
+
@if (showHeader) {
|
|
5353
|
+
<div class="lokotro-status-header">
|
|
5354
|
+
<h2 class="lokotro-status-title">{{ localization.translate('paymentStatus') }}</h2>
|
|
5355
|
+
@if (showCloseButton) {
|
|
5356
|
+
<button class="lokotro-close-btn" (click)="onClose.emit()">
|
|
5357
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
5358
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
5359
|
+
</svg>
|
|
5360
|
+
</button>
|
|
5361
|
+
}
|
|
5362
|
+
</div>
|
|
5363
|
+
}
|
|
5364
|
+
|
|
4596
5365
|
<!-- Content -->
|
|
4597
5366
|
<div class="lokotro-status-content">
|
|
4598
5367
|
<!-- Loading State -->
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
5368
|
+
@if (currentScreen === 'loading') {
|
|
5369
|
+
<lokotro-loading
|
|
5370
|
+
[message]="localization.translate('checkingPaymentStatus')">
|
|
5371
|
+
</lokotro-loading>
|
|
5372
|
+
}
|
|
5373
|
+
|
|
4604
5374
|
<!-- Pending State -->
|
|
4605
|
-
|
|
4606
|
-
<div class="status-
|
|
4607
|
-
<
|
|
4608
|
-
<
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
<h3 class="status-title">{{ localization.translate('paymentPending') }}</h3>
|
|
4613
|
-
<p class="status-message">{{ localization.translate('paymentPendingMessage') }}</p>
|
|
4614
|
-
<div class="payment-info" *ngIf="paymentDetails">
|
|
4615
|
-
<div class="info-row">
|
|
4616
|
-
<span class="info-label">{{ localization.translate('paymentId') }}:</span>
|
|
4617
|
-
<span class="info-value">{{ paymentDetails.paymentId }}</span>
|
|
5375
|
+
@if (currentScreen === 'pending') {
|
|
5376
|
+
<div class="status-section pending">
|
|
5377
|
+
<div class="status-icon pending-icon">
|
|
5378
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
5379
|
+
<circle cx="12" cy="12" r="10"/>
|
|
5380
|
+
<polyline points="12 6 12 12 16 14"/>
|
|
5381
|
+
</svg>
|
|
4618
5382
|
</div>
|
|
4619
|
-
<
|
|
4620
|
-
|
|
4621
|
-
|
|
5383
|
+
<h3 class="status-title">{{ localization.translate('paymentPending') }}</h3>
|
|
5384
|
+
<p class="status-message">{{ localization.translate('paymentPendingMessage') }}</p>
|
|
5385
|
+
@if (paymentDetails) {
|
|
5386
|
+
<div class="payment-info">
|
|
5387
|
+
<div class="info-row">
|
|
5388
|
+
<span class="info-label">{{ localization.translate('paymentId') }}:</span>
|
|
5389
|
+
<span class="info-value">{{ paymentDetails.paymentId }}</span>
|
|
5390
|
+
</div>
|
|
5391
|
+
@if (paymentDetails.amount) {
|
|
5392
|
+
<div class="info-row">
|
|
5393
|
+
<span class="info-label">{{ localization.translate('amount') }}:</span>
|
|
5394
|
+
<span class="info-value">{{ paymentDetails.amount }} {{ paymentDetails.currency }}</span>
|
|
5395
|
+
</div>
|
|
5396
|
+
}
|
|
5397
|
+
</div>
|
|
5398
|
+
}
|
|
5399
|
+
<div class="polling-indicator">
|
|
5400
|
+
<span class="pulse"></span>
|
|
5401
|
+
<span>{{ localization.translate('checkingForUpdates') }}</span>
|
|
4622
5402
|
</div>
|
|
4623
5403
|
</div>
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
<span>{{ localization.translate('checkingForUpdates') }}</span>
|
|
4627
|
-
</div>
|
|
4628
|
-
</div>
|
|
4629
|
-
|
|
5404
|
+
}
|
|
5405
|
+
|
|
4630
5406
|
<!-- Processing State -->
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
5407
|
+
@if (currentScreen === 'processing') {
|
|
5408
|
+
<lokotro-processing
|
|
5409
|
+
type="default"
|
|
5410
|
+
[message]="localization.translate('paymentProcessing')">
|
|
5411
|
+
</lokotro-processing>
|
|
5412
|
+
}
|
|
5413
|
+
|
|
4637
5414
|
<!-- Success State -->
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
5415
|
+
@if (currentScreen === 'success') {
|
|
5416
|
+
<lokotro-result
|
|
5417
|
+
type="success"
|
|
5418
|
+
[title]="localization.translate('paymentSuccessful')"
|
|
5419
|
+
[message]="paymentDetails?.message || localization.translate('paymentSuccessMessage')"
|
|
5420
|
+
[amount]="paymentDetails?.amount"
|
|
5421
|
+
[currency]="paymentDetails?.currency"
|
|
5422
|
+
[transactionId]="paymentDetails?.transactionId"
|
|
5423
|
+
(primaryAction)="onDone()"
|
|
5424
|
+
[primaryActionLabel]="localization.translate('done')">
|
|
5425
|
+
</lokotro-result>
|
|
5426
|
+
}
|
|
5427
|
+
|
|
4650
5428
|
<!-- Error State -->
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
5429
|
+
@if (currentScreen === 'error') {
|
|
5430
|
+
<lokotro-result
|
|
5431
|
+
type="error"
|
|
5432
|
+
[title]="localization.translate('paymentFailed')"
|
|
5433
|
+
[message]="errorMessage || localization.translate('paymentFailedMessage')"
|
|
5434
|
+
(primaryAction)="retryCheck()"
|
|
5435
|
+
[primaryActionLabel]="localization.translate('retry')"
|
|
5436
|
+
(secondaryAction)="onClose.emit()"
|
|
5437
|
+
[secondaryActionLabel]="localization.translate('close')">
|
|
5438
|
+
</lokotro-result>
|
|
5439
|
+
}
|
|
5440
|
+
|
|
4662
5441
|
<!-- Cancelled State -->
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
5442
|
+
@if (currentScreen === 'cancelled') {
|
|
5443
|
+
<lokotro-result
|
|
5444
|
+
type="error"
|
|
5445
|
+
[title]="localization.translate('paymentCancelled')"
|
|
5446
|
+
[message]="localization.translate('paymentCancelledMessage')"
|
|
5447
|
+
(primaryAction)="onClose.emit()"
|
|
5448
|
+
[primaryActionLabel]="localization.translate('close')">
|
|
5449
|
+
</lokotro-result>
|
|
5450
|
+
}
|
|
5451
|
+
|
|
4672
5452
|
<!-- Expired State -->
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
5453
|
+
@if (currentScreen === 'expired') {
|
|
5454
|
+
<lokotro-result
|
|
5455
|
+
type="warning"
|
|
5456
|
+
[title]="localization.translate('paymentExpired')"
|
|
5457
|
+
[message]="localization.translate('paymentExpiredMessage')"
|
|
5458
|
+
(primaryAction)="onClose.emit()"
|
|
5459
|
+
[primaryActionLabel]="localization.translate('close')">
|
|
5460
|
+
</lokotro-result>
|
|
5461
|
+
}
|
|
4681
5462
|
</div>
|
|
4682
5463
|
</div>
|
|
4683
|
-
|
|
5464
|
+
`, styles: [".lokotro-payment-status-container{min-height:300px;display:flex;flex-direction:column;background:var(--lokotro-background, #1C2621);border-radius:16px;border:1px solid var(--lokotro-border, rgba(59, 251, 218, .1));overflow:hidden;font-family:var(--lokotro-font-family, \"Comfortaa\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif)}.lokotro-status-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:var(--lokotro-surface, #2A3832);border-bottom:1px solid var(--lokotro-border, rgba(59, 251, 218, .1))}.lokotro-status-title{font-size:18px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5);margin:0}.lokotro-close-btn{background:none;border:none;padding:8px;cursor:pointer;color:var(--lokotro-text-primary, #F2F0D5);border-radius:8px;transition:background-color .2s}.lokotro-close-btn:hover{background:#ffffff1a}.lokotro-status-content{flex:1;padding:24px;display:flex;flex-direction:column;align-items:center;justify-content:center}.status-section{text-align:center;width:100%;max-width:400px}.status-icon{width:80px;height:80px;margin:0 auto 24px;display:flex;align-items:center;justify-content:center;border-radius:50%}.pending-icon{background:#fbbf241a;color:#fbbf24}.status-title{font-size:22px;font-weight:600;color:var(--lokotro-text-primary, #F2F0D5);margin:0 0 12px}.status-message{font-size:14px;color:var(--lokotro-text-secondary, rgba(242, 240, 213, .7));margin:0 0 24px;line-height:1.5}.payment-info{background:#5a5e3933;border-radius:12px;padding:16px;margin-bottom:24px}.info-row{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(242,240,213,.1)}.info-row:last-child{border-bottom:none}.info-label{color:var(--lokotro-text-secondary, rgba(242, 240, 213, .6));font-size:14px}.info-value{color:var(--lokotro-text-primary, #F2F0D5);font-size:14px;font-weight:500}.polling-indicator{display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;color:var(--lokotro-text-secondary, rgba(242, 240, 213, .5))}.pulse{width:8px;height:8px;background:var(--lokotro-primary, #3BFBDA);border-radius:50%;animation:pulse 1.5s ease-in-out infinite}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.2)}}\n"] }]
|
|
4684
5465
|
}], ctorParameters: () => [{ type: LokotroPaymentService }, { type: LokotroLocalizationService }, { type: LokotroHttpClientService }], propDecorators: { statusConfig: [{
|
|
4685
5466
|
type: Input
|
|
4686
5467
|
}], showHeader: [{
|