copilot-chat-widget 0.1.33 → 0.1.37

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.cjs CHANGED
@@ -1,7 +1,7 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const N="http://localhost:3000",k=64,T=720,$=({iframeUrl:f,launcherIcon:x})=>{const u=document.querySelector("[data-copilot-widget-root]");u&&u.remove();const y=t=>{const e=document.querySelector("[data-copilot-checkout-toast]");e&&e.remove();const n=document.createElement("div");n.setAttribute("data-copilot-checkout-toast","true"),n.innerText=t,Object.assign(n.style,{position:"fixed",top:"20px",left:"50%",transform:"translateX(-50%)",padding:"12px 16px",background:"#0f172a",color:"white",borderRadius:"12px",boxShadow:"0 8px 24px rgba(0,0,0,0.25)",zIndex:2147483647,fontSize:"14px",fontWeight:"600",maxWidth:"420px",lineHeight:"1.4",textAlign:"center"}),document.body.appendChild(n),setTimeout(()=>{n.remove()},4500)},w=document.createElement("div");w.setAttribute("data-copilot-widget-root","true");const a=w.attachShadow({mode:"open"});document.body.appendChild(w);const o=document.createElement("button");o.type="button",o.setAttribute("aria-label","Open Copilot chat"),o.innerHTML=`
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const k="http://localhost:3000",w=64,C=720,E=({iframeUrl:h,launcherIcon:u})=>{const d=document.querySelector("[data-copilot-widget-root]");d&&d.remove();const g=s=>{const o=document.querySelector("[data-copilot-checkout-toast]");o&&o.remove();const r=document.createElement("div");r.setAttribute("data-copilot-checkout-toast","true"),r.innerText=s,Object.assign(r.style,{position:"fixed",top:"20px",left:"50%",transform:"translateX(-50%)",padding:"12px 16px",background:"#0f172a",color:"white",borderRadius:"12px",boxShadow:"0 8px 24px rgba(0,0,0,0.25)",zIndex:2147483647,fontSize:"14px",fontWeight:"600",maxWidth:"420px",lineHeight:"1.4",textAlign:"center"}),document.body.appendChild(r),setTimeout(()=>{r.remove()},4500)},c=document.createElement("div");c.setAttribute("data-copilot-widget-root","true");const n=c.attachShadow({mode:"open"});document.body.appendChild(c);const t=document.createElement("button");t.type="button",t.setAttribute("aria-label","Open Copilot chat"),t.innerHTML=`
2
2
  <img
3
- src="${x}"
3
+ src="${u}"
4
4
  alt="Copilot chat launcher"
5
5
  style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
6
6
  />
7
- `,Object.assign(o.style,{position:"fixed",bottom:"24px",right:"24px",width:`${k}px`,height:`${k}px`,borderRadius:"50%",border:"none",background:"linear-gradient(135deg, #0078ff, #00c6ff)",color:"white",cursor:"pointer",zIndex:999998,display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 6px 14px rgba(0,0,0,0.25)",transition:"all 0.25s ease"}),o.onmouseover=()=>{o.style.transform="scale(1.12)",o.style.boxShadow="0 10px 25px rgba(0,0,0,0.3)"},o.onmouseout=()=>{o.style.transform="scale(1)",o.style.boxShadow="0 6px 14px rgba(0,0,0,0.25)"};const i=document.createElement("div");i.setAttribute("data-copilot-widget-root","true"),Object.assign(i.style,{display:"none",position:"fixed",bottom:`${k+36}px`,right:"24px",zIndex:"999999",transformOrigin:"bottom right",transform:"scale(0.8) translateY(20px)",opacity:"0",transition:"all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"});const g=document.createElement("div"),E=document.createElement("div"),v=document.createElement("div");Object.assign(g.style,{position:"absolute",bottom:"-14px",right:"28px",width:"30px",height:"20px",pointerEvents:"none",display:"none",zIndex:"1"}),Object.assign(E.style,{position:"absolute",bottom:"0",left:"0",right:"0",margin:"0 auto",width:"0",height:"0",borderLeft:"15px solid transparent",borderRight:"15px solid transparent",borderTop:"15px solid rgba(15,23,42,0.1)"}),Object.assign(v.style,{position:"absolute",bottom:"2px",left:"0",right:"0",margin:"0 auto",width:"0",height:"0",borderLeft:"13px solid transparent",borderRight:"13px solid transparent",borderTop:"13px solid white",boxShadow:"0 6px 16px rgba(15,23,42,0.12)",borderRadius:"2px"}),g.appendChild(E),g.appendChild(v);const b=document.createElement("div");Object.assign(b.style,{width:`${T}px`,maxWidth:"calc(100vw - 48px)",height:`${Math.min(T,Math.max(320,window.innerHeight-140))}px`,maxHeight:"calc(100vh - 150px)",borderRadius:"20px",background:"white",border:"1px solid rgba(15,23,42,0.12)",boxShadow:"0 18px 45px rgba(15,23,42,0.16)",overflow:"hidden"}),a.appendChild(b);const r=document.createElement("iframe");r.src=f,r.title="Copilot chat widget",r.allow="clipboard-read; clipboard-write; microphone; camera; display-capture",r.setAttribute("scrolling","no"),Object.assign(r.style,{width:"100%",height:"100%",border:"none",display:"block",background:"transparent",overflow:"hidden"}),a.appendChild(b),b.appendChild(r),i.appendChild(g),i.appendChild(b),document.body.appendChild(o),document.body.appendChild(i);let d=!1;const C=()=>{d&&(d=!1,i.style.opacity="0",i.style.transform="scale(0.8) translateY(20px)",g.style.display="none",setTimeout(()=>{i.style.display="none"},250),o.style.transform="scale(1)")},P=(t,e=null)=>{if(!t)return e;try{return JSON.parse(t)}catch{return e}},A=t=>String(t).toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),s=(t,e)=>({value:t,currency:e,__typename:"Money"}),R=(t,e)=>({maximum_price:{discount:{amount_off:0,percent_off:0,__typename:"ProductDiscount"},final_price:s(t,e),fixed_product_taxes:[],regular_price:s(t,e),__typename:"ProductPrice"},minimum_price:{discount:{amount_off:0,percent_off:0,__typename:"ProductDiscount"},final_price:s(t,e),fixed_product_taxes:[],regular_price:s(t,e),__typename:"ProductPrice"},__typename:"PriceRange"}),W=(t,e)=>{const n=Number(t?.quantity||0),m=Number(t?.price||t?.unitPrice||0),c=m*n,p=t?.name||"Chat widget product",S=t?.image||t?.thumbnail||"",h=Number(t?.productId||t?.id||0),l=String(t?.sku||t?.id||h||"chat-widget");return{id:String(t?.id||l||h||Date.now()),quantity:n,product:{id:h||Date.now(),sku:l,name:p,url_key:t?.url_key||A(p),url_suffix:".html",stock_status:"IN_STOCK",brand:null,has_gift:null,price_range:R(m,e),thumbnail:{disabled:null,label:p,position:null,url:S,__typename:"ProductImage"},small_image:{disabled:null,label:p,position:null,url:S,__typename:"ProductImage"},categories:[],special_from_date:null,special_price:null,special_to_date:null,__typename:"SimpleProduct"},prices:{discounts:null,price:s(m,e),row_total:s(c,e),row_total_including_tax:s(c,e),total_item_discount:s(0,e),__typename:"CartItemPrices"},__typename:"SimpleCartItem",itemTotal:c}},U=t=>{const e=P(window.localStorage.getItem("web-cart")),n=Array.isArray(t?.cart)?t.cart:[],m=t?.currency||"VND",c=n.map(l=>W(l,m)),p=c.reduce((l,I)=>l+(I.quantity||0),0),S=Number(t?.totalPrice||0)||c.reduce((l,I)=>l+(I.itemTotal||0),0),h={totalItems:p,total:s(S,m),id:e?.id||`chat-widget-${Date.now()}`,is_virtual:!1,shipping_addresses:Array.isArray(e?.shipping_addresses)?e.shipping_addresses:[],total_quantity:p,items:c,isCartIdLoading:!1,isFetchingCart:!1};window.localStorage.setItem("web-cart",JSON.stringify(h)),window.dispatchEvent(new StorageEvent("storage",{key:"web-cart",newValue:JSON.stringify(h)}))},j=t=>{const{data:e,source:n}=t||{};if(e?.type){if(e.type==="CART_CHECKOUT"&&n===r.contentWindow){console.log("[CopilotChat] Received checkout payload from widget:",e),U(e?.data),y("Cart updated on KidsPlaza demo. Open cart to see changes.");return}if(e.type==="WIDGET_READY"&&n===r.contentWindow){r.contentWindow.postMessage({type:"INIT_WIDGET"},"*");return}e.type==="CHAT_CLOSED"&&C()}};window.addEventListener("message",j),o.onclick=t=>{t.stopPropagation(),d=!d,d?(i.style.display="block",g.style.display="block",requestAnimationFrame(()=>{i.style.opacity="1",i.style.transform="scale(1) translateY(0)"})):C()},document.addEventListener("click",t=>{const e=t.target;e&&d&&!i.contains(e)&&e!==o&&C()});const _={close:C,open:()=>{d||o.click()}};return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.close=_.close,window.CopilotChat.open=_.open,window.CopilotChat.controls=_,_};async function O(f={}){if(typeof window>"u"||typeof document>"u")return null;const x=window.CopilotChatConfig||{},u=f.token||x.token||typeof window<"u"&&window.localStorage?.getItem("copilotChatToken")||null;if(!u)return console.error("[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."),null;const y=f.baseUrl||x.baseUrl||N,w=`${y.replace(/\/$/,"")}/api/chat-widget/config?token=${encodeURIComponent(u)}`;try{const a=await fetch(w,{credentials:"omit",mode:"cors"});if(!a.ok)throw new Error(`Server responded with ${a.status}`);const o=await a.json();if(!o?.iframeUrl||!o?.launcherIcon)throw new Error("Received incomplete widget configuration from server.");return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.token=u,window.CopilotChat.baseUrl=y,$({iframeUrl:o.iframeUrl,launcherIcon:o.launcherIcon})}catch(a){return console.error("[CopilotChat] Error during widget bootstrap:",a instanceof Error?a.message:a),null}}exports.default=O;exports.loadCopilotChatWidget=O;
7
+ `,Object.assign(t.style,{position:"fixed",bottom:"24px",right:"24px",width:`${w}px`,height:`${w}px`,borderRadius:"50%",border:"none",background:"linear-gradient(135deg, #0078ff, #00c6ff)",color:"white",cursor:"pointer",zIndex:999998,display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 6px 14px rgba(0,0,0,0.25)",transition:"all 0.25s ease"}),t.onmouseover=()=>{t.style.transform="scale(1.12)",t.style.boxShadow="0 10px 25px rgba(0,0,0,0.3)"},t.onmouseout=()=>{t.style.transform="scale(1)",t.style.boxShadow="0 6px 14px rgba(0,0,0,0.25)"};const e=document.createElement("div");e.setAttribute("data-copilot-widget-root","true"),Object.assign(e.style,{display:"none",position:"fixed",bottom:`${w+36}px`,right:"24px",zIndex:"999999",transformOrigin:"bottom right",transform:"scale(0.8) translateY(20px)",opacity:"0",transition:"all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"});const l=document.createElement("div"),f=document.createElement("div"),x=document.createElement("div");Object.assign(l.style,{position:"absolute",bottom:"-14px",right:"28px",width:"30px",height:"20px",pointerEvents:"none",display:"none",zIndex:"1"}),Object.assign(f.style,{position:"absolute",bottom:"0",left:"0",right:"0",margin:"0 auto",width:"0",height:"0",borderLeft:"15px solid transparent",borderRight:"15px solid transparent",borderTop:"15px solid rgba(15,23,42,0.1)"}),Object.assign(x.style,{position:"absolute",bottom:"2px",left:"0",right:"0",margin:"0 auto",width:"0",height:"0",borderLeft:"13px solid transparent",borderRight:"13px solid transparent",borderTop:"13px solid white",boxShadow:"0 6px 16px rgba(15,23,42,0.12)",borderRadius:"2px"}),l.appendChild(f),l.appendChild(x);const p=document.createElement("div");Object.assign(p.style,{width:`${C}px`,maxWidth:"calc(100vw - 48px)",height:`${Math.min(C,Math.max(320,window.innerHeight-140))}px`,maxHeight:"calc(100vh - 150px)",borderRadius:"20px",background:"white",border:"1px solid rgba(15,23,42,0.12)",boxShadow:"0 18px 45px rgba(15,23,42,0.16)",overflow:"hidden"}),n.appendChild(p);const i=document.createElement("iframe");i.src=h,i.title="Copilot chat widget",i.allow="clipboard-read; clipboard-write; microphone; camera; display-capture",i.setAttribute("scrolling","no"),Object.assign(i.style,{width:"100%",height:"100%",border:"none",display:"block",background:"transparent",overflow:"hidden"}),n.appendChild(p),p.appendChild(i),e.appendChild(l),e.appendChild(p),document.body.appendChild(t),document.body.appendChild(e);let a=!1;const m=()=>{a&&(a=!1,e.style.opacity="0",e.style.transform="scale(0.8) translateY(20px)",l.style.display="none",setTimeout(()=>{e.style.display="none"},250),t.style.transform="scale(1)")},v=s=>{const{data:o,source:r}=s||{};if(o?.type){if(o.type==="CART_CHECKOUT"&&r===i.contentWindow){console.log("[CopilotChat] Received checkout payload from widget:",o),g("Checkout message received from chat widget. Check console for payload.");return}if(o.type==="WIDGET_READY"&&r===i.contentWindow){i.contentWindow.postMessage({type:"INIT_WIDGET"},"*");return}o.type==="CHAT_CLOSED"&&m()}};window.addEventListener("message",v),t.onclick=s=>{s.stopPropagation(),a=!a,a?(e.style.display="block",l.style.display="block",requestAnimationFrame(()=>{e.style.opacity="1",e.style.transform="scale(1) translateY(0)"})):m()},document.addEventListener("click",s=>{const o=s.target;o&&a&&!e.contains(o)&&o!==t&&m()});const b={close:m,open:()=>{a||t.click()}};return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.close=b.close,window.CopilotChat.open=b.open,window.CopilotChat.controls=b,b};async function y(h={}){if(typeof window>"u"||typeof document>"u")return null;const u=window.CopilotChatConfig||{},d=h.token||u.token||typeof window<"u"&&window.localStorage?.getItem("copilotChatToken")||null;if(!d)return console.error("[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."),null;const g=h.baseUrl||u.baseUrl||k,c=`${g.replace(/\/$/,"")}/api/chat-widget/config?token=${encodeURIComponent(d)}`;try{const n=await fetch(c,{credentials:"omit",mode:"cors"});if(!n.ok)throw new Error(`Server responded with ${n.status}`);const t=await n.json();if(!t?.iframeUrl||!t?.launcherIcon)throw new Error("Received incomplete widget configuration from server.");return window.CopilotChat=window.CopilotChat||{},window.CopilotChat.token=d,window.CopilotChat.baseUrl=g,E({iframeUrl:t.iframeUrl,launcherIcon:t.launcherIcon})}catch(n){return console.error("[CopilotChat] Error during widget bootstrap:",n instanceof Error?n.message:n),null}}exports.default=y;exports.loadCopilotChatWidget=y;
package/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
- const U = "http://localhost:3000";
2
- const N = ({ iframeUrl: b, launcherIcon: x }) => {
3
- const u = document.querySelector("[data-copilot-widget-root]");
4
- u && u.remove();
5
- const y = (t) => {
6
- const e = document.querySelector("[data-copilot-checkout-toast]");
7
- e && e.remove();
8
- const n = document.createElement("div");
9
- n.setAttribute("data-copilot-checkout-toast", "true"), n.innerText = t, Object.assign(n.style, {
1
+ const C = "http://localhost:3000";
2
+ const y = ({ iframeUrl: h, launcherIcon: u }) => {
3
+ const d = document.querySelector("[data-copilot-widget-root]");
4
+ d && d.remove();
5
+ const g = (s) => {
6
+ const o = document.querySelector("[data-copilot-checkout-toast]");
7
+ o && o.remove();
8
+ const r = document.createElement("div");
9
+ r.setAttribute("data-copilot-checkout-toast", "true"), r.innerText = s, Object.assign(r.style, {
10
10
  position: "fixed",
11
11
  top: "20px",
12
12
  left: "50%",
@@ -22,21 +22,21 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
22
22
  maxWidth: "420px",
23
23
  lineHeight: "1.4",
24
24
  textAlign: "center"
25
- }), document.body.appendChild(n), setTimeout(() => {
26
- n.remove();
25
+ }), document.body.appendChild(r), setTimeout(() => {
26
+ r.remove();
27
27
  }, 4500);
28
- }, w = document.createElement("div");
29
- w.setAttribute("data-copilot-widget-root", "true");
30
- const a = w.attachShadow({ mode: "open" });
31
- document.body.appendChild(w);
32
- const o = document.createElement("button");
33
- o.type = "button", o.setAttribute("aria-label", "Open Copilot chat"), o.innerHTML = `
28
+ }, c = document.createElement("div");
29
+ c.setAttribute("data-copilot-widget-root", "true");
30
+ const n = c.attachShadow({ mode: "open" });
31
+ document.body.appendChild(c);
32
+ const t = document.createElement("button");
33
+ t.type = "button", t.setAttribute("aria-label", "Open Copilot chat"), t.innerHTML = `
34
34
  <img
35
- src="${x}"
35
+ src="${u}"
36
36
  alt="Copilot chat launcher"
37
37
  style="width: 38px; height: 38px; object-fit: contain; border-radius: 50%; pointer-events: none;"
38
38
  />
39
- `, Object.assign(o.style, {
39
+ `, Object.assign(t.style, {
40
40
  position: "fixed",
41
41
  bottom: "24px",
42
42
  right: "24px",
@@ -53,13 +53,13 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
53
53
  justifyContent: "center",
54
54
  boxShadow: "0 6px 14px rgba(0,0,0,0.25)",
55
55
  transition: "all 0.25s ease"
56
- }), o.onmouseover = () => {
57
- o.style.transform = "scale(1.12)", o.style.boxShadow = "0 10px 25px rgba(0,0,0,0.3)";
58
- }, o.onmouseout = () => {
59
- o.style.transform = "scale(1)", o.style.boxShadow = "0 6px 14px rgba(0,0,0,0.25)";
56
+ }), t.onmouseover = () => {
57
+ t.style.transform = "scale(1.12)", t.style.boxShadow = "0 10px 25px rgba(0,0,0,0.3)";
58
+ }, t.onmouseout = () => {
59
+ t.style.transform = "scale(1)", t.style.boxShadow = "0 6px 14px rgba(0,0,0,0.25)";
60
60
  };
61
- const i = document.createElement("div");
62
- i.setAttribute("data-copilot-widget-root", "true"), Object.assign(i.style, {
61
+ const e = document.createElement("div");
62
+ e.setAttribute("data-copilot-widget-root", "true"), Object.assign(e.style, {
63
63
  display: "none",
64
64
  position: "fixed",
65
65
  bottom: "100px",
@@ -70,8 +70,8 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
70
70
  opacity: "0",
71
71
  transition: "all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"
72
72
  });
73
- const m = document.createElement("div"), E = document.createElement("div"), k = document.createElement("div");
74
- Object.assign(m.style, {
73
+ const l = document.createElement("div"), b = document.createElement("div"), f = document.createElement("div");
74
+ Object.assign(l.style, {
75
75
  position: "absolute",
76
76
  bottom: "-14px",
77
77
  right: "28px",
@@ -80,7 +80,7 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
80
80
  pointerEvents: "none",
81
81
  display: "none",
82
82
  zIndex: "1"
83
- }), Object.assign(E.style, {
83
+ }), Object.assign(b.style, {
84
84
  position: "absolute",
85
85
  bottom: "0",
86
86
  left: "0",
@@ -91,7 +91,7 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
91
91
  borderLeft: "15px solid transparent",
92
92
  borderRight: "15px solid transparent",
93
93
  borderTop: "15px solid rgba(15,23,42,0.1)"
94
- }), Object.assign(k.style, {
94
+ }), Object.assign(f.style, {
95
95
  position: "absolute",
96
96
  bottom: "2px",
97
97
  left: "0",
@@ -104,9 +104,9 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
104
104
  borderTop: "13px solid white",
105
105
  boxShadow: "0 6px 16px rgba(15,23,42,0.12)",
106
106
  borderRadius: "2px"
107
- }), m.appendChild(E), m.appendChild(k);
108
- const f = document.createElement("div");
109
- Object.assign(f.style, {
107
+ }), l.appendChild(b), l.appendChild(f);
108
+ const p = document.createElement("div");
109
+ Object.assign(p.style, {
110
110
  width: "720px",
111
111
  maxWidth: "calc(100vw - 48px)",
112
112
  height: `${Math.min(720, Math.max(320, window.innerHeight - 140))}px`,
@@ -116,175 +116,84 @@ const N = ({ iframeUrl: b, launcherIcon: x }) => {
116
116
  border: "1px solid rgba(15,23,42,0.12)",
117
117
  boxShadow: "0 18px 45px rgba(15,23,42,0.16)",
118
118
  overflow: "hidden"
119
- }), a.appendChild(f);
120
- const r = document.createElement("iframe");
121
- r.src = b, r.title = "Copilot chat widget", r.allow = "clipboard-read; clipboard-write; microphone; camera; display-capture", r.setAttribute("scrolling", "no"), Object.assign(r.style, {
119
+ }), n.appendChild(p);
120
+ const i = document.createElement("iframe");
121
+ i.src = h, i.title = "Copilot chat widget", i.allow = "clipboard-read; clipboard-write; microphone; camera; display-capture", i.setAttribute("scrolling", "no"), Object.assign(i.style, {
122
122
  width: "100%",
123
123
  height: "100%",
124
124
  border: "none",
125
125
  display: "block",
126
126
  background: "transparent",
127
127
  overflow: "hidden"
128
- }), a.appendChild(f), f.appendChild(r), i.appendChild(m), i.appendChild(f), document.body.appendChild(o), document.body.appendChild(i);
129
- let d = !1;
130
- const _ = () => {
131
- d && (d = !1, i.style.opacity = "0", i.style.transform = "scale(0.8) translateY(20px)", m.style.display = "none", setTimeout(() => {
132
- i.style.display = "none";
133
- }, 250), o.style.transform = "scale(1)");
134
- }, T = (t, e = null) => {
135
- if (!t) return e;
136
- try {
137
- return JSON.parse(t);
138
- } catch {
139
- return e;
140
- }
141
- }, v = (t) => String(t).toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, ""), s = (t, e) => ({
142
- value: t,
143
- currency: e,
144
- __typename: "Money"
145
- }), O = (t, e) => ({
146
- maximum_price: {
147
- discount: { amount_off: 0, percent_off: 0, __typename: "ProductDiscount" },
148
- final_price: s(t, e),
149
- fixed_product_taxes: [],
150
- regular_price: s(t, e),
151
- __typename: "ProductPrice"
152
- },
153
- minimum_price: {
154
- discount: { amount_off: 0, percent_off: 0, __typename: "ProductDiscount" },
155
- final_price: s(t, e),
156
- fixed_product_taxes: [],
157
- regular_price: s(t, e),
158
- __typename: "ProductPrice"
159
- },
160
- __typename: "PriceRange"
161
- }), P = (t, e) => {
162
- const n = Number(t?.quantity || 0), g = Number(t?.price || t?.unitPrice || 0), c = g * n, p = t?.name || "Chat widget product", I = t?.image || t?.thumbnail || "", h = Number(t?.productId || t?.id || 0), l = String(t?.sku || t?.id || h || "chat-widget");
163
- return {
164
- id: String(t?.id || l || h || Date.now()),
165
- quantity: n,
166
- product: {
167
- id: h || Date.now(),
168
- sku: l,
169
- name: p,
170
- url_key: t?.url_key || v(p),
171
- url_suffix: ".html",
172
- stock_status: "IN_STOCK",
173
- brand: null,
174
- has_gift: null,
175
- price_range: O(g, e),
176
- thumbnail: {
177
- disabled: null,
178
- label: p,
179
- position: null,
180
- url: I,
181
- __typename: "ProductImage"
182
- },
183
- small_image: {
184
- disabled: null,
185
- label: p,
186
- position: null,
187
- url: I,
188
- __typename: "ProductImage"
189
- },
190
- categories: [],
191
- special_from_date: null,
192
- special_price: null,
193
- special_to_date: null,
194
- __typename: "SimpleProduct"
195
- },
196
- prices: {
197
- discounts: null,
198
- price: s(g, e),
199
- row_total: s(c, e),
200
- row_total_including_tax: s(c, e),
201
- total_item_discount: s(0, e),
202
- __typename: "CartItemPrices"
203
- },
204
- __typename: "SimpleCartItem",
205
- itemTotal: c
206
- };
207
- }, A = (t) => {
208
- const e = T(window.localStorage.getItem("web-cart")), n = Array.isArray(t?.cart) ? t.cart : [], g = t?.currency || "VND", c = n.map((l) => P(l, g)), p = c.reduce((l, S) => l + (S.quantity || 0), 0), I = Number(t?.totalPrice || 0) || c.reduce((l, S) => l + (S.itemTotal || 0), 0), h = {
209
- totalItems: p,
210
- total: s(I, g),
211
- id: e?.id || `chat-widget-${Date.now()}`,
212
- is_virtual: !1,
213
- shipping_addresses: Array.isArray(e?.shipping_addresses) ? e.shipping_addresses : [],
214
- total_quantity: p,
215
- items: c,
216
- isCartIdLoading: !1,
217
- isFetchingCart: !1
218
- };
219
- window.localStorage.setItem("web-cart", JSON.stringify(h)), window.dispatchEvent(
220
- new StorageEvent("storage", {
221
- key: "web-cart",
222
- newValue: JSON.stringify(h)
223
- })
224
- );
225
- }, R = (t) => {
226
- const { data: e, source: n } = t || {};
227
- if (e?.type) {
228
- if (e.type === "CART_CHECKOUT" && n === r.contentWindow) {
229
- console.log("[CopilotChat] Received checkout payload from widget:", e), A(e?.data), y("Cart updated on KidsPlaza demo. Open cart to see changes.");
128
+ }), n.appendChild(p), p.appendChild(i), e.appendChild(l), e.appendChild(p), document.body.appendChild(t), document.body.appendChild(e);
129
+ let a = !1;
130
+ const m = () => {
131
+ a && (a = !1, e.style.opacity = "0", e.style.transform = "scale(0.8) translateY(20px)", l.style.display = "none", setTimeout(() => {
132
+ e.style.display = "none";
133
+ }, 250), t.style.transform = "scale(1)");
134
+ }, x = (s) => {
135
+ const { data: o, source: r } = s || {};
136
+ if (o?.type) {
137
+ if (o.type === "CART_CHECKOUT" && r === i.contentWindow) {
138
+ console.log("[CopilotChat] Received checkout payload from widget:", o), g("Checkout message received from chat widget. Check console for payload.");
230
139
  return;
231
140
  }
232
- if (e.type === "WIDGET_READY" && n === r.contentWindow) {
233
- r.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
141
+ if (o.type === "WIDGET_READY" && r === i.contentWindow) {
142
+ i.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");
234
143
  return;
235
144
  }
236
- e.type === "CHAT_CLOSED" && _();
145
+ o.type === "CHAT_CLOSED" && m();
237
146
  }
238
147
  };
239
- window.addEventListener("message", R), o.onclick = (t) => {
240
- t.stopPropagation(), d = !d, d ? (i.style.display = "block", m.style.display = "block", requestAnimationFrame(() => {
241
- i.style.opacity = "1", i.style.transform = "scale(1) translateY(0)";
242
- })) : _();
243
- }, document.addEventListener("click", (t) => {
244
- const e = t.target;
245
- e && d && !i.contains(e) && e !== o && _();
148
+ window.addEventListener("message", x), t.onclick = (s) => {
149
+ s.stopPropagation(), a = !a, a ? (e.style.display = "block", l.style.display = "block", requestAnimationFrame(() => {
150
+ e.style.opacity = "1", e.style.transform = "scale(1) translateY(0)";
151
+ })) : m();
152
+ }, document.addEventListener("click", (s) => {
153
+ const o = s.target;
154
+ o && a && !e.contains(o) && o !== t && m();
246
155
  });
247
- const C = {
248
- close: _,
156
+ const w = {
157
+ close: m,
249
158
  open: () => {
250
- d || o.click();
159
+ a || t.click();
251
160
  }
252
161
  };
253
- return window.CopilotChat = window.CopilotChat || {}, window.CopilotChat.close = C.close, window.CopilotChat.open = C.open, window.CopilotChat.controls = C, C;
162
+ return window.CopilotChat = window.CopilotChat || {}, window.CopilotChat.close = w.close, window.CopilotChat.open = w.open, window.CopilotChat.controls = w, w;
254
163
  };
255
- async function W(b = {}) {
164
+ async function E(h = {}) {
256
165
  if (typeof window > "u" || typeof document > "u")
257
166
  return null;
258
- const x = window.CopilotChatConfig || {}, u = b.token || x.token || typeof window < "u" && window.localStorage?.getItem("copilotChatToken") || null;
259
- if (!u)
167
+ const u = window.CopilotChatConfig || {}, d = h.token || u.token || typeof window < "u" && window.localStorage?.getItem("copilotChatToken") || null;
168
+ if (!d)
260
169
  return console.error(
261
170
  "[CopilotChat] Missing token (provide via loadCopilotChatWidget({ token }) or window.CopilotChatConfig.token)."
262
171
  ), null;
263
- const y = b.baseUrl || x.baseUrl || U, w = `${y.replace(/\/$/, "")}/api/chat-widget/config?token=${encodeURIComponent(
264
- u
172
+ const g = h.baseUrl || u.baseUrl || C, c = `${g.replace(/\/$/, "")}/api/chat-widget/config?token=${encodeURIComponent(
173
+ d
265
174
  )}`;
266
175
  try {
267
- const a = await fetch(w, {
176
+ const n = await fetch(c, {
268
177
  credentials: "omit",
269
178
  mode: "cors"
270
179
  });
271
- if (!a.ok)
272
- throw new Error(`Server responded with ${a.status}`);
273
- const o = await a.json();
274
- if (!o?.iframeUrl || !o?.launcherIcon)
180
+ if (!n.ok)
181
+ throw new Error(`Server responded with ${n.status}`);
182
+ const t = await n.json();
183
+ if (!t?.iframeUrl || !t?.launcherIcon)
275
184
  throw new Error("Received incomplete widget configuration from server.");
276
- return window.CopilotChat = window.CopilotChat || {}, window.CopilotChat.token = u, window.CopilotChat.baseUrl = y, N({
277
- iframeUrl: o.iframeUrl,
278
- launcherIcon: o.launcherIcon
185
+ return window.CopilotChat = window.CopilotChat || {}, window.CopilotChat.token = d, window.CopilotChat.baseUrl = g, y({
186
+ iframeUrl: t.iframeUrl,
187
+ launcherIcon: t.launcherIcon
279
188
  });
280
- } catch (a) {
189
+ } catch (n) {
281
190
  return console.error(
282
191
  "[CopilotChat] Error during widget bootstrap:",
283
- a instanceof Error ? a.message : a
192
+ n instanceof Error ? n.message : n
284
193
  ), null;
285
194
  }
286
195
  }
287
196
  export {
288
- W as default,
289
- W as loadCopilotChatWidget
197
+ E as default,
198
+ E as loadCopilotChatWidget
290
199
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "copilot-chat-widget",
3
- "version": "0.1.33",
3
+ "version": "0.1.37",
4
4
  "description": "Embeddable Copilot chat widget that can be loaded via NPM or a script tag.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
package/src/index.js CHANGED
@@ -191,7 +191,7 @@ const buildWidget = ({ iframeUrl, launcherIcon }) => {
191
191
 
192
192
  let isOpen = false;
193
193
 
194
- const closeChat = () => {
194
+ const closeChat = () => {
195
195
  if (!isOpen) return;
196
196
  isOpen = false;
197
197
  container.style.opacity = "0";
@@ -201,146 +201,17 @@ const buildWidget = ({ iframeUrl, launcherIcon }) => {
201
201
  container.style.display = "none";
202
202
  }, 250);
203
203
  btn.style.transform = "scale(1)";
204
- };
205
-
206
- const parseJSON = (value, fallback = null) => {
207
- if (!value) return fallback;
208
- try {
209
- return JSON.parse(value);
210
- } catch (error) {
211
- return fallback;
212
- }
213
- };
214
-
215
- const slugify = (value) =>
216
- String(value || "")
217
- .toLowerCase()
218
- .trim()
219
- .replace(/[^a-z0-9]+/g, "-")
220
- .replace(/^-+|-+$/g, "");
221
-
222
- const createMoney = (value, currency) => ({
223
- value,
224
- currency,
225
- __typename: "Money",
226
- });
227
-
228
- const createPriceRange = (value, currency) => ({
229
- maximum_price: {
230
- discount: { amount_off: 0, percent_off: 0, __typename: "ProductDiscount" },
231
- final_price: createMoney(value, currency),
232
- fixed_product_taxes: [],
233
- regular_price: createMoney(value, currency),
234
- __typename: "ProductPrice",
235
- },
236
- minimum_price: {
237
- discount: { amount_off: 0, percent_off: 0, __typename: "ProductDiscount" },
238
- final_price: createMoney(value, currency),
239
- fixed_product_taxes: [],
240
- regular_price: createMoney(value, currency),
241
- __typename: "ProductPrice",
242
- },
243
- __typename: "PriceRange",
244
- });
245
-
246
- const mapToKidsPlazaItem = (item, currency) => {
247
- const quantity = Number(item?.quantity || 0);
248
- const unitPrice = Number(item?.price || item?.unitPrice || 0);
249
- const rowTotalValue = unitPrice * quantity;
250
- const name = item?.name || "Chat widget product";
251
- const imageUrl = item?.image || item?.thumbnail || "";
252
- const productId = Number(item?.productId || item?.id || 0);
253
- const productSku = String(item?.sku || item?.id || productId || "chat-widget");
254
-
255
- return {
256
- id: String(item?.id || productSku || productId || Date.now()),
257
- quantity,
258
- product: {
259
- id: productId || Date.now(),
260
- sku: productSku,
261
- name,
262
- url_key: item?.url_key || slugify(name),
263
- url_suffix: ".html",
264
- stock_status: "IN_STOCK",
265
- brand: null,
266
- has_gift: null,
267
- price_range: createPriceRange(unitPrice, currency),
268
- thumbnail: {
269
- disabled: null,
270
- label: name,
271
- position: null,
272
- url: imageUrl,
273
- __typename: "ProductImage",
274
- },
275
- small_image: {
276
- disabled: null,
277
- label: name,
278
- position: null,
279
- url: imageUrl,
280
- __typename: "ProductImage",
281
- },
282
- categories: [],
283
- special_from_date: null,
284
- special_price: null,
285
- special_to_date: null,
286
- __typename: "SimpleProduct",
287
- },
288
- prices: {
289
- discounts: null,
290
- price: createMoney(unitPrice, currency),
291
- row_total: createMoney(rowTotalValue, currency),
292
- row_total_including_tax: createMoney(rowTotalValue, currency),
293
- total_item_discount: createMoney(0, currency),
294
- __typename: "CartItemPrices",
295
- },
296
- __typename: "SimpleCartItem",
297
- itemTotal: rowTotalValue,
298
- };
299
- };
300
-
301
- const updateKidsPlazaCart = (payload) => {
302
- const existingCart = parseJSON(window.localStorage.getItem("web-cart"));
303
- const items = Array.isArray(payload?.cart) ? payload.cart : [];
304
- const currency = payload?.currency || "VND";
305
- const mappedItems = items.map((item) => mapToKidsPlazaItem(item, currency));
306
- const totalItems = mappedItems.reduce((sum, item) => sum + (item.quantity || 0), 0);
307
- const totalValue =
308
- Number(payload?.totalPrice || 0) ||
309
- mappedItems.reduce((sum, item) => sum + (item.itemTotal || 0), 0);
310
-
311
- const cart = {
312
- totalItems,
313
- total: createMoney(totalValue, currency),
314
- id: existingCart?.id || `chat-widget-${Date.now()}`,
315
- is_virtual: false,
316
- shipping_addresses: Array.isArray(existingCart?.shipping_addresses)
317
- ? existingCart.shipping_addresses
318
- : [],
319
- total_quantity: totalItems,
320
- items: mappedItems,
321
- isCartIdLoading: false,
322
- isFetchingCart: false,
323
- };
324
-
325
- window.localStorage.setItem("web-cart", JSON.stringify(cart));
326
- window.dispatchEvent(
327
- new StorageEvent("storage", {
328
- key: "web-cart",
329
- newValue: JSON.stringify(cart),
330
- })
331
- );
332
- };
333
-
334
- const handleWidgetMessage = (event) => {
335
- const { data, source } = event || {};
336
- if (!data?.type) return;
337
-
338
- if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
339
- console.log("[CopilotChat] Received checkout payload from widget:", data);
340
- updateKidsPlazaCart(data?.data);
341
- showCheckoutToast("Cart updated on KidsPlaza demo. Open cart to see changes.");
342
- return;
343
- }
204
+ };
205
+
206
+ const handleWidgetMessage = (event) => {
207
+ const { data, source } = event || {};
208
+ if (!data?.type) return;
209
+
210
+ if (data.type === "CART_CHECKOUT" && source === iframe.contentWindow) {
211
+ console.log("[CopilotChat] Received checkout payload from widget:", data);
212
+ showCheckoutToast("Checkout message received from chat widget. Check console for payload.");
213
+ return;
214
+ }
344
215
 
345
216
  if (data.type === "WIDGET_READY" && source === iframe.contentWindow) {
346
217
  iframe.contentWindow.postMessage({ type: "INIT_WIDGET" }, "*");