@getspot/spot-widget 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -1,8 +1,8 @@
1
- (function(u,f){typeof exports=="object"&&typeof module<"u"?module.exports=f():typeof define=="function"&&define.amd?define(f):(u=typeof globalThis<"u"?globalThis:u||self,u.SpotWidget=f())})(this,function(){"use strict";async function u(i,e,t){try{const o=await fetch(i,{method:"POST",headers:{"Content-Type":"application/json","X-Spot-Partner-Id":e},body:JSON.stringify(t)}),n=await o.json();if(!o.ok){const r=new Error((n==null?void 0:n.message)||"Failed to fetch quote");throw r.status=o.status,r.responseBody=n,r}return n}catch(o){throw o instanceof Error?o:new Error("Unknown error occurred while fetching quote")}}const f={sandbox:"https://api.sandbox.getspot.com/v1/quote",production:"https://api.getspot.com/v1/quote"};function g(i){const{apiConfig:e={},quoteRequestData:t,callbacks:o={},location:n,theme:r}=i,{environment:a="sandbox",partnerId:p,endpoint:c}=e;if(!p||typeof p!="string")throw new Error("Invalid or missing partnerId in apiConfig");if(!(c||f[a]))throw new Error(`Invalid environment in apiConfig: ${a}`);if(!t||typeof t!="object")throw new Error("quoteRequestData must be a non-null object");["startDate","endDate","currencyCode","eventType","productType","productDuration","productPrice","productId","cartId","productName"].forEach(m=>{if(!Object.prototype.hasOwnProperty.call(t,m)||t[m]===void 0||t[m]===null)throw new Error(`Missing required quoteRequestData field: '${m}'`)});const h=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;if(!h.test(t.startDate))throw new Error("startDate must be a valid ISO8601 string");if(!h.test(t.endDate))throw new Error("endDate must be a valid ISO8601 string");if(typeof t.currencyCode!="string")throw new Error("currencyCode must be a string");if(!["USD","CAD","AUD"].includes(t.currencyCode))throw new Error(`Invalid currency code: ${t.currencyCode}`);if(typeof t.eventType!="string")throw new Error("eventType must be a string");if(typeof t.productType!="string")throw new Error("productType must be a string");const y=["Pass","Trip","Registration"];if(!y.includes(t.productType))throw new Error(`productType must be one of ${y.join(", ")}`);if(typeof t.productDuration!="string")throw new Error("productDuration must be a string");const _=["Daily","Seasonal","Trip","Event"];if(!_.includes(t.productDuration))throw new Error(`productDuration must be one of ${_.join(", ")}`);if(typeof t.productPrice!="number"||isNaN(t.productPrice))throw new Error("productPrice must be a valid number");if(typeof t.productId!="string")throw new Error("productId must be a string");if(typeof t.cartId!="string")throw new Error("cartId must be a string");if(typeof t.productName!="string")throw new Error("productName must be a string");if(["onOptIn","onOptOut","onQuoteRetrieved","onError","noMatchingQuote"].forEach(m=>{const v=o[m];if(v&&typeof v!="function")throw new Error(`Callback '${m}' must be a function.`)}),typeof n=="string"&&!document.querySelector(n))throw new Error(`Invalid location selector: '${n}'`);if(r&&typeof r!="object")throw new Error("Theme must be an object with CSS variables, do not include the '--' prefix")}function s(i,{text:e,className:t,parent:o,innerHTML:n}={}){const r=document.createElement(i);return t&&(r.className=t),e!=null&&(r.textContent=e),n!=null&&(r.innerHTML=n),o&&o.appendChild(r),r}function w(i,{name:e,description:t}){s("div",{className:"spot-header__title",text:e,parent:i}),s("div",{className:"spot-header__description",text:t,parent:i})}function C(i,e=[]){const t=s("ul",{className:"spot-benefits__list",parent:i});e.forEach(o=>{const n=s("li",{parent:t});n.innerHTML=`
1
+ (function(w,v){typeof exports=="object"&&typeof module<"u"?module.exports=v():typeof define=="function"&&define.amd?define(v):(w=typeof globalThis<"u"?globalThis:w||self,w.SpotWidget=v())})(this,function(){"use strict";async function w(p,e,o){try{const n=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json","X-Spot-Partner-Id":e},body:JSON.stringify(o)}),t=await n.json();if(!n.ok){const r=new Error((t==null?void 0:t.message)||"Failed to fetch quote");throw r.status=n.status,r.responseBody=t,r}return t}catch(n){throw n instanceof Error?n:new Error("Unknown error occurred while fetching quote")}}async function v(p,e,o){try{const n=p.replace("/quote","/quote/batch"),t=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json","X-Spot-Partner-Id":e},body:JSON.stringify(o)}),r=await t.json();if(!t.ok){const c=new Error((r==null?void 0:r.message)||"Failed to fetch batch quote");throw c.status=t.status,c.responseBody=r,c}return r}catch(n){throw n instanceof Error?n:new Error("Unknown error occurred while fetching batch quote")}}async function I(p,e,o){try{const n={cartId:o.cartInfo.cartId,cartName:o.cartInfo.cartName,currencyCode:o.cartInfo.currencyCode,items:o.items.map((a,u)=>({cartItemId:a.cartItemId||`item-${u+1}`,productPrice:a.productPrice,productType:a.productType,productDuration:a.productDuration,productId:a.productId,productName:a.productName,participantDescription:a.participantDescription,eventType:a.eventType,startDate:a.startDate,endDate:a.endDate}))},t=await v(p,e,n);if(t.status!=="QUOTES_AVAILABLE"&&t.status!=="QUOTE_AVAILABLE")return{status:"NO_MATCHING_QUOTE"};const r=t.quotes.map(a=>{const u=o.items.find(h=>(h.cartItemId||`item-${o.items.indexOf(h)+1}`)===a.cartItemId);return u?u.participantDescription?`${u.productName} - ${u.participantDescription}`:u.productName:`Item ${a.cartItemId}`}),c=Math.round((t.totalSpotPrice||t.spotPrice||0)*100)/100;return{status:"QUOTE_AVAILABLE",data:{id:t.quotes?t.quotes.map(a=>a.id).join(","):t.id,spotPrice:c,currencyCode:t.currencyCode,communication:{...t.communication,yesOptionText:t.communication.yesOptionText.replace(t.totalSpotPrice,c)},payoutSchedule:t.payoutSchedule.map(a=>({...a,amount:a.amount!==void 0?a.amount:0})),coveredItems:r,originalQuotes:t.quotes||[t]},spotPrice:c,coveredItems:r}}catch(n){throw n instanceof Error?n:new Error("Unknown error occurred while fetching multiple quotes")}}const N={sandbox:"https://api.sandbox.getspot.com/v1/quote",production:"https://api.getspot.com/v1/quote",local:"http://localhost:3999/api/v1/quote"};function k(p){const{apiConfig:e={},quoteRequestData:o,callbacks:n={},location:t,theme:r}=p,{environment:c="sandbox",partnerId:a,endpoint:u}=e;if(!a||typeof a!="string")throw new Error("Invalid or missing partnerId in apiConfig");if(!(u||N[c]))throw new Error(`Invalid environment in apiConfig: ${c}`);if(!o||typeof o!="object"&&!Array.isArray(o))throw new Error("quoteRequestData must be a non-null object or array");const m=["startDate","endDate","currencyCode","eventType","productType","productDuration","productPrice","productId","cartId","productName"];function d(s,y=null){const f=y!==null?`quoteRequestData[${y}]`:"quoteRequestData";m.forEach(b=>{if(!Object.prototype.hasOwnProperty.call(s,b)||s[b]===void 0||s[b]===null)throw new Error(`Missing required ${f} field: '${b}'`)});const C=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;if(!C.test(s.startDate))throw new Error(`${f}.startDate must be a valid ISO8601 string`);if(!C.test(s.endDate))throw new Error(`${f}.endDate must be a valid ISO8601 string`);if(typeof s.currencyCode!="string")throw new Error(`${f}.currencyCode must be a string`);if(!["USD","CAD","AUD"].includes(s.currencyCode))throw new Error(`Invalid ${f}.currencyCode: ${s.currencyCode}`);if(typeof s.eventType!="string")throw new Error(`${f}.eventType must be a string`);if(typeof s.productType!="string")throw new Error(`${f}.productType must be a string`);const _=["Pass","Trip","Registration"];if(!_.includes(s.productType))throw new Error(`${f}.productType must be one of ${_.join(", ")}`);if(typeof s.productDuration!="string")throw new Error(`${f}.productDuration must be a string`);const g=["Daily","Seasonal","Trip","Event"];if(!g.includes(s.productDuration))throw new Error(`${f}.productDuration must be one of ${g.join(", ")}`);if(typeof s.productPrice!="number"||isNaN(s.productPrice))throw new Error(`${f}.productPrice must be a valid number`);if(typeof s.productId!="string")throw new Error(`${f}.productId must be a string`);if(typeof s.cartId!="string")throw new Error(`${f}.cartId must be a string`);if(typeof s.productName!="string")throw new Error(`${f}.productName must be a string`)}if(o.cartInfo&&o.items){const{cartInfo:s,items:y}=o;if(!s||typeof s!="object")throw new Error("quoteRequestData.cartInfo must be a non-null object");if(!s.cartId||typeof s.cartId!="string")throw new Error("quoteRequestData.cartInfo.cartId must be a string");if(!s.cartName||typeof s.cartName!="string")throw new Error("quoteRequestData.cartInfo.cartName must be a string");if(!s.currencyCode||typeof s.currencyCode!="string")throw new Error("quoteRequestData.cartInfo.currencyCode must be a string");if(!["USD","CAD","AUD"].includes(s.currencyCode))throw new Error(`Invalid quoteRequestData.cartInfo.currencyCode: ${s.currencyCode}`);if(!Array.isArray(y)||y.length===0)throw new Error("quoteRequestData.items must be a non-empty array");const C=m.filter(l=>l!=="cartId"&&l!=="currencyCode");y.forEach((l,_)=>{if(!l||typeof l!="object")throw new Error(`quoteRequestData.items[${_}] must be a non-null object`);const g=`quoteRequestData.items[${_}]`;C.forEach(E=>{if(!Object.prototype.hasOwnProperty.call(l,E)||l[E]===void 0||l[E]===null)throw new Error(`Missing required ${g} field: '${E}'`)});const b=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;if(!b.test(l.startDate))throw new Error(`${g}.startDate must be a valid ISO8601 string`);if(!b.test(l.endDate))throw new Error(`${g}.endDate must be a valid ISO8601 string`);if(typeof l.eventType!="string")throw new Error(`${g}.eventType must be a string`);if(typeof l.productType!="string")throw new Error(`${g}.productType must be a string`);const T=["Pass","Trip","Registration"];if(!T.includes(l.productType))throw new Error(`${g}.productType must be one of ${T.join(", ")}`);if(typeof l.productDuration!="string")throw new Error(`${g}.productDuration must be a string`);const x=["Daily","Seasonal","Trip","Event"];if(!x.includes(l.productDuration))throw new Error(`${g}.productDuration must be one of ${x.join(", ")}`);if(typeof l.productPrice!="number"||isNaN(l.productPrice))throw new Error(`${g}.productPrice must be a valid number`);if(typeof l.productId!="string")throw new Error(`${g}.productId must be a string`);if(typeof l.productName!="string")throw new Error(`${g}.productName must be a string`)})}else if(Array.isArray(o)){if(o.length===0)throw new Error("quoteRequestData array cannot be empty");o.forEach((s,y)=>{if(!s||typeof s!="object")throw new Error(`quoteRequestData[${y}] must be a non-null object`);d(s,y)})}else d(o);if(["onOptIn","onOptOut","onQuoteRetrieved","onError","noMatchingQuote"].forEach(s=>{const y=n[s];if(y&&typeof y!="function")throw new Error(`Callback '${s}' must be a function.`)}),typeof t=="string"&&!document.querySelector(t))throw new Error(`Invalid location selector: '${t}'`);if(r&&typeof r!="object")throw new Error("Theme must be an object with CSS variables, do not include the '--' prefix")}function i(p,{text:e,className:o,parent:n,innerHTML:t}={}){const r=document.createElement(p);return o&&(r.className=o),e!=null&&(r.textContent=e),t!=null&&(r.innerHTML=t),n&&n.appendChild(r),r}function O(p,{name:e,description:o}){i("div",{className:"spot-header__title",text:e,parent:p}),i("div",{className:"spot-header__description",text:o,parent:p})}function P(p,e=[]){const o=i("ul",{className:"spot-benefits__list",parent:p});e.forEach(n=>{const t=i("li",{parent:o});t.innerHTML=`
2
2
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
3
3
  <path d="M11.6666 3.5L5.24998 9.91667L2.33331 7"
4
4
  stroke="#2E2E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
5
- </svg>`,s("span",{text:o,parent:n})})}function E(i,e=[]){const t=s("div",{className:"spot-table__container",parent:i}),o=s("table",{className:"spot-refund__table spot-table--dynamic",parent:t}),n=s("thead",{parent:o}),r=s("tr",{parent:n});s("th",{text:"When you cancel",parent:r}),s("th",{text:"You will receive",parent:r});const a=s("tbody",{parent:o});e.forEach(({text:p,percent:c,amount:l})=>{const d=s("tr",{parent:a});s("td",{text:p,parent:d});const h=c==="Not eligible for refund"?"Not eligible for a refund":`$${l} refund`;s("td",{text:h,parent:d})})}function k(i,e,t){const o=s("div",{className:"spot-selection__options",parent:i}),n=s("label",{className:`spot-selection__option ${t?"selected":""}`,parent:o}),r=s("input",{parent:n});r.type="radio",r.name="selection",r.value="yes",t&&(r.checked=!0),s("strong",{text:`Yes, protect my booking for $${e}`,parent:n}),s("span",{className:"spot-selection__recommended-tag",text:"Recommended",parent:n});const a=s("label",{className:"spot-selection__option",parent:o}),p=s("input",{parent:a});return p.type="radio",p.name="selection",p.value="no",s("span",{text:"No, do not protect my booking",parent:a}),o}function x(i,e){var n;const t=(n=e.communication)==null?void 0:n.paymentTerms,o=s("div",{className:"spot-payment-terms",parent:i});return s("div",{className:"spot-payment-terms__header",text:"PAYMENT TERMS",parent:o}),s("div",{className:"spot-payment-terms__body",text:t,parent:o}),o}function q(i,e){const t=s("div",{className:"spot-footer__container",parent:i}),o=s("div",{className:"spot-footer__terms",parent:t});s("span",{innerHTML:e.communication.legalDisclaimer,parent:o}),s("br",{parent:o}),s("a",{href:e.communication.termsAndConditionsUrl,className:"spot-footer__terms-link",text:"Refund Guarantee Terms and Conditions",parent:o});const n=s("p",{className:"spot-footer__powered-by",parent:t});return n.innerHTML=`
5
+ </svg>`,i("span",{text:n,parent:t})})}function $(p,e=[]){if(e.length===0)return;const o=i("div",{className:"spot-covered-items__container",parent:p});i("div",{className:"spot-covered-items__title",text:"Items covered in your cart:",parent:o});const n=i("ul",{className:"spot-covered-items__list",parent:o});e.forEach(t=>{const r=i("li",{parent:n});i("span",{text:t,parent:r})})}function Q(p,e=[]){const o=i("div",{className:"spot-table__container",parent:p}),n=i("table",{className:"spot-refund__table spot-table--dynamic",parent:o}),t=i("thead",{parent:n}),r=i("tr",{parent:t});i("th",{text:"When you cancel",parent:r}),i("th",{text:"You will receive",parent:r});const c=i("tbody",{parent:n});e.forEach(({text:a,percent:u,amount:h})=>{const m=i("tr",{parent:c});i("td",{text:a,parent:m});const d=u==="Not eligible for refund"?"Not eligible for a refund":`$${h} refund`;i("td",{text:d,parent:m})})}function S(p,e,o){const n=i("div",{className:"spot-selection__options",parent:p}),t=i("label",{className:`spot-selection__option ${e?"selected":""}`,parent:n}),r=i("input",{parent:t});r.type="radio",r.name="selection",r.value="yes",e&&(r.checked=!0),i("strong",{text:o.yesOptionText,parent:t}),i("span",{className:"spot-selection__recommended-tag",text:"Recommended",parent:t});const c=i("label",{className:"spot-selection__option",parent:n}),a=i("input",{parent:c});return a.type="radio",a.name="selection",a.value="no",i("span",{text:o.noOptionText,parent:c}),n}function H(p,e){var t;const o=(t=e.communication)==null?void 0:t.paymentTerms,n=i("div",{className:"spot-payment-terms",parent:p});return i("div",{className:"spot-payment-terms__header",text:"PAYMENT TERMS",parent:n}),i("div",{className:"spot-payment-terms__body",text:o,parent:n}),n}function z(p,e){const o=i("div",{className:"spot-footer__container",parent:p}),n=i("div",{className:"spot-footer__terms",parent:o});i("span",{innerHTML:e.communication.legalDisclaimer,parent:n}),i("br",{parent:n}),i("a",{href:e.communication.termsAndConditionsUrl,className:"spot-footer__terms-link",text:"Refund Guarantee Terms and Conditions",parent:n});const t=i("p",{className:"spot-footer__powered-by",parent:o});return t.innerHTML=`
6
6
  <svg width="145" height="28" viewBox="0 0 145 28" fill="none" xmlns="http://www.w3.org/2000/svg">
7
7
  <rect width="145" height="28"/>
8
8
  <rect x="-655" y="-270" width="819" height="325" rx="10"/>
@@ -17,4 +17,4 @@
17
17
  <rect width="45.405" height="14.8867" fill="white" transform="translate(87 8)"/>
18
18
  </clipPath>
19
19
  </defs>
20
- </svg>`,t}const T=":root{--spot-font-family: Arial;--spot-padding: 1.25rem;--spot-background-color: #ffffff;--spot-font-color: #000000;--spot-border-radius: .5rem;--spot-title-font-size: 1.25rem;--spot-title-font-weight: 700;--spot-title-padding: 0 0 1.25rem 0;--spot-description-font-size: .875rem;--spot-description-font-weight: 400;--spot-description-padding: 0 0 .5rem 0;--spot-bullets-font-size: .875rem;--spot-bullets-font-weight: 400;--spot-bullets-padding: .3125rem;--spot-table-border-radius: .625rem;--spot-table-header-font-size: .875rem;--spot-table-header-font-weight: 700;--spot-table-header-padding: 0 .5rem .625rem;--spot-table-cell-font-size: .815rem;--spot-table-cell-font-weight: 400;--spot-table-cell-padding: 0 .625rem;--spot-radio-border: #000000;--spot-radio-border-radius: .625rem;--spot-radio-checked-background: #000000;--spot-radio-text-font-size: .875rem;--spot-radio-text-font-weight: 400;--spot-radio-text-padding: .625rem;--spot-radio-selection-background: #f4f4f4;--spot-radio-selection-border-radius: .625rem;--spot-radio-selection-padding: .625rem;--spot-recommended-tag-background: #000000;--spot-recommended-tag-font-color: #ffffff;--spot-recommended-tag-font-size: .875rem;--spot-recommended-tag-font-weight: 700;--spot-recommended-tag-padding: .25rem .5rem;--spot-recommended-tag-border-radius: .5rem;--spot-selection-error-font-color: #ff0000;--spot-selection-error-font-size: .875rem;--spot-selection-error-padding: .5rem;--spot-payment-terms-background: #f4f4f4;--spot-payment-terms-border-radius: .625rem;--spot-payment-terms-padding: 1rem;--spot-payment-terms-font-color: #636569;--spot-payment-terms-font-size: .75rem;--spot-payment-terms-header-font-weight: 700;--spot-payment-terms-header-font-size: .875rem;--spot-payment-terms-header-margin-bottom: .5rem;--spot-payment-terms-header-border-color: #c2c2c2;--spot-payment-terms-header-padding: 0 0 .5rem 0;--spot-terms-font-size: .75rem;--spot-terms-font-weight: 400;--spot-terms-font-color: #636569;--spot-terms-padding: 0;--spot-terms-link-text-decoration: underline;--spot-terms-link-font-size: .75rem;--spot-terms-link-font-weight: 400;--spot-terms-link-font-color: #636569;--spot-terms-link-padding: 0}.spot-refund-guarantee{font-family:var(--spot-font-family);padding:var(--spot-padding);background-color:var(--spot-background-color);color:var(--spot-font-color);border:.0625rem solid #e0e0e0;border-radius:var(--spot-border-radius);max-width:51rem;margin:1rem}.spot-refund-guarantee *{color:inherit}.spot-header__title{font-size:var(--spot-title-font-size);font-weight:var(--spot-title-font-weight);padding:var(--spot-title-padding);color:var(--spot-title-font-color);font-family:var(--spot-title-font-family);line-height:120%;letter-spacing:-.03125rem}.spot-header__description{font-size:var(--spot-description-font-size);font-weight:var(--spot-description-font-weight);color:var(--spot-description-font-color);font-family:var(--spot-description-font-family);padding:var(--spot-description-padding);line-height:125%;letter-spacing:-.025rem}.spot-content__wrapper{display:flex;flex-direction:column}@media (min-width: 48rem){.spot-content__wrapper.desktop-layout{display:grid;grid-template-columns:1fr 20.3125rem;align-items:start;gap:1rem}.desktop-layout .spot-benefits__list{grid-row:1}.desktop-layout .spot-selection__options{grid-row:2}.desktop-layout .spot-table__container{grid-row:1 / span 2}}@media (max-width: 52.438rem){.spot-selection__recommended-tag{display:inline-block;margin-left:0}}@media (max-width: 47.938rem){.spot-selection__recommended-tag{margin-top:0rem}}@media (max-width: 32.125rem){.spot-selection__recommended-tag{margin-top:.5rem}}@media (max-width: 47.9375rem){.spot-table__container{display:flex;justify-content:center}.spot-selection__recommended-tag{display:inline-block;margin-left:0}.spot-footer__container{flex-direction:column;margin-top:.5rem}.spot-refund__table{width:100%;table-layout:auto}.spot-refund__table th{padding:0rem}}.spot-benefits__list{list-style-type:none;line-height:125%;gap:.5625rem;font-size:var(--spot-bullets-font-size);font-weight:var(--spot-bullets-font-weight);color:var(--spot-bullets-font-color);font-family:var(--spot-bullets-font-family);padding:var(--spot-bullets-padding);margin-block-start:0rem;margin-block-end:0rem}.spot-benefits__list li{margin-bottom:.5rem;display:flex;align-items:flex-start;gap:.5rem}.spot-benefits__list li svg{flex-shrink:0;position:relative;top:.125rem}.spot-table__container{width:100%}.spot-refund__table{max-width:22rem;border-radius:var(--spot-table-border-radius);overflow:hidden;border:.09375rem solid #636569;table-layout:fixed;margin-bottom:1.5rem;margin-top:.25rem;padding:.625rem}.spot-refund__table--dynamic{height:auto!important;min-height:7.5rem}.spot-refund__table td,.spot-refund__table th{padding:.375rem .625rem;text-align:left}.spot-refund__table th{text-align:left;font-size:var(--spot-table-header-font-size);font-weight:var(--spot-table-header-font-weight);color:var(--spot-table-header-font-color);font-family:var(--spot-table-header-font-family);padding:var(--spot-table-header-padding)}.spot-refund__table td{text-align:left;font-size:var(--spot-table-cell-font-size);font-weight:var(--spot-table-cell-font-weight);color:var(--spot-table-cell-font-color);font-family:var(--spot-table-cell-font-family);padding:var(--spot-table-cell-padding)}input[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:.75rem;height:.75rem;border:.0625rem solid var(--spot-radio-border);border-radius:var(--spot-radio-border-radius);margin-right:.5rem;position:relative;vertical-align:middle;top:-.0625rem;cursor:pointer}input[type=radio]:checked{background:var(--spot-radio-checked-background);box-shadow:inset 0 0 0 .0625rem #fff}.spot-selection__options{display:flex;flex-direction:column;gap:.5rem}.spot-selection__option{display:block;position:relative;transition:background .2s;cursor:pointer;font-size:var(--spot-radio-text-font-size);font-weight:var(--spot-radio-text-font-weight);color:var(--spot-radio-text-font-color);font-family:var(--spot-radio-text-font-family);padding:var(--spot-radio-text-padding);margin-right:.5rem;gap:.5rem;flex:1 0 0;align-self:stretch}.spot-selection__option.selected{background:var(--spot-radio-selection-background);border-radius:var(--spot-radio-selection-border-radius);padding:var(--spot-radio-selection-padding)}.spot-selection__recommended-tag{background:var(--spot-recommended-tag-background);color:var(--spot-recommended-tag-font-color);font-size:var(--spot-recommended-tag-font-size);font-weight:var(--spot-recommended-tag-font-weight);padding:var(--spot-recommended-tag-padding);border-radius:var(--spot-recommended-tag-border-radius);margin-left:1.5rem;white-space:nowrap}.spot-selection__error{color:var(--spot-selection-error-font-color);font-size:var(--spot-selection-error-font-size);padding:var(--spot-selection-error-padding);display:none}.spot-payment-terms__wrapper{margin-top:1rem}.spot-payment-terms__header{font-weight:var(--spot-payment-terms-header-font-weight);margin-bottom:.5rem;padding:var(--spot-payment-terms-header-padding);font-size:var(--spot-payment-terms-header-font-size);border-bottom:1px solid var(--spot-payment-terms-header-border-color)}.spot-payment-terms{background-color:var(--spot-payment-terms-background);border-radius:var(--spot-payment-terms-border-radius);padding:var(--spot-payment-terms-padding);margin-right:.5rem;color:var(--spot-payment-terms-font-color);font-size:var(--spot-payment-terms-font-size)}.spot-footer__terms{margin-top:.625rem;margin-right:.25rem;font-size:var(--spot-terms-font-size);font-weight:var(--spot-terms-font-weight);color:var(--spot-terms-font-color);font-family:var(--spot-terms-font-family);padding:var(--spot-terms-padding)}.spot-footer__terms-link{text-decoration:var(--spot-terms-link-text-decoration);font-size:var(--spot-terms-link-font-size);font-weight:var(--spot-terms-link-font-weight);color:var(--spot-terms-link-font-color);font-family:var(--spot-terms-link-font-family);padding:var(--spot-terms-link-padding)}.spot-footer__container{display:flex;justify-content:space-between;align-items:center}.spot-footer__powered-by{margin-top:1.5rem}";function H(i){const e=document.createElement("style");e.textContent=i,document.head.appendChild(e)}H(T);const b={sandbox:"https://api.sandbox.getspot.com/api/v1/quote",production:"https://api.getspot.com/api/v1/quote"};class N{constructor(e={}){this.options={location:"body",showTable:!0,optInSelected:!1,apiConfig:{environment:"production",partnerId:""},quoteRequestData:{},callbacks:{},...e},this._onResize=this._updateLayout.bind(this),this.root=typeof this.options.location=="string"?document.querySelector(this.options.location):this.options.location,this.currentSelection=this.options.optInSelected?"yes":null,this._init()}async _init(){var e,t,o,n,r;try{g(this.options);const{environment:a,partnerId:p}=this.options.apiConfig,l=this.options.apiConfig.customEndpoint||b[a],d=await u(l,p,this.options.quoteRequestData);if(d.status!=="QUOTE_AVAILABLE"){d.status==="NO_MATCHING_QUOTE"&&((e=this.options.callbacks)!=null&&e.noMatchingQuote)&&this.options.callbacks.noMatchingQuote({status:"NO_MATCHING_QUOTE",data:this.options.quoteRequestData});return}this.quote=d.data,this._renderWidget(),this.options.optInSelected&&((t=this.options.callbacks)!=null&&t.onOptIn)&&this.options.callbacks.onOptIn({status:"QUOTE_ACCEPTED",spotPrice:this.quote.spotPrice,quoteId:this.quote.id}),(o=this.options.callbacks)!=null&&o.onQuoteRetrieved&&this.options.callbacks.onQuoteRetrieved(this.quote)}catch(a){(n=this.options.callbacks)!=null&&n.onError&&((r=this.options.callbacks)==null||r.onError({message:a.message,status:a.status,responseBody:a.responseBody}))}}_renderWidget(){this.container=document.createElement("div"),this.container.className="spot-refund-guarantee",this.root.appendChild(this.container),Object.entries(this.options.theme||{}).forEach(([o,n])=>{const r=`--${o}`;this.container.style.setProperty(r,n)}),w(this.container,this.quote.communication);const e=document.createElement("div");e.className="spot-content__wrapper",this.container.appendChild(e),C(e,this.quote.communication.bulletPoints),this.options.showTable&&E(e,this.quote.payoutSchedule);const t=k(e,this.quote.spotPrice,this.options.optInSelected);e.appendChild(t),this.paymentTermsEl=s("div",{className:"spot-payment-terms__wrapper",parent:e}),q(this.container,this.quote),window.addEventListener("resize",this._onResize),this._updateLayout(),this._setupOptionListeners(t)}_updateLayout(){const e=window.matchMedia("(min-width: 768px)").matches;this.container.querySelector(".spot-content__wrapper").classList.toggle("desktop-layout",e&&this.options.showTable)}_setupOptionListeners(e){const t=e.querySelectorAll('input[type="radio"]'),o=e.querySelectorAll(".spot-selection__option");t.forEach(n=>{n.addEventListener("change",r=>{var p,c,l;const a=r.target.value;this.hideSelectionError(),this.currentSelection=a,o.forEach(d=>d.classList.remove("selected")),(p=r.target.closest(".spot-selection__option"))==null||p.classList.add("selected"),this.paymentTermsEl&&(this.paymentTermsEl.innerHTML=""),a==="yes"&&(this.options.quoteRequestData.isPartialPayment&&x(this.paymentTermsEl,this.quote),(c=this.options.callbacks)!=null&&c.onOptIn&&this.options.callbacks.onOptIn({status:"QUOTE_ACCEPTED",spotPrice:this.quote.spotPrice,quoteId:this.quote.id})),a==="no"&&((l=this.options.callbacks)!=null&&l.onOptOut)&&this.options.callbacks.onOptOut({status:"QUOTE_DECLINED",quoteId:this.quote.id})})})}showSelectionError(){var e;if(!this.errorEl){this.errorEl=document.createElement("div"),this.errorEl.className="spot-selection__error",this.errorEl.textContent="Please make a selection";const t=(e=this.container)==null?void 0:e.querySelector(".spot-selection__options");t&&t.insertAdjacentElement("afterend",this.errorEl)}this.errorEl.style.display="block"}hideSelectionError(){this.errorEl&&(this.errorEl.style.display="none")}validateSelection(){if(!this.container)return!1;const e=!!this.container.querySelector('input[name="selection"]:checked');return e?this.hideSelectionError():this.showSelectionError(),e}async updateQuote(e){var t,o,n;try{const r={...this.options,quoteRequestData:{...this.options.quoteRequestData,...e}};g(r);const{environment:a,partnerId:p,endpoint:c}=this.options.apiConfig,l=c||b[a],d=await u(l,p,r.quoteRequestData);return d.status!=="QUOTE_AVAILABLE"?(d.status==="NO_MATCHING_QUOTE"&&((t=this.options.callbacks)!=null&&t.noMatchingQuote)&&this.options.callbacks.noMatchingQuote({status:"NO_MATCHING_QUOTE",data:r.quoteRequestData}),!1):(this.options.quoteRequestData=r.quoteRequestData,this.quote=d.data,this.currentSelection=null,this.destroy(),this._renderWidget(),(o=this.options.callbacks)!=null&&o.onQuoteRetrieved&&this.options.callbacks.onQuoteRetrieved(this.quote),!0)}catch(r){return(n=this.options.callbacks)==null||n.onError({message:r.message,status:r.status,responseBody:r.responseBody}),!1}}getSelection(){var e,t;return this.currentSelection==null?null:{selection:this.currentSelection,quoteId:(e=this.quote)==null?void 0:e.id,spotPrice:(t=this.quote)==null?void 0:t.spotPrice,status:this.currentSelection==="yes"?"QUOTE_ACCEPTED":"QUOTE_DECLINED"}}destroy(){window.removeEventListener("resize",this._onResize),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}}return N});
20
+ </svg>`,o}const M=":root{--spot-font-family: Arial;--spot-padding: 1.25rem;--spot-background-color: #ffffff;--spot-font-color: #000000;--spot-border-radius: .5rem;--spot-title-font-size: 1.25rem;--spot-title-font-weight: 700;--spot-title-padding: 0 0 1.25rem 0;--spot-description-font-size: .875rem;--spot-description-font-weight: 400;--spot-description-padding: 0 0 .5rem 0;--spot-bullets-font-size: .875rem;--spot-bullets-font-weight: 400;--spot-bullets-padding: .3125rem;--spot-table-border-radius: .625rem;--spot-table-header-font-size: .875rem;--spot-table-header-font-weight: 700;--spot-table-header-padding: 0 .5rem .625rem;--spot-table-cell-font-size: .815rem;--spot-table-cell-font-weight: 400;--spot-table-cell-padding: 0 .625rem;--spot-radio-border: #000000;--spot-radio-border-radius: .625rem;--spot-radio-checked-background: #000000;--spot-radio-text-font-size: .875rem;--spot-radio-text-font-weight: 400;--spot-radio-text-padding: .625rem;--spot-radio-selection-background: #f4f4f4;--spot-radio-selection-border-radius: .625rem;--spot-radio-selection-padding: .625rem;--spot-recommended-tag-background: #000000;--spot-recommended-tag-font-color: #ffffff;--spot-recommended-tag-font-size: .875rem;--spot-recommended-tag-font-weight: 700;--spot-recommended-tag-padding: .25rem .5rem;--spot-recommended-tag-border-radius: .5rem;--spot-selection-error-font-color: #ff0000;--spot-selection-error-font-size: .875rem;--spot-selection-error-padding: .5rem;--spot-payment-terms-background: #f4f4f4;--spot-payment-terms-border-radius: .625rem;--spot-payment-terms-padding: 1rem;--spot-payment-terms-font-color: #636569;--spot-payment-terms-font-size: .75rem;--spot-payment-terms-header-font-weight: 700;--spot-payment-terms-header-font-size: .875rem;--spot-payment-terms-header-margin-bottom: .5rem;--spot-payment-terms-header-border-color: #c2c2c2;--spot-payment-terms-header-padding: 0 0 .5rem 0;--spot-terms-font-size: .75rem;--spot-terms-font-weight: 400;--spot-terms-font-color: #636569;--spot-terms-padding: 0;--spot-terms-link-text-decoration: underline;--spot-terms-link-font-size: .75rem;--spot-terms-link-font-weight: 400;--spot-terms-link-font-color: #636569;--spot-terms-link-padding: 0}.spot-refund-guarantee{font-family:var(--spot-font-family);padding:var(--spot-padding);background-color:var(--spot-background-color);color:var(--spot-font-color);border:.0625rem solid #e0e0e0;border-radius:var(--spot-border-radius);max-width:51rem;margin:1rem}.spot-refund-guarantee *{color:inherit}.spot-header__title{font-size:var(--spot-title-font-size);font-weight:var(--spot-title-font-weight);padding:var(--spot-title-padding);color:var(--spot-title-font-color);font-family:var(--spot-title-font-family);line-height:120%;letter-spacing:-.03125rem}.spot-header__description{font-size:var(--spot-description-font-size);font-weight:var(--spot-description-font-weight);color:var(--spot-description-font-color);font-family:var(--spot-description-font-family);padding:var(--spot-description-padding);line-height:125%;letter-spacing:-.025rem}.spot-content__wrapper{display:flex;flex-direction:column}@media (min-width: 48rem){.spot-content__wrapper.desktop-layout{display:grid;grid-template-columns:1fr 20.3125rem;align-items:start;gap:1rem}.desktop-layout .spot-benefits__list{grid-row:1}.desktop-layout .spot-covered-items__container{grid-row:2;grid-column:1}.desktop-layout .spot-selection__options{grid-row:3}.desktop-layout .spot-table__container{grid-row:1 / span 3}}@media (max-width: 52.438rem){.spot-selection__recommended-tag{display:inline-block;margin-left:0}}@media (max-width: 47.938rem){.spot-selection__recommended-tag{margin-top:0rem}}@media (max-width: 32.125rem){.spot-selection__recommended-tag{margin-top:.5rem}}@media (max-width: 47.9375rem){.spot-table__container{display:flex;justify-content:center}.spot-selection__recommended-tag{display:inline-block;margin-left:0}.spot-footer__container{flex-direction:column;margin-top:.5rem}.spot-refund__table{width:100%;table-layout:auto}.spot-refund__table th{padding:0rem}}.spot-benefits__list{list-style-type:none;line-height:125%;gap:.5625rem;font-size:var(--spot-bullets-font-size);font-weight:var(--spot-bullets-font-weight);color:var(--spot-bullets-font-color);font-family:var(--spot-bullets-font-family);padding:var(--spot-bullets-padding);margin-block-start:0rem;margin-block-end:0rem}.spot-benefits__list li{margin-bottom:.5rem;display:flex;align-items:flex-start;gap:.5rem}.spot-benefits__list li svg{flex-shrink:0;position:relative;top:.125rem}.spot-covered-items__container{margin-top:0;margin-bottom:1rem}.spot-covered-items__title{font-size:var(--spot-description-font-size);font-weight:var(--spot-description-font-weight);color:var(--spot-description-font-color);font-family:var(--spot-description-font-family);padding:0 .3125rem .25rem;line-height:125%;margin:0}.spot-covered-items__list{list-style-type:disc;list-style-position:inside;line-height:125%;gap:.5625rem;font-size:var(--spot-bullets-font-size);font-weight:var(--spot-bullets-font-weight);color:var(--spot-bullets-font-color);font-family:var(--spot-bullets-font-family);padding:var(--spot-bullets-padding);margin-block-start:0rem;margin-block-end:0rem}.spot-covered-items__list li{margin-bottom:.3rem;text-align:left}.spot-table__container{width:100%}.spot-refund__table{max-width:22rem;border-radius:var(--spot-table-border-radius);overflow:hidden;border:.09375rem solid #636569;table-layout:fixed;margin-bottom:1.5rem;margin-top:.25rem;padding:.625rem}.spot-refund__table--dynamic{height:auto!important;min-height:7.5rem}.spot-refund__table td,.spot-refund__table th{padding:.375rem .625rem;text-align:left}.spot-refund__table th{text-align:left;font-size:var(--spot-table-header-font-size);font-weight:var(--spot-table-header-font-weight);color:var(--spot-table-header-font-color);font-family:var(--spot-table-header-font-family);padding:var(--spot-table-header-padding)}.spot-refund__table td{text-align:left;font-size:var(--spot-table-cell-font-size);font-weight:var(--spot-table-cell-font-weight);color:var(--spot-table-cell-font-color);font-family:var(--spot-table-cell-font-family);padding:var(--spot-table-cell-padding)}input[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:.75rem;height:.75rem;border:.0625rem solid var(--spot-radio-border);border-radius:var(--spot-radio-border-radius);margin-right:.5rem;position:relative;vertical-align:middle;top:-.0625rem;cursor:pointer}input[type=radio]:checked{background:var(--spot-radio-checked-background);box-shadow:inset 0 0 0 .0625rem #fff}.spot-selection__options{display:flex;flex-direction:column;gap:.5rem}.spot-selection__option{display:block;position:relative;transition:background .2s;cursor:pointer;font-size:var(--spot-radio-text-font-size);font-weight:var(--spot-radio-text-font-weight);color:var(--spot-radio-text-font-color);font-family:var(--spot-radio-text-font-family);padding:var(--spot-radio-text-padding);margin-right:.5rem;gap:.5rem;flex:1 0 0;align-self:stretch}.spot-selection__option.selected{background:var(--spot-radio-selection-background);border-radius:var(--spot-radio-selection-border-radius);padding:var(--spot-radio-selection-padding)}.spot-selection__recommended-tag{background:var(--spot-recommended-tag-background);color:var(--spot-recommended-tag-font-color);font-size:var(--spot-recommended-tag-font-size);font-weight:var(--spot-recommended-tag-font-weight);padding:var(--spot-recommended-tag-padding);border-radius:var(--spot-recommended-tag-border-radius);margin-left:1.5rem;white-space:nowrap}.spot-selection__error{color:var(--spot-selection-error-font-color);font-size:var(--spot-selection-error-font-size);padding:var(--spot-selection-error-padding);display:none}.spot-payment-terms__wrapper{margin-top:1rem}.spot-payment-terms__header{font-weight:var(--spot-payment-terms-header-font-weight);margin-bottom:.5rem;padding:var(--spot-payment-terms-header-padding);font-size:var(--spot-payment-terms-header-font-size);border-bottom:1px solid var(--spot-payment-terms-header-border-color)}.spot-payment-terms{background-color:var(--spot-payment-terms-background);border-radius:var(--spot-payment-terms-border-radius);padding:var(--spot-payment-terms-padding);margin-right:.5rem;color:var(--spot-payment-terms-font-color);font-size:var(--spot-payment-terms-font-size)}.spot-footer__terms{margin-top:.625rem;margin-right:.25rem;font-size:var(--spot-terms-font-size);font-weight:var(--spot-terms-font-weight);color:var(--spot-terms-font-color);font-family:var(--spot-terms-font-family);padding:var(--spot-terms-padding)}.spot-footer__terms-link{text-decoration:var(--spot-terms-link-text-decoration);font-size:var(--spot-terms-link-font-size);font-weight:var(--spot-terms-link-font-weight);color:var(--spot-terms-link-font-color);font-family:var(--spot-terms-link-font-family);padding:var(--spot-terms-link-padding)}.spot-footer__container{display:flex;justify-content:space-between;align-items:center}.spot-footer__powered-by{margin-top:1.5rem}";function R(p){const e=document.createElement("style");e.textContent=p,document.head.appendChild(e)}R(M);const D={sandbox:"https://api.sandbox.getspot.com/api/v1/quote",production:"https://api.getspot.com/api/v1/quote",local:"http://localhost:3999/api/v1/quote"};class L{constructor(e={}){this.options={location:"body",showTable:!0,optInSelected:!1,apiConfig:{environment:"production",partnerId:""},quoteRequestData:{},callbacks:{},...e},this._onResize=this._updateLayout.bind(this),this.root=typeof this.options.location=="string"?document.querySelector(this.options.location):this.options.location,this.currentSelection=this.options.optInSelected?"yes":null,this._init()}async _init(){var e,o,n,t,r;try{k(this.options);const{environment:c,partnerId:a}=this.options.apiConfig,h=this.options.apiConfig.customEndpoint||D[c],d=this.options.quoteRequestData.cartInfo&&this.options.quoteRequestData.items?await I(h,a,this.options.quoteRequestData):await w(h,a,this.options.quoteRequestData);if(d.status!=="QUOTE_AVAILABLE"){d.status==="NO_MATCHING_QUOTE"&&((e=this.options.callbacks)!=null&&e.noMatchingQuote)&&this.options.callbacks.noMatchingQuote({status:"NO_MATCHING_QUOTE",data:this.options.quoteRequestData});return}if(this.quote=d.data,this._renderWidget(),this.options.optInSelected&&((o=this.options.callbacks)!=null&&o.onOptIn)){const q={status:"QUOTE_ACCEPTED",spotPrice:this.quote.spotPrice,quoteId:this.quote.id};this.quote.originalQuotes&&this.quote.originalQuotes.length>0&&(q.batchQuoteDetails=this.quote.originalQuotes.map(s=>({quoteId:s.id,productPrice:s.spotPrice,cartItemId:s.cartItemId}))),this.options.callbacks.onOptIn(q)}(n=this.options.callbacks)!=null&&n.onQuoteRetrieved&&this.options.callbacks.onQuoteRetrieved(this.quote)}catch(c){(t=this.options.callbacks)!=null&&t.onError&&((r=this.options.callbacks)==null||r.onError({message:c.message,status:c.status,responseBody:c.responseBody}))}}_renderWidget(){this.container=document.createElement("div"),this.container.className="spot-refund-guarantee",this.root.appendChild(this.container),Object.entries(this.options.theme||{}).forEach(([n,t])=>{const r=`--${n}`;this.container.style.setProperty(r,t)}),O(this.container,this.quote.communication);const e=document.createElement("div");e.className="spot-content__wrapper",this.container.appendChild(e),P(e,this.quote.communication.bulletPoints),this.quote.coveredItems&&$(e,this.quote.coveredItems),this.options.showTable&&Q(e,this.quote.payoutSchedule);const o=S(e,this.options.optInSelected,this.quote.communication);e.appendChild(o),this.paymentTermsEl=i("div",{className:"spot-payment-terms__wrapper",parent:e}),z(this.container,this.quote),window.addEventListener("resize",this._onResize),this._updateLayout(),this._setupOptionListeners(o)}_updateLayout(){const e=window.matchMedia("(min-width: 768px)").matches;this.container.querySelector(".spot-content__wrapper").classList.toggle("desktop-layout",e&&this.options.showTable)}_setupOptionListeners(e){const o=e.querySelectorAll('input[type="radio"]'),n=e.querySelectorAll(".spot-selection__option");o.forEach(t=>{t.addEventListener("change",r=>{var a,u,h;const c=r.target.value;if(this.hideSelectionError(),this.currentSelection=c,n.forEach(m=>m.classList.remove("selected")),(a=r.target.closest(".spot-selection__option"))==null||a.classList.add("selected"),this.paymentTermsEl&&(this.paymentTermsEl.innerHTML=""),c==="yes"&&(this.options.quoteRequestData.isPartialPayment&&H(this.paymentTermsEl,this.quote),(u=this.options.callbacks)!=null&&u.onOptIn)){const m={status:"QUOTE_ACCEPTED",spotPrice:this.quote.spotPrice,quoteId:this.quote.id};this.quote.originalQuotes&&this.quote.originalQuotes.length>0&&(m.batchQuoteDetails=this.quote.originalQuotes.map(d=>({quoteId:d.id,productPrice:d.spotPrice,cartItemId:d.cartItemId}))),this.options.callbacks.onOptIn(m)}if(c==="no"&&((h=this.options.callbacks)!=null&&h.onOptOut)){const m={status:"QUOTE_DECLINED",quoteId:this.quote.id};this.quote.originalQuotes&&this.quote.originalQuotes.length>0&&(m.batchQuoteDetails=this.quote.originalQuotes.map(d=>({quoteId:d.id,productPrice:d.spotPrice,cartItemId:d.cartItemId}))),this.options.callbacks.onOptOut(m)}})})}showSelectionError(){var e;if(!this.errorEl){this.errorEl=document.createElement("div"),this.errorEl.className="spot-selection__error",this.errorEl.textContent="Please make a selection";const o=(e=this.container)==null?void 0:e.querySelector(".spot-selection__options");o&&o.insertAdjacentElement("afterend",this.errorEl)}this.errorEl.style.display="block"}hideSelectionError(){this.errorEl&&(this.errorEl.style.display="none")}validateSelection(){if(!this.container)return!1;const e=!!this.container.querySelector('input[name="selection"]:checked');return e?this.hideSelectionError():this.showSelectionError(),e}async updateQuote(e){var o,n,t;try{const r={...this.options,quoteRequestData:e};k(r);const{environment:c,partnerId:a,endpoint:u}=this.options.apiConfig,h=u||D[c],d=r.quoteRequestData.cartInfo&&r.quoteRequestData.items?await I(h,a,r.quoteRequestData):await w(h,a,r.quoteRequestData);return d.status!=="QUOTE_AVAILABLE"?(d.status==="NO_MATCHING_QUOTE"&&((o=this.options.callbacks)!=null&&o.noMatchingQuote)&&this.options.callbacks.noMatchingQuote({status:"NO_MATCHING_QUOTE",data:r.quoteRequestData}),!1):(this.options.quoteRequestData=r.quoteRequestData,this.quote=d.data,this.currentSelection=null,this.destroy(),this._renderWidget(),(n=this.options.callbacks)!=null&&n.onQuoteRetrieved&&this.options.callbacks.onQuoteRetrieved(this.quote),!0)}catch(r){return(t=this.options.callbacks)==null||t.onError({message:r.message,status:r.status,responseBody:r.responseBody}),!1}}getSelection(){var o,n,t;if(this.currentSelection==null)return null;const e={selection:this.currentSelection,quoteId:(o=this.quote)==null?void 0:o.id,spotPrice:(n=this.quote)==null?void 0:n.spotPrice,status:this.currentSelection==="yes"?"QUOTE_ACCEPTED":"QUOTE_DECLINED"};return(t=this.quote)!=null&&t.originalQuotes&&this.quote.originalQuotes.length>0&&(e.batchQuoteDetails=this.quote.originalQuotes.map(r=>({quoteId:r.id,productPrice:r.spotPrice,cartItemId:r.cartItemId}))),e}destroy(){window.removeEventListener("resize",this._onResize),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}}return L});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getspot/spot-widget",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/api.js CHANGED
@@ -30,3 +30,125 @@ export async function fetchQuote(endpoint, partnerId, payload) {
30
30
  : new Error("Unknown error occurred while fetching quote");
31
31
  }
32
32
  }
33
+
34
+ /**
35
+ * Retrieve batch quote from Spot API
36
+ * @param {string} endpoint – Spot API URL
37
+ * @param {string} partnerId – partner UUID
38
+ * @param {object} batchPayload – batch request data with items array
39
+ * @returns {Promise<{ status: string, data?: object }>}
40
+ */
41
+ export async function fetchBatchQuote(endpoint, partnerId, batchPayload) {
42
+ try {
43
+ const batchEndpoint = endpoint.replace('/quote', '/quote/batch');
44
+ const res = await fetch(batchEndpoint, {
45
+ method: "POST",
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ "X-Spot-Partner-Id": partnerId,
49
+ },
50
+ body: JSON.stringify(batchPayload),
51
+ });
52
+ const body = await res.json();
53
+ if (!res.ok) {
54
+ const error = new Error(body?.message || "Failed to fetch batch quote");
55
+ error.status = res.status;
56
+ error.responseBody = body;
57
+ throw error;
58
+ }
59
+
60
+ return body;
61
+ } catch (err) {
62
+ throw err instanceof Error
63
+ ? err
64
+ : new Error("Unknown error occurred while fetching batch quote");
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Retrieve multiple quotes in parallel from Spot API
70
+ * @param {string} endpoint – Spot API URL
71
+ * @param {string} partnerId – partner UUID
72
+ * @param {object} batchData – batch quote data with cartInfo and items
73
+ * @param {object} batchData.cartInfo – cart-level information
74
+ * @param {string} batchData.cartInfo.cartId – cart ID
75
+ * @param {string} batchData.cartInfo.cartName – cart name
76
+ * @param {string} batchData.cartInfo.currencyCode – currency code
77
+ * @param {object[]} batchData.items – array of item data
78
+ * @returns {Promise<{ status: string, data?: object, spotPrice?: number, coveredItems?: string[] }>}
79
+ */
80
+ export async function fetchMultipleQuotes(endpoint, partnerId, batchData) {
81
+ try {
82
+ // Transform into batch format for API
83
+ const batchPayload = {
84
+ cartId: batchData.cartInfo.cartId,
85
+ cartName: batchData.cartInfo.cartName,
86
+ currencyCode: batchData.cartInfo.currencyCode,
87
+ items: batchData.items.map((item, index) => ({
88
+ cartItemId: item.cartItemId || `item-${index + 1}`,
89
+ productPrice: item.productPrice,
90
+ productType: item.productType,
91
+ productDuration: item.productDuration,
92
+ productId: item.productId,
93
+ productName: item.productName,
94
+ participantDescription: item.participantDescription,
95
+ eventType: item.eventType,
96
+ startDate: item.startDate,
97
+ endDate: item.endDate
98
+ }))
99
+ };
100
+
101
+ const response = await fetchBatchQuote(endpoint, partnerId, batchPayload);
102
+
103
+ // Check for various success statuses
104
+ if (response.status !== "QUOTES_AVAILABLE" && response.status !== "QUOTE_AVAILABLE") {
105
+ return { status: "NO_MATCHING_QUOTE" };
106
+ }
107
+
108
+ // Extract covered items only for successful quotes
109
+ const coveredItems = response.quotes.map(quote => {
110
+ // Find the corresponding item from the original request using cartItemId
111
+ const originalItem = batchData.items.find(item =>
112
+ (item.cartItemId || `item-${batchData.items.indexOf(item) + 1}`) === quote.cartItemId
113
+ );
114
+
115
+ if (originalItem) {
116
+ return originalItem.participantDescription
117
+ ? `${originalItem.productName} - ${originalItem.participantDescription}`
118
+ : originalItem.productName;
119
+ }
120
+
121
+ // Fallback if we can't find the original item
122
+ return `Item ${quote.cartItemId}`;
123
+ });
124
+
125
+ // Fix floating point precision issue
126
+ const totalSpotPrice = Math.round((response.totalSpotPrice || response.spotPrice || 0) * 100) / 100;
127
+
128
+ // Build response in expected format
129
+ return {
130
+ status: "QUOTE_AVAILABLE",
131
+ data: {
132
+ id: response.quotes ? response.quotes.map(q => q.id).join(',') : response.id,
133
+ spotPrice: totalSpotPrice,
134
+ currencyCode: response.currencyCode,
135
+ communication: {
136
+ ...response.communication,
137
+ yesOptionText: response.communication.yesOptionText.replace(response.totalSpotPrice, totalSpotPrice)
138
+ },
139
+ payoutSchedule: response.payoutSchedule.map(item => ({
140
+ ...item,
141
+ amount: item.amount !== undefined ? item.amount : 0
142
+ })),
143
+ coveredItems: coveredItems,
144
+ originalQuotes: response.quotes || [response]
145
+ },
146
+ spotPrice: totalSpotPrice,
147
+ coveredItems
148
+ };
149
+ } catch (err) {
150
+ throw err instanceof Error
151
+ ? err
152
+ : new Error("Unknown error occurred while fetching multiple quotes");
153
+ }
154
+ }
package/src/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { fetchQuote } from "./api.js";
1
+ import { fetchQuote, fetchMultipleQuotes } from "./api.js";
2
2
  import { validateOptions } from "./validateOptions.js";
3
3
  import {
4
4
  renderHeader,
5
5
  renderBenefits,
6
+ renderCoveredItems,
6
7
  renderTable,
7
8
  renderOptions,
8
9
  renderFooter,
@@ -23,6 +24,7 @@ injectStyles(styles);
23
24
  const apiEndpoint = {
24
25
  sandbox: "https://api.sandbox.getspot.com/api/v1/quote",
25
26
  production: "https://api.getspot.com/api/v1/quote",
27
+ local: "http://localhost:3999/api/v1/quote"
26
28
  };
27
29
 
28
30
  class SpotWidget {
@@ -56,11 +58,10 @@ class SpotWidget {
56
58
 
57
59
  const endpoint = customEndpoint || apiEndpoint[environment];
58
60
 
59
- const response = await fetchQuote(
60
- endpoint,
61
- partnerId,
62
- this.options.quoteRequestData
63
- );
61
+ const isBatchQuote = this.options.quoteRequestData.cartInfo && this.options.quoteRequestData.items;
62
+ const response = isBatchQuote
63
+ ? await fetchMultipleQuotes(endpoint, partnerId, this.options.quoteRequestData)
64
+ : await fetchQuote(endpoint, partnerId, this.options.quoteRequestData);
64
65
 
65
66
  if (response.status !== "QUOTE_AVAILABLE") {
66
67
  if (
@@ -79,11 +80,22 @@ class SpotWidget {
79
80
  this._renderWidget();
80
81
 
81
82
  if (this.options.optInSelected && this.options.callbacks?.onOptIn) {
82
- this.options.callbacks.onOptIn({
83
+ const optInData = {
83
84
  status: "QUOTE_ACCEPTED",
84
85
  spotPrice: this.quote.spotPrice,
85
- quoteId: this.quote.id,
86
- });
86
+ quoteId: this.quote.id
87
+ };
88
+
89
+ // For batch quotes, include detailed quote information
90
+ if (this.quote.originalQuotes && this.quote.originalQuotes.length > 0) {
91
+ optInData.batchQuoteDetails = this.quote.originalQuotes.map(q => ({
92
+ quoteId: q.id,
93
+ productPrice: q.spotPrice,
94
+ cartItemId: q.cartItemId
95
+ }));
96
+ }
97
+
98
+ this.options.callbacks.onOptIn(optInData);
87
99
  }
88
100
 
89
101
  if (this.options.callbacks?.onQuoteRetrieved) {
@@ -116,11 +128,14 @@ class SpotWidget {
116
128
  this.container.appendChild(cw);
117
129
 
118
130
  renderBenefits(cw, this.quote.communication.bulletPoints);
131
+ if (this.quote.coveredItems) {
132
+ renderCoveredItems(cw, this.quote.coveredItems);
133
+ }
119
134
  if (this.options.showTable) renderTable(cw, this.quote.payoutSchedule);
120
135
  const optsEl = renderOptions(
121
136
  cw,
122
- this.quote.spotPrice,
123
- this.options.optInSelected
137
+ this.options.optInSelected,
138
+ this.quote.communication
124
139
  );
125
140
  cw.appendChild(optsEl);
126
141
  this.paymentTermsEl = makeEl("div", {
@@ -162,18 +177,40 @@ class SpotWidget {
162
177
  renderPaymentTerms(this.paymentTermsEl, this.quote);
163
178
  }
164
179
  if (this.options.callbacks?.onOptIn) {
165
- this.options.callbacks.onOptIn({
180
+ const optInData = {
166
181
  status: "QUOTE_ACCEPTED",
167
182
  spotPrice: this.quote.spotPrice,
168
- quoteId: this.quote.id,
169
- });
183
+ quoteId: this.quote.id
184
+ };
185
+
186
+ // For batch quotes, include detailed quote information
187
+ if (this.quote.originalQuotes && this.quote.originalQuotes.length > 0) {
188
+ optInData.batchQuoteDetails = this.quote.originalQuotes.map(q => ({
189
+ quoteId: q.id,
190
+ productPrice: q.spotPrice,
191
+ cartItemId: q.cartItemId
192
+ }));
193
+ }
194
+
195
+ this.options.callbacks.onOptIn(optInData);
170
196
  }
171
197
  }
172
198
  if (val === "no" && this.options.callbacks?.onOptOut) {
173
- this.options.callbacks.onOptOut({
199
+ const optOutData = {
174
200
  status: "QUOTE_DECLINED",
175
- quoteId: this.quote.id,
176
- });
201
+ quoteId: this.quote.id
202
+ };
203
+
204
+ // For batch quotes, include detailed quote information
205
+ if (this.quote.originalQuotes && this.quote.originalQuotes.length > 0) {
206
+ optOutData.batchQuoteDetails = this.quote.originalQuotes.map(q => ({
207
+ quoteId: q.id,
208
+ productPrice: q.spotPrice,
209
+ cartItemId: q.cartItemId
210
+ }));
211
+ }
212
+
213
+ this.options.callbacks.onOptOut(optOutData);
177
214
  }
178
215
  });
179
216
  });
@@ -221,10 +258,7 @@ class SpotWidget {
221
258
  try {
222
259
  const updatedOptions = {
223
260
  ...this.options,
224
- quoteRequestData: {
225
- ...this.options.quoteRequestData,
226
- ...newQuoteRequestData,
227
- },
261
+ quoteRequestData: newQuoteRequestData
228
262
  };
229
263
 
230
264
  validateOptions(updatedOptions);
@@ -237,11 +271,10 @@ class SpotWidget {
237
271
 
238
272
  const endpoint = customEndpoint || apiEndpoint[environment];
239
273
 
240
- const response = await fetchQuote(
241
- endpoint,
242
- partnerId,
243
- updatedOptions.quoteRequestData
244
- );
274
+ const isBatchQuote = updatedOptions.quoteRequestData.cartInfo && updatedOptions.quoteRequestData.items;
275
+ const response = isBatchQuote
276
+ ? await fetchMultipleQuotes(endpoint, partnerId, updatedOptions.quoteRequestData)
277
+ : await fetchQuote(endpoint, partnerId, updatedOptions.quoteRequestData);
245
278
 
246
279
  if (response.status !== "QUOTE_AVAILABLE") {
247
280
  if (
@@ -282,13 +315,24 @@ class SpotWidget {
282
315
  getSelection() {
283
316
  if (this.currentSelection == null) return null;
284
317
 
285
- return {
318
+ const selectionData = {
286
319
  selection: this.currentSelection,
287
320
  quoteId: this.quote?.id,
288
321
  spotPrice: this.quote?.spotPrice,
289
322
  status:
290
- this.currentSelection === "yes" ? "QUOTE_ACCEPTED" : "QUOTE_DECLINED",
323
+ this.currentSelection === "yes" ? "QUOTE_ACCEPTED" : "QUOTE_DECLINED"
291
324
  };
325
+
326
+ // For batch quotes, include detailed quote information
327
+ if (this.quote?.originalQuotes && this.quote.originalQuotes.length > 0) {
328
+ selectionData.batchQuoteDetails = this.quote.originalQuotes.map(q => ({
329
+ quoteId: q.id,
330
+ productPrice: q.spotPrice,
331
+ cartItemId: q.cartItemId
332
+ }));
333
+ }
334
+
335
+ return selectionData;
292
336
  }
293
337
 
294
338
  destroy() {
package/src/styles.css CHANGED
@@ -127,12 +127,17 @@
127
127
  grid-row: 1;
128
128
  }
129
129
 
130
- .desktop-layout .spot-selection__options {
130
+ .desktop-layout .spot-covered-items__container {
131
131
  grid-row: 2;
132
+ grid-column: 1;
133
+ }
134
+
135
+ .desktop-layout .spot-selection__options {
136
+ grid-row: 3;
132
137
  }
133
138
 
134
139
  .desktop-layout .spot-table__container {
135
- grid-row: 1 / span 2;
140
+ grid-row: 1 / span 3;
136
141
  }
137
142
  }
138
143
 
@@ -207,6 +212,41 @@
207
212
  top: 0.125rem;
208
213
  }
209
214
 
215
+ /* Covered Items List */
216
+ .spot-covered-items__container {
217
+ margin-top: 0;
218
+ margin-bottom: 1rem;
219
+ }
220
+
221
+ .spot-covered-items__title {
222
+ font-size: var(--spot-description-font-size);
223
+ font-weight: var(--spot-description-font-weight);
224
+ color: var(--spot-description-font-color);
225
+ font-family: var(--spot-description-font-family);
226
+ padding: 0 0.3125rem 0.25rem 0.3125rem;
227
+ line-height: 125%;
228
+ margin: 0;
229
+ }
230
+
231
+ .spot-covered-items__list {
232
+ list-style-type: disc;
233
+ list-style-position: inside;
234
+ line-height: 125%;
235
+ gap: 0.5625rem;
236
+ font-size: var(--spot-bullets-font-size);
237
+ font-weight: var(--spot-bullets-font-weight);
238
+ color: var(--spot-bullets-font-color);
239
+ font-family: var(--spot-bullets-font-family);
240
+ padding: var(--spot-bullets-padding);
241
+ margin-block-start: 0rem;
242
+ margin-block-end: 0rem;
243
+ }
244
+
245
+ .spot-covered-items__list li {
246
+ margin-bottom: 0.3rem;
247
+ text-align: left;
248
+ }
249
+
210
250
  /* Payout Table */
211
251
  .spot-table__container {
212
252
  width: 100%;
package/src/ui.js CHANGED
@@ -38,6 +38,32 @@ export function renderBenefits(container, bullets = []) {
38
38
  });
39
39
  }
40
40
 
41
+ // covered items for multi-quote
42
+ export function renderCoveredItems(container, coveredItems = []) {
43
+ if (coveredItems.length === 0) return;
44
+
45
+ const wrapper = makeEl("div", {
46
+ className: "spot-covered-items__container",
47
+ parent: container,
48
+ });
49
+
50
+ makeEl("div", {
51
+ className: "spot-covered-items__title",
52
+ text: "Items covered in your cart:",
53
+ parent: wrapper,
54
+ });
55
+
56
+ const ul = makeEl("ul", {
57
+ className: "spot-covered-items__list",
58
+ parent: wrapper,
59
+ });
60
+
61
+ coveredItems.forEach((item) => {
62
+ const li = makeEl("li", { parent: ul });
63
+ makeEl("span", { text: item, parent: li });
64
+ });
65
+ }
66
+
41
67
  // payout table
42
68
  export function renderTable(container, schedule = []) {
43
69
  const wrapper = makeEl("div", {
@@ -67,7 +93,7 @@ export function renderTable(container, schedule = []) {
67
93
  }
68
94
 
69
95
  // radio buttons
70
- export function renderOptions(container, spotPrice, optInSelected) {
96
+ export function renderOptions(container, optInSelected, communication) {
71
97
  const optionsWrapper = makeEl("div", {
72
98
  className: "spot-selection__options",
73
99
  parent: container,
@@ -85,7 +111,7 @@ export function renderOptions(container, spotPrice, optInSelected) {
85
111
  if (optInSelected) yesInput.checked = true;
86
112
 
87
113
  makeEl("strong", {
88
- text: `Yes, protect my booking for $${spotPrice}`,
114
+ text: communication.yesOptionText,
89
115
  parent: yesOption,
90
116
  });
91
117
 
@@ -105,7 +131,7 @@ export function renderOptions(container, spotPrice, optInSelected) {
105
131
  noInput.name = "selection";
106
132
  noInput.value = "no";
107
133
 
108
- makeEl("span", { text: "No, do not protect my booking", parent: noOption });
134
+ makeEl("span", { text: communication.noOptionText, parent: noOption });
109
135
 
110
136
  return optionsWrapper;
111
137
  }