@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 +12 -0
- package/README.md +375 -5
- package/dist/__mocks__/ui.d.ts +12 -0
- package/dist/__mocks__/ui.d.ts.map +1 -0
- package/dist/api.d.ts +26 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/briefcase.svg +1 -0
- package/dist/building.svg +1 -0
- package/dist/cross.svg +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.es.js +433 -340
- package/dist/index.umd.js +3 -3
- package/dist/medal.svg +1 -0
- package/dist/plane.svg +1 -0
- package/dist/scale.svg +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui.d.ts +11 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/umbrella.svg +1 -0
- package/dist/users.svg +1 -0
- package/dist/validateOptions.d.ts +3 -0
- package/dist/validateOptions.d.ts.map +1 -0
- package/package.json +22 -3
- package/.turbo/turbo-build.log +0 -13
- package/src/api.js +0 -154
- package/src/index.js +0 -366
- package/src/styles.css +0 -411
- package/src/ui.js +0 -209
- package/src/validateOptions.js +0 -253
- package/vite.config.js +0 -17
package/src/validateOptions.js
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
const apiEndpoint = {
|
|
2
|
-
sandbox: "https://api.sandbox.getspot.com/v1/quote",
|
|
3
|
-
production: "https://api.getspot.com/v1/quote",
|
|
4
|
-
local: "http://localhost:3999/api/v1/quote"
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export function validateOptions(options) {
|
|
8
|
-
const {
|
|
9
|
-
apiConfig = {},
|
|
10
|
-
quoteRequestData,
|
|
11
|
-
callbacks = {},
|
|
12
|
-
location,
|
|
13
|
-
theme,
|
|
14
|
-
} = options;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const {
|
|
18
|
-
environment = "sandbox",
|
|
19
|
-
partnerId,
|
|
20
|
-
endpoint: customEndpoint,
|
|
21
|
-
} = apiConfig;
|
|
22
|
-
|
|
23
|
-
if (!partnerId || typeof partnerId !== "string") {
|
|
24
|
-
throw new Error("Invalid or missing partnerId in apiConfig");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const endpoint = customEndpoint || apiEndpoint[environment];
|
|
28
|
-
|
|
29
|
-
if (!endpoint) {
|
|
30
|
-
throw new Error(`Invalid environment in apiConfig: ${environment}`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (!quoteRequestData || (typeof quoteRequestData !== "object" && !Array.isArray(quoteRequestData))) {
|
|
34
|
-
throw new Error("quoteRequestData must be a non-null object or array");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const requiredFields = [
|
|
38
|
-
"startDate",
|
|
39
|
-
"endDate",
|
|
40
|
-
"currencyCode",
|
|
41
|
-
"eventType",
|
|
42
|
-
"productType",
|
|
43
|
-
"productDuration",
|
|
44
|
-
"productPrice",
|
|
45
|
-
"productId",
|
|
46
|
-
"cartId",
|
|
47
|
-
"productName",
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
function validateQuoteItem(item, index = null) {
|
|
51
|
-
const prefix = index !== null ? `quoteRequestData[${index}]` : "quoteRequestData";
|
|
52
|
-
|
|
53
|
-
requiredFields.forEach((field) => {
|
|
54
|
-
if (
|
|
55
|
-
!Object.prototype.hasOwnProperty.call(item, field) ||
|
|
56
|
-
item[field] === undefined ||
|
|
57
|
-
item[field] === null
|
|
58
|
-
) {
|
|
59
|
-
throw new Error(`Missing required ${prefix} field: '${field}'`);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
64
|
-
if (!iso8601Regex.test(item.startDate)) {
|
|
65
|
-
throw new Error(`${prefix}.startDate must be a valid ISO8601 string`);
|
|
66
|
-
}
|
|
67
|
-
if (!iso8601Regex.test(item.endDate)) {
|
|
68
|
-
throw new Error(`${prefix}.endDate must be a valid ISO8601 string`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (typeof item.currencyCode !== "string") {
|
|
72
|
-
throw new Error(`${prefix}.currencyCode must be a string`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const validCurrencyCodes = ["USD", "CAD", "AUD"];
|
|
76
|
-
if (!validCurrencyCodes.includes(item.currencyCode)) {
|
|
77
|
-
throw new Error(`Invalid ${prefix}.currencyCode: ${item.currencyCode}`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (typeof item.eventType !== "string") {
|
|
81
|
-
throw new Error(`${prefix}.eventType must be a string`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (typeof item.productType !== "string") {
|
|
85
|
-
throw new Error(`${prefix}.productType must be a string`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const validProductTypes = ["Pass", "Trip", "Registration"];
|
|
89
|
-
if (!validProductTypes.includes(item.productType)) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
`${prefix}.productType must be one of ${validProductTypes.join(", ")}`
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (typeof item.productDuration !== "string") {
|
|
96
|
-
throw new Error(`${prefix}.productDuration must be a string`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const validDurations = ["Daily", "Seasonal", "Trip", "Event"];
|
|
100
|
-
if (!validDurations.includes(item.productDuration)) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`${prefix}.productDuration must be one of ${validDurations.join(", ")}`
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
typeof item.productPrice !== "number" ||
|
|
108
|
-
isNaN(item.productPrice)
|
|
109
|
-
) {
|
|
110
|
-
throw new Error(`${prefix}.productPrice must be a valid number`);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (typeof item.productId !== "string") {
|
|
114
|
-
throw new Error(`${prefix}.productId must be a string`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (typeof item.cartId !== "string") {
|
|
118
|
-
throw new Error(`${prefix}.cartId must be a string`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (typeof item.productName !== "string") {
|
|
122
|
-
throw new Error(`${prefix}.productName must be a string`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Check if it's a batch quote format
|
|
127
|
-
if (quoteRequestData.cartInfo && quoteRequestData.items) {
|
|
128
|
-
// Validate batch format
|
|
129
|
-
const { cartInfo, items } = quoteRequestData;
|
|
130
|
-
|
|
131
|
-
if (!cartInfo || typeof cartInfo !== "object") {
|
|
132
|
-
throw new Error("quoteRequestData.cartInfo must be a non-null object");
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Validate cart-level fields
|
|
136
|
-
if (!cartInfo.cartId || typeof cartInfo.cartId !== "string") {
|
|
137
|
-
throw new Error("quoteRequestData.cartInfo.cartId must be a string");
|
|
138
|
-
}
|
|
139
|
-
if (!cartInfo.cartName || typeof cartInfo.cartName !== "string") {
|
|
140
|
-
throw new Error("quoteRequestData.cartInfo.cartName must be a string");
|
|
141
|
-
}
|
|
142
|
-
if (!cartInfo.currencyCode || typeof cartInfo.currencyCode !== "string") {
|
|
143
|
-
throw new Error("quoteRequestData.cartInfo.currencyCode must be a string");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const validCurrencyCodes = ["USD", "CAD", "AUD"];
|
|
147
|
-
if (!validCurrencyCodes.includes(cartInfo.currencyCode)) {
|
|
148
|
-
throw new Error(`Invalid quoteRequestData.cartInfo.currencyCode: ${cartInfo.currencyCode}`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (!Array.isArray(items) || items.length === 0) {
|
|
152
|
-
throw new Error("quoteRequestData.items must be a non-empty array");
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Validate each item but without cartId and currencyCode since they're at cart level
|
|
156
|
-
const itemRequiredFields = requiredFields.filter(f => f !== "cartId" && f !== "currencyCode");
|
|
157
|
-
|
|
158
|
-
items.forEach((item, index) => {
|
|
159
|
-
if (!item || typeof item !== "object") {
|
|
160
|
-
throw new Error(`quoteRequestData.items[${index}] must be a non-null object`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const prefix = `quoteRequestData.items[${index}]`;
|
|
164
|
-
|
|
165
|
-
itemRequiredFields.forEach((field) => {
|
|
166
|
-
if (!Object.prototype.hasOwnProperty.call(item, field) || item[field] === undefined || item[field] === null) {
|
|
167
|
-
throw new Error(`Missing required ${prefix} field: '${field}'`);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Validate item-specific fields
|
|
172
|
-
const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
173
|
-
if (!iso8601Regex.test(item.startDate)) {
|
|
174
|
-
throw new Error(`${prefix}.startDate must be a valid ISO8601 string`);
|
|
175
|
-
}
|
|
176
|
-
if (!iso8601Regex.test(item.endDate)) {
|
|
177
|
-
throw new Error(`${prefix}.endDate must be a valid ISO8601 string`);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (typeof item.eventType !== "string") {
|
|
181
|
-
throw new Error(`${prefix}.eventType must be a string`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (typeof item.productType !== "string") {
|
|
185
|
-
throw new Error(`${prefix}.productType must be a string`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const validProductTypes = ["Pass", "Trip", "Registration"];
|
|
189
|
-
if (!validProductTypes.includes(item.productType)) {
|
|
190
|
-
throw new Error(`${prefix}.productType must be one of ${validProductTypes.join(", ")}`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (typeof item.productDuration !== "string") {
|
|
194
|
-
throw new Error(`${prefix}.productDuration must be a string`);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const validDurations = ["Daily", "Seasonal", "Trip", "Event"];
|
|
198
|
-
if (!validDurations.includes(item.productDuration)) {
|
|
199
|
-
throw new Error(`${prefix}.productDuration must be one of ${validDurations.join(", ")}`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (typeof item.productPrice !== "number" || isNaN(item.productPrice)) {
|
|
203
|
-
throw new Error(`${prefix}.productPrice must be a valid number`);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (typeof item.productId !== "string") {
|
|
207
|
-
throw new Error(`${prefix}.productId must be a string`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (typeof item.productName !== "string") {
|
|
211
|
-
throw new Error(`${prefix}.productName must be a string`);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
} else if (Array.isArray(quoteRequestData)) {
|
|
215
|
-
// Legacy array format - kept for backward compatibility
|
|
216
|
-
if (quoteRequestData.length === 0) {
|
|
217
|
-
throw new Error("quoteRequestData array cannot be empty");
|
|
218
|
-
}
|
|
219
|
-
quoteRequestData.forEach((item, index) => {
|
|
220
|
-
if (!item || typeof item !== "object") {
|
|
221
|
-
throw new Error(`quoteRequestData[${index}] must be a non-null object`);
|
|
222
|
-
}
|
|
223
|
-
validateQuoteItem(item, index);
|
|
224
|
-
});
|
|
225
|
-
} else {
|
|
226
|
-
// Single quote format
|
|
227
|
-
validateQuoteItem(quoteRequestData);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const callbackNames = [
|
|
231
|
-
"onOptIn",
|
|
232
|
-
"onOptOut",
|
|
233
|
-
"onQuoteRetrieved",
|
|
234
|
-
"onError",
|
|
235
|
-
"noMatchingQuote",
|
|
236
|
-
];
|
|
237
|
-
callbackNames.forEach((cbName) => {
|
|
238
|
-
const cb = callbacks[cbName];
|
|
239
|
-
if (cb && typeof cb !== "function") {
|
|
240
|
-
throw new Error(`Callback '${cbName}' must be a function.`);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
if (typeof location === "string" && !document.querySelector(location)) {
|
|
245
|
-
throw new Error(`Invalid location selector: '${location}'`);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (theme && typeof theme !== "object") {
|
|
249
|
-
throw new Error(
|
|
250
|
-
"Theme must be an object with CSS variables, do not include the '--' prefix"
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
}
|
package/vite.config.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
build: {
|
|
6
|
-
outDir: "dist",
|
|
7
|
-
lib: {
|
|
8
|
-
entry: path.resolve(__dirname, "src/index.js"),
|
|
9
|
-
name: "SpotWidget",
|
|
10
|
-
fileName: (format) => `index.${format}.js`,
|
|
11
|
-
formats: ["umd", "es"],
|
|
12
|
-
},
|
|
13
|
-
rollupOptions: {
|
|
14
|
-
external: [], // no dependencies
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
});
|