canvasframework 0.4.4 → 0.4.5
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/components/QRCodeReader.js +2 -2
- package/components/TimePicker.js +2 -2
- package/index.js +10 -1
- package/package.json +1 -1
- package/utils/FirebaseAuth.js +653 -0
- package/utils/FirebaseCore.js +246 -0
- package/utils/FirebaseFirestore.js +581 -0
- package/utils/FirebaseFunctions.js +97 -0
- package/utils/FirebaseRealtimeDB.js +498 -0
- package/utils/FirebaseStorage.js +612 -0
- package/utils/PayPalPayment.js +678 -0
- package/utils/StripePayment.js +552 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PayPalPayment - Utilitaire pour gérer les paiements PayPal
|
|
3
|
+
* Version avec création/suppression automatique des éléments DOM
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const paypal = new PayPalPayment('YOUR_CLIENT_ID');
|
|
7
|
+
* await paypal.initialize();
|
|
8
|
+
* await paypal.createTemporaryButton({
|
|
9
|
+
* amount: '50.00',
|
|
10
|
+
* currency: 'EUR'
|
|
11
|
+
* });
|
|
12
|
+
*/
|
|
13
|
+
class PayPalPayment {
|
|
14
|
+
constructor(clientId, options = {}) {
|
|
15
|
+
this.clientId = clientId;
|
|
16
|
+
this.currency = options.currency || 'EUR';
|
|
17
|
+
this.locale = options.locale || 'fr_FR';
|
|
18
|
+
this.intent = options.intent || 'capture';
|
|
19
|
+
this.environment = options.environment || 'sandbox';
|
|
20
|
+
|
|
21
|
+
// Callbacks
|
|
22
|
+
this.onPaymentSuccess = options.onPaymentSuccess || null;
|
|
23
|
+
this.onPaymentError = options.onPaymentError || null;
|
|
24
|
+
this.onPaymentCancel = options.onPaymentCancel || null;
|
|
25
|
+
this.onPaymentProcessing = options.onPaymentProcessing || null;
|
|
26
|
+
|
|
27
|
+
// Stockage des éléments DOM temporaires
|
|
28
|
+
this.temporaryElements = {
|
|
29
|
+
script: null,
|
|
30
|
+
container: null,
|
|
31
|
+
buttonContainer: null,
|
|
32
|
+
overlay: null
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
this.isInitialized = false;
|
|
36
|
+
this.buttons = [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Créer un élément DOM temporaire
|
|
41
|
+
*/
|
|
42
|
+
createTemporaryElement(tagName, attributes = {}, parent = document.body) {
|
|
43
|
+
if (typeof document === 'undefined') {
|
|
44
|
+
throw new Error('DOM non disponible');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const element = document.createElement(tagName);
|
|
48
|
+
|
|
49
|
+
// Appliquer les attributs
|
|
50
|
+
Object.keys(attributes).forEach(key => {
|
|
51
|
+
if (key === 'style' && typeof attributes[key] === 'object') {
|
|
52
|
+
Object.assign(element.style, attributes[key]);
|
|
53
|
+
} else if (key === 'textContent') {
|
|
54
|
+
element.textContent = attributes[key];
|
|
55
|
+
} else if (key === 'innerHTML') {
|
|
56
|
+
element.innerHTML = attributes[key];
|
|
57
|
+
} else if (key.startsWith('on')) {
|
|
58
|
+
element[key] = attributes[key];
|
|
59
|
+
} else {
|
|
60
|
+
element.setAttribute(key, attributes[key]);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Ajouter au parent
|
|
65
|
+
if (parent) {
|
|
66
|
+
parent.appendChild(element);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return element;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Supprimer un élément DOM temporaire
|
|
74
|
+
*/
|
|
75
|
+
removeTemporaryElement(element) {
|
|
76
|
+
if (element && element.parentNode) {
|
|
77
|
+
element.parentNode.removeChild(element);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Nettoyer tous les éléments DOM temporaires
|
|
83
|
+
*/
|
|
84
|
+
cleanupTemporaryElements() {
|
|
85
|
+
Object.keys(this.temporaryElements).forEach(key => {
|
|
86
|
+
if (this.temporaryElements[key]) {
|
|
87
|
+
this.removeTemporaryElement(this.temporaryElements[key]);
|
|
88
|
+
this.temporaryElements[key] = null;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Fermer les boutons PayPal
|
|
93
|
+
this.buttons.forEach(button => {
|
|
94
|
+
if (button && typeof button.close === 'function') {
|
|
95
|
+
try {
|
|
96
|
+
button.close();
|
|
97
|
+
} catch (e) {
|
|
98
|
+
// Ignorer les erreurs de fermeture
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
this.buttons = [];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Créer un overlay temporaire
|
|
107
|
+
*/
|
|
108
|
+
createOverlay(options = {}) {
|
|
109
|
+
if (this.temporaryElements.overlay) {
|
|
110
|
+
return this.temporaryElements.overlay;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.temporaryElements.overlay = this.createTemporaryElement('div', {
|
|
114
|
+
id: 'paypal-overlay-' + Date.now(),
|
|
115
|
+
style: {
|
|
116
|
+
position: 'fixed',
|
|
117
|
+
top: '0',
|
|
118
|
+
left: '0',
|
|
119
|
+
width: '100%',
|
|
120
|
+
height: '100%',
|
|
121
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
122
|
+
zIndex: '9998',
|
|
123
|
+
display: 'flex',
|
|
124
|
+
justifyContent: 'center',
|
|
125
|
+
alignItems: 'center',
|
|
126
|
+
opacity: '0',
|
|
127
|
+
transition: 'opacity 0.3s ease'
|
|
128
|
+
}
|
|
129
|
+
}, document.body);
|
|
130
|
+
|
|
131
|
+
// Animer l'apparition
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
if (this.temporaryElements.overlay) {
|
|
134
|
+
this.temporaryElements.overlay.style.opacity = '1';
|
|
135
|
+
}
|
|
136
|
+
}, 10);
|
|
137
|
+
|
|
138
|
+
return this.temporaryElements.overlay;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Créer un conteneur modal temporaire
|
|
143
|
+
*/
|
|
144
|
+
createTemporaryModal(options = {}) {
|
|
145
|
+
if (this.temporaryElements.container) {
|
|
146
|
+
return this.temporaryElements.container;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Créer l'overlay
|
|
150
|
+
this.createOverlay();
|
|
151
|
+
|
|
152
|
+
// Créer la modal
|
|
153
|
+
this.temporaryElements.container = this.createTemporaryElement('div', {
|
|
154
|
+
id: 'paypal-modal-' + Date.now(),
|
|
155
|
+
style: {
|
|
156
|
+
position: 'fixed',
|
|
157
|
+
top: '50%',
|
|
158
|
+
left: '50%',
|
|
159
|
+
transform: 'translate(-50%, -50%)',
|
|
160
|
+
backgroundColor: '#fff',
|
|
161
|
+
borderRadius: '12px',
|
|
162
|
+
padding: '30px',
|
|
163
|
+
width: '400px',
|
|
164
|
+
maxWidth: '90%',
|
|
165
|
+
maxHeight: '90%',
|
|
166
|
+
overflow: 'auto',
|
|
167
|
+
zIndex: '9999',
|
|
168
|
+
boxShadow: '0 10px 30px rgba(0, 0, 0, 0.3)',
|
|
169
|
+
opacity: '0',
|
|
170
|
+
transition: 'opacity 0.3s ease, transform 0.3s ease'
|
|
171
|
+
}
|
|
172
|
+
}, document.body);
|
|
173
|
+
|
|
174
|
+
// Ajouter un bouton de fermeture
|
|
175
|
+
const closeButton = this.createTemporaryElement('button', {
|
|
176
|
+
style: {
|
|
177
|
+
position: 'absolute',
|
|
178
|
+
top: '15px',
|
|
179
|
+
right: '15px',
|
|
180
|
+
background: 'none',
|
|
181
|
+
border: 'none',
|
|
182
|
+
fontSize: '24px',
|
|
183
|
+
color: '#666',
|
|
184
|
+
cursor: 'pointer',
|
|
185
|
+
width: '30px',
|
|
186
|
+
height: '30px',
|
|
187
|
+
display: 'flex',
|
|
188
|
+
alignItems: 'center',
|
|
189
|
+
justifyContent: 'center',
|
|
190
|
+
borderRadius: '50%',
|
|
191
|
+
transition: 'background-color 0.2s'
|
|
192
|
+
},
|
|
193
|
+
textContent: '×',
|
|
194
|
+
onmouseover: function() { this.style.backgroundColor = '#f0f0f0'; },
|
|
195
|
+
onmouseout: function() { this.style.backgroundColor = 'transparent'; },
|
|
196
|
+
onclick: () => this.destroyTemporaryModal()
|
|
197
|
+
}, this.temporaryElements.container);
|
|
198
|
+
|
|
199
|
+
// Ajouter un titre
|
|
200
|
+
if (options.title) {
|
|
201
|
+
const title = this.createTemporaryElement('h2', {
|
|
202
|
+
style: {
|
|
203
|
+
margin: '0 0 20px 0',
|
|
204
|
+
color: '#333',
|
|
205
|
+
fontSize: '24px',
|
|
206
|
+
textAlign: 'center'
|
|
207
|
+
},
|
|
208
|
+
textContent: options.title
|
|
209
|
+
}, this.temporaryElements.container);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Animer l'apparition
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
if (this.temporaryElements.container) {
|
|
215
|
+
this.temporaryElements.container.style.opacity = '1';
|
|
216
|
+
this.temporaryElements.container.style.transform = 'translate(-50%, -50%)';
|
|
217
|
+
}
|
|
218
|
+
}, 10);
|
|
219
|
+
|
|
220
|
+
return this.temporaryElements.container;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Détruire la modal temporaire
|
|
225
|
+
*/
|
|
226
|
+
destroyTemporaryModal() {
|
|
227
|
+
if (this.temporaryElements.container) {
|
|
228
|
+
// Animation de disparition
|
|
229
|
+
this.temporaryElements.container.style.opacity = '0';
|
|
230
|
+
this.temporaryElements.container.style.transform = 'translate(-50%, -60%)';
|
|
231
|
+
|
|
232
|
+
setTimeout(() => {
|
|
233
|
+
this.removeTemporaryElement(this.temporaryElements.container);
|
|
234
|
+
this.temporaryElements.container = null;
|
|
235
|
+
}, 300);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (this.temporaryElements.overlay) {
|
|
239
|
+
// Animation de disparition de l'overlay
|
|
240
|
+
this.temporaryElements.overlay.style.opacity = '0';
|
|
241
|
+
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
this.removeTemporaryElement(this.temporaryElements.overlay);
|
|
244
|
+
this.temporaryElements.overlay = null;
|
|
245
|
+
}, 300);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Charger le script PayPal SDK avec gestion temporaire
|
|
251
|
+
*/
|
|
252
|
+
loadPayPalScript() {
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
if (typeof paypal !== 'undefined') {
|
|
255
|
+
resolve();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Vérifier si un script existe déjà
|
|
260
|
+
const existingScript = document.querySelector('script[src*="paypal.com/sdk/js"]');
|
|
261
|
+
if (existingScript) {
|
|
262
|
+
this.temporaryElements.script = existingScript;
|
|
263
|
+
|
|
264
|
+
// Vérifier que PayPal est chargé
|
|
265
|
+
const checkPayPal = () => {
|
|
266
|
+
if (typeof paypal !== 'undefined') {
|
|
267
|
+
resolve();
|
|
268
|
+
} else {
|
|
269
|
+
setTimeout(checkPayPal, 100);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
checkPayPal();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
// Créer le script temporaire
|
|
278
|
+
const scriptUrl = `https://www.paypal.com/sdk/js?client-id=${this.clientId}¤cy=${this.currency}&locale=${this.locale}&intent=${this.intent}`;
|
|
279
|
+
|
|
280
|
+
this.temporaryElements.script = this.createTemporaryElement('script', {
|
|
281
|
+
src: scriptUrl,
|
|
282
|
+
async: true,
|
|
283
|
+
onload: () => {
|
|
284
|
+
if (typeof paypal === 'undefined') {
|
|
285
|
+
reject(new Error('SDK PayPal chargé mais non défini'));
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
resolve();
|
|
289
|
+
},
|
|
290
|
+
onerror: () => {
|
|
291
|
+
reject(new Error('Échec du chargement du SDK PayPal'));
|
|
292
|
+
this.cleanupTemporaryElements();
|
|
293
|
+
}
|
|
294
|
+
}, document.head);
|
|
295
|
+
|
|
296
|
+
} catch (error) {
|
|
297
|
+
reject(error);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Initialiser PayPal SDK
|
|
304
|
+
*/
|
|
305
|
+
async initialize() {
|
|
306
|
+
if (this.isInitialized) return;
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
await this.loadPayPalScript();
|
|
310
|
+
this.isInitialized = true;
|
|
311
|
+
console.log('✅ PayPal initialisé');
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error('❌ Erreur initialisation PayPal:', error);
|
|
314
|
+
this.cleanupTemporaryElements();
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Créer un bouton PayPal dans un conteneur temporaire
|
|
321
|
+
*/
|
|
322
|
+
async createTemporaryButton(orderData) {
|
|
323
|
+
if (!this.isInitialized) {
|
|
324
|
+
await this.initialize();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
// Créer la modal temporaire
|
|
329
|
+
const modal = this.createTemporaryModal({
|
|
330
|
+
title: orderData.title || 'Paiement sécurisé'
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Créer un conteneur pour le bouton
|
|
334
|
+
this.temporaryElements.buttonContainer = this.createTemporaryElement('div', {
|
|
335
|
+
id: 'paypal-button-container-' + Date.now(),
|
|
336
|
+
style: {
|
|
337
|
+
margin: '20px 0',
|
|
338
|
+
minHeight: '50px'
|
|
339
|
+
}
|
|
340
|
+
}, modal);
|
|
341
|
+
|
|
342
|
+
// Créer le bouton PayPal
|
|
343
|
+
const button = paypal.Buttons({
|
|
344
|
+
style: orderData.style || {
|
|
345
|
+
layout: 'vertical',
|
|
346
|
+
color: 'gold',
|
|
347
|
+
shape: 'rect',
|
|
348
|
+
label: 'paypal',
|
|
349
|
+
height: 45
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
// Créer la commande
|
|
353
|
+
createOrder: async (data, actions) => {
|
|
354
|
+
if (this.onPaymentProcessing) {
|
|
355
|
+
this.onPaymentProcessing();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
// Si serverUrl fourni, créer la commande côté serveur
|
|
360
|
+
if (orderData.serverUrl) {
|
|
361
|
+
const response = await fetch(orderData.serverUrl, {
|
|
362
|
+
method: 'POST',
|
|
363
|
+
headers: { 'Content-Type': 'application/json' },
|
|
364
|
+
body: JSON.stringify({
|
|
365
|
+
amount: orderData.amount,
|
|
366
|
+
currency: orderData.currency || this.currency,
|
|
367
|
+
description: orderData.description || '',
|
|
368
|
+
items: orderData.items || []
|
|
369
|
+
})
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
const data = await response.json();
|
|
373
|
+
return data.orderID;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Sinon, créer la commande directement
|
|
377
|
+
return actions.order.create({
|
|
378
|
+
purchase_units: [{
|
|
379
|
+
amount: {
|
|
380
|
+
currency_code: orderData.currency || this.currency,
|
|
381
|
+
value: orderData.amount,
|
|
382
|
+
breakdown: orderData.breakdown || undefined
|
|
383
|
+
},
|
|
384
|
+
description: orderData.description || '',
|
|
385
|
+
items: orderData.items || undefined,
|
|
386
|
+
shipping: orderData.shipping || undefined
|
|
387
|
+
}],
|
|
388
|
+
application_context: {
|
|
389
|
+
brand_name: orderData.brandName || '',
|
|
390
|
+
shipping_preference: orderData.shippingPreference || 'NO_SHIPPING'
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
} catch (error) {
|
|
395
|
+
console.error('❌ Erreur createOrder:', error);
|
|
396
|
+
if (this.onPaymentError) {
|
|
397
|
+
this.onPaymentError(error);
|
|
398
|
+
}
|
|
399
|
+
throw error;
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
|
|
403
|
+
// Approuver le paiement
|
|
404
|
+
onApprove: async (data, actions) => {
|
|
405
|
+
try {
|
|
406
|
+
// Capturer le paiement
|
|
407
|
+
const details = await actions.order.capture();
|
|
408
|
+
|
|
409
|
+
console.log('✅ Paiement PayPal réussi:', details);
|
|
410
|
+
|
|
411
|
+
// Appeler le callback de succès
|
|
412
|
+
if (this.onPaymentSuccess) {
|
|
413
|
+
this.onPaymentSuccess(details);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Nettoyer la modal après succès
|
|
417
|
+
setTimeout(() => {
|
|
418
|
+
this.destroyTemporaryModal();
|
|
419
|
+
}, 1000);
|
|
420
|
+
|
|
421
|
+
// Notifier le serveur si serverUrl fourni
|
|
422
|
+
if (orderData.onApproveUrl) {
|
|
423
|
+
await fetch(orderData.onApproveUrl, {
|
|
424
|
+
method: 'POST',
|
|
425
|
+
headers: { 'Content-Type': 'application/json' },
|
|
426
|
+
body: JSON.stringify({
|
|
427
|
+
orderID: data.orderID,
|
|
428
|
+
details: details
|
|
429
|
+
})
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return details;
|
|
434
|
+
|
|
435
|
+
} catch (error) {
|
|
436
|
+
console.error('❌ Erreur onApprove:', error);
|
|
437
|
+
if (this.onPaymentError) {
|
|
438
|
+
this.onPaymentError(error);
|
|
439
|
+
}
|
|
440
|
+
throw error;
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
// Annulation du paiement
|
|
445
|
+
onCancel: (data) => {
|
|
446
|
+
console.log('⚠️ Paiement annulé:', data);
|
|
447
|
+
if (this.onPaymentCancel) {
|
|
448
|
+
this.onPaymentCancel(data);
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
|
|
452
|
+
// Erreur
|
|
453
|
+
onError: (err) => {
|
|
454
|
+
console.error('❌ Erreur PayPal:', err);
|
|
455
|
+
if (this.onPaymentError) {
|
|
456
|
+
this.onPaymentError(err);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// Rendre le bouton
|
|
462
|
+
if (button.isEligible()) {
|
|
463
|
+
await button.render(`#${this.temporaryElements.buttonContainer.id}`);
|
|
464
|
+
this.buttons.push(button);
|
|
465
|
+
|
|
466
|
+
// Ajouter un message d'information
|
|
467
|
+
const info = this.createTemporaryElement('p', {
|
|
468
|
+
style: {
|
|
469
|
+
textAlign: 'center',
|
|
470
|
+
color: '#666',
|
|
471
|
+
fontSize: '14px',
|
|
472
|
+
marginTop: '20px'
|
|
473
|
+
},
|
|
474
|
+
textContent: 'Paiement 100% sécurisé par PayPal'
|
|
475
|
+
}, modal);
|
|
476
|
+
|
|
477
|
+
console.log('✅ Bouton PayPal créé dans modal temporaire');
|
|
478
|
+
return button;
|
|
479
|
+
|
|
480
|
+
} else {
|
|
481
|
+
throw new Error('Bouton PayPal non éligible');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
} catch (error) {
|
|
485
|
+
console.error('❌ Erreur création bouton:', error);
|
|
486
|
+
this.cleanupTemporaryElements();
|
|
487
|
+
throw error;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Créer un formulaire de paiement alternatif (cartes bancaires)
|
|
493
|
+
*/
|
|
494
|
+
async createAlternativePaymentForm(orderData) {
|
|
495
|
+
if (!this.isInitialized) {
|
|
496
|
+
await this.initialize();
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
// Créer la modal temporaire
|
|
501
|
+
const modal = this.createTemporaryModal({
|
|
502
|
+
title: 'Paiement par carte bancaire'
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Créer un conteneur pour les boutons de paiement
|
|
506
|
+
this.temporaryElements.buttonContainer = this.createTemporaryElement('div', {
|
|
507
|
+
id: 'paypal-cards-container-' + Date.now(),
|
|
508
|
+
style: {
|
|
509
|
+
margin: '20px 0'
|
|
510
|
+
}
|
|
511
|
+
}, modal);
|
|
512
|
+
|
|
513
|
+
// Créer les boutons PayPal (tous les financements)
|
|
514
|
+
const buttons = paypal.Buttons({
|
|
515
|
+
fundingSource: undefined, // Affiche tous les moyens
|
|
516
|
+
|
|
517
|
+
style: orderData.style || {
|
|
518
|
+
layout: 'vertical',
|
|
519
|
+
color: 'black',
|
|
520
|
+
shape: 'rect',
|
|
521
|
+
label: 'checkout',
|
|
522
|
+
height: 45
|
|
523
|
+
},
|
|
524
|
+
|
|
525
|
+
createOrder: async (data, actions) => {
|
|
526
|
+
return this.createOrder(orderData);
|
|
527
|
+
},
|
|
528
|
+
|
|
529
|
+
onApprove: async (data, actions) => {
|
|
530
|
+
const details = await actions.order.capture();
|
|
531
|
+
|
|
532
|
+
if (this.onPaymentSuccess) {
|
|
533
|
+
this.onPaymentSuccess(details);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
setTimeout(() => {
|
|
537
|
+
this.destroyTemporaryModal();
|
|
538
|
+
}, 1000);
|
|
539
|
+
|
|
540
|
+
return details;
|
|
541
|
+
},
|
|
542
|
+
|
|
543
|
+
onCancel: (data) => {
|
|
544
|
+
if (this.onPaymentCancel) {
|
|
545
|
+
this.onPaymentCancel(data);
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
onError: (err) => {
|
|
550
|
+
if (this.onPaymentError) {
|
|
551
|
+
this.onPaymentError(err);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
await buttons.render(`#${this.temporaryElements.buttonContainer.id}`);
|
|
557
|
+
this.buttons.push(buttons);
|
|
558
|
+
|
|
559
|
+
console.log('✅ Formulaire de paiement alternatif créé');
|
|
560
|
+
return buttons;
|
|
561
|
+
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error('❌ Erreur création formulaire:', error);
|
|
564
|
+
this.cleanupTemporaryElements();
|
|
565
|
+
throw error;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Méthode utilitaire pour créer une commande
|
|
571
|
+
*/
|
|
572
|
+
async createOrder(orderData) {
|
|
573
|
+
if (this.onPaymentProcessing) {
|
|
574
|
+
this.onPaymentProcessing();
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (orderData.serverUrl) {
|
|
578
|
+
const response = await fetch(orderData.serverUrl, {
|
|
579
|
+
method: 'POST',
|
|
580
|
+
headers: { 'Content-Type': 'application/json' },
|
|
581
|
+
body: JSON.stringify({
|
|
582
|
+
amount: orderData.amount,
|
|
583
|
+
currency: orderData.currency || this.currency,
|
|
584
|
+
description: orderData.description || '',
|
|
585
|
+
items: orderData.items || []
|
|
586
|
+
})
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
const data = await response.json();
|
|
590
|
+
return data.orderID;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Création côté client par défaut
|
|
594
|
+
return paypal.rest.payment.create({
|
|
595
|
+
transactions: [{
|
|
596
|
+
amount: {
|
|
597
|
+
total: orderData.amount,
|
|
598
|
+
currency: orderData.currency || this.currency
|
|
599
|
+
}
|
|
600
|
+
}]
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Lancer un paiement PayPal simple
|
|
606
|
+
*/
|
|
607
|
+
async startPaymentFlow(orderData) {
|
|
608
|
+
try {
|
|
609
|
+
// Initialiser PayPal
|
|
610
|
+
await this.initialize();
|
|
611
|
+
|
|
612
|
+
// Créer le bouton dans une modal
|
|
613
|
+
await this.createTemporaryButton(orderData);
|
|
614
|
+
|
|
615
|
+
return {
|
|
616
|
+
success: true,
|
|
617
|
+
message: 'Interface de paiement PayPal prête'
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
} catch (error) {
|
|
621
|
+
console.error('❌ Erreur démarrage paiement:', error);
|
|
622
|
+
this.cleanupTemporaryElements();
|
|
623
|
+
throw error;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Fermer le flux de paiement manuellement
|
|
629
|
+
*/
|
|
630
|
+
closePaymentFlow() {
|
|
631
|
+
this.destroyTemporaryModal();
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Détruire proprement toutes les ressources
|
|
636
|
+
*/
|
|
637
|
+
destroy() {
|
|
638
|
+
// Détruire la modal si elle existe
|
|
639
|
+
this.destroyTemporaryModal();
|
|
640
|
+
|
|
641
|
+
// Nettoyer tous les éléments temporaires
|
|
642
|
+
this.cleanupTemporaryElements();
|
|
643
|
+
|
|
644
|
+
// Réinitialiser l'état
|
|
645
|
+
this.isInitialized = false;
|
|
646
|
+
|
|
647
|
+
console.log('✅ PayPalPayment détruit proprement');
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Détruire avec callback
|
|
652
|
+
*/
|
|
653
|
+
destroyWithCallback(onComplete) {
|
|
654
|
+
this.destroy();
|
|
655
|
+
if (typeof onComplete === 'function') {
|
|
656
|
+
onComplete();
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Méthodes statiques utilitaires
|
|
662
|
+
PayPalPayment.isPayPalSupported = function() {
|
|
663
|
+
return typeof window !== 'undefined' &&
|
|
664
|
+
typeof document !== 'undefined' &&
|
|
665
|
+
typeof paypal !== 'undefined';
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
PayPalPayment.getSupportedFundingSources = function() {
|
|
669
|
+
if (typeof paypal === 'undefined') return [];
|
|
670
|
+
|
|
671
|
+
return paypal.getFundingSources ?
|
|
672
|
+
paypal.getFundingSources().map(source => ({
|
|
673
|
+
source: source,
|
|
674
|
+
eligible: paypal.isFundingEligible ? paypal.isFundingEligible(source) : true
|
|
675
|
+
})) : [];
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
export default PayPalPayment;
|