ui.shipaid.com 0.3.66 → 0.3.67
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/README.md +200 -200
- package/dist/widget.es.js +2 -2
- package/dist/widget.iife.js +2 -2
- package/dist/widget.umd.js +2 -2
- package/dist-types/common/shopify/index.d.ts +6 -6
- package/dist-types/common/shopify/protection.d.ts +7 -7
- package/dist-types/common/shopify/types/ShopifyCart.d.ts +29 -29
- package/dist-types/common/shopify/types/ShopifyProduct.d.ts +12 -12
- package/dist-types/common/types/ShipAid.d.ts +82 -82
- package/dist-types/widget/src/assets/confirmation-styles.d.ts +2 -2
- package/dist-types/widget/src/assets/icons.d.ts +9 -9
- package/dist-types/widget/src/assets/learn-more-styles.d.ts +2 -2
- package/dist-types/widget/src/assets/styles.d.ts +2 -2
- package/dist-types/widget/src/components/checkout-package-protection.d.ts +13 -13
- package/dist-types/widget/src/components/confirmation-popup.d.ts +9 -9
- package/dist-types/widget/src/components/learn-more-popup.d.ts +8 -8
- package/dist-types/widget/src/components/product-add-confirmation.d.ts +13 -0
- package/dist-types/widget/src/components/shipaid-cart-confirmation.d.ts +15 -15
- package/dist-types/widget/src/shipaid-widget.d.ts +145 -145
- package/dist-types/widget/src/utils/fetch_interceptor.d.ts +3 -3
- package/dist-types/widget/src/utils/fetch_interceptor.test.d.ts +1 -1
- package/dist-types/widget/types/shipaid.d.ts +10 -10
- package/dist-types/widget/types/shopify.d.ts +29 -29
- package/dist-types/widget/types/widget.d.ts +13 -13
- package/package.json +48 -48
- package/dist-types/widget/src/components/checkout-button.d.ts +0 -7
- package/dist-types/widget/src/components/checkoutButton.d.ts +0 -13
- package/dist-types/widget/src/components/content-loader.d.ts +0 -6
package/README.md
CHANGED
|
@@ -1,200 +1,200 @@
|
|
|
1
|
-
# ShipAid Shopify Widget
|
|
2
|
-
|
|
3
|
-
This is the repository for the ShipAid Shopify (and possibly others in future) widget. It uses the [Lit](https://lit.dev/) web components library, so it is recommended to become familiar with it before contributing to this repository.
|
|
4
|
-
|
|
5
|
-
Using Lit provides a framework that allows us to build a reactive UI, using JSX-like syntax - no need to use JQuery etc. And it can easily be installed in a page by using the custom web component name:
|
|
6
|
-
```html
|
|
7
|
-
<shipaid-widget>Fallback Content</shipaid-widget>
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## Overview
|
|
11
|
-
|
|
12
|
-
This widget provides an interface where a user can choose to add or remove ShipAid protection - this is actually a product in their store that can be added to cart. When the component is loaded, we immediately run a request to fetch the ShipAid protection product details from our API, as well as the customers current cart from the [Shopify AJAX API](https://shopify.dev/api/ajax/reference/cart).
|
|
13
|
-
Once we have this data, we can check whether the customer currently has the ShipAid product in their cart, and show either the add or remove product buttons based on this.
|
|
14
|
-
|
|
15
|
-
We also emit various [custom events](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#adding_custom_data_%E2%80%93_customevent) when we add or remove the ShipAid product from the cart, so other developers can listen to these events, and update AJAX carts.
|
|
16
|
-
|
|
17
|
-
### Installation
|
|
18
|
-
|
|
19
|
-
Add the script tag to the theme - if the theme has an ajax cart, you'll likely want to add this to the `theme.liquid` file, otherwise if the store has only a cart page (`/cart`), then you can add it to just that page, to save it being unecessarily loaded when it isn't needed.
|
|
20
|
-
As we don't want to affect a stores speed at all, you should add it to the bottom of the page just before the ending body tag (`</body>`), rather than inside the `<head>` block.
|
|
21
|
-
|
|
22
|
-
```html
|
|
23
|
-
<!-- ShipAid Widget -->
|
|
24
|
-
<script src="https://unpkg.com/ui.shipaid.com/dist/widget.es.js" type="module"></script>
|
|
25
|
-
```
|
|
26
|
-
Then add the widget element where needed:
|
|
27
|
-
|
|
28
|
-
```html
|
|
29
|
-
<shipaid-widget></shipaid-widget>
|
|
30
|
-
|
|
31
|
-
<!-- Disable polling example -->
|
|
32
|
-
<shipaid-widget disablePolling></shipaid-widget>
|
|
33
|
-
|
|
34
|
-
<!-- With customised text -->
|
|
35
|
-
<shipaid-widget>
|
|
36
|
-
<p slot="loading">Loading ShipAid Protection</p>
|
|
37
|
-
</shipaid-widget>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
#### Test Mode
|
|
41
|
-
|
|
42
|
-
Sometimes, a store won't have activated their subscription before you install the widget - in this case, the widget does not display (you will notice a message in the console reflecting this). So to force the widget to show while you are installing and testing it, you can add this query param to the page URL: `shipaid-test`.
|
|
43
|
-
For example: `https://some-store.myshopify.com/cart?shipaid-text`
|
|
44
|
-
|
|
45
|
-
### Slots
|
|
46
|
-
|
|
47
|
-
Slots, with the syntax `slot="<slot name>"`, can be used to customise the widgets content - for example, a merchant may want to add a custom subtitle, which can be done like so:
|
|
48
|
-
```html
|
|
49
|
-
<shipaid-widget>
|
|
50
|
-
<p slot="subtitle">Shipping protection is required to be able to return or refunds items.</p>
|
|
51
|
-
</shipaid-widget>
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
The default content will be replaced by any slot content. You can also add inline styles to the slots, if you need to change the font size/weight for example - but color changes should be handled by CSS variables:
|
|
55
|
-
```html
|
|
56
|
-
<span slot="title" style="font-weight: 500;">Package Protection</span>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
| Name | Description |
|
|
60
|
-
|--------|-------------|
|
|
61
|
-
| `loading` | Replaces the text that is shown whilst the widget is loading - I.e. fetching content from the Shopify or ShipAid API's. |
|
|
62
|
-
| `title` | Replaces the default title. |
|
|
63
|
-
| `subtitle` | Replaces the default subtitle. |
|
|
64
|
-
|
|
65
|
-
### Props
|
|
66
|
-
|
|
67
|
-
This is a list of props that can be used to configure the widget:
|
|
68
|
-
|
|
69
|
-
| Prop | Description | Value/Type |
|
|
70
|
-
|--------|-------------|---------|
|
|
71
|
-
| `disablePolling` | Sets whether the cart should disable polling (enabled by default) - should be disabled if integrating manually with an ajax cart. | `boolean` |
|
|
72
|
-
| `pollingInterval` | If polling is enabled, it sets the interval (in ms) between API updates. | `number` in milliseconds |
|
|
73
|
-
| `disableRefresh ` | Sets whether the store cart should be updated when the protection item is added/removed. Add if you want to initially hide the protection product from the cart, even if it has just been added. | `boolean` |
|
|
74
|
-
| `customerId ` | Passes the information of the customer to the widget. Add if merchant wants to disable auto opt-in for some customers based on the customer tags. | `boolean` |
|
|
75
|
-
| `lang ` | Sets the widget language (see the translations section below). This value can be any supported [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). | `string` defaults to `en` |
|
|
76
|
-
| `refreshCart` | Refresh the page if shipaid product quantity is greater than one to sync product qty at checkout | `boolean` |
|
|
77
|
-
| `persistPopup` | Use local storage to show popup so that popup don't re-render on script refresh | `boolean` |
|
|
78
|
-
|
|
79
|
-
### Events
|
|
80
|
-
|
|
81
|
-
This is a list of the events emitted by the widget. You can listen to these events like so:
|
|
82
|
-
```js
|
|
83
|
-
document.addEventListener('shipaid-protection-status', ({ detail }) => {
|
|
84
|
-
console.log(detail.cart) // ShopifyCart
|
|
85
|
-
})
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
| Event | Description | Payload |
|
|
89
|
-
|-------|-------------|---------|
|
|
90
|
-
| `shipaid-loaded` | Dispatched when the widget has finished fetching data from the API, and has successfully rendered. | Contains the data from the ShipAid API: [`ShipAidStore`](/types/shipaid.ts) |
|
|
91
|
-
| `shipaid-protection-status` | Dispatched when a user either adds or removes the protection product from their cart. | `{ protection: boolean, cart: ShopifyCart, lineItem: ShopifyCartItem }` |
|
|
92
|
-
|
|
93
|
-
### Methods
|
|
94
|
-
|
|
95
|
-
This is a list of public methods available on the widget HTMLElement that can be used to change protection settings. These can be used by querying the element:
|
|
96
|
-
|
|
97
|
-
```js
|
|
98
|
-
const shipAidEl = document.querySelector('shipaid-widget')
|
|
99
|
-
if (shipAidEl) await shipAidEl.updateCart()
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
| Method | Description | Payload |
|
|
103
|
-
|--------|-------------|---------|
|
|
104
|
-
| `hasProtection` | Returns a boolean which indicates whether the protection item is currently in the cart. | |
|
|
105
|
-
| `updateCart` | Updates the internal cart, and triggers any protection product updates - use this method with with ajax carts, to update protection state without needing to reload the page. | Optional - the cart object from the ajax API. |
|
|
106
|
-
| `addProtection` | Adds the relevant protection item to cart. | |
|
|
107
|
-
| `removeProtection` | Removes the protection item from the cart. | |
|
|
108
|
-
|
|
109
|
-
### Styles
|
|
110
|
-
|
|
111
|
-
If you need to change any of the widget colors to suit a specific theme, there are various CSS variables you can use to do so. These should be added to the style attribute on the widget element:
|
|
112
|
-
|
|
113
|
-
```html
|
|
114
|
-
<shipaid-widget
|
|
115
|
-
style="
|
|
116
|
-
--shipaid-text: #fff;
|
|
117
|
-
--shipaid-prompt-actions-price-color: #fff;
|
|
118
|
-
"
|
|
119
|
-
>
|
|
120
|
-
</shipaid-widget>
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
| Variable | Description | Default |
|
|
124
|
-
|----------|-------------|---------|
|
|
125
|
-
| `--shipaid-text` | Changes the global text color. | `#000000` |
|
|
126
|
-
| `--shipaid-text-muted` | Changes the global muted text color. | `#aaaaaa` |
|
|
127
|
-
| `--shipaid-prompt-margin` | Changes the margins of the main container element. | `2rem 0px 4rem auto` |
|
|
128
|
-
| `--shipaid-prompt-width` | Changes the width of the main container element. | `400px` |
|
|
129
|
-
| `--shipaid-prompt-width-mobile` | Changes the mobile width of the main container element. | `100%` |
|
|
130
|
-
| `--shipaid-prompt-actions-price-color` | Changes the color of the price element. | `var(--shipaid-text-muted)` |
|
|
131
|
-
| `--shipaid-prompt-actions-button-color` | Changes the color of the add/remove button element. | `var(--shipaid-primary)` |
|
|
132
|
-
| `--shipaid-prompt-badge-background-color` | Changes the background color of the learn more button element. | `var(--shipaid-light-grey)` |
|
|
133
|
-
| `--shipaid-prompt-badge-text-color` | Changes the color of the learn more button element. | `var(--shipaid-text)` |
|
|
134
|
-
| `--shipaid-logo-height` | Changes the height of ShipAid logo. | `var(--shipaid-logo-height, 35px)` |
|
|
135
|
-
| `--shipaid-logo-max-height` | Changes the max height of ShipAid logo. | `var(--shipaid-logo-max-height, 35px)` |
|
|
136
|
-
| `--shipaid-logo-width` | Changes the width of ShipAid logo. | `var(--shipaid-logo-width, auto)` |
|
|
137
|
-
| `--shipaid-logo-max-width` | Changes the max width of ShipAid logo. | `var(--shipaid-logo-max-width, 50px)` |
|
|
138
|
-
| `--shipaid-prompt-footer-button-size` | Changes the height of info button in footer. | `var(--shipaid-prompt-footer-button-size, 10px)` |
|
|
139
|
-
| `--shipaid-prompt-badge-border-radius` | Changes border radius of footer | `var(--shipaid-prompt-badge-border-radius, 30px)` |
|
|
140
|
-
| `--shipaid-footer-badge-logo-height` | Changes the height of logo in footer. | `var(--shipaid-footer-badge-logo-height, 9px)` |
|
|
141
|
-
| `--shipaid-prompt-footer-location` | Changes the position of footer badge | `var(--shipaid-prompt-footer-location, flex-start)` |
|
|
142
|
-
| `--shipaid-prompt-product-actions-content` | Changes the spaces between price and add/remove button | `var(--shipaid-prompt-product-actions-content, space-between)` |
|
|
143
|
-
| `--shipaid-prompt-footer-topMargin` | Changes margin between header and badge footer | `var(--shipaid-prompt-footer-topMargin, 0px)` |
|
|
144
|
-
| `-shipaid-prompt-footer-display` | Changes the display option for footer | `var(-shipaid-prompt-footer-display, flex)` |
|
|
145
|
-
|
|
146
|
-
Other variables can be found [here](/widget/src/assets/styles.ts) (`/widget/src/assets/styles.ts`).
|
|
147
|
-
|
|
148
|
-
### Translations
|
|
149
|
-
|
|
150
|
-
This widget also supports multiple languages, using the `lit-translate` plugin. The widget language can be configured using an attribute and would usally be static, but supports reactively swapping the language if a theme needs - i.e. if a user switches the language using a select option in the theme, then the widget language could be updated at the same time by selecting the widget element, and setting the `lang` attribute.
|
|
151
|
-
|
|
152
|
-
To create lang files, you should copy the default `/lang/en.json` file, and rename it to an [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) - for example `cp /src/lang/en.json /src/lang/fs.json`. You can then go through each key, and translate the existing text to the relevant language. This should be all you need to do - the widget automatically (and lazily, to save bundle size) imports the relevant lang file when it is specified. It will also fallback to the default `en.json` lang file if a certain language doesn't exist yet.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
## Contributing
|
|
156
|
-
|
|
157
|
-
### Requirements
|
|
158
|
-
|
|
159
|
-
- Node v16+
|
|
160
|
-
- PNPM
|
|
161
|
-
- Development Shopify store (with the ShipAid app installed)
|
|
162
|
-
- ShipAid API development/staging instance
|
|
163
|
-
|
|
164
|
-
### Development
|
|
165
|
-
|
|
166
|
-
You will need to make sure your development store has the ShipAid app installed, so the store and its protection product is added to the DB. You will also need to ensure the Shopify app you are testing this with has an app proxy added, and pointed towards an API instance.
|
|
167
|
-
|
|
168
|
-
```sh
|
|
169
|
-
pnpm install
|
|
170
|
-
pnpm run develop
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Once the project is running, add the below to your development Shopify store `theme.liquid`:
|
|
174
|
-
|
|
175
|
-
```html
|
|
176
|
-
<!-- Dev -->
|
|
177
|
-
<script src="http://localhost:3000/src/shipaid-widget.ts"type="module" ></script>
|
|
178
|
-
|
|
179
|
-
<!-- Prod -->
|
|
180
|
-
<!-- ShipAid Widget -->
|
|
181
|
-
<script src="https://unpkg.com/ui.shipaid.com/dist/widget.es.js" type="module"></script>
|
|
182
|
-
```
|
|
183
|
-
And add the widget element where needed:
|
|
184
|
-
|
|
185
|
-
```html
|
|
186
|
-
<shipaid-widget>
|
|
187
|
-
<p>Loading ShipAid Protection</p>
|
|
188
|
-
</shipaid-widget>
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Build
|
|
192
|
-
|
|
193
|
-
Once the project has been built, you can publish the project to NPM, and users can add the script to their store using a package CDN (I.e. [Unpkg](https://unpkg.com/)).
|
|
194
|
-
|
|
195
|
-
```sh
|
|
196
|
-
pnpm install
|
|
197
|
-
pnpm run lint
|
|
198
|
-
pnpm run build
|
|
199
|
-
pnpm publish
|
|
200
|
-
```
|
|
1
|
+
# ShipAid Shopify Widget
|
|
2
|
+
|
|
3
|
+
This is the repository for the ShipAid Shopify (and possibly others in future) widget. It uses the [Lit](https://lit.dev/) web components library, so it is recommended to become familiar with it before contributing to this repository.
|
|
4
|
+
|
|
5
|
+
Using Lit provides a framework that allows us to build a reactive UI, using JSX-like syntax - no need to use JQuery etc. And it can easily be installed in a page by using the custom web component name:
|
|
6
|
+
```html
|
|
7
|
+
<shipaid-widget>Fallback Content</shipaid-widget>
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
This widget provides an interface where a user can choose to add or remove ShipAid protection - this is actually a product in their store that can be added to cart. When the component is loaded, we immediately run a request to fetch the ShipAid protection product details from our API, as well as the customers current cart from the [Shopify AJAX API](https://shopify.dev/api/ajax/reference/cart).
|
|
13
|
+
Once we have this data, we can check whether the customer currently has the ShipAid product in their cart, and show either the add or remove product buttons based on this.
|
|
14
|
+
|
|
15
|
+
We also emit various [custom events](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#adding_custom_data_%E2%80%93_customevent) when we add or remove the ShipAid product from the cart, so other developers can listen to these events, and update AJAX carts.
|
|
16
|
+
|
|
17
|
+
### Installation
|
|
18
|
+
|
|
19
|
+
Add the script tag to the theme - if the theme has an ajax cart, you'll likely want to add this to the `theme.liquid` file, otherwise if the store has only a cart page (`/cart`), then you can add it to just that page, to save it being unecessarily loaded when it isn't needed.
|
|
20
|
+
As we don't want to affect a stores speed at all, you should add it to the bottom of the page just before the ending body tag (`</body>`), rather than inside the `<head>` block.
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<!-- ShipAid Widget -->
|
|
24
|
+
<script src="https://unpkg.com/ui.shipaid.com/dist/widget.es.js" type="module"></script>
|
|
25
|
+
```
|
|
26
|
+
Then add the widget element where needed:
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<shipaid-widget></shipaid-widget>
|
|
30
|
+
|
|
31
|
+
<!-- Disable polling example -->
|
|
32
|
+
<shipaid-widget disablePolling></shipaid-widget>
|
|
33
|
+
|
|
34
|
+
<!-- With customised text -->
|
|
35
|
+
<shipaid-widget>
|
|
36
|
+
<p slot="loading">Loading ShipAid Protection</p>
|
|
37
|
+
</shipaid-widget>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Test Mode
|
|
41
|
+
|
|
42
|
+
Sometimes, a store won't have activated their subscription before you install the widget - in this case, the widget does not display (you will notice a message in the console reflecting this). So to force the widget to show while you are installing and testing it, you can add this query param to the page URL: `shipaid-test`.
|
|
43
|
+
For example: `https://some-store.myshopify.com/cart?shipaid-text`
|
|
44
|
+
|
|
45
|
+
### Slots
|
|
46
|
+
|
|
47
|
+
Slots, with the syntax `slot="<slot name>"`, can be used to customise the widgets content - for example, a merchant may want to add a custom subtitle, which can be done like so:
|
|
48
|
+
```html
|
|
49
|
+
<shipaid-widget>
|
|
50
|
+
<p slot="subtitle">Shipping protection is required to be able to return or refunds items.</p>
|
|
51
|
+
</shipaid-widget>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The default content will be replaced by any slot content. You can also add inline styles to the slots, if you need to change the font size/weight for example - but color changes should be handled by CSS variables:
|
|
55
|
+
```html
|
|
56
|
+
<span slot="title" style="font-weight: 500;">Package Protection</span>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| Name | Description |
|
|
60
|
+
|--------|-------------|
|
|
61
|
+
| `loading` | Replaces the text that is shown whilst the widget is loading - I.e. fetching content from the Shopify or ShipAid API's. |
|
|
62
|
+
| `title` | Replaces the default title. |
|
|
63
|
+
| `subtitle` | Replaces the default subtitle. |
|
|
64
|
+
|
|
65
|
+
### Props
|
|
66
|
+
|
|
67
|
+
This is a list of props that can be used to configure the widget:
|
|
68
|
+
|
|
69
|
+
| Prop | Description | Value/Type |
|
|
70
|
+
|--------|-------------|---------|
|
|
71
|
+
| `disablePolling` | Sets whether the cart should disable polling (enabled by default) - should be disabled if integrating manually with an ajax cart. | `boolean` |
|
|
72
|
+
| `pollingInterval` | If polling is enabled, it sets the interval (in ms) between API updates. | `number` in milliseconds |
|
|
73
|
+
| `disableRefresh ` | Sets whether the store cart should be updated when the protection item is added/removed. Add if you want to initially hide the protection product from the cart, even if it has just been added. | `boolean` |
|
|
74
|
+
| `customerId ` | Passes the information of the customer to the widget. Add if merchant wants to disable auto opt-in for some customers based on the customer tags. | `boolean` |
|
|
75
|
+
| `lang ` | Sets the widget language (see the translations section below). This value can be any supported [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). | `string` defaults to `en` |
|
|
76
|
+
| `refreshCart` | Refresh the page if shipaid product quantity is greater than one to sync product qty at checkout | `boolean` |
|
|
77
|
+
| `persistPopup` | Use local storage to show popup so that popup don't re-render on script refresh | `boolean` |
|
|
78
|
+
|
|
79
|
+
### Events
|
|
80
|
+
|
|
81
|
+
This is a list of the events emitted by the widget. You can listen to these events like so:
|
|
82
|
+
```js
|
|
83
|
+
document.addEventListener('shipaid-protection-status', ({ detail }) => {
|
|
84
|
+
console.log(detail.cart) // ShopifyCart
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| Event | Description | Payload |
|
|
89
|
+
|-------|-------------|---------|
|
|
90
|
+
| `shipaid-loaded` | Dispatched when the widget has finished fetching data from the API, and has successfully rendered. | Contains the data from the ShipAid API: [`ShipAidStore`](/types/shipaid.ts) |
|
|
91
|
+
| `shipaid-protection-status` | Dispatched when a user either adds or removes the protection product from their cart. | `{ protection: boolean, cart: ShopifyCart, lineItem: ShopifyCartItem }` |
|
|
92
|
+
|
|
93
|
+
### Methods
|
|
94
|
+
|
|
95
|
+
This is a list of public methods available on the widget HTMLElement that can be used to change protection settings. These can be used by querying the element:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
const shipAidEl = document.querySelector('shipaid-widget')
|
|
99
|
+
if (shipAidEl) await shipAidEl.updateCart()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
| Method | Description | Payload |
|
|
103
|
+
|--------|-------------|---------|
|
|
104
|
+
| `hasProtection` | Returns a boolean which indicates whether the protection item is currently in the cart. | |
|
|
105
|
+
| `updateCart` | Updates the internal cart, and triggers any protection product updates - use this method with with ajax carts, to update protection state without needing to reload the page. | Optional - the cart object from the ajax API. |
|
|
106
|
+
| `addProtection` | Adds the relevant protection item to cart. | |
|
|
107
|
+
| `removeProtection` | Removes the protection item from the cart. | |
|
|
108
|
+
|
|
109
|
+
### Styles
|
|
110
|
+
|
|
111
|
+
If you need to change any of the widget colors to suit a specific theme, there are various CSS variables you can use to do so. These should be added to the style attribute on the widget element:
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<shipaid-widget
|
|
115
|
+
style="
|
|
116
|
+
--shipaid-text: #fff;
|
|
117
|
+
--shipaid-prompt-actions-price-color: #fff;
|
|
118
|
+
"
|
|
119
|
+
>
|
|
120
|
+
</shipaid-widget>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Variable | Description | Default |
|
|
124
|
+
|----------|-------------|---------|
|
|
125
|
+
| `--shipaid-text` | Changes the global text color. | `#000000` |
|
|
126
|
+
| `--shipaid-text-muted` | Changes the global muted text color. | `#aaaaaa` |
|
|
127
|
+
| `--shipaid-prompt-margin` | Changes the margins of the main container element. | `2rem 0px 4rem auto` |
|
|
128
|
+
| `--shipaid-prompt-width` | Changes the width of the main container element. | `400px` |
|
|
129
|
+
| `--shipaid-prompt-width-mobile` | Changes the mobile width of the main container element. | `100%` |
|
|
130
|
+
| `--shipaid-prompt-actions-price-color` | Changes the color of the price element. | `var(--shipaid-text-muted)` |
|
|
131
|
+
| `--shipaid-prompt-actions-button-color` | Changes the color of the add/remove button element. | `var(--shipaid-primary)` |
|
|
132
|
+
| `--shipaid-prompt-badge-background-color` | Changes the background color of the learn more button element. | `var(--shipaid-light-grey)` |
|
|
133
|
+
| `--shipaid-prompt-badge-text-color` | Changes the color of the learn more button element. | `var(--shipaid-text)` |
|
|
134
|
+
| `--shipaid-logo-height` | Changes the height of ShipAid logo. | `var(--shipaid-logo-height, 35px)` |
|
|
135
|
+
| `--shipaid-logo-max-height` | Changes the max height of ShipAid logo. | `var(--shipaid-logo-max-height, 35px)` |
|
|
136
|
+
| `--shipaid-logo-width` | Changes the width of ShipAid logo. | `var(--shipaid-logo-width, auto)` |
|
|
137
|
+
| `--shipaid-logo-max-width` | Changes the max width of ShipAid logo. | `var(--shipaid-logo-max-width, 50px)` |
|
|
138
|
+
| `--shipaid-prompt-footer-button-size` | Changes the height of info button in footer. | `var(--shipaid-prompt-footer-button-size, 10px)` |
|
|
139
|
+
| `--shipaid-prompt-badge-border-radius` | Changes border radius of footer | `var(--shipaid-prompt-badge-border-radius, 30px)` |
|
|
140
|
+
| `--shipaid-footer-badge-logo-height` | Changes the height of logo in footer. | `var(--shipaid-footer-badge-logo-height, 9px)` |
|
|
141
|
+
| `--shipaid-prompt-footer-location` | Changes the position of footer badge | `var(--shipaid-prompt-footer-location, flex-start)` |
|
|
142
|
+
| `--shipaid-prompt-product-actions-content` | Changes the spaces between price and add/remove button | `var(--shipaid-prompt-product-actions-content, space-between)` |
|
|
143
|
+
| `--shipaid-prompt-footer-topMargin` | Changes margin between header and badge footer | `var(--shipaid-prompt-footer-topMargin, 0px)` |
|
|
144
|
+
| `-shipaid-prompt-footer-display` | Changes the display option for footer | `var(-shipaid-prompt-footer-display, flex)` |
|
|
145
|
+
|
|
146
|
+
Other variables can be found [here](/widget/src/assets/styles.ts) (`/widget/src/assets/styles.ts`).
|
|
147
|
+
|
|
148
|
+
### Translations
|
|
149
|
+
|
|
150
|
+
This widget also supports multiple languages, using the `lit-translate` plugin. The widget language can be configured using an attribute and would usally be static, but supports reactively swapping the language if a theme needs - i.e. if a user switches the language using a select option in the theme, then the widget language could be updated at the same time by selecting the widget element, and setting the `lang` attribute.
|
|
151
|
+
|
|
152
|
+
To create lang files, you should copy the default `/lang/en.json` file, and rename it to an [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) - for example `cp /src/lang/en.json /src/lang/fs.json`. You can then go through each key, and translate the existing text to the relevant language. This should be all you need to do - the widget automatically (and lazily, to save bundle size) imports the relevant lang file when it is specified. It will also fallback to the default `en.json` lang file if a certain language doesn't exist yet.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
### Requirements
|
|
158
|
+
|
|
159
|
+
- Node v16+
|
|
160
|
+
- PNPM
|
|
161
|
+
- Development Shopify store (with the ShipAid app installed)
|
|
162
|
+
- ShipAid API development/staging instance
|
|
163
|
+
|
|
164
|
+
### Development
|
|
165
|
+
|
|
166
|
+
You will need to make sure your development store has the ShipAid app installed, so the store and its protection product is added to the DB. You will also need to ensure the Shopify app you are testing this with has an app proxy added, and pointed towards an API instance.
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
pnpm install
|
|
170
|
+
pnpm run develop
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Once the project is running, add the below to your development Shopify store `theme.liquid`:
|
|
174
|
+
|
|
175
|
+
```html
|
|
176
|
+
<!-- Dev -->
|
|
177
|
+
<script src="http://localhost:3000/src/shipaid-widget.ts"type="module" ></script>
|
|
178
|
+
|
|
179
|
+
<!-- Prod -->
|
|
180
|
+
<!-- ShipAid Widget -->
|
|
181
|
+
<script src="https://unpkg.com/ui.shipaid.com/dist/widget.es.js" type="module"></script>
|
|
182
|
+
```
|
|
183
|
+
And add the widget element where needed:
|
|
184
|
+
|
|
185
|
+
```html
|
|
186
|
+
<shipaid-widget>
|
|
187
|
+
<p>Loading ShipAid Protection</p>
|
|
188
|
+
</shipaid-widget>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Build
|
|
192
|
+
|
|
193
|
+
Once the project has been built, you can publish the project to NPM, and users can add the script to their store using a package CDN (I.e. [Unpkg](https://unpkg.com/)).
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
pnpm install
|
|
197
|
+
pnpm run lint
|
|
198
|
+
pnpm run build
|
|
199
|
+
pnpm publish
|
|
200
|
+
```
|
package/dist/widget.es.js
CHANGED
|
@@ -2833,7 +2833,7 @@ const _ShipAidWidget = class _ShipAidWidget extends s$1 {
|
|
|
2833
2833
|
/** Try adding ShipAid shipping protection during polling if applicable */
|
|
2834
2834
|
async attemptAddProtection() {
|
|
2835
2835
|
var _a, _b, _c, _d, _e, _f;
|
|
2836
|
-
if (!((_a = this._store) == null ? void 0 : _a.widgetAutoOptIn)
|
|
2836
|
+
if (!((_a = this._store) == null ? void 0 : _a.widgetAutoOptIn)) return;
|
|
2837
2837
|
if (!((_b = this._cart) == null ? void 0 : _b.items) || !((_c = this._cart) == null ? void 0 : _c.item_count)) return;
|
|
2838
2838
|
const protectionCartItemIndex = (_d = this._cart.items) == null ? void 0 : _d.findIndex((item) => {
|
|
2839
2839
|
var _a2, _b2;
|
|
@@ -3523,7 +3523,7 @@ const _ShipAidWidget = class _ShipAidWidget extends s$1 {
|
|
|
3523
3523
|
this._dispatchEvent(Events.LOADED, this._store);
|
|
3524
3524
|
setTimeout(async () => {
|
|
3525
3525
|
var _a2, _b2, _c2, _d2;
|
|
3526
|
-
if (!((_a2 = this._store) == null ? void 0 : _a2.widgetAutoOptIn)
|
|
3526
|
+
if (!((_a2 = this._store) == null ? void 0 : _a2.widgetAutoOptIn)) return;
|
|
3527
3527
|
if (!((_b2 = this._cart) == null ? void 0 : _b2.item_count)) return;
|
|
3528
3528
|
if (this.customerId && this._store.excludedCustomersIdsAutoOptIn && ((_c2 = this._store.excludedCustomersIdsAutoOptIn) == null ? void 0 : _c2.length) && this._store.excludedCustomersIdsAutoOptIn.includes(`gid://shopify/Customer/${this.customerId}`)) {
|
|
3529
3529
|
return;
|
package/dist/widget.iife.js
CHANGED
|
@@ -1168,7 +1168,7 @@ function qt(t,e,i){return t?e():null==i?void 0:i()}const jt=u`
|
|
|
1168
1168
|
.shipaid-prompt .prompt-footer .prompt-footer-badge svg {
|
|
1169
1169
|
height:var(--shipaid-footer-badge-logo-height, 9px);
|
|
1170
1170
|
}
|
|
1171
|
-
`;var me=(t=>(t.LOADED="shipaid-loaded",t.STATUS_UPDATE="shipaid-protection-status",t))(me||{});var ge=Object.defineProperty,fe=(t,e,i,o)=>{for(var r,n=void 0,s=t.length-1;s>=0;s--)(r=t[s])&&(n=r(e,i,n)||n);return n&&ge(e,i,n),n};const ve=t=>({items:t.lines.edges.map((({node:t})=>({id:t.id,key:t.id,variant_id:t.merchandise.id,sku:t.merchandise.sku,final_line_price:parseFloat(t.cost.totalAmount.amount),quantity:t.quantity}))),total_price:parseFloat(t.cost.totalAmount.amount),item_count:t.lines.edges.length}),be=async(t,e)=>{try{const i=await fetch(t,e);if(!i.ok)throw new Error(await i.text());return await i.json()}catch(i){throw console.error(i),new Error("Failed to complete fetch request.")}},ye=t=>console.warn(`[ShipAid] ${t}`),_e=t=>console.error(`[ShipAid] ${t}`),we="shipaid-protection",Ce="shipaid-protection-popup-show",xe="shipaid-protection",$e="query StoreByDomain ($store: String!) {\n store: storeByDomain (input: {store: $store}) {\n currency\n planActive\n store\n widgetAutoOptIn\n widgetPollProtection\n widgetShowCart\n excludedProductSkus\n excludedCustomersIdsAutoOptIn\n protectionSettings\n widgetConfigurations\n useCustomApp\n }\n}",ke=Object.assign({"./lang/de.json":()=>Promise.resolve().then((()=>qe)).then((t=>t.default)),"./lang/en.json":()=>Promise.resolve().then((()=>he)).then((t=>t.default)),"./lang/es.json":()=>Promise.resolve().then((()=>Be)).then((t=>t.default)),"./lang/fr.json":()=>Promise.resolve().then((()=>Ke)).then((t=>t.default)),"./lang/it.json":()=>Promise.resolve().then((()=>ii)).then((t=>t.default)),"./lang/nl.json":()=>Promise.resolve().then((()=>pi)).then((t=>t.default)),"./lang/pt.json":()=>Promise.resolve().then((()=>fi)).then((t=>t.default))});var Se;Se={loader:async t=>{if("en"===t)return ce;const e=Reflect.get(ke,`./lang/${t}.json`);return e?await e():ce}},bt=Object.assign(Object.assign({},bt),Se);const Ae=class extends ht{constructor(){var t,e,i;super(...arguments),this.env="prod",this.useCustomStoreFront=!1,this.storeDomain="",this.storeAccessToken="",this.cartId="",this.disablePolling=!1,this.disableActions=!1,this.pollingInterval=2500,this.disableRefresh=!1,this.refreshCart=!1,this.persistPopup=!1,this.defaultToggleButton=!1,this.lang="en",this.currency=void 0,this.customerId=void 0,this.supportSubscriptions=!1,this.dataSelector="",this.useShipAidCheckout=!1,this._apiEndpoint="/apps/shipaid",this._storeDomain=(null==(t=window.Shopify)?void 0:t.shop)??(null==(i=null==(e=window.Shopify)?void 0:e.Checkout)?void 0:i.apiHost),this._hasFinishedSetup=!1,this._shouldShowWidget=!1,this._hasProtectionInCart=!1,this.hasLoadedStrings=!1,this.fetchInterceptorCleanup=()=>{},this.intervalId=null,this._state={loading:!1,success:null,error:!1},this._popup=null,this._fetch={get:t=>be(t),post:(t,e)=>be(t,{method:"POST",headers:{"Content-Type":"application/json","X-ShipAid":"1"},body:JSON.stringify(e)})}}shouldUpdate(t){return this.hasLoadedStrings&&super.shouldUpdate(t)}shouldPersistPopup(){return"true"===localStorage.getItem(`${Ce}`)?"learn-more":null}setPopupKey(){this.persistPopup&&localStorage.setItem(`${Ce}`,"true")}get nhost(){const t=`https://${"prod"===this.env?"gjiyysyzjwuculcymsvb":"staging"===this.env?"xfnjpunvafvudwuzwjlm":"local"}.graphql.us-east-1.nhost.run/v1`;return{request:async(e,i)=>{try{const o=await fetch(t,{method:"post",body:JSON.stringify({query:e,variables:i})});return await o.json()}catch(o){console.log(`Nhost Error: ${o}`)}}}}async runStoreFrontQuery(t,e){try{const i=new Headers;i.append("Content-Type","application/json"),i.append("X-Shopify-Storefront-Access-Token",this.storeAccessToken);const o={method:"POST",headers:i,body:JSON.stringify({query:t,variables:e})},r=await fetch(`https://${this.storeDomain}/api/2021-07/graphql.json`,o);if(!r.ok)throw new Error(`GraphQL request failed: ${r.statusText}`);const n=await r.json();if(n.errors)throw new Error(n.errors[0].message);return n.data}catch(i){throw console.error("GraphQL query error:",i),new Error("Failed to execute GraphQL query")}}get shouldRefreshOnUpdate(){return!this.disablePolling&&!this.disableRefresh}get planActive(){var t,e;const{searchParams:i}=new URL(window.location.href);return(null==(t=window.Shopify)?void 0:t.designMode)||i.has("shipaid-test")?(ye("Currently in preview mode."),!0):!!(null==(e=this._store)?void 0:e.planActive)}_currencyFormat(t){var e,i,o,r,n,s;const a=this.currency||(null==(i=null==(e=window.Shopify)?void 0:e.currency)?void 0:i.active)||(null==(o=this._store)?void 0:o.currency)||"USD";if(null==(s=null==(n=null==(r=this._store)?void 0:r.widgetConfigurations)?void 0:n.widget)?void 0:s.currencyFormat){return this._store.widgetConfigurations.widget.currencyFormat.replace("_value_",Number(t)).replace("_currency_",a)}return new Intl.NumberFormat(void 0,{currency:a,style:"currency"}).format(Number(t))}_dispatchEvent(t,e={}){this.dispatchEvent(new CustomEvent(t,{bubbles:!0,composed:!0,detail:e}))}_handleRefreshCart(){if(this.refreshCart)return window.location.reload()}async _handleRefresh(t){const e=Reflect.has(t,"items");if(this.shouldRefreshOnUpdate)return window.location.reload();e||await this.updateCart(),this._dispatchEvent(me.STATUS_UPDATE,{protection:this._hasProtectionInCart,cart:e?t:this._cart,lineItem:e?this._protectionCartItem:t})}async calculateProtectionTotal(t){if(t||(t=await this._fetchCart()),!t)throw new Error("Could not fetch cart.");if(!this._store)throw new Error("Missing ShipAid store");if(!this._protectionProduct)throw new Error("Missing Shopify protection product");return i.calculateProtectionTotal(this._store,this._protectionProduct,t)}_findProtectionVariant(t){if(!this._store)throw new Error("Missing ShipAid store");if(!this._protectionProduct)throw new Error("Missing Shopify protection product");return i.findProtectionVariant(this._store,this._protectionProduct,t)}_setState(t,e){this._state={loading:"loading"===t,success:"success"===t,error:"error"===t&&(e||!0)}}_handleConfirmationPopup(){"confirmation"!==this._popup&&(this._popup="confirmation")}_updateProtection(){var t,e,i;const o=null==(i=null==(e=null==(t=this._store)?void 0:t.widgetConfigurations)?void 0:e.widget)?void 0:i.removeWithConfirmation;if(this._hasProtectionInCart)return o?this._handleConfirmationPopup():this.removeProtection();this.addProtection()}async _fetchShipAidData(){var t,e,i,o,r;let n;if(n=this.storeDomain?this.storeDomain:(null==(t=window.Shopify)?void 0:t.shop)??(null==(i=null==(e=window.Shopify)?void 0:e.Checkout)?void 0:i.apiHost),!n)throw new Error("No shop found in Shopify object.");try{let t,e;if(this.useCustomStoreFront)e=await this.nhost.request($e,{store:n});else{t=new URL(window.location.href),t.pathname=this._apiEndpoint;const i={query:$e,variables:{store:n}};e=await this._fetch.post(t.toString(),i)}if(!e)throw new Error("Missing response for store query.");if(null==(o=e.errors)?void 0:o.length)throw new Error(e.errors[0].message);if(!(null==(r=e.data)?void 0:r.store))throw new Error("Missing store from store query response.");return e.data.store}catch(s){throw console.error(s),new Error(`Could not find a store for ${this._storeDomain}`)}}_findSellingPlanByName(t,e){for(const i of t){const t=i.node;for(const i of t.sellingPlans.edges){const t=i.node;if(e===t.name)return t}}return null}async _fetchSellingPlanFromVariant(t){var e,i,o,r,n,s,a,d,p,l,c,h,u;const m=(null==(e=window.Shopify)?void 0:e.shop)??(null==(o=null==(i=window.Shopify)?void 0:i.Checkout)?void 0:o.apiHost);if(!m)throw new Error("No shop found in Shopify object.");try{const e=new URL(window.location.href);e.pathname=this._apiEndpoint;const i={query:"query SellingPlanFromVariant($store: String!, $variantId: String!){\n sellingPlanFromVariant(input: {store: $store, variantId: $variantId })\n}",variables:{store:m,variantId:`gid://shopify/ProductVariant/${null==(r=this._protectionVariant)?void 0:r.id}`}},o=await this._fetch.post(e.toString(),i);if(!o)throw new Error("Missing response for selling plan query.");if(null==(n=o.errors)?void 0:n.length)throw new Error(o.errors[0].message);if(!(null==(s=o.data)?void 0:s.sellingPlanFromVariant))throw new Error("Missing variant from selling plan query response.");const g=(null==(d=null==(a=o.data.sellingPlanFromVariant)?void 0:a.sellingPlanGroups)?void 0:d.edges)||[],f=(null==(u=null==(h=null==(c=null==(l=null==(p=g[0])?void 0:p.node)?void 0:l.sellingPlans)?void 0:c.edges)?void 0:h[0])?void 0:u.node)||null;return this._findSellingPlanByName(g,t.name)||f}catch(g){console.error("Error during the query ====>",g)}}async _fetchCart(){try{if(this.useCustomStoreFront&&this.cartId){const t=await this.runStoreFrontQuery("query getCart($cartId: ID!){ cart( id: $cartId ) { id createdAt updatedAt lines(first: 10) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } cost{ totalAmount{ amount currencyCode } } } } } cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } } } }",{cartId:this.cartId});return ve(t.cart)}return await this._fetch.get("/cart.js")}catch(t){throw _e(t.message),new Error("Could not fetch cart for current domain.")}}async _fetchProduct(){var t,e,i,o,r,n,s,a;try{let d;if(this.useCustomStoreFront){const p=await this.runStoreFrontQuery("query product($handle: String!) { product(handle: $handle) { id title images(first: 1) {edges { node { id url altText } } } handle variants(first: 100) { edges { node { id title price { amount } } } } } }",{handle:xe});if(null==p?void 0:p.product){const l=p.product;d={id:l.id,title:l.title,image:{id:null==(o=null==(i=null==(e=null==(t=null==l?void 0:l.images)?void 0:t.edges)?void 0:e[0])?void 0:i.node)?void 0:o.id,src:null==(a=null==(s=null==(n=null==(r=null==l?void 0:l.images)?void 0:r.edges)?void 0:n[0])?void 0:s.node)?void 0:a.url},variants:l.variants.edges.map((t=>({id:t.node.id,price:t.node.price.amount})))}}}else d=(await this._fetch.get(`/products/${xe}.json`)).product;return d}catch(d){throw _e(d.message),new Error("Could not fetch protection product for current domain.")}}hasProtection(){return this._hasProtectionInCart}async updateCart(t){t||(t=await this._fetchCart()),this._cart=t}async addCartProtectionVariant(){var t,i,o,r;let n,s;if(this.supportSubscriptions){const o=null==(i=null==(t=this._cart)?void 0:t.items)?void 0:i.find((t=>{var e;return t.id!==(null==(e=this._protectionVariant)?void 0:e.id)&&!!(null==t?void 0:t.selling_plan_allocation)}));if(o){const t=await this._fetchSellingPlanFromVariant(o.selling_plan_allocation.selling_plan);s=t?e(t.id):null}}if(this.useCustomStoreFront){const t=await this.runStoreFrontQuery("mutation AddItemToCart($cartId: ID!, $lines: [CartLineInput!]!) { cartLinesAdd(cartId: $cartId, lines: $lines) { cart { id lines(first: 10) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } cost{ totalAmount{ amount currencyCode } } } } } cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } } } } }",{cartId:this.cartId,lines:[{merchandiseId:String(null==(o=this._protectionVariant)?void 0:o.id),quantity:1,sellingPlanId:s}]});n=ve(t.cartLinesAdd.cart)}else{const t={quantity:1,id:String(null==(r=this._protectionVariant)?void 0:r.id),selling_plan:s};n=await this._fetch.post("/cart/add.js",t)}return n}async updateCartProtectionVariant(t,e=null,i=null){var o,r;let n;if(this.useCustomStoreFront){const r=await this.runStoreFrontQuery("mutation RemoveItemToCart($cartId: ID!, $lines: [CartLineUpdateInput!]!) { cartLinesUpdate(cartId: $cartId, lines: $lines) { cart { id lines(first: 10) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } cost{ totalAmount{ amount currencyCode } } } } } cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } } } } }",{cartId:this.cartId,lines:[{id:String(e?e.key:null==(o=this._protectionCartItem)?void 0:o.key),quantity:t,sellingPlanId:i}]});n=ve(r.cartLinesUpdate.cart)}else{const o={quantity:t,id:String(e?e.key:null==(r=this._protectionCartItem)?void 0:r.key),selling_plan:i};n=await this._fetch.post("/cart/change.js",o)}return n}async addProtection(){var t,e;try{if(!this._store)throw new Error("Store has not been loaded.");if(!(null==(t=this._cart)?void 0:t.items))throw new Error("Cart has not been loaded.");if(!(null==(e=this._protectionVariant)?void 0:e.id))throw new Error("No protection variant found.");this._setState("loading");const i=await this.addCartProtectionVariant();await this._handleRefresh(i),this._setState("success")}catch(i){_e(i.message)}finally{this._cart=await this._fetchCart(),this._setState("success")}}async removeProtection(){try{if(!this._store)throw new Error("Store has not been loaded.");if(!this._protectionCartItem)throw new Error("Protection product not found.");this._setState("loading");const t=await this.updateCartProtectionVariant(0,this._protectionCartItem);await this._handleRefresh(t),this._cart=t,this._setState("success")}catch(t){_e(t.message)}finally{this._cart=await this._fetchCart(),this._setState("success")}}async attemptAddProtection(){var t,e,i,o,r,n;if(!(null==(t=this._store)?void 0:t.widgetAutoOptIn)||!this._store.useCustomApp)return;if(!(null==(e=this._cart)?void 0:e.items)||!(null==(i=this._cart)?void 0:i.item_count))return;const s=null==(o=this._cart.items)?void 0:o.findIndex((t=>{var e,i;return null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id))})),a=null==(r=this._cart)?void 0:r.items[s];if(this._hasProtectionInCart=!!a,1===this._cart.item_count&&a)return;!!sessionStorage.getItem(we)||!this._hasProtectionInCart&&(null==(n=this._cart)?void 0:n.item_count)&&this._store.widgetShowCart&&(await this.addProtection(),sessionStorage.setItem(we,JSON.stringify({loaded:!0})))}async handleMultipleProtectionVariants(){var t,e,i,o,r;if(!(null==(t=this._cart)?void 0:t.items)||!(null==(e=this._cart)?void 0:e.item_count))return;let n=0;if(null==(i=this._cart.items)||i.forEach((t=>{var e,i;(null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id)))&&n++})),n>1){const t=null==(o=this._cart.items)?void 0:o.findIndex((t=>{var e,i;return null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id))})),e=null==(r=this._cart)?void 0:r.items[t],i=await this.updateCartProtectionVariant(0,e);return await this._handleRefresh(i)}}learnMorePopupTemplate(){return H`
|
|
1171
|
+
`;var me=(t=>(t.LOADED="shipaid-loaded",t.STATUS_UPDATE="shipaid-protection-status",t))(me||{});var ge=Object.defineProperty,fe=(t,e,i,o)=>{for(var r,n=void 0,s=t.length-1;s>=0;s--)(r=t[s])&&(n=r(e,i,n)||n);return n&&ge(e,i,n),n};const ve=t=>({items:t.lines.edges.map((({node:t})=>({id:t.id,key:t.id,variant_id:t.merchandise.id,sku:t.merchandise.sku,final_line_price:parseFloat(t.cost.totalAmount.amount),quantity:t.quantity}))),total_price:parseFloat(t.cost.totalAmount.amount),item_count:t.lines.edges.length}),be=async(t,e)=>{try{const i=await fetch(t,e);if(!i.ok)throw new Error(await i.text());return await i.json()}catch(i){throw console.error(i),new Error("Failed to complete fetch request.")}},ye=t=>console.warn(`[ShipAid] ${t}`),_e=t=>console.error(`[ShipAid] ${t}`),we="shipaid-protection",Ce="shipaid-protection-popup-show",xe="shipaid-protection",$e="query StoreByDomain ($store: String!) {\n store: storeByDomain (input: {store: $store}) {\n currency\n planActive\n store\n widgetAutoOptIn\n widgetPollProtection\n widgetShowCart\n excludedProductSkus\n excludedCustomersIdsAutoOptIn\n protectionSettings\n widgetConfigurations\n useCustomApp\n }\n}",ke=Object.assign({"./lang/de.json":()=>Promise.resolve().then((()=>qe)).then((t=>t.default)),"./lang/en.json":()=>Promise.resolve().then((()=>he)).then((t=>t.default)),"./lang/es.json":()=>Promise.resolve().then((()=>Be)).then((t=>t.default)),"./lang/fr.json":()=>Promise.resolve().then((()=>Ke)).then((t=>t.default)),"./lang/it.json":()=>Promise.resolve().then((()=>ii)).then((t=>t.default)),"./lang/nl.json":()=>Promise.resolve().then((()=>pi)).then((t=>t.default)),"./lang/pt.json":()=>Promise.resolve().then((()=>fi)).then((t=>t.default))});var Se;Se={loader:async t=>{if("en"===t)return ce;const e=Reflect.get(ke,`./lang/${t}.json`);return e?await e():ce}},bt=Object.assign(Object.assign({},bt),Se);const Ae=class extends ht{constructor(){var t,e,i;super(...arguments),this.env="prod",this.useCustomStoreFront=!1,this.storeDomain="",this.storeAccessToken="",this.cartId="",this.disablePolling=!1,this.disableActions=!1,this.pollingInterval=2500,this.disableRefresh=!1,this.refreshCart=!1,this.persistPopup=!1,this.defaultToggleButton=!1,this.lang="en",this.currency=void 0,this.customerId=void 0,this.supportSubscriptions=!1,this.dataSelector="",this.useShipAidCheckout=!1,this._apiEndpoint="/apps/shipaid",this._storeDomain=(null==(t=window.Shopify)?void 0:t.shop)??(null==(i=null==(e=window.Shopify)?void 0:e.Checkout)?void 0:i.apiHost),this._hasFinishedSetup=!1,this._shouldShowWidget=!1,this._hasProtectionInCart=!1,this.hasLoadedStrings=!1,this.fetchInterceptorCleanup=()=>{},this.intervalId=null,this._state={loading:!1,success:null,error:!1},this._popup=null,this._fetch={get:t=>be(t),post:(t,e)=>be(t,{method:"POST",headers:{"Content-Type":"application/json","X-ShipAid":"1"},body:JSON.stringify(e)})}}shouldUpdate(t){return this.hasLoadedStrings&&super.shouldUpdate(t)}shouldPersistPopup(){return"true"===localStorage.getItem(`${Ce}`)?"learn-more":null}setPopupKey(){this.persistPopup&&localStorage.setItem(`${Ce}`,"true")}get nhost(){const t=`https://${"prod"===this.env?"gjiyysyzjwuculcymsvb":"staging"===this.env?"xfnjpunvafvudwuzwjlm":"local"}.graphql.us-east-1.nhost.run/v1`;return{request:async(e,i)=>{try{const o=await fetch(t,{method:"post",body:JSON.stringify({query:e,variables:i})});return await o.json()}catch(o){console.log(`Nhost Error: ${o}`)}}}}async runStoreFrontQuery(t,e){try{const i=new Headers;i.append("Content-Type","application/json"),i.append("X-Shopify-Storefront-Access-Token",this.storeAccessToken);const o={method:"POST",headers:i,body:JSON.stringify({query:t,variables:e})},r=await fetch(`https://${this.storeDomain}/api/2021-07/graphql.json`,o);if(!r.ok)throw new Error(`GraphQL request failed: ${r.statusText}`);const n=await r.json();if(n.errors)throw new Error(n.errors[0].message);return n.data}catch(i){throw console.error("GraphQL query error:",i),new Error("Failed to execute GraphQL query")}}get shouldRefreshOnUpdate(){return!this.disablePolling&&!this.disableRefresh}get planActive(){var t,e;const{searchParams:i}=new URL(window.location.href);return(null==(t=window.Shopify)?void 0:t.designMode)||i.has("shipaid-test")?(ye("Currently in preview mode."),!0):!!(null==(e=this._store)?void 0:e.planActive)}_currencyFormat(t){var e,i,o,r,n,s;const a=this.currency||(null==(i=null==(e=window.Shopify)?void 0:e.currency)?void 0:i.active)||(null==(o=this._store)?void 0:o.currency)||"USD";if(null==(s=null==(n=null==(r=this._store)?void 0:r.widgetConfigurations)?void 0:n.widget)?void 0:s.currencyFormat){return this._store.widgetConfigurations.widget.currencyFormat.replace("_value_",Number(t)).replace("_currency_",a)}return new Intl.NumberFormat(void 0,{currency:a,style:"currency"}).format(Number(t))}_dispatchEvent(t,e={}){this.dispatchEvent(new CustomEvent(t,{bubbles:!0,composed:!0,detail:e}))}_handleRefreshCart(){if(this.refreshCart)return window.location.reload()}async _handleRefresh(t){const e=Reflect.has(t,"items");if(this.shouldRefreshOnUpdate)return window.location.reload();e||await this.updateCart(),this._dispatchEvent(me.STATUS_UPDATE,{protection:this._hasProtectionInCart,cart:e?t:this._cart,lineItem:e?this._protectionCartItem:t})}async calculateProtectionTotal(t){if(t||(t=await this._fetchCart()),!t)throw new Error("Could not fetch cart.");if(!this._store)throw new Error("Missing ShipAid store");if(!this._protectionProduct)throw new Error("Missing Shopify protection product");return i.calculateProtectionTotal(this._store,this._protectionProduct,t)}_findProtectionVariant(t){if(!this._store)throw new Error("Missing ShipAid store");if(!this._protectionProduct)throw new Error("Missing Shopify protection product");return i.findProtectionVariant(this._store,this._protectionProduct,t)}_setState(t,e){this._state={loading:"loading"===t,success:"success"===t,error:"error"===t&&(e||!0)}}_handleConfirmationPopup(){"confirmation"!==this._popup&&(this._popup="confirmation")}_updateProtection(){var t,e,i;const o=null==(i=null==(e=null==(t=this._store)?void 0:t.widgetConfigurations)?void 0:e.widget)?void 0:i.removeWithConfirmation;if(this._hasProtectionInCart)return o?this._handleConfirmationPopup():this.removeProtection();this.addProtection()}async _fetchShipAidData(){var t,e,i,o,r;let n;if(n=this.storeDomain?this.storeDomain:(null==(t=window.Shopify)?void 0:t.shop)??(null==(i=null==(e=window.Shopify)?void 0:e.Checkout)?void 0:i.apiHost),!n)throw new Error("No shop found in Shopify object.");try{let t,e;if(this.useCustomStoreFront)e=await this.nhost.request($e,{store:n});else{t=new URL(window.location.href),t.pathname=this._apiEndpoint;const i={query:$e,variables:{store:n}};e=await this._fetch.post(t.toString(),i)}if(!e)throw new Error("Missing response for store query.");if(null==(o=e.errors)?void 0:o.length)throw new Error(e.errors[0].message);if(!(null==(r=e.data)?void 0:r.store))throw new Error("Missing store from store query response.");return e.data.store}catch(s){throw console.error(s),new Error(`Could not find a store for ${this._storeDomain}`)}}_findSellingPlanByName(t,e){for(const i of t){const t=i.node;for(const i of t.sellingPlans.edges){const t=i.node;if(e===t.name)return t}}return null}async _fetchSellingPlanFromVariant(t){var e,i,o,r,n,s,a,d,p,l,c,h,u;const m=(null==(e=window.Shopify)?void 0:e.shop)??(null==(o=null==(i=window.Shopify)?void 0:i.Checkout)?void 0:o.apiHost);if(!m)throw new Error("No shop found in Shopify object.");try{const e=new URL(window.location.href);e.pathname=this._apiEndpoint;const i={query:"query SellingPlanFromVariant($store: String!, $variantId: String!){\n sellingPlanFromVariant(input: {store: $store, variantId: $variantId })\n}",variables:{store:m,variantId:`gid://shopify/ProductVariant/${null==(r=this._protectionVariant)?void 0:r.id}`}},o=await this._fetch.post(e.toString(),i);if(!o)throw new Error("Missing response for selling plan query.");if(null==(n=o.errors)?void 0:n.length)throw new Error(o.errors[0].message);if(!(null==(s=o.data)?void 0:s.sellingPlanFromVariant))throw new Error("Missing variant from selling plan query response.");const g=(null==(d=null==(a=o.data.sellingPlanFromVariant)?void 0:a.sellingPlanGroups)?void 0:d.edges)||[],f=(null==(u=null==(h=null==(c=null==(l=null==(p=g[0])?void 0:p.node)?void 0:l.sellingPlans)?void 0:c.edges)?void 0:h[0])?void 0:u.node)||null;return this._findSellingPlanByName(g,t.name)||f}catch(g){console.error("Error during the query ====>",g)}}async _fetchCart(){try{if(this.useCustomStoreFront&&this.cartId){const t=await this.runStoreFrontQuery("query getCart($cartId: ID!){ cart( id: $cartId ) { id createdAt updatedAt lines(first: 10) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } cost{ totalAmount{ amount currencyCode } } } } } cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } } } }",{cartId:this.cartId});return ve(t.cart)}return await this._fetch.get("/cart.js")}catch(t){throw _e(t.message),new Error("Could not fetch cart for current domain.")}}async _fetchProduct(){var t,e,i,o,r,n,s,a;try{let d;if(this.useCustomStoreFront){const p=await this.runStoreFrontQuery("query product($handle: String!) { product(handle: $handle) { id title images(first: 1) {edges { node { id url altText } } } handle variants(first: 100) { edges { node { id title price { amount } } } } } }",{handle:xe});if(null==p?void 0:p.product){const l=p.product;d={id:l.id,title:l.title,image:{id:null==(o=null==(i=null==(e=null==(t=null==l?void 0:l.images)?void 0:t.edges)?void 0:e[0])?void 0:i.node)?void 0:o.id,src:null==(a=null==(s=null==(n=null==(r=null==l?void 0:l.images)?void 0:r.edges)?void 0:n[0])?void 0:s.node)?void 0:a.url},variants:l.variants.edges.map((t=>({id:t.node.id,price:t.node.price.amount})))}}}else d=(await this._fetch.get(`/products/${xe}.json`)).product;return d}catch(d){throw _e(d.message),new Error("Could not fetch protection product for current domain.")}}hasProtection(){return this._hasProtectionInCart}async updateCart(t){t||(t=await this._fetchCart()),this._cart=t}async addCartProtectionVariant(){var t,i,o,r;let n,s;if(this.supportSubscriptions){const o=null==(i=null==(t=this._cart)?void 0:t.items)?void 0:i.find((t=>{var e;return t.id!==(null==(e=this._protectionVariant)?void 0:e.id)&&!!(null==t?void 0:t.selling_plan_allocation)}));if(o){const t=await this._fetchSellingPlanFromVariant(o.selling_plan_allocation.selling_plan);s=t?e(t.id):null}}if(this.useCustomStoreFront){const t=await this.runStoreFrontQuery("mutation AddItemToCart($cartId: ID!, $lines: [CartLineInput!]!) { cartLinesAdd(cartId: $cartId, lines: $lines) { cart { id lines(first: 10) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } cost{ totalAmount{ amount currencyCode } } } } } cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } } } } }",{cartId:this.cartId,lines:[{merchandiseId:String(null==(o=this._protectionVariant)?void 0:o.id),quantity:1,sellingPlanId:s}]});n=ve(t.cartLinesAdd.cart)}else{const t={quantity:1,id:String(null==(r=this._protectionVariant)?void 0:r.id),selling_plan:s};n=await this._fetch.post("/cart/add.js",t)}return n}async updateCartProtectionVariant(t,e=null,i=null){var o,r;let n;if(this.useCustomStoreFront){const r=await this.runStoreFrontQuery("mutation RemoveItemToCart($cartId: ID!, $lines: [CartLineUpdateInput!]!) { cartLinesUpdate(cartId: $cartId, lines: $lines) { cart { id lines(first: 10) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } cost{ totalAmount{ amount currencyCode } } } } } cost { totalAmount { amount currencyCode } subtotalAmount { amount currencyCode } } } } }",{cartId:this.cartId,lines:[{id:String(e?e.key:null==(o=this._protectionCartItem)?void 0:o.key),quantity:t,sellingPlanId:i}]});n=ve(r.cartLinesUpdate.cart)}else{const o={quantity:t,id:String(e?e.key:null==(r=this._protectionCartItem)?void 0:r.key),selling_plan:i};n=await this._fetch.post("/cart/change.js",o)}return n}async addProtection(){var t,e;try{if(!this._store)throw new Error("Store has not been loaded.");if(!(null==(t=this._cart)?void 0:t.items))throw new Error("Cart has not been loaded.");if(!(null==(e=this._protectionVariant)?void 0:e.id))throw new Error("No protection variant found.");this._setState("loading");const i=await this.addCartProtectionVariant();await this._handleRefresh(i),this._setState("success")}catch(i){_e(i.message)}finally{this._cart=await this._fetchCart(),this._setState("success")}}async removeProtection(){try{if(!this._store)throw new Error("Store has not been loaded.");if(!this._protectionCartItem)throw new Error("Protection product not found.");this._setState("loading");const t=await this.updateCartProtectionVariant(0,this._protectionCartItem);await this._handleRefresh(t),this._cart=t,this._setState("success")}catch(t){_e(t.message)}finally{this._cart=await this._fetchCart(),this._setState("success")}}async attemptAddProtection(){var t,e,i,o,r,n;if(!(null==(t=this._store)?void 0:t.widgetAutoOptIn))return;if(!(null==(e=this._cart)?void 0:e.items)||!(null==(i=this._cart)?void 0:i.item_count))return;const s=null==(o=this._cart.items)?void 0:o.findIndex((t=>{var e,i;return null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id))})),a=null==(r=this._cart)?void 0:r.items[s];if(this._hasProtectionInCart=!!a,1===this._cart.item_count&&a)return;!!sessionStorage.getItem(we)||!this._hasProtectionInCart&&(null==(n=this._cart)?void 0:n.item_count)&&this._store.widgetShowCart&&(await this.addProtection(),sessionStorage.setItem(we,JSON.stringify({loaded:!0})))}async handleMultipleProtectionVariants(){var t,e,i,o,r;if(!(null==(t=this._cart)?void 0:t.items)||!(null==(e=this._cart)?void 0:e.item_count))return;let n=0;if(null==(i=this._cart.items)||i.forEach((t=>{var e,i;(null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id)))&&n++})),n>1){const t=null==(o=this._cart.items)?void 0:o.findIndex((t=>{var e,i;return null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id))})),e=null==(r=this._cart)?void 0:r.items[t],i=await this.updateCartProtectionVariant(0,e);return await this._handleRefresh(i)}}learnMorePopupTemplate(){return H`
|
|
1172
1172
|
<shipaid-popup-learn-more
|
|
1173
1173
|
?active=${"learn-more"===this._popup}
|
|
1174
1174
|
@close=${()=>{this.persistPopup&&localStorage.removeItem(`${Ce}`),this._popup=null}}
|
|
@@ -1430,7 +1430,7 @@ function qt(t,e,i){return t?e():null==i?void 0:i()}const jt=u`
|
|
|
1430
1430
|
</a>
|
|
1431
1431
|
</div>
|
|
1432
1432
|
</div>
|
|
1433
|
-
`}async connectedCallback(){super.connectedCallback(),await async function(t,e=bt){const i=await e.loader(t,e);e.translationCache={},yt(t,i,e)}(this.lang),this.hasLoadedStrings=!0,this.fetchInterceptorCleanup=function(t){const e=window.fetch;let i=!0;const o=async(o,r)=>{const n=e(o,r);if(i)try{await t([o,r],n)}catch(s){console.warn(s)}return await n};return window.fetch=o,()=>{window.fetch===o?window.fetch=e:i=!1}}((async(t,e)=>{var i,o,r,n;if(null==(o=null==(i=t[1])?void 0:i.headers)?void 0:o["X-ShipAid"])return;if(!t[0].startsWith("/cart/change")&&!t[0].startsWith("/cart/update"))return;const s=(null==(n=null==(r=this._store)?void 0:r.widgetConfigurations)?void 0:n.checkoutButtonSelector)||'button[type="submit"][name="checkout"][form="cart"]',a=document.querySelector(s);if(console.log("q",a),a){a.setAttribute("disabled","true"),console.debug("button","t");try{await e,await this.updateCart(),await this.updateProtection()}finally{a.removeAttribute("disabled"),console.debug("button","f")}}}))}disconnectedCallback(){var t;super.disconnectedCallback(),null==(t=this.fetchInterceptorCleanup)||t.call(this)}async updateProtection(){var t,i,o,r;if(this._cartLastUpdated=new Date,!(null==(t=this._cart)?void 0:t.items))return;const n=null==(i=this._cart.items)?void 0:i.findIndex((t=>{var e,i;return null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id))})),s=null==(o=this._cart)?void 0:o.items[n];if(this._hasProtectionInCart=!!s,!this._store)return;const a=await this.calculateProtectionTotal(this._cart);if(this._cart.item_count>0&&s&&(this._cart.total_price===(null==s?void 0:s.final_line_price)||!a)){const t=await this.updateCartProtectionVariant(0,s);return sessionStorage.removeItem(we),await this._handleRefresh(t)}const d=this._findProtectionVariant(a);if(a?(this._protectionVariant=d,this._shouldShowWidget=!0):this._protectionVariant={id:0,price:"0"},!(null==d?void 0:d.id))return this._shouldShowWidget=!1,void _e("No matching protection variant found.");if(!(null==(r=this._protectionVariant)?void 0:r.id))return void(this._shouldShowWidget=!1);if(!s)return;if(this.supportSubscriptions){const t=this._cart.items.find((t=>{var e;return t.id!==(null==(e=this._protectionVariant)?void 0:e.id)&&!!(null==t?void 0:t.selling_plan_allocation)}));let i=null;if(!t&&(null==s?void 0:s.selling_plan_allocation))i={id:s.key,quantity:1,selling_plan:null};else if(t&&!(null==s?void 0:s.selling_plan_allocation)){const o=await this._fetchSellingPlanFromVariant(t.selling_plan_allocation.selling_plan),r=o?e(o.id):null;i={id:s.key,quantity:1,selling_plan:r}}if(i){const t=await this.updateCartProtectionVariant(i.quantity,s,i.selling_plan);await this._handleRefresh(t)}}if(d.id===s.variant_id){if(this._protectionCartItem={...s,index:n,position:n+1},1===s.quantity)return;const t=await this.updateCartProtectionVariant(1,s);return this._handleRefreshCart(),await this._handleRefresh(t)}const p={updates:{[s.variant_id]:0,[d.id]:1}},l=await this._fetch.post("/cart/update.js",p);await this._handleRefresh(l)}render(){return Tt(this,(async()=>{var t,e,i,o,r,n;const s=document.createElement("link");s.setAttribute("href","https://fonts.googleapis.com/css2?family=Lato&display=swap"),s.setAttribute("rel","stylesheet"),document.head.appendChild(s);try{const[t,e,i]=await Promise.all([this._fetchShipAidData(),this._fetchCart(),this._fetchProduct()]);this._store=t,this._cart=e,this._protectionProduct=i}catch(a){return _e(a.message),this._hasFinishedSetup=!0,void(this._shouldShowWidget=!1)}return this.planActive?(null==(e=null==(t=this._store)?void 0:t.protectionSettings)?void 0:e.protectionType)?this._protectionProduct?(this._hasFinishedSetup=!0,this._dispatchEvent(me.LOADED,this._store),setTimeout((async()=>{var t,e,i,o;(null==(t=this._store)?void 0:t.widgetAutoOptIn)&&
|
|
1433
|
+
`}async connectedCallback(){super.connectedCallback(),await async function(t,e=bt){const i=await e.loader(t,e);e.translationCache={},yt(t,i,e)}(this.lang),this.hasLoadedStrings=!0,this.fetchInterceptorCleanup=function(t){const e=window.fetch;let i=!0;const o=async(o,r)=>{const n=e(o,r);if(i)try{await t([o,r],n)}catch(s){console.warn(s)}return await n};return window.fetch=o,()=>{window.fetch===o?window.fetch=e:i=!1}}((async(t,e)=>{var i,o,r,n;if(null==(o=null==(i=t[1])?void 0:i.headers)?void 0:o["X-ShipAid"])return;if(!t[0].startsWith("/cart/change")&&!t[0].startsWith("/cart/update"))return;const s=(null==(n=null==(r=this._store)?void 0:r.widgetConfigurations)?void 0:n.checkoutButtonSelector)||'button[type="submit"][name="checkout"][form="cart"]',a=document.querySelector(s);if(console.log("q",a),a){a.setAttribute("disabled","true"),console.debug("button","t");try{await e,await this.updateCart(),await this.updateProtection()}finally{a.removeAttribute("disabled"),console.debug("button","f")}}}))}disconnectedCallback(){var t;super.disconnectedCallback(),null==(t=this.fetchInterceptorCleanup)||t.call(this)}async updateProtection(){var t,i,o,r;if(this._cartLastUpdated=new Date,!(null==(t=this._cart)?void 0:t.items))return;const n=null==(i=this._cart.items)?void 0:i.findIndex((t=>{var e,i;return null==(i=null==(e=this._protectionProduct)?void 0:e.variants)?void 0:i.some((e=>e.id===t.variant_id))})),s=null==(o=this._cart)?void 0:o.items[n];if(this._hasProtectionInCart=!!s,!this._store)return;const a=await this.calculateProtectionTotal(this._cart);if(this._cart.item_count>0&&s&&(this._cart.total_price===(null==s?void 0:s.final_line_price)||!a)){const t=await this.updateCartProtectionVariant(0,s);return sessionStorage.removeItem(we),await this._handleRefresh(t)}const d=this._findProtectionVariant(a);if(a?(this._protectionVariant=d,this._shouldShowWidget=!0):this._protectionVariant={id:0,price:"0"},!(null==d?void 0:d.id))return this._shouldShowWidget=!1,void _e("No matching protection variant found.");if(!(null==(r=this._protectionVariant)?void 0:r.id))return void(this._shouldShowWidget=!1);if(!s)return;if(this.supportSubscriptions){const t=this._cart.items.find((t=>{var e;return t.id!==(null==(e=this._protectionVariant)?void 0:e.id)&&!!(null==t?void 0:t.selling_plan_allocation)}));let i=null;if(!t&&(null==s?void 0:s.selling_plan_allocation))i={id:s.key,quantity:1,selling_plan:null};else if(t&&!(null==s?void 0:s.selling_plan_allocation)){const o=await this._fetchSellingPlanFromVariant(t.selling_plan_allocation.selling_plan),r=o?e(o.id):null;i={id:s.key,quantity:1,selling_plan:r}}if(i){const t=await this.updateCartProtectionVariant(i.quantity,s,i.selling_plan);await this._handleRefresh(t)}}if(d.id===s.variant_id){if(this._protectionCartItem={...s,index:n,position:n+1},1===s.quantity)return;const t=await this.updateCartProtectionVariant(1,s);return this._handleRefreshCart(),await this._handleRefresh(t)}const p={updates:{[s.variant_id]:0,[d.id]:1}},l=await this._fetch.post("/cart/update.js",p);await this._handleRefresh(l)}render(){return Tt(this,(async()=>{var t,e,i,o,r,n;const s=document.createElement("link");s.setAttribute("href","https://fonts.googleapis.com/css2?family=Lato&display=swap"),s.setAttribute("rel","stylesheet"),document.head.appendChild(s);try{const[t,e,i]=await Promise.all([this._fetchShipAidData(),this._fetchCart(),this._fetchProduct()]);this._store=t,this._cart=e,this._protectionProduct=i}catch(a){return _e(a.message),this._hasFinishedSetup=!0,void(this._shouldShowWidget=!1)}return this.planActive?(null==(e=null==(t=this._store)?void 0:t.protectionSettings)?void 0:e.protectionType)?this._protectionProduct?(this._hasFinishedSetup=!0,this._dispatchEvent(me.LOADED,this._store),setTimeout((async()=>{var t,e,i,o;(null==(t=this._store)?void 0:t.widgetAutoOptIn)&&(null==(e=this._cart)?void 0:e.item_count)&&(this.customerId&&this._store.excludedCustomersIdsAutoOptIn&&(null==(i=this._store.excludedCustomersIdsAutoOptIn)?void 0:i.length)&&this._store.excludedCustomersIdsAutoOptIn.includes(`gid://shopify/Customer/${this.customerId}`)||sessionStorage.getItem(we)||!this._hasProtectionInCart&&(null==(o=this._cart)?void 0:o.item_count)&&this._store.widgetShowCart&&(await this.addProtection(),sessionStorage.setItem(we,JSON.stringify({loaded:!0}))))}),500),void(this.disablePolling||(setInterval((async()=>{const t=this._cartLastUpdated;t&&(new Date).getTime()-t.getTime()<this.pollingInterval||await this.updateCart()}),this.pollingInterval),(null==(i=this._store)?void 0:i.widgetPollProtection)&&!this.intervalId&&(this.intervalId=setInterval((async()=>{await this.attemptAddProtection()}),400),localStorage.setItem(`polling-shipaid-protection_${this.intervalId}`,`${this.intervalId}`)),(null==(n=null==(r=null==(o=this._store)?void 0:o.widgetConfigurations)?void 0:r.widget)?void 0:n.pollVariantsCheck)&&setInterval((async()=>{await this.handleMultipleProtectionVariants()}),400)))):(ye("No protection settings product for this store - skipping setup."),this._hasFinishedSetup=!0,void(this._shouldShowWidget=!1)):(ye("No protection settings for this store - skipping setup."),this._hasFinishedSetup=!0,void(this._shouldShowWidget=!1)):(ye("No plan is active for this store - skipping setup."),this._hasFinishedSetup=!0,void(this._shouldShowWidget=!1))}),[]),Tt(this,(async()=>{await this.updateProtection()}),[this._store,this._cart]),Tt(this,(async()=>{pt(this.renderPopups(),document.body)}),[this._popup]),H`
|
|
1434
1434
|
<style>
|
|
1435
1435
|
:host {
|
|
1436
1436
|
--shipaid-primary: #002bd6;
|