notify-me-wl 1.4.0 → 1.4.2

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.
Files changed (4) hide show
  1. package/README.md +64 -359
  2. package/index.html +21 -21
  3. package/index.js +503 -289
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -1,359 +1,64 @@
1
- ### Coming Soon/Notify Me Widget
2
-
3
- This JavaScript widget allows users to register their interest in a product that is either "coming soon" or "out of stock". Depending on the `data-type` attribute provided, the widget will display appropriate messages and functionality.
4
-
5
- #### Features:
6
- - Dynamically display a form to collect user information (mobile, first name, last name).
7
- - Adjust form and button text based on the widget type (`notify-me` or `coming-soon`).
8
- - Submit user data to a specified API endpoint with email or mobile as a path parameter and appropriate query parameters.
9
-
10
- ### Installation
11
-
12
- Add the following script to your HTML to include the widget:
13
-
14
- ```html
15
- <script src="https://cdn.jsdelivr.net/npm/notify-me-wl/index.js"></script>
16
- ```
17
-
18
- ### Usage
19
-
20
- Add a button to your HTML where you want the widget to appear. The button should have an `id` of `popup-open`, a `data-fields` attribute with the fields you want to include in the form (as a JSON string), and a `data-type` attribute to specify the widget type (`notify-me` or `coming-soon`).
21
-
22
- ```html
23
- <div id="notification-widget"></div>
24
- <button id="popup-open" data-fields='["mobile", "firstName", "lastName"]' data-type="notify-me">Open Popup</button>
25
- ```
26
-
27
- ### Configuration
28
-
29
- - `data-fields`: A JSON array specifying the fields to include in the form. Possible values are `"mobile"`, `"firstName"`, and `"lastName"`.
30
- - `data-type`: Specifies the type of the widget. Possible values are `"notify-me"` and `"coming-soon"`.
31
-
32
- ### Example
33
-
34
- ```html
35
- <div id="notification-widget"></div>
36
- <button id="popup-open" data-fields='["mobile"]' data-type="notify-me">Open Popup</button>
37
-
38
- <script>
39
- // The script provided will be included here
40
- </script>
41
- ```
42
-
43
- ### How It Works
44
-
45
- 1. **Initialization**: The script listens for the `DOMContentLoaded` event to initialize the widget.
46
- 2. **Styles Injection**: It injects necessary styles for the modal and form elements.
47
- 3. **Modal Creation**: Creates the modal structure and appends it to the `notification-widget` div.
48
- 4. **Dynamic Content**: Based on the `data-type`, it sets the appropriate messages and button text.
49
- 5. **Form Submission**: Collects form data and submits it to the API with the mandatory email field and other possible fields.
50
-
51
- ### API Request Example
52
-
53
- # For sandbox environment
54
- ```
55
- https://api.au-sandbox.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest
56
- ```
57
- # For production environment
58
- ```
59
- https://api.au-aws.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest
60
- ```
61
-
62
-
63
- ### Full Script
64
-
65
- ```javascript
66
- // Access token for the API
67
- const ACCESS_TOKEN = "123"; // Replace `ACCESS_TOKEN` with your actual access token to authenticate API requests.
68
- const TENANT_ID = "victoria-woods"; // Replace `TENANT_ID` with your actual tenant ID.
69
-
70
- document.addEventListener("DOMContentLoaded", function () {
71
- const wrapper = document.getElementById("notification-widget");
72
- if (!wrapper) return;
73
-
74
- // Define and apply styles for the popup and button
75
- const styles = `
76
- .notification-btn {
77
- background-color: #fff;
78
- border: 1px solid black;
79
- color: black;
80
- padding: 12px 24px;
81
- text-align: center;
82
- width: 100%;
83
- cursor: pointer;
84
- text-transform: uppercase;
85
- }
86
- #popup-body.overlay {
87
- position: fixed;
88
- z-index: 9998;
89
- top: 0;
90
- bottom: 0;
91
- left: 0;
92
- right: 0;
93
- background: rgba(0, 0, 0, 0.7);
94
- transition: opacity 200ms;
95
- visibility: hidden;
96
- opacity: 0;
97
- }
98
- #popup-wrapper {
99
- margin: 70px auto;
100
- z-index: 9999;
101
- padding: 15px;
102
- background: #fff;
103
- border-radius: 5px;
104
- max-width: 360px;
105
- position: relative;
106
- }
107
- #popup-close {
108
- position: absolute;
109
- top: 5px;
110
- right: 15px;
111
- transition: all 200ms;
112
- font-size: 30px;
113
- font-weight: bold;
114
- text-decoration: none;
115
- color: #333;
116
- cursor: pointer;
117
- }
118
- #popup-close:hover {
119
- color: #d80606;
120
- }
121
- #popup-title {
122
- margin: 0;
123
- font-size: 20px;
124
- max-width: 350px;
125
- text-transform: uppercase;
126
- }
127
- #popup-text {
128
- margin: 10px 0;
129
- font-size: 14px;
130
- }
131
- #popup-form {
132
- display: flex;
133
- flex-direction: column;
134
- gap: 10px;
135
- }
136
- #popup-form input {
137
- padding: 0.475em 1em;
138
- border: 1px solid #caced1;
139
- border-radius: 0.25rem;
140
- font-size: 1.15rem;
141
- max-width: 100%;
142
- }
143
- #popup-form input::placeholder {
144
- font-size: 1rem;
145
- }
146
- #popup-form button {
147
- font-size: 0.85rem;
148
- padding: 0.975em 1em;
149
- font-weight: 600;
150
- border: none;
151
- text-transform: uppercase;
152
- background: #aca475;
153
- color: #fff;
154
- cursor: pointer;
155
- }
156
- .custom-select {
157
- position: relative;
158
- }
159
- .custom-select select {
160
- appearance: none;
161
- width: 100%;
162
- font-size: 1.15rem;
163
- padding: 0.475em 1em;
164
- background-color: #fff;
165
- border: 1px solid #caced1;
166
- border-radius: 0.25rem;
167
- color: #000;
168
- cursor: pointer;
169
- }
170
- .custom-select::before,
171
- .custom-select::after {
172
- --size: 0.3rem;
173
- content: "";
174
- position: absolute;
175
- right: 1rem;
176
- pointer-events: none;
177
- }
178
- .custom-select::before {
179
- border-left: var(--size) solid transparent;
180
- border-right: var(--size) solid transparent;
181
- border-bottom: var(--size) solid black;
182
- top: 40%;
183
- }
184
- .custom-select::after {
185
- border-left: var(--size) solid transparent;
186
- border-right: var(--size) solid transparent;
187
- border-top: var(--size) solid black;
188
- top: 55%;
189
- }
190
- `;
191
-
192
- const styleSheet = document.createElement("style");
193
- styleSheet.type = "text/css";
194
- styleSheet.innerText = styles;
195
- document.head.appendChild(styleSheet);
196
-
197
- // Create and append the overlay for the popup
198
- const overlay = document.createElement("div");
199
- overlay.innerHTML = `
200
- <div id="popup-body" class="overlay">
201
- <div id="popup-wrapper">
202
- <h3 id="popup-title"></h3>
203
- <span id="popup-close">&times;</span>
204
- <div id="popup-text"></div>
205
- <form id="popup-form">
206
- <div class="custom-select">
207
- <select name="select-size" required>
208
- </select>
209
- </div>
210
- <input name="email" placeholder="Email" type="email" required />
211
- </form>
212
- </div>
213
- </div>
214
- `;
215
-
216
- wrapper.appendChild(overlay);
217
-
218
- const popupBody = document.getElementById("popup-body");
219
- const popupClose = document.getElementById("popup-close");
220
- const popupOpenButton = document.getElementById("popup-open");
221
- const popupTitle = document.getElementById("popup-title");
222
- const popupText = document.getElementById("popup-text");
223
- const sizeSelect = document.querySelector("select[name='select-size']");
224
- const form = overlay.querySelector("#popup-form");
225
-
226
- if (!popupBody || !popupClose || !popupOpenButton || !popupTitle || !sizeSelect) return;
227
-
228
- // Parse fields and type to be included in the form from data attribute
229
- const fields = JSON.parse(popupOpenButton.getAttribute("data-fields") || '["email"]');
230
- const type = popupOpenButton.getAttribute("data-type") || "notify-me";
231
- const typeConfig = {
232
- "notify-me": {
233
- text: "Register to receive a notification as soon as this item is back in stock",
234
- buttonText: "Notify me",
235
- },
236
- "coming-soon": {
237
- text: "Register your interest to hear more about this item",
238
- buttonText: "Register Interest",
239
- },
240
- };
241
-
242
- // Get product data from Shopify's global variable
243
- const productData = window?.currentProduct;
244
-
245
- // Map for form fields
246
- popupText.innerText = typeConfig[type].text;
247
-
248
- const fieldMap = {
249
- email: `<input name="email" placeholder="Email" type="email" required />`,
250
- mobile: `<input name="mobile" placeholder="Mobile" type="tel" required />`,
251
- firstName: `<input name="firstName" placeholder="First name" type="text" required />`,
252
- lastName: `<input name="lastName" placeholder="Last name" type="text" required />`,
253
- };
254
-
255
- // Add fields to the form based on the parsed fields
256
- fields.forEach((field) => {
257
- if (fieldMap[field]) {
258
- form.insertAdjacentHTML("beforeend", fieldMap[field]);
259
- }
260
- });
261
-
262
- form.insertAdjacentHTML("beforeend", `<div id="checkbox-wrapper"></div>`);
263
- const checkboxWrapper = document.getElementById("checkbox-wrapper");
264
- checkboxWrapper.insertAdjacentHTML("beforeend", `<input type="checkbox" name="mailList" id="mailList" />`);
265
- checkboxWrapper.insertAdjacentHTML("beforeend", `<label for="mailList">Subscribe to our mailing list</label>`);
266
- form.insertAdjacentHTML("beforeend", `<button type="submit">${typeConfig[type].buttonText}</button>`);
267
-
268
- // Show/hide the popup
269
- function showPopup() {
270
- if (!productData) {
271
- alert("Product data not found");
272
- return;
273
- }
274
- // Set the popup title and populate the size dropdown
275
- popupTitle.innerHTML = productData.title;
276
- productData.variants.forEach((variant) => {
277
- const option = document.createElement("option");
278
- option.value = variant.title;
279
- option.textContent = variant.title;
280
- sizeSelect.appendChild(option);
281
- });
282
- popupBody.style.visibility = "visible";
283
- popupBody.style.opacity = 1;
284
- }
285
-
286
- function hidePopup() {
287
- popupBody.style.visibility = "hidden";
288
- popupBody.style.opacity = 0;
289
- }
290
-
291
- popupOpenButton.addEventListener("click", showPopup);
292
- popupClose.addEventListener("click", hidePopup);
293
-
294
- // Form submission handler
295
- if (form) {
296
- form.addEventListener("submit", function (event) {
297
- event.preventDefault();
298
-
299
- const selectedSize = sizeSelect.value;
300
- const selectedVariant = productData.variants.find((variant) => variant.title === selectedSize);
301
-
302
- if (selectedVariant) {
303
- const formData = {
304
- variantRef: selectedVariant.id,
305
- email: form.querySelector("input[name='email']").value,
306
- subscribe: form.querySelector("input[name='mailList']").checked,
307
- };
308
-
309
- if (type === "coming-soon") {
310
- formData.comingSoon = true;
311
- // formData.productRef = productData.id;
312
- } else {
313
- formData.notifyMe = true;
314
- }
315
- if (fields.includes("firstName")) {
316
- formData.firstName = form.querySelector("input[name='firstName']").value;
317
- }
318
- if (fields.includes("lastName")) {
319
- formData.lastName = form.querySelector("input[name='lastName']").value;
320
- }
321
- if (fields.includes("mobile")) {
322
- formData.mobile = form.querySelector("input[name='mobile']").value;
323
- // formData.phone = form.querySelector("input[name='mobile']").value;
324
- }
325
-
326
- let url = `https://api.au-sandbox.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest`;
327
-
328
- fetch(url, {
329
- method: "POST",
330
- headers: {
331
- "Content-Type": "application/json",
332
- Authorization: ACCESS_TOKEN,
333
- "X-Twc-Tenant": TENANT_ID,
334
- },
335
- body: JSON.stringify(formData),
336
- })
337
- .then((response) => {
338
- if (response.ok) {
339
- alert("Form submitted");
340
- hidePopup();
341
- } else {
342
- alert("Form submission failed");
343
- }
344
- })
345
- .catch((error) => {
346
- console.error("Error submitting form:", error);
347
- alert("Form submission failed");
348
- });
349
- } else {
350
- alert("Selected variant not found");
351
- }
352
- });
353
- }
354
- });
355
-
356
- ```
357
-
358
- Replace `ACCESS_TOKEN` with your actual access token to authenticate API requests.
359
- Replace `TENANT_ID` with your actual tenant to authenticate API requests.
1
+ ### Coming Soon/Notify Me Widget
2
+
3
+ This JavaScript widget allows users to register their interest in a product that is either "coming soon" or "out of stock" (aka "notify me"). Depending on the `data-type` attribute provided, the widget will display appropriate messages and functionality.
4
+
5
+ #### Features:
6
+ - Dynamically display a form to collect user information (mobile, first name, last name).
7
+ - Adjust form and button text based on the widget type (`notify-me` or `coming-soon`).
8
+ - Submit user data to a specified API endpoint with email or mobile as a path parameter and appropriate query parameters.
9
+ - An option for the user to subscribe to the database (opt-in)
10
+
11
+ ### Installation
12
+
13
+ Add the following script to your HTML to include the widget:
14
+
15
+ ```html
16
+ <script src="https://cdn.jsdelivr.net/npm/notify-me-wl/index.js"></script>
17
+ ```
18
+
19
+ ### Usage
20
+
21
+ Add a button to your HTML where you want the widget to appear. The button should have an `id` of `popup-open`, a `data-fields` attribute with the fields you want to include in the form (as a JSON string), and a `data-type` attribute to specify the widget type (`notify-me` or `coming-soon`).
22
+
23
+ ```html
24
+ <div id="notification-widget"></div>
25
+ <button id="popup-open" data-fields='["mobile", "firstName", "lastName"]' data-type="notify-me">Open Popup</button>
26
+ ```
27
+
28
+ ### Configuration
29
+
30
+ - `data-fields`: A JSON array specifying the fields to include in the form. Possible values are `"mobile"`, `"firstName"`, and `"lastName"`.
31
+ - `data-type`: Specifies the type of the widget. Possible values are `"notify-me"` and `"coming-soon"`.
32
+
33
+ ### Example
34
+
35
+ ```html
36
+ <div id="notification-widget"></div>
37
+ <button id="popup-open" data-fields='["mobile"]' data-type="notify-me">Open Popup</button>
38
+
39
+ <script>
40
+ // The script provided will be included here
41
+ </script>
42
+ ```
43
+
44
+ ### How It Works
45
+
46
+ 1. **Initialization**: The script listens for the `DOMContentLoaded` event to initialize the widget.
47
+ 2. **Styles Injection**: It injects necessary styles for the modal and form elements.
48
+ 3. **Modal Creation**: Creates the modal structure and appends it to the `notification-widget` div.
49
+ 4. **Dynamic Content**: Based on the `data-type`, it sets the appropriate messages and button text.
50
+ 5. **Form Submission**: Collects form data and submits it to the API with the mandatory email field and other possible fields.
51
+
52
+ ### API Request Example
53
+
54
+ # For sandbox environment
55
+ ```
56
+ https://api.au-sandbox.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest
57
+ ```
58
+ # For production environment
59
+ ```
60
+ https://api.au-aws.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest
61
+ ```
62
+
63
+ Replace `ACCESS_TOKEN` with your actual access token to authenticate API requests.
64
+ Replace `TENANT_ID` with your actual tenant to authenticate API requests.
package/index.html CHANGED
@@ -1,21 +1,21 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Notify me</title>
7
- <style>
8
- body {
9
- height: 100vh;
10
- margin: 100px auto;
11
- width: 300px;
12
- }
13
- </style>
14
- </head>
15
- <body>
16
- <div id="notification-widget">
17
- <button id="popup-open" class="notification-btn" type="button" data-type="notify-me" data-fields='["firstName", "lastName"]'>Notify Me - Join Waitlist</button>
18
- </div>
19
- </body>
20
- <script src="/index.js"></script>
21
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Notify me</title>
7
+ <style>
8
+ body {
9
+ height: 100vh;
10
+ margin: 100px auto;
11
+ width: 300px;
12
+ }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <div id="notification-widget">
17
+ <button id="popup-open" class="notification-btn" type="button" data-type="notify-me" data-fields='["firstName", "lastName"]'>Notify Me - Join Waitlist</button>
18
+ </div>
19
+ </body>
20
+ <script src="/index.js"></script>
21
+ </html>
package/index.js CHANGED
@@ -1,289 +1,503 @@
1
- // Access token for the API
2
- const ACCESS_TOKEN = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJRWlJkS3JabXJmMEk3WkhXRUtqNWRLTEhQanFubWJFeV9iNmpSbHdya1drIn0.eyJleHAiOjE3MjMwMzI3NzIsImlhdCI6MTcyMzAyOTE3MiwianRpIjoiNDJiNGYwM2QtMDNiNS00NmZlLTk5YmItZDQ2NTdhNjk5NGNiIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmF1LWF3cy50aGV3aXNobGlzdC5pby9hdXRoL3JlYWxtcy90d2NNYWluIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjI2YTIyNTAyLWRhNzQtNDhkMC1iZWFiLTgzY2E0YTlmMDdlOSIsInR5cCI6IkJlYXJlciIsImF6cCI6InR3Yy1wb3MtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjQxYWQwMDc4LWVmYTItNGVjMi1hM2I2LTIzYjBkNDM3YjEzOCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9sb2NhbGhvc3QiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInR3Yy1wb3MtdXNlciIsIm9mZmxpbmVfYWNjZXNzIiwidHdjLXN0b3JlLW93bmVyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InRlbmFudGlkIHN0b3JlIHByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudGlkIjoidmlrdG9yaWEtd29vZHMiLCJuYW1lIjoiTWF0dCBIYW1wc2hpcmUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJtYXR0QHRoZXdpc2hsaXN0LmlvIiwic3RvcmUiOiIyMDUiLCJnaXZlbl9uYW1lIjoiTWF0dCIsImZhbWlseV9uYW1lIjoiSGFtcHNoaXJlIiwiZW1haWwiOiJtYXR0QHRoZXdpc2hsaXN0LmlvIn0.iZkMgwH74njjXUWvImkJomHYr91Lr8ZGrZGwslEGcV3vbNuoNc5CocvNWW476o-LoSh-LsKf-MLiYN1XvOuPDF3fGoGCEbMh6_M0RJcrhVWogkj81fx4ukvDPCFIjgoDCV9WIuehV9dsSWa7E0irZeE6MUVhLwRIaTzKtxgzUUKrAqBtI_HKpyo8TUGQBiYlrc85QFUyuoKbKg-QaRn_SObRLDB8ooIBJvIlgklXQt1ZYBM2HUOc5L1bAQwfzcrWEvl6eYiQHXCSPqS0rPGoaGC6v5ydBo9VMxtVHGladDHLrO3Gt2BnIGMBoYrKTAmt7j0KABwPyB3CmAIwj_pOBQ"; // Replace `ACCESS_TOKEN` with your actual access token to authenticate API requests.
3
- const TENANT_ID = "victoria-woods"; // Replace `TENANT_ID` with your actual tenant ID.
4
-
5
- document.addEventListener("DOMContentLoaded", function () {
6
- const wrapper = document.getElementById("notification-widget");
7
- if (!wrapper) return;
8
-
9
- // Define and apply styles for the popup and button
10
- const styles = `
11
- .notification-btn {
12
- background-color: #fff;
13
- border: 1px solid black;
14
- color: black;
15
- padding: 12px 24px;
16
- text-align: center;
17
- width: 100%;
18
- cursor: pointer;
19
- text-transform: uppercase;
20
- }
21
- #popup-body.overlay {
22
- position: fixed;
23
- z-index: 9998;
24
- top: 0;
25
- bottom: 0;
26
- left: 0;
27
- right: 0;
28
- background: rgba(0, 0, 0, 0.7);
29
- transition: opacity 200ms;
30
- visibility: hidden;
31
- opacity: 0;
32
- }
33
- #popup-wrapper {
34
- margin: 70px auto;
35
- z-index: 9999;
36
- padding: 15px;
37
- background: #fff;
38
- border-radius: 5px;
39
- max-width: 360px;
40
- position: relative;
41
- }
42
- #popup-close {
43
- position: absolute;
44
- top: 5px;
45
- right: 15px;
46
- transition: all 200ms;
47
- font-size: 30px;
48
- font-weight: bold;
49
- text-decoration: none;
50
- color: #333;
51
- cursor: pointer;
52
- }
53
- #popup-close:hover {
54
- color: #d80606;
55
- }
56
- #popup-title {
57
- margin: 0;
58
- font-size: 20px;
59
- max-width: 350px;
60
- text-transform: uppercase;
61
- }
62
- #popup-text {
63
- margin: 10px 0;
64
- font-size: 14px;
65
- }
66
- #popup-form {
67
- display: flex;
68
- flex-direction: column;
69
- gap: 10px;
70
- }
71
- #popup-form input {
72
- padding: 0.475em 1em;
73
- border: 1px solid #caced1;
74
- border-radius: 0.25rem;
75
- font-size: 1.15rem;
76
- max-width: 100%;
77
- }
78
- #popup-form input::placeholder {
79
- font-size: 1rem;
80
- }
81
- #popup-form button {
82
- font-size: 0.85rem;
83
- padding: 0.975em 1em;
84
- font-weight: 600;
85
- border: none;
86
- text-transform: uppercase;
87
- background: #aca475;
88
- color: #fff;
89
- cursor: pointer;
90
- }
91
- .custom-select {
92
- position: relative;
93
- }
94
- .custom-select select {
95
- appearance: none;
96
- width: 100%;
97
- font-size: 1.15rem;
98
- padding: 0.475em 1em;
99
- background-color: #fff;
100
- border: 1px solid #caced1;
101
- border-radius: 0.25rem;
102
- color: #000;
103
- cursor: pointer;
104
- }
105
- .custom-select::before,
106
- .custom-select::after {
107
- --size: 0.3rem;
108
- content: "";
109
- position: absolute;
110
- right: 1rem;
111
- pointer-events: none;
112
- }
113
- .custom-select::before {
114
- border-left: var(--size) solid transparent;
115
- border-right: var(--size) solid transparent;
116
- border-bottom: var(--size) solid black;
117
- top: 40%;
118
- }
119
- .custom-select::after {
120
- border-left: var(--size) solid transparent;
121
- border-right: var(--size) solid transparent;
122
- border-top: var(--size) solid black;
123
- top: 55%;
124
- }
125
- `;
126
-
127
- const styleSheet = document.createElement("style");
128
- styleSheet.type = "text/css";
129
- styleSheet.innerText = styles;
130
- document.head.appendChild(styleSheet);
131
-
132
- // Create and append the overlay for the popup
133
- const overlay = document.createElement("div");
134
- overlay.innerHTML = `
135
- <div id="popup-body" class="overlay">
136
- <div id="popup-wrapper">
137
- <h3 id="popup-title"></h3>
138
- <span id="popup-close">&times;</span>
139
- <div id="popup-text"></div>
140
- <form id="popup-form">
141
- <div class="custom-select">
142
- <select name="select-size" required>
143
- </select>
144
- </div>
145
- <input name="email" placeholder="Email" type="email" required />
146
- </form>
147
- </div>
148
- </div>
149
- `;
150
-
151
- wrapper.appendChild(overlay);
152
-
153
- const popupBody = document.getElementById("popup-body");
154
- const popupClose = document.getElementById("popup-close");
155
- const popupOpenButton = document.getElementById("popup-open");
156
- const popupTitle = document.getElementById("popup-title");
157
- const popupText = document.getElementById("popup-text");
158
- const sizeSelect = document.querySelector("select[name='select-size']");
159
- const form = overlay.querySelector("#popup-form");
160
-
161
- if (!popupBody || !popupClose || !popupOpenButton || !popupTitle || !sizeSelect) return;
162
-
163
- // Parse fields and type to be included in the form from data attribute
164
- const fields = JSON.parse(popupOpenButton.getAttribute("data-fields") || '["email"]');
165
- const type = popupOpenButton.getAttribute("data-type") || "notify-me";
166
- const typeConfig = {
167
- "notify-me": {
168
- text: "Register to receive a notification as soon as this item is back in stock",
169
- buttonText: "Notify me",
170
- },
171
- "coming-soon": {
172
- text: "Register your interest to hear more about this item",
173
- buttonText: "Register Interest",
174
- },
175
- };
176
-
177
- // Get product data from Shopify's global variable
178
- const productData = window?.currentProduct;
179
-
180
- // Map for form fields
181
- popupText.innerText = typeConfig[type].text;
182
-
183
- const fieldMap = {
184
- email: `<input name="email" placeholder="Email" type="email" required />`,
185
- mobile: `<input name="mobile" placeholder="Mobile" type="tel" required />`,
186
- firstName: `<input name="firstName" placeholder="First name" type="text" required />`,
187
- lastName: `<input name="lastName" placeholder="Last name" type="text" required />`,
188
- };
189
-
190
- // Add fields to the form based on the parsed fields
191
- fields.forEach((field) => {
192
- if (fieldMap[field]) {
193
- form.insertAdjacentHTML("beforeend", fieldMap[field]);
194
- }
195
- });
196
-
197
- form.insertAdjacentHTML("beforeend", `<div id="checkbox-wrapper"></div>`);
198
- const checkboxWrapper = document.getElementById("checkbox-wrapper");
199
- checkboxWrapper.insertAdjacentHTML("beforeend", `<input type="checkbox" name="mailList" id="mailList" />`);
200
- checkboxWrapper.insertAdjacentHTML("beforeend", `<label for="mailList">Subscribe to our mailing list</label>`);
201
- form.insertAdjacentHTML("beforeend", `<button type="submit">${typeConfig[type].buttonText}</button>`);
202
-
203
- // Show/hide the popup
204
- function showPopup() {
205
- if (!productData) {
206
- alert("Product data not found");
207
- return;
208
- }
209
- // Set the popup title and populate the size dropdown
210
- popupTitle.innerHTML = productData.title;
211
- productData.variants.forEach((variant) => {
212
- const option = document.createElement("option");
213
- option.value = variant.title;
214
- option.textContent = variant.title;
215
- sizeSelect.appendChild(option);
216
- });
217
- popupBody.style.visibility = "visible";
218
- popupBody.style.opacity = 1;
219
- }
220
-
221
- function hidePopup() {
222
- popupBody.style.visibility = "hidden";
223
- popupBody.style.opacity = 0;
224
- }
225
-
226
- popupOpenButton.addEventListener("click", showPopup);
227
- popupClose.addEventListener("click", hidePopup);
228
-
229
- // Form submission handler
230
- if (form) {
231
- form.addEventListener("submit", function (event) {
232
- event.preventDefault();
233
-
234
- const selectedSize = sizeSelect.value;
235
- const selectedVariant = productData.variants.find((variant) => variant.title === selectedSize);
236
-
237
- if (selectedVariant) {
238
- const formData = {
239
- variantRef: selectedVariant.id,
240
- email: form.querySelector("input[name='email']").value,
241
- subscribe: form.querySelector("input[name='mailList']").checked,
242
- };
243
-
244
- if (type === "coming-soon") {
245
- formData.comingSoon = true;
246
- // formData.productRef = productData.id;
247
- } else {
248
- formData.notifyMe = true;
249
- }
250
- if (fields.includes("firstName")) {
251
- formData.firstName = form.querySelector("input[name='firstName']").value;
252
- }
253
- if (fields.includes("lastName")) {
254
- formData.lastName = form.querySelector("input[name='lastName']").value;
255
- }
256
- if (fields.includes("mobile")) {
257
- formData.mobile = form.querySelector("input[name='mobile']").value;
258
- // formData.phone = form.querySelector("input[name='mobile']").value;
259
- }
260
-
261
- let url = `https://api.au-sandbox.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest`;
262
-
263
- fetch(url, {
264
- method: "POST",
265
- headers: {
266
- "Content-Type": "application/json",
267
- Authorization: ACCESS_TOKEN,
268
- "X-Twc-Tenant": TENANT_ID,
269
- },
270
- body: JSON.stringify(formData),
271
- })
272
- .then((response) => {
273
- if (response.ok) {
274
- alert("Form submitted");
275
- hidePopup();
276
- } else {
277
- alert("Form submission failed");
278
- }
279
- })
280
- .catch((error) => {
281
- console.error("Error submitting form:", error);
282
- alert("Form submission failed");
283
- });
284
- } else {
285
- alert("Selected variant not found");
286
- }
287
- });
288
- }
289
- });
1
+ // Access token for the API
2
+ const ACCESS_TOKEN =
3
+ 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJRWlJkS3JabXJmMEk3WkhXRUtqNWRLTEhQanFubWJFeV9iNmpSbHdya1drIn0.eyJleHAiOjE3MjMwMzI3NzIsImlhdCI6MTcyMzAyOTE3MiwianRpIjoiNDJiNGYwM2QtMDNiNS00NmZlLTk5YmItZDQ2NTdhNjk5NGNiIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmF1LWF3cy50aGV3aXNobGlzdC5pby9hdXRoL3JlYWxtcy90d2NNYWluIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjI2YTIyNTAyLWRhNzQtNDhkMC1iZWFiLTgzY2E0YTlmMDdlOSIsInR5cCI6IkJlYXJlciIsImF6cCI6InR3Yy1wb3MtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjQxYWQwMDc4LWVmYTItNGVjMi1hM2I2LTIzYjBkNDM3YjEzOCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9sb2NhbGhvc3QiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInR3Yy1wb3MtdXNlciIsIm9mZmxpbmVfYWNjZXNzIiwidHdjLXN0b3JlLW93bmVyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InRlbmFudGlkIHN0b3JlIHByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudGlkIjoidmlrdG9yaWEtd29vZHMiLCJuYW1lIjoiTWF0dCBIYW1wc2hpcmUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJtYXR0QHRoZXdpc2hsaXN0LmlvIiwic3RvcmUiOiIyMDUiLCJnaXZlbl9uYW1lIjoiTWF0dCIsImZhbWlseV9uYW1lIjoiSGFtcHNoaXJlIiwiZW1haWwiOiJtYXR0QHRoZXdpc2hsaXN0LmlvIn0.iZkMgwH74njjXUWvImkJomHYr91Lr8ZGrZGwslEGcV3vbNuoNc5CocvNWW476o-LoSh-LsKf-MLiYN1XvOuPDF3fGoGCEbMh6_M0RJcrhVWogkj81fx4ukvDPCFIjgoDCV9WIuehV9dsSWa7E0irZeE6MUVhLwRIaTzKtxgzUUKrAqBtI_HKpyo8TUGQBiYlrc85QFUyuoKbKg-QaRn_SObRLDB8ooIBJvIlgklXQt1ZYBM2HUOc5L1bAQwfzcrWEvl6eYiQHXCSPqS0rPGoaGC6v5ydBo9VMxtVHGladDHLrO3Gt2BnIGMBoYrKTAmt7j0KABwPyB3CmAIwj_pOBQ'; // Replace `ACCESS_TOKEN` with your actual access token to authenticate API requests.
4
+ const TENANT_ID = 'victoria-woods'; // Replace `TENANT_ID` with your actual tenant ID.
5
+
6
+ const COUNTRY_CODES = [
7
+ { code: 'AF', name: 'Afghanistan' }, { code: 'AX', name: 'Åland Islands' },
8
+ { code: 'AL', name: 'Albania' }, { code: 'DZ', name: 'Algeria' },
9
+ { code: 'AS', name: 'American Samoa' }, { code: 'AD', name: 'Andorra' },
10
+ { code: 'AO', name: 'Angola' }, { code: 'AI', name: 'Anguilla' },
11
+ { code: 'AG', name: 'Antigua and Barbuda' }, { code: 'AR', name: 'Argentina' },
12
+ { code: 'AM', name: 'Armenia' }, { code: 'AW', name: 'Aruba' },
13
+ { code: 'AU', name: 'Australia' }, { code: 'AT', name: 'Austria' },
14
+ { code: 'AZ', name: 'Azerbaijan' }, { code: 'BS', name: 'Bahamas' },
15
+ { code: 'BH', name: 'Bahrain' }, { code: 'BD', name: 'Bangladesh' },
16
+ { code: 'BB', name: 'Barbados' }, { code: 'BY', name: 'Belarus' },
17
+ { code: 'BE', name: 'Belgium' }, { code: 'BZ', name: 'Belize' },
18
+ { code: 'BJ', name: 'Benin' }, { code: 'BM', name: 'Bermuda' },
19
+ { code: 'BT', name: 'Bhutan' }, { code: 'BO', name: 'Bolivia' },
20
+ { code: 'BA', name: 'Bosnia and Herzegovina' }, { code: 'BW', name: 'Botswana' },
21
+ { code: 'BR', name: 'Brazil' }, { code: 'BN', name: 'Brunei' },
22
+ { code: 'BG', name: 'Bulgaria' }, { code: 'BF', name: 'Burkina Faso' },
23
+ { code: 'BI', name: 'Burundi' }, { code: 'CV', name: 'Cabo Verde' },
24
+ { code: 'KH', name: 'Cambodia' }, { code: 'CM', name: 'Cameroon' },
25
+ { code: 'CA', name: 'Canada' }, { code: 'KY', name: 'Cayman Islands' },
26
+ { code: 'CF', name: 'Central African Republic' }, { code: 'TD', name: 'Chad' },
27
+ { code: 'CL', name: 'Chile' }, { code: 'CN', name: 'China' },
28
+ { code: 'CO', name: 'Colombia' }, { code: 'KM', name: 'Comoros' },
29
+ { code: 'CG', name: 'Congo' }, { code: 'CD', name: 'Congo, DR' },
30
+ { code: 'CK', name: 'Cook Islands' }, { code: 'CR', name: 'Costa Rica' },
31
+ { code: 'HR', name: 'Croatia' }, { code: 'CU', name: 'Cuba' },
32
+ { code: 'CW', name: 'Curaçao' }, { code: 'CY', name: 'Cyprus' },
33
+ { code: 'CZ', name: 'Czech Republic' }, { code: 'DK', name: 'Denmark' },
34
+ { code: 'DJ', name: 'Djibouti' }, { code: 'DM', name: 'Dominica' },
35
+ { code: 'DO', name: 'Dominican Republic' }, { code: 'EC', name: 'Ecuador' },
36
+ { code: 'EG', name: 'Egypt' }, { code: 'SV', name: 'El Salvador' },
37
+ { code: 'GQ', name: 'Equatorial Guinea' }, { code: 'ER', name: 'Eritrea' },
38
+ { code: 'EE', name: 'Estonia' }, { code: 'SZ', name: 'Eswatini' },
39
+ { code: 'ET', name: 'Ethiopia' }, { code: 'FO', name: 'Faroe Islands' },
40
+ { code: 'FJ', name: 'Fiji' }, { code: 'FI', name: 'Finland' },
41
+ { code: 'FR', name: 'France' }, { code: 'GF', name: 'French Guiana' },
42
+ { code: 'PF', name: 'French Polynesia' }, { code: 'GA', name: 'Gabon' },
43
+ { code: 'GM', name: 'Gambia' }, { code: 'GE', name: 'Georgia' },
44
+ { code: 'DE', name: 'Germany' }, { code: 'GH', name: 'Ghana' },
45
+ { code: 'GI', name: 'Gibraltar' }, { code: 'GR', name: 'Greece' },
46
+ { code: 'GL', name: 'Greenland' }, { code: 'GD', name: 'Grenada' },
47
+ { code: 'GP', name: 'Guadeloupe' }, { code: 'GU', name: 'Guam' },
48
+ { code: 'GT', name: 'Guatemala' }, { code: 'GN', name: 'Guinea' },
49
+ { code: 'GW', name: 'Guinea-Bissau' }, { code: 'GY', name: 'Guyana' },
50
+ { code: 'HT', name: 'Haiti' }, { code: 'HN', name: 'Honduras' },
51
+ { code: 'HK', name: 'Hong Kong' }, { code: 'HU', name: 'Hungary' },
52
+ { code: 'IS', name: 'Iceland' }, { code: 'IN', name: 'India' },
53
+ { code: 'ID', name: 'Indonesia' }, { code: 'IR', name: 'Iran' },
54
+ { code: 'IQ', name: 'Iraq' }, { code: 'IE', name: 'Ireland' },
55
+ { code: 'IM', name: 'Isle of Man' }, { code: 'IL', name: 'Israel' },
56
+ { code: 'IT', name: 'Italy' }, { code: 'JM', name: 'Jamaica' },
57
+ { code: 'JP', name: 'Japan' }, { code: 'JE', name: 'Jersey' },
58
+ { code: 'JO', name: 'Jordan' }, { code: 'KZ', name: 'Kazakhstan' },
59
+ { code: 'KE', name: 'Kenya' }, { code: 'KI', name: 'Kiribati' },
60
+ { code: 'KR', name: 'Korea, South' }, { code: 'XK', name: 'Kosovo' },
61
+ { code: 'KW', name: 'Kuwait' }, { code: 'KG', name: 'Kyrgyzstan' },
62
+ { code: 'LA', name: 'Laos' }, { code: 'LV', name: 'Latvia' },
63
+ { code: 'LB', name: 'Lebanon' }, { code: 'LS', name: 'Lesotho' },
64
+ { code: 'LR', name: 'Liberia' }, { code: 'LY', name: 'Libya' },
65
+ { code: 'LI', name: 'Liechtenstein' }, { code: 'LT', name: 'Lithuania' },
66
+ { code: 'LU', name: 'Luxembourg' }, { code: 'MO', name: 'Macao' },
67
+ { code: 'MG', name: 'Madagascar' }, { code: 'MW', name: 'Malawi' },
68
+ { code: 'MY', name: 'Malaysia' }, { code: 'MV', name: 'Maldives' },
69
+ { code: 'ML', name: 'Mali' }, { code: 'MT', name: 'Malta' },
70
+ { code: 'MH', name: 'Marshall Islands' }, { code: 'MQ', name: 'Martinique' },
71
+ { code: 'MR', name: 'Mauritania' }, { code: 'MU', name: 'Mauritius' },
72
+ { code: 'MX', name: 'Mexico' }, { code: 'FM', name: 'Micronesia' },
73
+ { code: 'MD', name: 'Moldova' }, { code: 'MC', name: 'Monaco' },
74
+ { code: 'MN', name: 'Mongolia' }, { code: 'ME', name: 'Montenegro' },
75
+ { code: 'MS', name: 'Montserrat' }, { code: 'MA', name: 'Morocco' },
76
+ { code: 'MZ', name: 'Mozambique' }, { code: 'MM', name: 'Myanmar' },
77
+ { code: 'NA', name: 'Namibia' }, { code: 'NR', name: 'Nauru' },
78
+ { code: 'NP', name: 'Nepal' }, { code: 'NL', name: 'Netherlands' },
79
+ { code: 'NC', name: 'New Caledonia' }, { code: 'NZ', name: 'New Zealand' },
80
+ { code: 'NI', name: 'Nicaragua' }, { code: 'NE', name: 'Niger' },
81
+ { code: 'NG', name: 'Nigeria' }, { code: 'NU', name: 'Niue' },
82
+ { code: 'MK', name: 'North Macedonia' }, { code: 'NO', name: 'Norway' },
83
+ { code: 'OM', name: 'Oman' }, { code: 'PK', name: 'Pakistan' },
84
+ { code: 'PW', name: 'Palau' }, { code: 'PS', name: 'Palestine' },
85
+ { code: 'PA', name: 'Panama' }, { code: 'PG', name: 'Papua New Guinea' },
86
+ { code: 'PY', name: 'Paraguay' }, { code: 'PE', name: 'Peru' },
87
+ { code: 'PH', name: 'Philippines' }, { code: 'PL', name: 'Poland' },
88
+ { code: 'PT', name: 'Portugal' }, { code: 'PR', name: 'Puerto Rico' },
89
+ { code: 'QA', name: 'Qatar' }, { code: 'RE', name: 'Réunion' },
90
+ { code: 'RO', name: 'Romania' },
91
+ { code: 'RW', name: 'Rwanda' }, { code: 'KN', name: 'Saint Kitts and Nevis' },
92
+ { code: 'LC', name: 'Saint Lucia' }, { code: 'VC', name: 'Saint Vincent and the Grenadines' },
93
+ { code: 'WS', name: 'Samoa' }, { code: 'SM', name: 'San Marino' },
94
+ { code: 'SA', name: 'Saudi Arabia' }, { code: 'SN', name: 'Senegal' },
95
+ { code: 'RS', name: 'Serbia' }, { code: 'SC', name: 'Seychelles' },
96
+ { code: 'SL', name: 'Sierra Leone' }, { code: 'SG', name: 'Singapore' },
97
+ { code: 'SK', name: 'Slovakia' }, { code: 'SI', name: 'Slovenia' },
98
+ { code: 'SB', name: 'Solomon Islands' }, { code: 'SO', name: 'Somalia' },
99
+ { code: 'ZA', name: 'South Africa' }, { code: 'SS', name: 'South Sudan' },
100
+ { code: 'ES', name: 'Spain' }, { code: 'LK', name: 'Sri Lanka' },
101
+ { code: 'SD', name: 'Sudan' }, { code: 'SR', name: 'Suriname' },
102
+ { code: 'SE', name: 'Sweden' }, { code: 'CH', name: 'Switzerland' },
103
+ { code: 'SY', name: 'Syria' }, { code: 'TW', name: 'Taiwan' },
104
+ { code: 'TJ', name: 'Tajikistan' }, { code: 'TZ', name: 'Tanzania' },
105
+ { code: 'TH', name: 'Thailand' }, { code: 'TL', name: 'Timor-Leste' },
106
+ { code: 'TG', name: 'Togo' }, { code: 'TO', name: 'Tonga' },
107
+ { code: 'TT', name: 'Trinidad and Tobago' }, { code: 'TN', name: 'Tunisia' },
108
+ { code: 'TR', name: 'Turkey' }, { code: 'TM', name: 'Turkmenistan' },
109
+ { code: 'TC', name: 'Turks and Caicos Islands' }, { code: 'TV', name: 'Tuvalu' },
110
+ { code: 'UG', name: 'Uganda' }, { code: 'UA', name: 'Ukraine' },
111
+ { code: 'AE', name: 'United Arab Emirates' }, { code: 'GB', name: 'United Kingdom' },
112
+ { code: 'US', name: 'United States' }, { code: 'UY', name: 'Uruguay' },
113
+ { code: 'UZ', name: 'Uzbekistan' }, { code: 'VU', name: 'Vanuatu' },
114
+ { code: 'VE', name: 'Venezuela' }, { code: 'VN', name: 'Vietnam' },
115
+ { code: 'VG', name: 'Virgin Islands, British' }, { code: 'VI', name: 'Virgin Islands, U.S.' },
116
+ { code: 'YE', name: 'Yemen' }, { code: 'ZM', name: 'Zambia' },
117
+ { code: 'ZW', name: 'Zimbabwe' },
118
+ ];
119
+
120
+ // Detect country/province/market context using priority fallback chain
121
+ function detectCountryContext() {
122
+ const ctx = { countryCode: null, provinceCode: null, marketId: null };
123
+
124
+ // Priority 1: Shopify localization/country context
125
+ const shopify = window.Shopify;
126
+ if (shopify) {
127
+ if (typeof shopify.country === 'string') ctx.countryCode = shopify.country;
128
+ const mkt = shopify.markets?.currentMarket;
129
+ if (mkt) {
130
+ if (mkt.countryCode) ctx.countryCode = mkt.countryCode;
131
+ if (mkt.id != null) ctx.marketId = String(mkt.id);
132
+ }
133
+ if (!ctx.countryCode && typeof shopify.locale === 'string') {
134
+ const parts = shopify.locale.split('-');
135
+ if (parts.length > 1) ctx.countryCode = parts[parts.length - 1].toUpperCase();
136
+ }
137
+ }
138
+
139
+ // Priority 2: Existing customer shipping country
140
+ if (!ctx.countryCode || !ctx.provinceCode) {
141
+ const addr = window.customer?.default_address;
142
+ if (addr) {
143
+ if (!ctx.countryCode && addr.country_code) ctx.countryCode = addr.country_code;
144
+ if (!ctx.provinceCode && addr.province_code) ctx.provinceCode = addr.province_code;
145
+ }
146
+ }
147
+
148
+ // Priority 3: Browser locale fallback
149
+ if (!ctx.countryCode) {
150
+ const parts = (navigator.language || '').split('-');
151
+ if (parts.length > 1) ctx.countryCode = parts[parts.length - 1].toUpperCase();
152
+ }
153
+
154
+ return ctx;
155
+ }
156
+
157
+ document.addEventListener('DOMContentLoaded', function () {
158
+ const wrapper = document.getElementById('notification-widget');
159
+ if (!wrapper) return;
160
+
161
+ // Define and apply styles for the popup and button
162
+ const styles = `
163
+ .notification-btn {
164
+ background-color: #fff;
165
+ border: 1px solid black;
166
+ color: black;
167
+ padding: 12px 24px;
168
+ text-align: center;
169
+ width: 100%;
170
+ cursor: pointer;
171
+ text-transform: uppercase;
172
+ }
173
+ #popup-body.overlay {
174
+ position: fixed;
175
+ z-index: 9998;
176
+ top: 0;
177
+ bottom: 0;
178
+ left: 0;
179
+ right: 0;
180
+ background: rgba(0, 0, 0, 0.7);
181
+ transition: opacity 200ms;
182
+ visibility: hidden;
183
+ opacity: 0;
184
+ }
185
+ #popup-wrapper {
186
+ margin: 70px auto;
187
+ z-index: 9999;
188
+ padding: 15px;
189
+ background: #fff;
190
+ border-radius: 5px;
191
+ max-width: 360px;
192
+ position: relative;
193
+ }
194
+ #popup-close {
195
+ position: absolute;
196
+ top: 5px;
197
+ right: 15px;
198
+ transition: all 200ms;
199
+ font-size: 30px;
200
+ font-weight: bold;
201
+ text-decoration: none;
202
+ color: #333;
203
+ cursor: pointer;
204
+ }
205
+ #popup-close:hover {
206
+ color: #d80606;
207
+ }
208
+ #popup-title {
209
+ margin: 0;
210
+ font-size: 20px;
211
+ max-width: 350px;
212
+ text-transform: uppercase;
213
+ }
214
+ #popup-text {
215
+ margin: 10px 0;
216
+ font-size: 14px;
217
+ }
218
+ #popup-form {
219
+ display: flex;
220
+ flex-direction: column;
221
+ gap: 10px;
222
+ }
223
+ #popup-form input {
224
+ padding: 0.475em 1em;
225
+ border: 1px solid #caced1;
226
+ border-radius: 0.25rem;
227
+ font-size: 1.15rem;
228
+ max-width: 100%;
229
+ }
230
+ #popup-form input::placeholder {
231
+ font-size: 1rem;
232
+ }
233
+ #popup-form button {
234
+ font-size: 0.85rem;
235
+ padding: 0.975em 1em;
236
+ font-weight: 600;
237
+ border: none;
238
+ text-transform: uppercase;
239
+ background: #aca475;
240
+ color: #fff;
241
+ cursor: pointer;
242
+ }
243
+ .checkbox-item {
244
+ display: flex;
245
+ align-items: center;
246
+ gap: 8px;
247
+ }
248
+ .checkbox-item input[type="checkbox"] {
249
+ width: auto;
250
+ margin: 0;
251
+ }
252
+ .custom-select {
253
+ position: relative;
254
+ }
255
+ .custom-select select {
256
+ appearance: none;
257
+ width: 100%;
258
+ font-size: 1.15rem;
259
+ padding: 0.475em 1em;
260
+ background-color: #fff;
261
+ border: 1px solid #caced1;
262
+ border-radius: 0.25rem;
263
+ color: #000;
264
+ cursor: pointer;
265
+ }
266
+ .custom-select::before,
267
+ .custom-select::after {
268
+ --size: 0.3rem;
269
+ content: "";
270
+ position: absolute;
271
+ right: 1rem;
272
+ pointer-events: none;
273
+ }
274
+ .custom-select::before {
275
+ border-left: var(--size) solid transparent;
276
+ border-right: var(--size) solid transparent;
277
+ border-bottom: var(--size) solid black;
278
+ top: 40%;
279
+ }
280
+ .custom-select::after {
281
+ border-left: var(--size) solid transparent;
282
+ border-right: var(--size) solid transparent;
283
+ border-top: var(--size) solid black;
284
+ top: 55%;
285
+ }
286
+ `;
287
+
288
+ const styleSheet = document.createElement('style');
289
+ styleSheet.type = 'text/css';
290
+ styleSheet.innerText = styles;
291
+ document.head.appendChild(styleSheet);
292
+
293
+ // Create and append the overlay for the popup
294
+ const overlay = document.createElement('div');
295
+ overlay.innerHTML = `
296
+ <div id="popup-body" class="overlay">
297
+ <div id="popup-wrapper">
298
+ <h3 id="popup-title"></h3>
299
+ <span id="popup-close">&times;</span>
300
+ <div id="popup-text"></div>
301
+ <form id="popup-form">
302
+ <div class="custom-select">
303
+ <select name="select-size" required>
304
+ </select>
305
+ </div>
306
+ <input name="email" placeholder="Email" type="email" required />
307
+ </form>
308
+ </div>
309
+ </div>
310
+ `;
311
+
312
+ wrapper.appendChild(overlay);
313
+
314
+ const popupBody = document.getElementById('popup-body');
315
+ const popupClose = document.getElementById('popup-close');
316
+ const popupOpenButton = document.getElementById('popup-open');
317
+ const popupTitle = document.getElementById('popup-title');
318
+ const popupText = document.getElementById('popup-text');
319
+ const sizeSelect = document.querySelector("select[name='select-size']");
320
+ const form = overlay.querySelector('#popup-form');
321
+
322
+ if (
323
+ !popupBody ||
324
+ !popupClose ||
325
+ !popupOpenButton ||
326
+ !popupTitle ||
327
+ !sizeSelect
328
+ )
329
+ return;
330
+
331
+ // Parse fields and type to be included in the form from data attribute
332
+ const fields = JSON.parse(
333
+ popupOpenButton.getAttribute('data-fields') || '["email"]',
334
+ );
335
+ const type = popupOpenButton.getAttribute('data-type') || 'notify-me';
336
+ const typeConfig = {
337
+ 'notify-me': {
338
+ text: 'Register to receive a notification as soon as this item is back in stock',
339
+ buttonText: 'Notify me',
340
+ },
341
+ 'coming-soon': {
342
+ text: 'Register your interest to hear more about this item',
343
+ buttonText: 'Register Interest',
344
+ },
345
+ };
346
+
347
+ // Get product data from Shopify's global variable
348
+ const productData = window?.currentProduct;
349
+
350
+ const countryCtx = detectCountryContext();
351
+ const resolvedMarketId =
352
+ popupOpenButton.getAttribute('data-market-id') || countryCtx.marketId;
353
+
354
+ // Map for form fields
355
+ popupText.innerText = typeConfig[type].text;
356
+
357
+ const countryOptions = COUNTRY_CODES.map(
358
+ (c) =>
359
+ `<option value="${c.code}"${c.code === countryCtx.countryCode ? ' selected' : ''}>${c.name}</option>`,
360
+ ).join('');
361
+
362
+ const fieldMap = {
363
+ email: `<input name="email" placeholder="Email" type="email" required />`,
364
+ mobile: `<input name="mobile" placeholder="Mobile" type="tel" required />`,
365
+ firstName: `<input name="firstName" placeholder="First name" type="text" required />`,
366
+ lastName: `<input name="lastName" placeholder="Last name" type="text" required />`,
367
+ countryCode: `<div class="custom-select"><select name="countryCode"><option value="">Select country</option>${countryOptions}</select></div>`,
368
+ provinceCode: `<input name="provinceCode" placeholder="State / Province code" type="text" value="${countryCtx.provinceCode || ''}" />`,
369
+ };
370
+
371
+ // Add fields to the form based on the parsed fields
372
+ fields.forEach((field) => {
373
+ if (fieldMap[field]) {
374
+ form.insertAdjacentHTML('beforeend', fieldMap[field]);
375
+ }
376
+ });
377
+
378
+ form.insertAdjacentHTML('beforeend', `<div id="checkbox-wrapper"></div>`);
379
+ const checkboxWrapper = document.getElementById('checkbox-wrapper');
380
+ checkboxWrapper.insertAdjacentHTML(
381
+ 'beforeend',
382
+ `<div class="checkbox-item"><input type="checkbox" name="mailList" id="mailList" /><label for="mailList">Subscribe to our mailing list</label></div>`,
383
+ );
384
+ checkboxWrapper.insertAdjacentHTML(
385
+ 'beforeend',
386
+ `<div class="checkbox-item"><input type="checkbox" name="mailListSms" id="mailListSms" /><label for="mailListSms">Subscribe to our mailing list via SMS</label></div>`,
387
+ );
388
+ form.insertAdjacentHTML(
389
+ 'beforeend',
390
+ `<button type="submit">${typeConfig[type].buttonText}</button>`,
391
+ );
392
+
393
+ // Show/hide the popup
394
+ function showPopup() {
395
+ if (!productData) {
396
+ alert('Product data not found');
397
+ return;
398
+ }
399
+ // Set the popup title and populate the size dropdown
400
+ popupTitle.innerHTML = productData.title;
401
+ productData.variants.forEach((variant) => {
402
+ const option = document.createElement('option');
403
+ option.value = variant.title;
404
+ option.textContent = variant.title;
405
+ sizeSelect.appendChild(option);
406
+ });
407
+ popupBody.style.visibility = 'visible';
408
+ popupBody.style.opacity = 1;
409
+ }
410
+
411
+ function hidePopup() {
412
+ popupBody.style.visibility = 'hidden';
413
+ popupBody.style.opacity = 0;
414
+ }
415
+
416
+ popupOpenButton.addEventListener('click', showPopup);
417
+ popupClose.addEventListener('click', hidePopup);
418
+
419
+ // Form submission handler
420
+ if (form) {
421
+ form.addEventListener('submit', function (event) {
422
+ event.preventDefault();
423
+
424
+ const selectedSize = sizeSelect.value;
425
+ const selectedVariant = productData.variants.find(
426
+ (variant) => variant.title === selectedSize,
427
+ );
428
+
429
+ if (selectedVariant) {
430
+ const formData = {
431
+ variantRef: selectedVariant.id,
432
+ email: form.querySelector("input[name='email']").value,
433
+ subscribe: form.querySelector("input[name='mailList']").checked,
434
+ subscribeSms: form.querySelector("input[name='mailListSms']").checked,
435
+ };
436
+
437
+ if (type === 'coming-soon') {
438
+ formData.comingSoon = true;
439
+ // formData.productRef = productData.id;
440
+ } else {
441
+ formData.notifyMe = true;
442
+ }
443
+ if (fields.includes('firstName')) {
444
+ formData.firstName = form.querySelector(
445
+ "input[name='firstName']",
446
+ ).value;
447
+ }
448
+ if (fields.includes('lastName')) {
449
+ formData.lastName = form.querySelector(
450
+ "input[name='lastName']",
451
+ ).value;
452
+ }
453
+ if (fields.includes('mobile')) {
454
+ formData.mobile = form.querySelector("input[name='mobile']").value;
455
+ // formData.phone = form.querySelector("input[name='mobile']").value;
456
+ }
457
+
458
+ // Country / province / market — manual fields take precedence over auto-detected values
459
+ if (fields.includes('countryCode')) {
460
+ const selected = form.querySelector("select[name='countryCode']").value;
461
+ if (selected) formData.countryCode = selected;
462
+ } else if (countryCtx.countryCode) {
463
+ formData.countryCode = countryCtx.countryCode;
464
+ }
465
+
466
+ if (fields.includes('provinceCode')) {
467
+ const val = form.querySelector("input[name='provinceCode']").value;
468
+ if (val) formData.provinceCode = val;
469
+ } else if (countryCtx.provinceCode) {
470
+ formData.provinceCode = countryCtx.provinceCode;
471
+ }
472
+
473
+ if (resolvedMarketId) formData.marketId = resolvedMarketId;
474
+
475
+ let url = `https://api.au-sandbox.thewishlist.io/services/wsservice/api/wishlist/items/customerInterest`;
476
+
477
+ fetch(url, {
478
+ method: 'POST',
479
+ headers: {
480
+ 'Content-Type': 'application/json',
481
+ Authorization: ACCESS_TOKEN,
482
+ 'X-Twc-Tenant': TENANT_ID,
483
+ },
484
+ body: JSON.stringify(formData),
485
+ })
486
+ .then((response) => {
487
+ if (response.ok) {
488
+ alert('Form submitted');
489
+ hidePopup();
490
+ } else {
491
+ alert('Form submission failed');
492
+ }
493
+ })
494
+ .catch((error) => {
495
+ console.error('Error submitting form:', error);
496
+ alert('Form submission failed');
497
+ });
498
+ } else {
499
+ alert('Selected variant not found');
500
+ }
501
+ });
502
+ }
503
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notify-me-wl",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"