@getspot/spot-widget 1.4.0 → 2.0.1

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/ui.js DELETED
@@ -1,267 +0,0 @@
1
- export function makeEl(tag, { text, className, parent, innerHTML } = {}) {
2
- const el = document.createElement(tag);
3
- if (className) el.className = className;
4
- if (text != null) el.textContent = text;
5
- if (innerHTML != null) el.innerHTML = innerHTML;
6
- if (parent) parent.appendChild(el);
7
- return el;
8
- }
9
-
10
- // header
11
- export function renderHeader(container, { name, description }) {
12
- makeEl("div", {
13
- className: "spot-header__title",
14
- text: name,
15
- parent: container,
16
- });
17
- makeEl("div", {
18
- className: "spot-header__description",
19
- text: description,
20
- parent: container,
21
- });
22
- }
23
-
24
- // bullet points
25
- export function renderBenefits(container, bullets = []) {
26
- const ul = makeEl("ul", {
27
- className: "spot-benefits__list",
28
- parent: container,
29
- });
30
- bullets.forEach((b) => {
31
- const li = makeEl("li", { parent: ul });
32
- li.innerHTML = `
33
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
34
- <path d="M11.6666 3.5L5.24998 9.91667L2.33331 7"
35
- stroke="#2E2E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
36
- </svg>`;
37
- makeEl("span", { text: b, parent: li });
38
- });
39
- }
40
-
41
- // qualifying reasons
42
- export function renderQualifyingReasons(container, qualifyingReasons = []) {
43
- if (!qualifyingReasons || qualifyingReasons.length === 0) return;
44
-
45
- const wrapper = makeEl("div", {
46
- className: "spot-qualifying-reasons__container",
47
- parent: container,
48
- });
49
-
50
- const sortedReasons = [...qualifyingReasons].sort((a, b) => a.rank - b.rank);
51
-
52
- const grid = makeEl("div", {
53
- className: "spot-qualifying-reasons__grid",
54
- parent: wrapper,
55
- });
56
-
57
- const ICON_MAPPING = {
58
- "Accident & Illness": "cross.svg",
59
- "Family Emergencies": "users.svg",
60
- Layoffs: "building.svg",
61
- "Jury Duty": "scale.svg",
62
- "Work Travel Conflict": "briefcase.svg",
63
- "Severe Weather": "umbrella.svg",
64
- "Travel Interruption": "plane.svg",
65
- "Military Duty": "medal.svg",
66
- };
67
-
68
- // Get the base URL for assets
69
- const scriptUrl = new URL(import.meta.url);
70
- const baseUrl = scriptUrl.origin + scriptUrl.pathname.replace(/\/src\/[^/]*$/, "/assets/");
71
-
72
- sortedReasons.forEach((reason) => {
73
- const reasonEl = makeEl("div", {
74
- className: "spot-qualifying-reasons__item",
75
- parent: grid,
76
- });
77
-
78
- const iconWrapper = makeEl("div", {
79
- className: "spot-qualifying-reasons__icon-wrapper",
80
- parent: reasonEl,
81
- });
82
-
83
- const iconFileName =
84
- ICON_MAPPING[reason.benefitType?.name] || ICON_MAPPING[reason.name];
85
- if (iconFileName) {
86
- const img = makeEl("img", {
87
- parent: iconWrapper,
88
- });
89
- img.src = baseUrl + iconFileName;
90
- img.alt = reason.benefitType?.name || reason.name || "";
91
- img.className = "spot-qualifying-reasons__icon";
92
- }
93
-
94
- makeEl("span", {
95
- className: "spot-qualifying-reasons__label",
96
- text: reason.benefitType?.name || reason.name || "",
97
- parent: reasonEl,
98
- });
99
- });
100
- }
101
-
102
- // covered items for multi-quote
103
- export function renderCoveredItems(container, coveredItems = []) {
104
- if (coveredItems.length === 0) return;
105
-
106
- const wrapper = makeEl("div", {
107
- className: "spot-covered-items__container",
108
- parent: container,
109
- });
110
- makeEl("div", {
111
- className: "spot-covered-items__title",
112
- text: "Items covered in your cart:",
113
- parent: wrapper,
114
- });
115
- const ul = makeEl("ul", {
116
- className: "spot-covered-items__list",
117
- parent: wrapper,
118
- });
119
- coveredItems.forEach((item) => {
120
- const li = makeEl("li", { parent: ul });
121
- makeEl("span", { text: item, parent: li });
122
- });
123
- }
124
-
125
- // payout table
126
- export function renderTable(container, schedule = []) {
127
- const wrapper = makeEl("div", {
128
- className: "spot-table__container",
129
- parent: container,
130
- });
131
- const tbl = makeEl("table", {
132
- className: "spot-refund__table spot-table--dynamic",
133
- parent: wrapper,
134
- });
135
-
136
- const thead = makeEl("thead", { parent: tbl });
137
- const headRow = makeEl("tr", { parent: thead });
138
- makeEl("th", { text: "When you cancel", parent: headRow });
139
- makeEl("th", { text: "You will receive", parent: headRow });
140
-
141
- const tbody = makeEl("tbody", { parent: tbl });
142
- schedule.forEach(({ text, percent, amount }) => {
143
- const row = makeEl("tr", { parent: tbody });
144
- makeEl("td", { text, parent: row });
145
- const amt =
146
- percent === "Not eligible for refund"
147
- ? "Not eligible for a refund"
148
- : `$${amount} refund`;
149
- makeEl("td", { text: amt, parent: row });
150
- });
151
- }
152
-
153
- // radio buttons
154
- export function renderOptions(container, optInSelected, communication) {
155
- const optionsWrapper = makeEl("div", {
156
- className: "spot-selection__options",
157
- parent: container,
158
- });
159
-
160
- // yes
161
- const yesOption = makeEl("label", {
162
- className: `spot-selection__option ${optInSelected ? "selected" : ""}`,
163
- parent: optionsWrapper,
164
- });
165
- const yesInput = makeEl("input", { parent: yesOption });
166
- yesInput.type = "radio";
167
- yesInput.name = "selection";
168
- yesInput.value = "yes";
169
- if (optInSelected) yesInput.checked = true;
170
-
171
- makeEl("strong", {
172
- text: communication.yesOptionText,
173
- parent: yesOption,
174
- });
175
-
176
- makeEl("span", {
177
- className: "spot-selection__recommended-tag",
178
- text: "Recommended",
179
- parent: yesOption,
180
- });
181
-
182
- // no
183
- const noOption = makeEl("label", {
184
- className: "spot-selection__option",
185
- parent: optionsWrapper,
186
- });
187
- const noInput = makeEl("input", { parent: noOption });
188
- noInput.type = "radio";
189
- noInput.name = "selection";
190
- noInput.value = "no";
191
-
192
- makeEl("span", { text: communication.noOptionText, parent: noOption });
193
-
194
- return optionsWrapper;
195
- }
196
-
197
- // payment terms
198
- export function renderPaymentTerms(container, quote) {
199
- const terms = quote.communication?.paymentTerms;
200
-
201
- const wrapper = makeEl("div", {
202
- className: "spot-payment-terms",
203
- parent: container,
204
- });
205
-
206
- makeEl("div", {
207
- className: "spot-payment-terms__header",
208
- text: "PAYMENT TERMS",
209
- parent: wrapper,
210
- });
211
-
212
- makeEl("div", {
213
- className: "spot-payment-terms__body",
214
- text: terms,
215
- parent: wrapper,
216
- });
217
-
218
- return wrapper;
219
- }
220
-
221
- // footer
222
- export function renderFooter(container, quote) {
223
- const footer = makeEl("div", {
224
- className: "spot-footer__container",
225
- parent: container,
226
- });
227
-
228
- const termsDiv = makeEl("div", {
229
- className: "spot-footer__terms",
230
- parent: footer,
231
- });
232
- makeEl("span", {
233
- innerHTML: quote.communication.legalDisclaimer,
234
- parent: termsDiv,
235
- });
236
- makeEl("br", { parent: termsDiv });
237
- makeEl("a", {
238
- href: quote.communication.termsAndConditionsUrl,
239
- target: "_blank",
240
- className: "spot-footer__terms-link",
241
- text: "Refund Guarantee Terms and Conditions",
242
- parent: termsDiv,
243
- });
244
-
245
- const poweredBy = makeEl("p", {
246
- className: "spot-footer__powered-by",
247
- parent: footer,
248
- });
249
- poweredBy.innerHTML = `
250
- <svg width="145" height="28" viewBox="0 0 145 28" fill="none" xmlns="http://www.w3.org/2000/svg">
251
- <rect width="145" height="28"/>
252
- <rect x="-655" y="-270" width="819" height="325" rx="10"/>
253
- <path d="M0 10C0 4.47715 4.47715 0 10 0H134.161C139.684 0 144.161 4.47715 144.161 10V18C144.161 23.5228 139.684 28 134.161 28H10C4.47716 28 0 23.5228 0 18V10Z" fill="#F3FD00"/>
254
- <path d="M11.98 19V9.2H14.878C16.754 9.2 18.154 10.474 18.154 12.364C18.154 14.254 16.754 15.528 14.878 15.528H13.828V19H11.98ZM13.828 13.806H14.878C15.746 13.806 16.236 13.176 16.236 12.364C16.236 11.552 15.746 10.936 14.878 10.936H13.828V13.806ZM22.0258 19.196C20.0938 19.196 18.2178 17.894 18.2178 15.43C18.2178 12.952 20.0938 11.65 22.0258 11.65C23.9438 11.65 25.8198 12.952 25.8198 15.43C25.8198 17.894 23.9438 19.196 22.0258 19.196ZM20.0518 15.43C20.0518 16.774 20.8778 17.544 22.0258 17.544C23.1598 17.544 23.9858 16.774 23.9858 15.43C23.9858 14.072 23.1598 13.302 22.0258 13.302C20.8778 13.302 20.0518 14.072 20.0518 15.43ZM27.7226 19L25.2446 11.846H27.0926L28.7026 16.732L29.9486 11.846H31.7266L33.0146 16.746L34.5966 11.846H36.4026L33.9946 19H32.1186L30.8446 14.198L29.6266 19H27.7226ZM39.531 19.196C37.683 19.196 35.849 17.894 35.849 15.43C35.849 12.952 37.641 11.65 39.461 11.65C41.253 11.65 43.073 12.924 43.073 15.416V15.962H37.599C37.795 17.096 38.607 17.614 39.531 17.614C40.161 17.614 40.609 17.418 40.889 17.054H42.933C42.317 18.496 40.889 19.196 39.531 19.196ZM37.627 14.702H41.211C41.043 13.526 40.217 13.092 39.461 13.092C38.607 13.092 37.851 13.624 37.627 14.702ZM44.0159 19V11.846H45.7799V12.798C46.3539 12.028 47.2219 11.65 48.0759 11.65V13.47C46.5919 13.19 45.7799 13.834 45.7799 15.024V19H44.0159ZM51.967 19.196C50.119 19.196 48.285 17.894 48.285 15.43C48.285 12.952 50.077 11.65 51.897 11.65C53.689 11.65 55.509 12.924 55.509 15.416V15.962H50.035C50.231 17.096 51.043 17.614 51.967 17.614C52.597 17.614 53.045 17.418 53.325 17.054H55.369C54.753 18.496 53.325 19.196 51.967 19.196ZM50.063 14.702H53.647C53.479 13.526 52.653 13.092 51.897 13.092C51.043 13.092 50.287 13.624 50.063 14.702ZM59.4762 19.196C57.7542 19.196 56.1022 17.894 56.1022 15.43C56.1022 12.952 57.7542 11.65 59.4762 11.65C60.4842 11.65 61.3102 12.014 61.8562 12.714V9.2H63.6202V19H61.8562V18.146C61.3102 18.832 60.4842 19.196 59.4762 19.196ZM57.9362 15.43C57.9362 16.774 58.7622 17.544 59.8962 17.544C61.0442 17.544 61.8562 16.774 61.8562 15.43C61.8562 14.072 61.0442 13.302 59.8962 13.302C58.7622 13.302 57.9362 14.072 57.9362 15.43ZM72.526 19.196C71.518 19.196 70.692 18.832 70.146 18.146V19H68.382V9.2H70.146V12.714C70.692 12.014 71.518 11.65 72.526 11.65C74.248 11.65 75.9 12.952 75.9 15.43C75.9 17.894 74.248 19.196 72.526 19.196ZM70.146 15.43C70.146 16.774 70.958 17.544 72.106 17.544C73.254 17.544 74.066 16.774 74.066 15.43C74.066 14.072 73.254 13.302 72.106 13.302C70.958 13.302 70.146 14.072 70.146 15.43ZM76.9259 21.66L78.2699 18.342L75.4559 11.846H77.3879L79.2079 16.158L80.9299 11.846H82.7639L78.7599 21.66H76.9259Z" fill="#111820"/>
255
- <path d="M87 15.5385C87 11.3751 90.3751 8 94.5385 8H124.867C129.03 8 132.405 11.3751 132.405 15.5385C132.405 19.7018 129.03 23.0769 124.867 23.0769H94.5385C90.3751 23.0769 87 19.7018 87 15.5385Z" fill="#F3FD00"/>
256
- <g clip-path="url(#clip0_295_2094)">
257
- <path d="M117.826 19.7575C116.253 19.7575 115.064 18.7369 115.064 17.2054V13.1218H113.674V11.2615H115.064V9.21918H117.172V11.2615H119.164V13.1218H117.172V17.2054C117.172 17.6501 117.373 17.8972 117.825 17.8972H119.164V19.7586H117.825M113.846 15.5591C113.846 18.4577 111.603 19.9892 109.309 19.9892C107.016 19.9892 104.757 18.4577 104.757 15.5591C104.757 12.6606 107 11.1126 109.309 11.1126C111.619 11.1126 113.846 12.6441 113.846 15.5591ZM111.653 15.5591C111.653 13.9615 110.665 13.0556 109.31 13.0556C107.956 13.0556 106.951 13.9615 106.951 15.5591C106.951 17.1568 107.939 18.0461 109.31 18.0461C110.682 18.0461 111.653 17.1403 111.653 15.5591ZM104.339 15.5591C104.339 18.4577 102.364 19.9892 100.305 19.9892C99.0996 19.9892 98.1127 19.561 97.46 18.7545V22.8877H95.3516V11.2605H97.46V12.3638C98.1127 11.5407 99.1006 11.1126 100.305 11.1126C102.364 11.1126 104.339 12.6441 104.339 15.5591ZM102.147 15.5591C102.147 13.9615 101.175 13.0556 99.8038 13.0556C98.4322 13.0556 97.461 13.9615 97.461 15.5591C97.461 17.1568 98.4322 18.0461 99.8038 18.0461C101.175 18.0461 102.147 17.1403 102.147 15.5591ZM91.0833 19.9892C93.0078 19.9892 94.8155 18.5404 94.8155 16.465C94.8155 12.0184 89.5099 13.6823 89.5099 11.3101C89.5099 10.6183 90.0123 10.1075 90.8153 10.1075C91.6183 10.1075 92.1039 10.5025 92.3214 11.2605H94.681C94.2637 9.05373 92.7744 8 90.8163 8C88.9749 8 87.2176 9.28433 87.2176 11.3597C87.2176 15.7732 92.5232 14.0773 92.5232 16.5146C92.5232 17.2395 91.9872 17.8817 91.0833 17.8817C90.1794 17.8817 89.5603 17.3874 89.3596 16.5643H87C87.3847 18.7379 88.8908 19.9892 91.0843 19.9892M126.313 19.9892C129.678 19.9892 132.406 17.3057 132.406 13.9946C132.406 10.6834 129.678 8 126.312 8C122.947 8 120.219 10.6834 120.219 13.9946C120.219 17.3057 122.947 19.9892 126.312 19.9892" fill="#111820"/>
258
- </g>
259
- <defs>
260
- <clipPath id="clip0_295_2094">
261
- <rect width="45.405" height="14.8867" fill="white" transform="translate(87 8)"/>
262
- </clipPath>
263
- </defs>
264
- </svg>`;
265
-
266
- return footer;
267
- }
@@ -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,18 +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
- publicDir: "assets",
18
- });