@apolopay-sdk/ui 1.0.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 +54 -0
- package/dist/assets/icon_error.d.ts +1 -0
- package/dist/assets/icon_error.js +1 -0
- package/dist/assets/logo_apolo.d.ts +1 -0
- package/dist/assets/logo_apolo.js +1 -0
- package/dist/components/payment-modal.d.ts +48 -0
- package/dist/components/payment-modal.js +668 -0
- package/dist/components/payment-timer.d.ts +18 -0
- package/dist/components/payment-timer.js +84 -0
- package/dist/components/trigger-button.d.ts +16 -0
- package/dist/components/trigger-button.js +151 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/payment-button.d.ts +51 -0
- package/dist/payment-button.js +371 -0
- package/dist/styles/modal-base.d.ts +1 -0
- package/dist/styles/modal-base.js +75 -0
- package/dist/styles/qr-base.d.ts +1 -0
- package/dist/styles/qr-base.js +48 -0
- package/dist/styles/shared-styles.d.ts +1 -0
- package/dist/styles/shared-styles.js +28 -0
- package/dist/styles/spinner-styles.d.ts +1 -0
- package/dist/styles/spinner-styles.js +29 -0
- package/dist/styles/text-field-base.d.ts +1 -0
- package/dist/styles/text-field-base.js +44 -0
- package/dist/utils/image_error.d.ts +1 -0
- package/dist/utils/image_error.js +5 -0
- package/package.json +34 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, html, css } from 'lit';
|
|
8
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
9
|
+
import { I18n } from '@apolopay-sdk/core';
|
|
10
|
+
let PaymentTimer = class PaymentTimer extends LitElement {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
this.expiresAt = 0;
|
|
14
|
+
this.timerString = '-- : --';
|
|
15
|
+
this._interval = null;
|
|
16
|
+
}
|
|
17
|
+
connectedCallback() {
|
|
18
|
+
super.connectedCallback();
|
|
19
|
+
this.startTimer();
|
|
20
|
+
}
|
|
21
|
+
disconnectedCallback() {
|
|
22
|
+
this.stopTimer();
|
|
23
|
+
super.disconnectedCallback();
|
|
24
|
+
}
|
|
25
|
+
updated(changedProperties) {
|
|
26
|
+
if (changedProperties.has('expiresAt')) {
|
|
27
|
+
this.startTimer();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
startTimer() {
|
|
31
|
+
this.stopTimer();
|
|
32
|
+
if (!this.expiresAt || isNaN(this.expiresAt))
|
|
33
|
+
return;
|
|
34
|
+
const tick = () => {
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
const distance = this.expiresAt - now;
|
|
37
|
+
if (distance <= 0) {
|
|
38
|
+
this.stopTimer();
|
|
39
|
+
const minLabel = I18n.t.modal.labels.minutes;
|
|
40
|
+
const secLabel = I18n.t.modal.labels.seconds;
|
|
41
|
+
this.timerString = `00 ${minLabel} : 00 ${secLabel}`;
|
|
42
|
+
this.dispatchEvent(new CustomEvent('expired'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
|
46
|
+
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
|
47
|
+
const m = minutes.toString().padStart(2, '0');
|
|
48
|
+
const s = seconds.toString().padStart(2, '0');
|
|
49
|
+
const minLabel = I18n.t.modal.labels.minutes;
|
|
50
|
+
const secLabel = I18n.t.modal.labels.seconds;
|
|
51
|
+
this.timerString = `${m} ${minLabel} : ${s} ${secLabel}`;
|
|
52
|
+
};
|
|
53
|
+
tick();
|
|
54
|
+
this._interval = window.setInterval(tick, 1000);
|
|
55
|
+
}
|
|
56
|
+
stopTimer() {
|
|
57
|
+
if (this._interval) {
|
|
58
|
+
clearInterval(this._interval);
|
|
59
|
+
this._interval = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
render() {
|
|
63
|
+
return html `${this.timerString}`;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
PaymentTimer.styles = css `
|
|
67
|
+
:host {
|
|
68
|
+
display: block;
|
|
69
|
+
color: var(--apolo-accent, #ea580c);
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
font-size: 0.9rem;
|
|
72
|
+
margin-bottom: 1rem;
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
__decorate([
|
|
76
|
+
property({ type: Number })
|
|
77
|
+
], PaymentTimer.prototype, "expiresAt", void 0);
|
|
78
|
+
__decorate([
|
|
79
|
+
state()
|
|
80
|
+
], PaymentTimer.prototype, "timerString", void 0);
|
|
81
|
+
PaymentTimer = __decorate([
|
|
82
|
+
customElement('payment-timer')
|
|
83
|
+
], PaymentTimer);
|
|
84
|
+
export { PaymentTimer };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { type Locale } from '@apolopay-sdk/core';
|
|
3
|
+
export declare class TriggerButton extends LitElement {
|
|
4
|
+
lang: Locale;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
disabled: boolean;
|
|
7
|
+
label?: string;
|
|
8
|
+
hasError: boolean;
|
|
9
|
+
static styles: import("lit").CSSResult[];
|
|
10
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
11
|
+
}
|
|
12
|
+
declare global {
|
|
13
|
+
interface HTMLElementTagNameMap {
|
|
14
|
+
'trigger-button': TriggerButton;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, html, css } from 'lit';
|
|
8
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
9
|
+
import { sharedStyles } from '../styles/shared-styles.js';
|
|
10
|
+
import { logoApolo } from '../assets/logo_apolo.js';
|
|
11
|
+
import { I18n } from '@apolopay-sdk/core';
|
|
12
|
+
let TriggerButton = class TriggerButton extends LitElement {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.lang = 'es';
|
|
16
|
+
this.loading = false;
|
|
17
|
+
this.disabled = false;
|
|
18
|
+
this.label = undefined;
|
|
19
|
+
this.hasError = false;
|
|
20
|
+
}
|
|
21
|
+
render() {
|
|
22
|
+
const t = I18n.t;
|
|
23
|
+
const defaultLabel = this.hasError
|
|
24
|
+
? (t.errors.config || 'Config Error')
|
|
25
|
+
: (this.loading ? t.trigger.loading : (this.label || 'Apolo Pay'));
|
|
26
|
+
return html `
|
|
27
|
+
<div class="button-wrapper">
|
|
28
|
+
${this.hasError ? '' : html `
|
|
29
|
+
<img class="logo-apolo" src="${logoApolo}" alt="Icon" />
|
|
30
|
+
`}
|
|
31
|
+
<button
|
|
32
|
+
?disabled=${this.disabled || this.loading || this.hasError}
|
|
33
|
+
class="${this.hasError ? 'error' : ''}"
|
|
34
|
+
type="button"
|
|
35
|
+
>
|
|
36
|
+
${defaultLabel}
|
|
37
|
+
</button>
|
|
38
|
+
</div>
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
TriggerButton.styles = [
|
|
43
|
+
sharedStyles,
|
|
44
|
+
css `
|
|
45
|
+
:host { display: inline-block; }
|
|
46
|
+
|
|
47
|
+
.button-wrapper {
|
|
48
|
+
--img-size: 24px;
|
|
49
|
+
--gap: 8px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
button {
|
|
53
|
+
position: relative;
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
width: 100%;
|
|
58
|
+
height: 100%;
|
|
59
|
+
padding: 12px 32px;
|
|
60
|
+
|
|
61
|
+
font-size: 0.9rem;
|
|
62
|
+
letter-spacing: 0.5px;
|
|
63
|
+
color: var(--apolo-on-primary);
|
|
64
|
+
|
|
65
|
+
background: #74727225;
|
|
66
|
+
border: none;
|
|
67
|
+
border-radius: 9999px;
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
transition: transform 0.2s, background-color 0.2s;
|
|
70
|
+
|
|
71
|
+
text-indent: var(--img-size);
|
|
72
|
+
mix-blend-mode: difference;
|
|
73
|
+
z-index: 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
button::before {
|
|
77
|
+
content: "";
|
|
78
|
+
position: absolute;
|
|
79
|
+
inset: 0;
|
|
80
|
+
border-radius: 9999px;
|
|
81
|
+
padding: 2px;
|
|
82
|
+
background: linear-gradient(90deg, var(--apolo-primary), #ffffff);
|
|
83
|
+
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
84
|
+
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
85
|
+
-webkit-mask-composite: xor;
|
|
86
|
+
mask-composite: exclude;
|
|
87
|
+
z-index: -1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
button:hover {
|
|
91
|
+
transform: translateY(-1px);
|
|
92
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
93
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.button-wrapper:hover img {
|
|
97
|
+
transform: translateY(calc(-50% - 1px));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
button:active {
|
|
101
|
+
transform: translateY(0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
button:disabled {
|
|
105
|
+
opacity: 0.6;
|
|
106
|
+
cursor: not-allowed;
|
|
107
|
+
filter: grayscale(1);
|
|
108
|
+
transform: none;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
button.error {
|
|
112
|
+
background-color: rgba(239, 68, 68, 0.1);
|
|
113
|
+
color: #ef4444;
|
|
114
|
+
text-indent: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
button.error::before {
|
|
118
|
+
background: linear-gradient(90deg, #ef4444, #fca5a5);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.logo-apolo {
|
|
122
|
+
position: absolute;
|
|
123
|
+
top: 50%;
|
|
124
|
+
left: calc((var(--img-size) / 2) + var(--gap));
|
|
125
|
+
transform: translateY(-50%);
|
|
126
|
+
width: var(--img-size);
|
|
127
|
+
height: var(--img-size);
|
|
128
|
+
margin-right: var(--gap);
|
|
129
|
+
transition: transform 0.2s;
|
|
130
|
+
}
|
|
131
|
+
`
|
|
132
|
+
];
|
|
133
|
+
__decorate([
|
|
134
|
+
property({ type: String })
|
|
135
|
+
], TriggerButton.prototype, "lang", void 0);
|
|
136
|
+
__decorate([
|
|
137
|
+
property({ type: Boolean })
|
|
138
|
+
], TriggerButton.prototype, "loading", void 0);
|
|
139
|
+
__decorate([
|
|
140
|
+
property({ type: Boolean })
|
|
141
|
+
], TriggerButton.prototype, "disabled", void 0);
|
|
142
|
+
__decorate([
|
|
143
|
+
property({ type: String })
|
|
144
|
+
], TriggerButton.prototype, "label", void 0);
|
|
145
|
+
__decorate([
|
|
146
|
+
property({ type: Boolean })
|
|
147
|
+
], TriggerButton.prototype, "hasError", void 0);
|
|
148
|
+
TriggerButton = __decorate([
|
|
149
|
+
customElement('trigger-button')
|
|
150
|
+
], TriggerButton);
|
|
151
|
+
export { TriggerButton };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { ApoloPayClient, type Locale } from '@apolopay-sdk/core';
|
|
3
|
+
import './components/trigger-button.js';
|
|
4
|
+
import './components/payment-modal.js';
|
|
5
|
+
export declare class ApoloPayButton extends LitElement {
|
|
6
|
+
client: ApoloPayClient | undefined;
|
|
7
|
+
processId: string | undefined;
|
|
8
|
+
productTitle?: undefined;
|
|
9
|
+
lang: Locale;
|
|
10
|
+
label?: string;
|
|
11
|
+
loading: boolean;
|
|
12
|
+
disabled: boolean;
|
|
13
|
+
barrierDismissible: boolean;
|
|
14
|
+
willUpdate(changedProperties: Map<string, any>): void;
|
|
15
|
+
private isOpen;
|
|
16
|
+
private status;
|
|
17
|
+
private currentStep;
|
|
18
|
+
private selectedAsset;
|
|
19
|
+
private selectedNetwork;
|
|
20
|
+
private qrCodeUrl;
|
|
21
|
+
private qrCodeExpiresAt;
|
|
22
|
+
private paymentAddress;
|
|
23
|
+
private paymentUrl;
|
|
24
|
+
private assets;
|
|
25
|
+
private error;
|
|
26
|
+
private isLoadingData;
|
|
27
|
+
private amount;
|
|
28
|
+
private hasConfigError;
|
|
29
|
+
private email;
|
|
30
|
+
private _service;
|
|
31
|
+
connectedCallback(): void;
|
|
32
|
+
private initService;
|
|
33
|
+
get isValidProcessId(): boolean;
|
|
34
|
+
private validateConfig;
|
|
35
|
+
disconnectedCallback(): void;
|
|
36
|
+
loadInitialData(): Promise<void>;
|
|
37
|
+
private resetState;
|
|
38
|
+
private handleOpen;
|
|
39
|
+
private handleCloseRequest;
|
|
40
|
+
private handleAssetSelect;
|
|
41
|
+
private handleExpired;
|
|
42
|
+
private handleInitiatePayment;
|
|
43
|
+
private handleChangeStep;
|
|
44
|
+
static styles: import("lit").CSSResult;
|
|
45
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
46
|
+
}
|
|
47
|
+
declare global {
|
|
48
|
+
interface HTMLElementTagNameMap {
|
|
49
|
+
'apolopay-button': ApoloPayButton;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, html, css } from 'lit';
|
|
8
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
9
|
+
import { I18n, ModalStep, PaymentService, } from '@apolopay-sdk/core';
|
|
10
|
+
// Import child components
|
|
11
|
+
import './components/trigger-button.js';
|
|
12
|
+
import './components/payment-modal.js';
|
|
13
|
+
let ApoloPayButton = class ApoloPayButton extends LitElement {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
// --- Component Properties ---
|
|
17
|
+
this.client = undefined;
|
|
18
|
+
this.processId = undefined;
|
|
19
|
+
this.productTitle = undefined;
|
|
20
|
+
this.lang = 'es';
|
|
21
|
+
this.label = undefined;
|
|
22
|
+
this.loading = false;
|
|
23
|
+
this.disabled = false;
|
|
24
|
+
this.barrierDismissible = false;
|
|
25
|
+
// --- Internal State ---
|
|
26
|
+
this.isOpen = false; // Controls modal visibility
|
|
27
|
+
this.status = 'idle'; // General status, used for QR generation and final result
|
|
28
|
+
this.currentStep = ModalStep.SELECT_ASSET; // Current step in the modal flow
|
|
29
|
+
this.selectedAsset = null; // ID of the chosen asset
|
|
30
|
+
this.selectedNetwork = null; // ID of the chosen blockchain
|
|
31
|
+
this.qrCodeUrl = null; // URL for the QR code image
|
|
32
|
+
this.qrCodeExpiresAt = null; // Expiration time for the QR code
|
|
33
|
+
this.paymentAddress = null; // Wallet address for payment
|
|
34
|
+
this.paymentUrl = null; // Direct link for single-device payment
|
|
35
|
+
this.assets = []; // List fetched from API
|
|
36
|
+
this.error = null; // Stores error details if something fails
|
|
37
|
+
this.isLoadingData = true; // Tracks initial loading of assets/networks
|
|
38
|
+
this.amount = 0; // Fetched from processId
|
|
39
|
+
this.hasConfigError = false; // Invalid publicKey or missing client
|
|
40
|
+
this.email = null; // TODO set email from socket response
|
|
41
|
+
this._service = null; // Internal business logic manager
|
|
42
|
+
}
|
|
43
|
+
// Detectar cambios en propiedades
|
|
44
|
+
willUpdate(changedProperties) {
|
|
45
|
+
if (changedProperties.has('lang'))
|
|
46
|
+
I18n.setLocale(this.lang);
|
|
47
|
+
if (changedProperties.has('client') ||
|
|
48
|
+
changedProperties.has('processId')) {
|
|
49
|
+
this.validateConfig();
|
|
50
|
+
if (this.client && this._service === null) {
|
|
51
|
+
this.initService();
|
|
52
|
+
}
|
|
53
|
+
if (this.client && this.processId) {
|
|
54
|
+
this.loadInitialData();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
super.willUpdate(changedProperties);
|
|
58
|
+
}
|
|
59
|
+
// --- API Client Instance ---
|
|
60
|
+
// If the 'client' property is not provided, the component might fail.
|
|
61
|
+
// We no longer manage the client instance internally.
|
|
62
|
+
// --- Lifecycle Methods ---
|
|
63
|
+
// Called when the component is added to the DOM
|
|
64
|
+
connectedCallback() {
|
|
65
|
+
super.connectedCallback();
|
|
66
|
+
this.validateConfig();
|
|
67
|
+
if (this.client) {
|
|
68
|
+
this.initService();
|
|
69
|
+
if (this.processId) {
|
|
70
|
+
this.loadInitialData(); // Fetch assets and blockchains immediately
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
initService() {
|
|
75
|
+
if (!this.client || this.hasConfigError)
|
|
76
|
+
return;
|
|
77
|
+
this._service = new PaymentService(this.client);
|
|
78
|
+
}
|
|
79
|
+
get isValidProcessId() {
|
|
80
|
+
if (!this.processId)
|
|
81
|
+
return false;
|
|
82
|
+
const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
83
|
+
return uuidRegex.test(this.processId);
|
|
84
|
+
}
|
|
85
|
+
validateConfig() {
|
|
86
|
+
const key = this.client?.getPublicKey();
|
|
87
|
+
const isKeyValid = !!(key && key.startsWith('pk_') && key.length === 35);
|
|
88
|
+
if (this.client && !isKeyValid) {
|
|
89
|
+
console.error(`PaymentButton Error: Invalid publicKey "${key}". Must start with "pk_" and be 35 characters long.`);
|
|
90
|
+
}
|
|
91
|
+
this.hasConfigError = !this.client || !isKeyValid;
|
|
92
|
+
}
|
|
93
|
+
// Called when the component is removed from the DOM
|
|
94
|
+
disconnectedCallback() {
|
|
95
|
+
super.disconnectedCallback();
|
|
96
|
+
// Ensure WebSocket is disconnected if the component is removed
|
|
97
|
+
this._service?.disconnectWebSocket();
|
|
98
|
+
}
|
|
99
|
+
// Replaced by external client initialization
|
|
100
|
+
// --- Data Loading ---
|
|
101
|
+
async loadInitialData() {
|
|
102
|
+
if (!this._service)
|
|
103
|
+
return;
|
|
104
|
+
this.isLoadingData = true;
|
|
105
|
+
this.error = null;
|
|
106
|
+
if (!this.processId)
|
|
107
|
+
return;
|
|
108
|
+
try {
|
|
109
|
+
this.assets = await this._service.getAssets();
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
console.error('Error loading initial payment options:', e);
|
|
113
|
+
this.error = { code: 'DATA_LOAD_ERROR', message: 'Could not load payment options.' };
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.isLoadingData = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
resetState() {
|
|
120
|
+
this.currentStep = ModalStep.SELECT_ASSET;
|
|
121
|
+
this.status = 'idle';
|
|
122
|
+
this.error = null;
|
|
123
|
+
this.selectedAsset = null;
|
|
124
|
+
this.selectedNetwork = null;
|
|
125
|
+
this.qrCodeUrl = null;
|
|
126
|
+
this.paymentAddress = null;
|
|
127
|
+
this.paymentUrl = null;
|
|
128
|
+
this.qrCodeExpiresAt = null;
|
|
129
|
+
}
|
|
130
|
+
// --- Event Handlers (Triggered by Child Components) ---
|
|
131
|
+
// Triggered by <trigger-button> when clicked
|
|
132
|
+
handleOpen() {
|
|
133
|
+
this.resetState();
|
|
134
|
+
if (this.hasConfigError || !this.client || !this.processId) {
|
|
135
|
+
console.error('PaymentButton Error: client and process-id are required and must be valid');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (this.loading)
|
|
139
|
+
return;
|
|
140
|
+
this.isOpen = true;
|
|
141
|
+
}
|
|
142
|
+
// Triggered by <payment-modal> requesting to close (X, backdrop, Escape)
|
|
143
|
+
handleCloseRequest() {
|
|
144
|
+
this.isOpen = false;
|
|
145
|
+
// Disconnect WebSocket if the user cancels before payment completion
|
|
146
|
+
if (this.currentStep === ModalStep.SHOW_QR && this.status !== 'success' && this.status !== 'error') {
|
|
147
|
+
this._service?.disconnectWebSocket();
|
|
148
|
+
}
|
|
149
|
+
setTimeout(() => this.resetState(), 300);
|
|
150
|
+
}
|
|
151
|
+
// Triggered by <payment-modal> when an asset is selected
|
|
152
|
+
handleAssetSelect(event) {
|
|
153
|
+
this.selectedAsset = event.detail.assetId;
|
|
154
|
+
this.currentStep = ModalStep.SELECT_NETWORK;
|
|
155
|
+
this.error = null;
|
|
156
|
+
}
|
|
157
|
+
handleExpired(event) {
|
|
158
|
+
this.dispatchEvent(new CustomEvent('error', { detail: event.detail.error }));
|
|
159
|
+
}
|
|
160
|
+
// Triggered by <payment-modal> when a network is selected
|
|
161
|
+
async handleInitiatePayment(event) {
|
|
162
|
+
if (!this.client || !this.processId)
|
|
163
|
+
return;
|
|
164
|
+
this.selectedNetwork = event.detail.networkId;
|
|
165
|
+
if (!this.selectedAsset || !this.selectedNetwork)
|
|
166
|
+
return;
|
|
167
|
+
const detail = {
|
|
168
|
+
assetId: this.selectedAsset,
|
|
169
|
+
networkId: this.selectedNetwork
|
|
170
|
+
};
|
|
171
|
+
this.dispatchEvent(new CustomEvent('generateQr', { detail }));
|
|
172
|
+
this.status = 'loading';
|
|
173
|
+
this.currentStep = ModalStep.SHOW_QR;
|
|
174
|
+
this.qrCodeUrl = null;
|
|
175
|
+
this.paymentAddress = null;
|
|
176
|
+
this.error = null;
|
|
177
|
+
try {
|
|
178
|
+
const qrData = await this._service.fetchQrCodeDetails(detail, {
|
|
179
|
+
processId: this.processId,
|
|
180
|
+
onSuccess: (response) => {
|
|
181
|
+
if (!this.isOpen)
|
|
182
|
+
return;
|
|
183
|
+
this.status = 'success';
|
|
184
|
+
this.currentStep = ModalStep.RESULT;
|
|
185
|
+
this.dispatchEvent(new CustomEvent('success', { detail: response }));
|
|
186
|
+
},
|
|
187
|
+
onError: (error) => {
|
|
188
|
+
if (!this.isOpen)
|
|
189
|
+
return;
|
|
190
|
+
this.status = 'error';
|
|
191
|
+
this.error = error;
|
|
192
|
+
this.currentStep = ModalStep.RESULT;
|
|
193
|
+
this.dispatchEvent(new CustomEvent('error', { detail: error }));
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
this.qrCodeUrl = qrData.qrCodeUrl;
|
|
197
|
+
this.paymentAddress = qrData.address;
|
|
198
|
+
this.paymentUrl = qrData.paymentUrl || null;
|
|
199
|
+
this.qrCodeExpiresAt = qrData.expiresAtMs;
|
|
200
|
+
this.amount = typeof qrData.amount === 'string' ? parseFloat(qrData.amount) : qrData.amount;
|
|
201
|
+
this.status = 'idle';
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
console.error("Error fetching QR code details:", e);
|
|
205
|
+
this.error = { code: 'QR_FETCH_ERROR', message: (e instanceof Error ? e.message : 'Failed to get payment details.') };
|
|
206
|
+
this.status = 'error';
|
|
207
|
+
this.currentStep = ModalStep.SELECT_NETWORK;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Triggered by <payment-modal> "Back" buttons
|
|
211
|
+
handleChangeStep(event) {
|
|
212
|
+
// Disconnect WebSocket if going back from QR step before completion
|
|
213
|
+
if (this.currentStep === ModalStep.SHOW_QR && event.detail !== ModalStep.RESULT) {
|
|
214
|
+
this._service?.disconnectWebSocket();
|
|
215
|
+
}
|
|
216
|
+
this.currentStep = event.detail;
|
|
217
|
+
this.status = 'idle'; // Reset status when moving back
|
|
218
|
+
this.error = null;
|
|
219
|
+
// Clear QR data if moving back from the QR step
|
|
220
|
+
if (this.currentStep !== ModalStep.SHOW_QR) {
|
|
221
|
+
this.qrCodeUrl = null;
|
|
222
|
+
this.paymentAddress = null;
|
|
223
|
+
this.paymentUrl = null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// --- Render Method ---
|
|
227
|
+
render() {
|
|
228
|
+
// Renders the trigger button and the modal, passing down all necessary state
|
|
229
|
+
return html `
|
|
230
|
+
<div id="trigger-wrapper" @click=${this.handleOpen}>
|
|
231
|
+
<slot>
|
|
232
|
+
<trigger-button
|
|
233
|
+
.lang=${this.lang}
|
|
234
|
+
.label=${this.label}
|
|
235
|
+
.loading=${this.loading ||
|
|
236
|
+
(this.isLoadingData && !this.hasConfigError) ||
|
|
237
|
+
!this.isValidProcessId}
|
|
238
|
+
.hasError=${this.hasConfigError}
|
|
239
|
+
?disabled=${this.disabled ||
|
|
240
|
+
this.hasConfigError ||
|
|
241
|
+
!this.isValidProcessId}
|
|
242
|
+
></trigger-button>
|
|
243
|
+
</slot>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
<payment-modal
|
|
247
|
+
?isOpen=${this.isOpen}
|
|
248
|
+
.barrierDismissible=${this.barrierDismissible}
|
|
249
|
+
.lang=${this.lang}
|
|
250
|
+
.currentStep=${this.currentStep}
|
|
251
|
+
.status=${this.status}
|
|
252
|
+
.productTitle=${this.productTitle}
|
|
253
|
+
.error=${this.error}
|
|
254
|
+
.isLoadingData=${this.isLoadingData}
|
|
255
|
+
.assets=${this.assets}
|
|
256
|
+
.selectedAsset=${this.selectedAsset}
|
|
257
|
+
.selectedNetwork=${this.selectedNetwork}
|
|
258
|
+
.qrCodeUrl=${this.qrCodeUrl}
|
|
259
|
+
.paymentAddress=${this.paymentAddress}
|
|
260
|
+
.amount=${this.amount}
|
|
261
|
+
.email=${this.email}
|
|
262
|
+
.qrCodeExpiresAt=${this.qrCodeExpiresAt}
|
|
263
|
+
.paymentUrl=${this.paymentUrl}
|
|
264
|
+
@closeRequest=${this.handleCloseRequest}
|
|
265
|
+
@assetSelect=${this.handleAssetSelect}
|
|
266
|
+
@networkSelect=${this.handleInitiatePayment}
|
|
267
|
+
@changeStep=${this.handleChangeStep}
|
|
268
|
+
@expired=${this.handleExpired}
|
|
269
|
+
></payment-modal>
|
|
270
|
+
`;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
// --- Styles ---
|
|
274
|
+
ApoloPayButton.styles = css `
|
|
275
|
+
:host {
|
|
276
|
+
display: inline-block;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#trigger-wrapper {
|
|
280
|
+
position: relative;
|
|
281
|
+
display: inline-block;
|
|
282
|
+
cursor: pointer;
|
|
283
|
+
}
|
|
284
|
+
`;
|
|
285
|
+
__decorate([
|
|
286
|
+
property({ type: Object })
|
|
287
|
+
], ApoloPayButton.prototype, "client", void 0);
|
|
288
|
+
__decorate([
|
|
289
|
+
property({ type: String, attribute: 'process-id' })
|
|
290
|
+
], ApoloPayButton.prototype, "processId", void 0);
|
|
291
|
+
__decorate([
|
|
292
|
+
property({ type: String, attribute: 'product-title' })
|
|
293
|
+
], ApoloPayButton.prototype, "productTitle", void 0);
|
|
294
|
+
__decorate([
|
|
295
|
+
property({ type: String })
|
|
296
|
+
], ApoloPayButton.prototype, "lang", void 0);
|
|
297
|
+
__decorate([
|
|
298
|
+
property({ type: String })
|
|
299
|
+
], ApoloPayButton.prototype, "label", void 0);
|
|
300
|
+
__decorate([
|
|
301
|
+
property({ type: Boolean })
|
|
302
|
+
], ApoloPayButton.prototype, "loading", void 0);
|
|
303
|
+
__decorate([
|
|
304
|
+
property({ type: Boolean })
|
|
305
|
+
], ApoloPayButton.prototype, "disabled", void 0);
|
|
306
|
+
__decorate([
|
|
307
|
+
property({
|
|
308
|
+
type: Boolean,
|
|
309
|
+
attribute: 'barrier-dismissible',
|
|
310
|
+
converter: {
|
|
311
|
+
fromAttribute: (value) => {
|
|
312
|
+
if (value === null)
|
|
313
|
+
return false;
|
|
314
|
+
return value !== 'false';
|
|
315
|
+
},
|
|
316
|
+
toAttribute: (value) => value ? '' : null
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
], ApoloPayButton.prototype, "barrierDismissible", void 0);
|
|
320
|
+
__decorate([
|
|
321
|
+
state()
|
|
322
|
+
], ApoloPayButton.prototype, "isOpen", void 0);
|
|
323
|
+
__decorate([
|
|
324
|
+
state()
|
|
325
|
+
], ApoloPayButton.prototype, "status", void 0);
|
|
326
|
+
__decorate([
|
|
327
|
+
state()
|
|
328
|
+
], ApoloPayButton.prototype, "currentStep", void 0);
|
|
329
|
+
__decorate([
|
|
330
|
+
state()
|
|
331
|
+
], ApoloPayButton.prototype, "selectedAsset", void 0);
|
|
332
|
+
__decorate([
|
|
333
|
+
state()
|
|
334
|
+
], ApoloPayButton.prototype, "selectedNetwork", void 0);
|
|
335
|
+
__decorate([
|
|
336
|
+
state()
|
|
337
|
+
], ApoloPayButton.prototype, "qrCodeUrl", void 0);
|
|
338
|
+
__decorate([
|
|
339
|
+
state()
|
|
340
|
+
], ApoloPayButton.prototype, "qrCodeExpiresAt", void 0);
|
|
341
|
+
__decorate([
|
|
342
|
+
state()
|
|
343
|
+
], ApoloPayButton.prototype, "paymentAddress", void 0);
|
|
344
|
+
__decorate([
|
|
345
|
+
state()
|
|
346
|
+
], ApoloPayButton.prototype, "paymentUrl", void 0);
|
|
347
|
+
__decorate([
|
|
348
|
+
state()
|
|
349
|
+
], ApoloPayButton.prototype, "assets", void 0);
|
|
350
|
+
__decorate([
|
|
351
|
+
state()
|
|
352
|
+
], ApoloPayButton.prototype, "error", void 0);
|
|
353
|
+
__decorate([
|
|
354
|
+
state()
|
|
355
|
+
], ApoloPayButton.prototype, "isLoadingData", void 0);
|
|
356
|
+
__decorate([
|
|
357
|
+
state()
|
|
358
|
+
], ApoloPayButton.prototype, "amount", void 0);
|
|
359
|
+
__decorate([
|
|
360
|
+
state()
|
|
361
|
+
], ApoloPayButton.prototype, "hasConfigError", void 0);
|
|
362
|
+
__decorate([
|
|
363
|
+
state()
|
|
364
|
+
], ApoloPayButton.prototype, "email", void 0);
|
|
365
|
+
__decorate([
|
|
366
|
+
state()
|
|
367
|
+
], ApoloPayButton.prototype, "_service", void 0);
|
|
368
|
+
ApoloPayButton = __decorate([
|
|
369
|
+
customElement('apolopay-button')
|
|
370
|
+
], ApoloPayButton);
|
|
371
|
+
export { ApoloPayButton };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const modalBaseStyles: import("lit").CSSResult;
|