breezi-js
Version:
Vanilla JavaScript SDK for Breezi PayPal integration
223 lines (218 loc) • 9.98 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BreeziWidget = {}));
})(this, (function (exports) { 'use strict';
/**
* Vanilla JavaScript Breezi Widget
*/
class BreeziWidget {
constructor(config) {
this.sdkLoaded = false;
this.config = config;
this.logger = {
debug: (message, data) => {
if (this.config.debug && typeof console !== 'undefined' && console.debug) {
console.debug(`[Breezi Debug] ${message}`, data || '');
}
},
error: (message, error) => {
if (typeof console !== 'undefined' && console.error) {
console.error(`[Breezi Error] ${message}`, error || '');
}
},
};
this.validateConfig();
}
validateConfig() {
if (!this.config.environment) {
throw this.createError('Environment is required', 'CONFIG_ERROR', 'MISSING_ENVIRONMENT');
}
if (!['sandbox', 'production'].includes(this.config.environment)) {
throw this.createError('Environment must be "sandbox" or "production"', 'CONFIG_ERROR', 'INVALID_ENVIRONMENT');
}
if (!this.config.providers?.paypal?.clientId) {
throw this.createError('PayPal client ID is required in providers.paypal.clientId', 'CONFIG_ERROR', 'MISSING_PAYPAL_CLIENT_ID');
}
}
createError(message, type, code) {
const error = new Error(message);
error.type = type;
error.code = code;
error.retryable = type === 'NETWORK_ERROR';
return error;
}
/**
* Load PayPal SDK
*/
async loadPayPalSDK(currency) {
return new Promise((resolve, reject) => {
if (window.paypal) {
this.sdkLoaded = true;
resolve();
return;
}
const script = document.createElement('script');
script.src = `https://www.paypal.com/sdk/js?client-id=${this.config.providers.paypal.clientId}¤cy=${currency}&components=buttons`;
script.onload = () => {
this.sdkLoaded = true;
this.logger.debug('PayPal SDK loaded successfully');
resolve();
};
script.onerror = () => {
const error = this.createError('Failed to load PayPal SDK', 'NETWORK_ERROR', 'SDK_LOAD_FAILED');
this.logger.error('PayPal SDK loading failed', error);
reject(error);
};
document.body.appendChild(script);
});
}
/**
* Render PayPal button in the specified container
*/
async renderPayPalButton(containerId, options) {
try {
// Validate inputs
if (!containerId) {
throw this.createError('Container ID is required', 'VALIDATION_ERROR', 'MISSING_CONTAINER_ID');
}
if (!options.amount || options.amount <= 0) {
throw this.createError('Amount must be greater than 0', 'VALIDATION_ERROR', 'INVALID_AMOUNT');
}
if (!options.currency || options.currency.length !== 3) {
throw this.createError('Currency must be a valid 3-letter ISO code', 'VALIDATION_ERROR', 'INVALID_CURRENCY');
}
const container = document.getElementById(containerId);
if (!container) {
throw this.createError(`Container with ID "${containerId}" not found`, 'VALIDATION_ERROR', 'CONTAINER_NOT_FOUND');
}
// Load PayPal SDK if not already loaded
if (!this.sdkLoaded) {
await this.loadPayPalSDK(options.currency);
}
// Clear container
container.innerHTML = '';
this.logger.debug('Rendering PayPal button', { containerId, options });
// Render PayPal button
window.paypal.Buttons({
createOrder: (data, actions) => {
this.logger.debug('Creating PayPal order');
return actions.order.create({
purchase_units: [{
amount: {
value: options.amount.toString(),
currency_code: options.currency
},
description: options.description || `Payment of ${options.currency} ${options.amount}`
}]
});
},
onApprove: async (data, actions) => {
try {
this.logger.debug('Payment approved, capturing...');
const orderData = await actions.order.capture();
this.logger.debug('Payment captured successfully:', orderData);
const result = {
id: orderData.id,
status: 'completed',
amount: options.amount,
currency: options.currency,
provider: 'paypal',
createdAt: new Date().toISOString(),
details: orderData
};
options.onSuccess?.(result);
}
catch (error) {
this.logger.error('Payment capture failed:', error);
const breeziError = this.createError('Payment capture failed', 'PROVIDER_ERROR', 'CAPTURE_FAILED');
options.onError?.(breeziError);
}
},
onCancel: () => {
this.logger.debug('Payment cancelled by user');
options.onCancel?.();
},
onError: (err) => {
this.logger.error('PayPal SDK error:', err);
const breeziError = this.createError('PayPal error occurred', 'PROVIDER_ERROR', 'PAYPAL_ERROR');
options.onError?.(breeziError);
},
style: {
color: 'blue',
shape: 'rect',
label: 'paypal',
height: 40,
},
}).render(container);
}
catch (error) {
this.logger.error('Failed to render PayPal button:', error);
throw error;
}
}
/**
* Create a simple payment button with custom styling
*/
createPaymentButton(containerId, options) {
const container = document.getElementById(containerId);
if (!container) {
throw this.createError(`Container with ID "${containerId}" not found`, 'VALIDATION_ERROR', 'CONTAINER_NOT_FOUND');
}
const button = document.createElement('button');
button.textContent = options.buttonText || `Pay ${options.currency} ${options.amount}`;
// Default styling
Object.assign(button.style, {
padding: '12px 24px',
backgroundColor: '#0070f3',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '16px',
fontWeight: '500',
transition: 'all 0.2s ease',
...options.buttonStyle
});
button.addEventListener('click', () => {
// For now, show message that custom buttons need server implementation
const error = this.createError('Custom payment buttons require server-side implementation. Use renderPayPalButton() for direct PayPal integration.', 'CONFIG_ERROR', 'CUSTOM_BUTTON_NOT_IMPLEMENTED');
options.onError?.(error);
});
container.innerHTML = '';
container.appendChild(button);
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
this.validateConfig();
}
}
// Global factory function for easy usage
function createBreeziWidget(config) {
return new BreeziWidget(config);
}
// Expose globally when loaded as UMD
if (typeof window !== 'undefined') {
window.BreeziWidget = BreeziWidget;
window.createBreeziWidget = createBreeziWidget;
// Auto-initialize if config is available
if (window.BreeziConfig) {
const widget = new BreeziWidget(window.BreeziConfig);
window.breezi = widget;
}
}
exports.BreeziWidget = BreeziWidget;
exports.createBreeziWidget = createBreeziWidget;
exports.default = BreeziWidget;
Object.defineProperty(exports, '__esModule', { value: true });
}));
//# sourceMappingURL=widget.js.map