@voxepay/checkout 0.3.2 → 0.3.3

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/src/voxepay.ts ADDED
@@ -0,0 +1,202 @@
1
+ /**
2
+ * VoxePay - Modern Payment Checkout SDK
3
+ *
4
+ * A beautiful, modern payment modal for the web.
5
+ *
6
+ * @example
7
+ * ```javascript
8
+ * // Initialize VoxePay
9
+ * VoxePay.init({ apiKey: 'pk_live_xxxxx' });
10
+ *
11
+ * // Open checkout
12
+ * VoxePay.checkout({
13
+ * amount: 4999,
14
+ * currency: 'NGN',
15
+ * description: 'Premium Plan',
16
+ * onSuccess: (result) => console.log('Paid!', result),
17
+ * onError: (error) => console.error('Failed', error),
18
+ * });
19
+ * ```
20
+ */
21
+
22
+ import { VoxePayModal } from './components/modal';
23
+ import type { VoxePayConfig, CheckoutOptions, VoxePayTheme } from './types';
24
+
25
+ class VoxePaySDK {
26
+ private config: VoxePayConfig | null = null;
27
+ private currentModal: VoxePayModal | null = null;
28
+ private initialized = false;
29
+
30
+ /**
31
+ * Initialize VoxePay with your configuration
32
+ * @param config - Configuration object with API key and optional settings
33
+ */
34
+ init(config: VoxePayConfig): void {
35
+ if (!config.apiKey) {
36
+ console.error('[VoxePay] API key is required. Get your API key from the VoxePay dashboard: Settings > API Keys');
37
+ return;
38
+ }
39
+
40
+ if (!config.organizationId) {
41
+ console.error('[VoxePay] Organization ID is required. Find it in your VoxePay dashboard.');
42
+ return;
43
+ }
44
+
45
+ this.config = {
46
+ theme: 'dark',
47
+ locale: 'en-US',
48
+ ...config,
49
+ };
50
+ this.initialized = true;
51
+
52
+ // Apply theme
53
+ if (config.theme === 'auto') {
54
+ this.applyAutoTheme();
55
+ } else if (config.theme === 'light') {
56
+ document.documentElement.classList.add('voxepay-light');
57
+ }
58
+
59
+ // Apply custom styles
60
+ if (config.customStyles) {
61
+ this.applyCustomStyles(config.customStyles);
62
+ }
63
+
64
+ console.log('[VoxePay] Initialized successfully');
65
+ }
66
+
67
+ /**
68
+ * Open the checkout modal
69
+ * @param options - Checkout options including amount, currency, and callbacks
70
+ */
71
+ checkout(options: CheckoutOptions): void {
72
+ if (!this.initialized) {
73
+ console.error('[VoxePay] Not initialized. Call VoxePay.init() first.');
74
+ options.onError({
75
+ code: 'NOT_INITIALIZED',
76
+ message: 'VoxePay SDK not initialized. Call VoxePay.init() first.',
77
+ recoverable: false,
78
+ });
79
+ return;
80
+ }
81
+
82
+ if (!options.amount || options.amount <= 0) {
83
+ console.error('[VoxePay] Invalid amount');
84
+ options.onError({
85
+ code: 'INVALID_AMOUNT',
86
+ message: 'Payment amount must be greater than 0',
87
+ recoverable: false,
88
+ });
89
+ return;
90
+ }
91
+
92
+ if (!options.currency) {
93
+ console.error('[VoxePay] Currency is required');
94
+ options.onError({
95
+ code: 'INVALID_CURRENCY',
96
+ message: 'Currency code is required',
97
+ recoverable: false,
98
+ });
99
+ return;
100
+ }
101
+
102
+ // Close any existing modal
103
+ this.closeModal();
104
+
105
+ // Create and open new modal
106
+ this.currentModal = new VoxePayModal({
107
+ ...options,
108
+ _sdkConfig: {
109
+ apiKey: this.config!.apiKey,
110
+ organizationId: this.config!.organizationId,
111
+ baseUrl: this.config!.baseUrl,
112
+ },
113
+ onClose: () => {
114
+ this.currentModal = null;
115
+ options.onClose?.();
116
+ },
117
+ });
118
+
119
+ this.currentModal.open();
120
+ }
121
+
122
+ /**
123
+ * Close the current checkout modal
124
+ */
125
+ closeModal(): void {
126
+ if (this.currentModal) {
127
+ this.currentModal.close();
128
+ this.currentModal = null;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Set the theme
134
+ * @param theme - 'dark', 'light', or 'auto'
135
+ */
136
+ setTheme(theme: 'dark' | 'light' | 'auto'): void {
137
+ document.documentElement.classList.remove('voxepay-light');
138
+
139
+ if (theme === 'light') {
140
+ document.documentElement.classList.add('voxepay-light');
141
+ } else if (theme === 'auto') {
142
+ this.applyAutoTheme();
143
+ }
144
+
145
+ if (this.config) {
146
+ this.config.theme = theme;
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Apply system theme preference
152
+ */
153
+ private applyAutoTheme(): void {
154
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
155
+ if (!prefersDark) {
156
+ document.documentElement.classList.add('voxepay-light');
157
+ }
158
+
159
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
160
+ if (this.config?.theme === 'auto') {
161
+ document.documentElement.classList.toggle('voxepay-light', !e.matches);
162
+ }
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Apply custom CSS variables
168
+ */
169
+ private applyCustomStyles(styles: Partial<VoxePayTheme>): void {
170
+ const root = document.documentElement;
171
+ for (const [key, value] of Object.entries(styles)) {
172
+ if (value) {
173
+ root.style.setProperty(key, value);
174
+ }
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Get the SDK version
180
+ */
181
+ get version(): string {
182
+ return '0.3.0';
183
+ }
184
+
185
+ /**
186
+ * Check if SDK is initialized
187
+ */
188
+ get isInitialized(): boolean {
189
+ return this.initialized;
190
+ }
191
+ }
192
+
193
+ // Create singleton instance
194
+ const VoxePay = new VoxePaySDK();
195
+
196
+ // Export for different module systems
197
+ export { VoxePay, VoxePaySDK };
198
+
199
+ // Make available on window for script tag usage
200
+ if (typeof window !== 'undefined') {
201
+ (window as unknown as { VoxePay: VoxePaySDK }).VoxePay = VoxePay;
202
+ }