@getspot/spot-widget 1.3.0 → 2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @getspot/spot-widget
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 4c59d56: Typescript support
8
+
9
+ ## 1.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 5b3eaaf: add qualifying reasons for pass/trip offers
14
+
3
15
  ## 1.3.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -1,12 +1,382 @@
1
- # Spot Widget
1
+ # @getspot/spot-widget
2
2
 
3
- ## Description
4
- This is a UI component for displaying a quote offer to users in a checkout flow
3
+ Core JavaScript/TypeScript library for integrating Spot's refund guarantee widget into your applications.
5
4
 
6
5
  ## Installation
7
6
 
8
7
  ```bash
9
- npm install --save @getspot/spot-widget
8
+ npm install @getspot/spot-widget
10
9
  ```
11
10
 
12
- ## Usage
11
+ ## Quick Start
12
+
13
+ ```javascript
14
+ import SpotWidget from '@getspot/spot-widget';
15
+
16
+ // Create widget instance
17
+ const widget = new SpotWidget({
18
+ location: '#spot-widget-container', // CSS selector or DOM element
19
+ apiConfig: {
20
+ environment: 'production', // 'sandbox' for testing
21
+ partnerId: 'your-partner-id'
22
+ },
23
+ quoteRequestData: {
24
+ startDate: '2024-01-01T00:00:00Z',
25
+ endDate: '2024-01-07T23:59:59Z',
26
+ currencyCode: 'USD',
27
+ eventType: 'Ski Trip',
28
+ productType: 'Trip',
29
+ productDuration: 'Trip',
30
+ productPrice: 500,
31
+ productId: 'ski-trip-2024',
32
+ cartId: 'cart-123',
33
+ productName: 'Aspen Ski Trip 2024'
34
+ },
35
+ callbacks: {
36
+ onOptIn: (data) => {
37
+ console.log('User opted in:', data);
38
+ // Handle opt-in logic
39
+ },
40
+ onOptOut: (data) => {
41
+ console.log('User opted out:', data);
42
+ // Handle opt-out logic
43
+ },
44
+ onQuoteRetrieved: (quote) => {
45
+ console.log('Quote retrieved:', quote);
46
+ },
47
+ onError: (error) => {
48
+ console.error('Widget error:', error);
49
+ }
50
+ }
51
+ });
52
+ ```
53
+
54
+ ## TypeScript Support
55
+
56
+ This package is written in TypeScript and includes full type definitions.
57
+
58
+ ```typescript
59
+ import SpotWidget, { SpotWidgetOptions, SelectionData, Quote } from '@getspot/spot-widget';
60
+
61
+ const options: SpotWidgetOptions = {
62
+ // ... your configuration
63
+ };
64
+
65
+ const widget = new SpotWidget(options);
66
+ ```
67
+
68
+ ## Configuration
69
+
70
+ ### SpotWidgetOptions
71
+
72
+ | Option | Type | Required | Default | Description |
73
+ |--------|------|----------|---------|-------------|
74
+ | `location` | `string \| HTMLElement` | No | `"body"` | Target element for the widget |
75
+ | `apiConfig` | `ApiConfig` | Yes | - | API configuration |
76
+ | `quoteRequestData` | `QuoteRequestData` | Yes | - | Quote request information |
77
+ | `showTable` | `boolean` | No | `true` | Whether to show payout table |
78
+ | `optInSelected` | `boolean` | No | `false` | Pre-select opt-in option |
79
+ | `theme` | `Theme` | No | - | Custom styling |
80
+ | `callbacks` | `Callbacks` | No | `{}` | Event callbacks |
81
+
82
+ ### ApiConfig
83
+
84
+ ```typescript
85
+ {
86
+ environment: 'production' | 'sandbox' | 'local';
87
+ partnerId: string;
88
+ customEndpoint?: string; // Optional custom API endpoint
89
+ }
90
+ ```
91
+
92
+ ### QuoteRequestData
93
+
94
+ #### Single Product Quote
95
+
96
+ ```typescript
97
+ {
98
+ startDate: string; // ISO 8601 date
99
+ endDate: string; // ISO 8601 date
100
+ currencyCode: 'USD' | 'CAD' | 'AUD';
101
+ eventType: string; // Event description
102
+ productType: 'Pass' | 'Trip' | 'Registration';
103
+ productDuration: 'Daily' | 'Seasonal' | 'Trip' | 'Event';
104
+ productPrice: number; // Price in specified currency
105
+ productId: string; // Unique product identifier
106
+ cartId: string; // Shopping cart identifier
107
+ productName: string; // Human-readable product name
108
+ participantDescription?: string; // Optional participant info
109
+ }
110
+ ```
111
+
112
+ #### Batch Quote (Multiple Products)
113
+
114
+ ```typescript
115
+ {
116
+ cartInfo: {
117
+ cartId: string;
118
+ cartName: string;
119
+ currencyCode: 'USD' | 'CAD' | 'AUD';
120
+ };
121
+ items: Array<{
122
+ // All single product fields except cartId and currencyCode
123
+ cartItemId?: string; // Optional item identifier
124
+ }>;
125
+ }
126
+ ```
127
+
128
+ ## Widget Methods
129
+
130
+ ### updateQuote(newQuoteRequestData)
131
+
132
+ Update the widget with new quote data.
133
+
134
+ ```javascript
135
+ const success = await widget.updateQuote({
136
+ // new quote request data
137
+ });
138
+ console.log('Update successful:', success);
139
+ ```
140
+
141
+ **Returns:** `Promise<boolean>`
142
+
143
+ ### getSelection()
144
+
145
+ Get the current user selection.
146
+
147
+ ```javascript
148
+ const selection = widget.getSelection();
149
+ console.log('User selection:', selection);
150
+ ```
151
+
152
+ **Returns:** `SelectionData | null`
153
+
154
+ ### validateSelection()
155
+
156
+ Check if the user has made a selection.
157
+
158
+ ```javascript
159
+ const isValid = widget.validateSelection();
160
+ if (!isValid) {
161
+ console.log('Please make a selection');
162
+ }
163
+ ```
164
+
165
+ **Returns:** `boolean`
166
+
167
+ ### destroy()
168
+
169
+ Clean up the widget instance.
170
+
171
+ ```javascript
172
+ widget.destroy();
173
+ ```
174
+
175
+ ## Callbacks
176
+
177
+ ### onOptIn(data: SelectionData)
178
+
179
+ Called when user opts into the refund guarantee.
180
+
181
+ ```javascript
182
+ {
183
+ onOptIn: (data) => {
184
+ console.log('Opt-in data:', data);
185
+ // data.status === 'QUOTE_ACCEPTED'
186
+ // data.quoteId - unique quote identifier
187
+ // data.spotPrice - refund guarantee price
188
+ }
189
+ }
190
+ ```
191
+
192
+ ### onOptOut(data: SelectionData)
193
+
194
+ Called when user opts out of the refund guarantee.
195
+
196
+ ```javascript
197
+ {
198
+ onOptOut: (data) => {
199
+ console.log('Opt-out data:', data);
200
+ // data.status === 'QUOTE_DECLINED'
201
+ // data.quoteId - unique quote identifier
202
+ }
203
+ }
204
+ ```
205
+
206
+ ### onQuoteRetrieved(quote: Quote)
207
+
208
+ Called when a quote is successfully retrieved.
209
+
210
+ ```javascript
211
+ {
212
+ onQuoteRetrieved: (quote) => {
213
+ console.log('Quote:', quote);
214
+ // quote.id - quote identifier
215
+ // quote.spotPrice - refund guarantee price
216
+ // quote.communication - display text and labels
217
+ }
218
+ }
219
+ ```
220
+
221
+ ### onError(error: ErrorData)
222
+
223
+ Called when an error occurs.
224
+
225
+ ```javascript
226
+ {
227
+ onError: (error) => {
228
+ console.error('Error:', error);
229
+ // error.message - error description
230
+ // error.status - HTTP status code (if applicable)
231
+ // error.responseBody - API response (if applicable)
232
+ }
233
+ }
234
+ ```
235
+
236
+ ### noMatchingQuote(data)
237
+
238
+ Called when no quote is available for the request.
239
+
240
+ ```javascript
241
+ {
242
+ noMatchingQuote: (data) => {
243
+ console.log('No quote available:', data);
244
+ // Handle case where product isn't eligible
245
+ }
246
+ }
247
+ ```
248
+
249
+ ## Styling
250
+
251
+ Customize the widget appearance using the `theme` option:
252
+
253
+ ```javascript
254
+ const widget = new SpotWidget({
255
+ // ... other options
256
+ theme: {
257
+ primaryColor: '#007bff',
258
+ secondaryColor: '#6c757d',
259
+ borderRadius: '8px',
260
+ fontFamily: 'Arial, sans-serif',
261
+ fontSize: '14px'
262
+ // Any CSS custom properties (without -- prefix)
263
+ }
264
+ });
265
+ ```
266
+
267
+ ## Error Handling
268
+
269
+ Always implement comprehensive error handling:
270
+
271
+ ```javascript
272
+ const widget = new SpotWidget({
273
+ // ... configuration
274
+ callbacks: {
275
+ onError: (error) => {
276
+ // Log for debugging
277
+ console.error('Spot Widget Error:', error);
278
+
279
+ // Handle different error types
280
+ if (error.status === 404) {
281
+ console.log('Product not eligible for refund guarantee');
282
+ } else if (error.status >= 500) {
283
+ console.log('Service temporarily unavailable');
284
+ }
285
+
286
+ // Track in analytics
287
+ if (window.analytics) {
288
+ window.analytics.track('spot_widget_error', {
289
+ message: error.message,
290
+ status: error.status
291
+ });
292
+ }
293
+ },
294
+ noMatchingQuote: (data) => {
295
+ console.log('No refund guarantee available');
296
+ // Hide widget or show alternative messaging
297
+ }
298
+ }
299
+ });
300
+ ```
301
+
302
+ ## Environments
303
+
304
+ ### Sandbox (Development)
305
+
306
+ Use the sandbox environment for testing:
307
+
308
+ ```javascript
309
+ {
310
+ apiConfig: {
311
+ environment: 'sandbox',
312
+ partnerId: 'your-sandbox-partner-id'
313
+ }
314
+ }
315
+ ```
316
+
317
+ ### Production
318
+
319
+ Use the production environment for live applications:
320
+
321
+ ```javascript
322
+ {
323
+ apiConfig: {
324
+ environment: 'production',
325
+ partnerId: 'your-production-partner-id'
326
+ }
327
+ }
328
+ ```
329
+
330
+ ## API Reference
331
+
332
+ This package exports the following types and interfaces:
333
+
334
+ ### Interfaces
335
+
336
+ - [ApiConfig](docs/interfaces/ApiConfig.md)
337
+ - [ApiError](docs/interfaces/ApiError.md)
338
+ - [ApiResponse](docs/interfaces/ApiResponse.md)
339
+ - [BatchQuoteItem](docs/interfaces/BatchQuoteItem.md)
340
+ - [BatchQuoteRequest](docs/interfaces/BatchQuoteRequest.md)
341
+ - [Callbacks](docs/interfaces/Callbacks.md)
342
+ - [CartInfo](docs/interfaces/CartInfo.md)
343
+ - [Communication](docs/interfaces/Communication.md)
344
+ - [ElementOptions](docs/interfaces/ElementOptions.md)
345
+ - [PayoutScheduleItem](docs/interfaces/PayoutScheduleItem.md)
346
+ - [QualifyingReason](docs/interfaces/QualifyingReason.md)
347
+ - [Quote](docs/interfaces/Quote.md)
348
+ - [QuoteItem](docs/interfaces/QuoteItem.md)
349
+ - [QuoteMetadata](docs/interfaces/QuoteMetadata.md)
350
+ - [SelectionData](docs/interfaces/SelectionData.md)
351
+ - [SpotWidgetOptions](docs/interfaces/SpotWidgetOptions.md)
352
+ - [Theme](docs/interfaces/Theme.md)
353
+
354
+ ### Type Aliases
355
+
356
+ - [QuoteRequestData](docs/type-aliases/QuoteRequestData.md)
357
+
358
+ > **📚 Full API Documentation**: See [docs/](docs/) for detailed documentation of all types and interfaces.
359
+
360
+ ## Framework Integration
361
+
362
+ This is the core library. For framework-specific wrappers:
363
+
364
+ - **React**: [@getspot/spot-widget-react](../react)
365
+ - **Vue 3**: [@getspot/spot-widget-vue](../vue)
366
+ - **Vue 2**: [@getspot/spot-widget-vue2](../vue2)
367
+
368
+ ## Browser Support
369
+
370
+ - Modern browsers (ES2020+)
371
+ - Chrome 80+
372
+ - Firefox 74+
373
+ - Safari 13+
374
+ - Edge 80+
375
+
376
+ ## License
377
+
378
+ See the main package for license information.
379
+
380
+ ## Support
381
+
382
+ For support, please contact [support@getspot.com](mailto:support@getspot.com).
@@ -0,0 +1,12 @@
1
+ /// <reference types="jest" />
2
+ export declare const renderHeader: jest.Mock<any, any, any>;
3
+ export declare const renderBenefits: jest.Mock<any, any, any>;
4
+ export declare const renderQualifyingReasons: jest.Mock<any, any, any>;
5
+ export declare const renderPayoutTable: jest.Mock<any, any, any>;
6
+ export declare const renderConsentSection: jest.Mock<any, any, any>;
7
+ export declare const renderError: jest.Mock<any, any, any>;
8
+ export declare const renderNoMatchingQuote: jest.Mock<any, any, any>;
9
+ export declare const addEventListeners: jest.Mock<any, any, any>;
10
+ export declare const toggleOptIn: jest.Mock<any, any, any>;
11
+ export declare const updateQualifyingReasonVisibility: jest.Mock<any, any, any>;
12
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/__mocks__/ui.ts"],"names":[],"mappings":";AAEA,eAAO,MAAM,YAAY,0BAA2D,CAAC;AACrF,eAAO,MAAM,cAAc,0BAAY,CAAC;AACxC,eAAO,MAAM,uBAAuB,0BAAY,CAAC;AACjD,eAAO,MAAM,iBAAiB,0BAAY,CAAC;AAC3C,eAAO,MAAM,oBAAoB,0BAAY,CAAC;AAC9C,eAAO,MAAM,WAAW,0BAAY,CAAC;AACrC,eAAO,MAAM,qBAAqB,0BAAY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,0BAAY,CAAC;AAC3C,eAAO,MAAM,WAAW,0BAAY,CAAC;AACrC,eAAO,MAAM,gCAAgC,0BAAY,CAAC"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import type { ApiResponse, QuoteRequestData, BatchQuoteRequest } from './types.js';
2
+ /**
3
+ * Retrieve quote from Spot API
4
+ * @param endpoint – Spot API URL
5
+ * @param partnerId – partner UUID
6
+ * @param payload – quoteRequestData
7
+ * @returns Promise resolving to API response
8
+ */
9
+ export declare function fetchQuote(endpoint: string, partnerId: string, payload: QuoteRequestData): Promise<ApiResponse>;
10
+ /**
11
+ * Retrieve batch quote from Spot API
12
+ * @param endpoint – Spot API URL
13
+ * @param partnerId – partner UUID
14
+ * @param batchPayload – batch request data with items array
15
+ * @returns Promise resolving to API response
16
+ */
17
+ export declare function fetchBatchQuote(endpoint: string, partnerId: string, batchPayload: any): Promise<ApiResponse>;
18
+ /**
19
+ * Retrieve multiple quotes in parallel from Spot API
20
+ * @param endpoint – Spot API URL
21
+ * @param partnerId – partner UUID
22
+ * @param batchData – batch quote data with cartInfo and items
23
+ * @returns Promise resolving to formatted API response
24
+ */
25
+ export declare function fetchMultipleQuotes(endpoint: string, partnerId: string, batchData: BatchQuoteRequest): Promise<ApiResponse>;
26
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAY,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7F;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,CAwBtB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,GAAG,GAChB,OAAO,CAAC,WAAW,CAAC,CAyBtB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAAC,WAAW,CAAC,CA8EtB"}
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-briefcase-icon lucide-briefcase"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/><rect width="20" height="14" x="2" y="6" rx="2"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-building2-icon lucide-building-2"><path d="M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z"/><path d="M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2"/><path d="M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2"/><path d="M10 6h4"/><path d="M10 10h4"/><path d="M10 14h4"/><path d="M10 18h4"/></svg>
package/dist/cross.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cross-icon lucide-cross"><path d="M4 9a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h4a1 1 0 0 1 1 1v4a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2v-4a1 1 0 0 1 1-1h4a2 2 0 0 0 2-2v-2a2 2 0 0 0-2-2h-4a1 1 0 0 1-1-1V4a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2v4a1 1 0 0 1-1 1z"/></svg>
@@ -0,0 +1,25 @@
1
+ import type { SpotWidgetOptions, SelectionData } from "./types.js";
2
+ declare class SpotWidget {
3
+ private options;
4
+ private root;
5
+ private currentSelection;
6
+ private container?;
7
+ private paymentTermsEl?;
8
+ private errorEl?;
9
+ private quote?;
10
+ private _onResize;
11
+ constructor(options?: Partial<SpotWidgetOptions>);
12
+ private _init;
13
+ private _renderWidget;
14
+ private _updateLayout;
15
+ private _setupOptionListeners;
16
+ showSelectionError(): void;
17
+ hideSelectionError(): void;
18
+ validateSelection(): boolean;
19
+ updateQuote(newQuoteRequestData: SpotWidgetOptions['quoteRequestData']): Promise<boolean>;
20
+ getSelection(): SelectionData | null;
21
+ destroy(): void;
22
+ }
23
+ export default SpotWidget;
24
+ export type { SpotWidgetOptions, SelectionData, Quote, ApiConfig, QuoteRequestData, QuoteItem, BatchQuoteItem, BatchQuoteRequest, CartInfo, QualifyingReason, PayoutScheduleItem, Communication, ApiResponse, ApiError, ElementOptions, QuoteMetadata, Callbacks, Theme } from './types.js';
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAS,aAAa,EAAqB,MAAM,YAAY,CAAC;AAkB7F,cAAM,UAAU;IACd,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,SAAS,CAAC,CAAc;IAChC,OAAO,CAAC,cAAc,CAAC,CAAc;IACrC,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,SAAS,CAAa;gBAElB,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM;YAqBtC,KAAK;IAgFnB,OAAO,CAAC,aAAa;IAiDrB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,qBAAqB;IA6F7B,kBAAkB,IAAI,IAAI;IAgB1B,kBAAkB,IAAI,IAAI;IAM1B,iBAAiB,IAAI,OAAO;IAgBtB,WAAW,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAqE/F,YAAY,IAAI,aAAa,GAAG,IAAI;IAiCpC,OAAO,IAAI,IAAI;CAMhB;AAED,eAAe,UAAU,CAAC;AAC1B,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,KAAK,EACL,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,QAAQ,EACR,cAAc,EACd,aAAa,EACb,SAAS,EACT,KAAK,EACN,MAAM,YAAY,CAAC"}