@getwidgets/live-chat-widget 1.1.2 → 1.1.4

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.
@@ -19752,6 +19752,8 @@
19752
19752
  };
19753
19753
  const LiveChatWidget = ({ widgetId, name: name2 = null, email = null, unique_id = null }) => {
19754
19754
  var _a, _b;
19755
+ const [showMenu, setShowMenu] = reactExports.useState(false);
19756
+ const endChatButtonRef = reactExports.useRef(null);
19755
19757
  const [config, setConfig] = reactExports.useState(null);
19756
19758
  const [messages, setMessages] = reactExports.useState([]);
19757
19759
  const [inputMessage, setInputMessage] = reactExports.useState("");
@@ -20235,13 +20237,10 @@
20235
20237
  if (isMobile2) {
20236
20238
  return {
20237
20239
  width: "95vw",
20238
- height: "85vh",
20239
- // Changed from 60vh to 85vh for better mobile experience
20240
+ height: "85dvh",
20240
20241
  maxWidth: "95vw",
20241
- maxHeight: "95vh",
20242
- bottom: "0",
20243
- right: "0",
20244
- borderRadius: "12px 12px 0 0"
20242
+ maxHeight: "calc(100dvh - 24px)",
20243
+ borderRadius: appearanceConfig.border_radius || "12px"
20245
20244
  };
20246
20245
  }
20247
20246
  return {
@@ -20255,19 +20254,16 @@
20255
20254
  const position2 = appearanceConfig.position || "bottom-right";
20256
20255
  const isMobile2 = windowWidth < 768;
20257
20256
  const baseStyles = { position: "fixed", zIndex: 9999 };
20258
- if (isMobile2) {
20259
- return { ...baseStyles, left: 0, right: 0, bottom: 0 };
20260
- }
20261
- const desktopSpacing = "20px";
20257
+ const edgeSpacing = isMobile2 ? "12px" : "20px";
20262
20258
  switch (position2) {
20263
20259
  case "bottom-left":
20264
- return { ...baseStyles, left: desktopSpacing, bottom: desktopSpacing };
20260
+ return { ...baseStyles, left: edgeSpacing, bottom: edgeSpacing };
20265
20261
  case "top-left":
20266
- return { ...baseStyles, left: desktopSpacing, top: desktopSpacing };
20262
+ return { ...baseStyles, left: edgeSpacing, top: edgeSpacing };
20267
20263
  case "top-right":
20268
- return { ...baseStyles, right: desktopSpacing, top: desktopSpacing };
20264
+ return { ...baseStyles, right: edgeSpacing, top: edgeSpacing };
20269
20265
  default:
20270
- return { ...baseStyles, right: desktopSpacing, bottom: desktopSpacing };
20266
+ return { ...baseStyles, right: edgeSpacing, bottom: edgeSpacing };
20271
20267
  }
20272
20268
  };
20273
20269
  const responsiveDimensions = getResponsiveDimensions();
@@ -20313,7 +20309,12 @@
20313
20309
  setShowContactFields(false);
20314
20310
  }
20315
20311
  }, [inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email, authToken, isOpen]);
20316
- const isContactValid = !(inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) || (!showContactFields ? true : contactName.trim() && contactEmail.trim());
20312
+ const isValidEmail = (value) => {
20313
+ if (!value) return false;
20314
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value).trim());
20315
+ };
20316
+ const emailIsInvalid = showContactFields && contactEmail.trim() && !isValidEmail(contactEmail);
20317
+ const isContactValid = !(inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) || (!showContactFields ? true : contactName.trim() && contactEmail.trim() && isValidEmail(contactEmail));
20317
20318
  const createAndStoreAuthToken = () => {
20318
20319
  const payload = { name: contactName.trim(), email: contactEmail.trim(), unique_id };
20319
20320
  const token = buildUnsignedJwt(payload);
@@ -20328,7 +20329,8 @@
20328
20329
  if ((inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) && !authToken) {
20329
20330
  const missingName = !contactName.trim();
20330
20331
  const missingEmail = !contactEmail.trim();
20331
- if (missingName || missingEmail) {
20332
+ const invalidEmail = !missingEmail && !isValidEmail(contactEmail);
20333
+ if (missingName || missingEmail || invalidEmail) {
20332
20334
  setShowContactErrors(true);
20333
20335
  return;
20334
20336
  }
@@ -20337,7 +20339,72 @@
20337
20339
  }
20338
20340
  await performSend();
20339
20341
  };
20342
+ reactExports.useEffect(() => {
20343
+ if (!showMenu) return;
20344
+ const handleClickOutside = (e) => {
20345
+ try {
20346
+ const composedPath = e.composedPath ? e.composedPath() : [e.target];
20347
+ const hasMenuElement = composedPath.some((el2) => {
20348
+ if (!el2.classList) return false;
20349
+ const isMenuTrigger = el2.classList.contains("livechat-menu-trigger");
20350
+ const isMenuPopup = el2.classList.contains("livechat-menu-popup");
20351
+ return isMenuTrigger || isMenuPopup;
20352
+ });
20353
+ if (!hasMenuElement) {
20354
+ setShowMenu(false);
20355
+ }
20356
+ } catch (err) {
20357
+ }
20358
+ };
20359
+ document.addEventListener("click", handleClickOutside, false);
20360
+ return () => {
20361
+ document.removeEventListener("click", handleClickOutside, false);
20362
+ };
20363
+ }, [showMenu]);
20364
+ reactExports.useEffect(() => {
20365
+ const btn = endChatButtonRef.current;
20366
+ if (!btn) return;
20367
+ const handleClick = (e) => {
20368
+ e.preventDefault();
20369
+ e.stopPropagation();
20370
+ handleEndChat();
20371
+ setShowMenu(false);
20372
+ };
20373
+ btn.addEventListener("click", handleClick, true);
20374
+ return () => btn.removeEventListener("click", handleClick, true);
20375
+ }, []);
20340
20376
  if (!config) return null;
20377
+ const handleStartNewChat = () => {
20378
+ try {
20379
+ const newSessionId = v4();
20380
+ if (wsRef.current) {
20381
+ try {
20382
+ wsRef.current.close();
20383
+ } catch (e) {
20384
+ }
20385
+ wsRef.current = null;
20386
+ }
20387
+ localStorage.setItem("live-chat-widget/session-id", newSessionId);
20388
+ setSessionId(newSessionId);
20389
+ setHasCheckedSession(false);
20390
+ setIsConnecting(false);
20391
+ setLocalLoading(false);
20392
+ setAuthToken(null);
20393
+ setMessages([]);
20394
+ setLocalMessages([]);
20395
+ setInputMessage("");
20396
+ setIsSessionInitialized(false);
20397
+ setShowMenu(false);
20398
+ setContactName("");
20399
+ setContactEmail("");
20400
+ setShowContactFields(!!(inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email));
20401
+ } catch (e) {
20402
+ }
20403
+ };
20404
+ const handleEndChat = () => {
20405
+ handleStartNewChat();
20406
+ };
20407
+ const MenuDotsIcon = ({ color: color2 = "#fff", size = 22 }) => /* @__PURE__ */ React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "5", r: "2", fill: color2 }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "2", fill: color2 }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "19", r: "2", fill: color2 }));
20341
20408
  return /* @__PURE__ */ React.createElement("div", { style: getPositionStyles() }, !isOpen && showNotificationPreview && /* @__PURE__ */ React.createElement(
20342
20409
  "div",
20343
20410
  {
@@ -20492,6 +20559,83 @@
20492
20559
  minHeight: "auto"
20493
20560
  }
20494
20561
  },
20562
+ /* @__PURE__ */ React.createElement(
20563
+ "button",
20564
+ {
20565
+ className: "livechat-menu-trigger absolute left-3 top-1/2 transform -translate-y-1/2 hover:opacity-80 transition-opacity",
20566
+ style: {
20567
+ background: "none",
20568
+ border: "none",
20569
+ cursor: "pointer",
20570
+ width: isMobile ? "40px" : "36px",
20571
+ height: isMobile ? "40px" : "36px",
20572
+ display: "flex",
20573
+ alignItems: "center",
20574
+ justifyContent: "center",
20575
+ padding: 0,
20576
+ zIndex: 20
20577
+ },
20578
+ onClick: (e) => {
20579
+ e.stopPropagation();
20580
+ setShowMenu((v2) => !v2);
20581
+ },
20582
+ "aria-label": "Open menu"
20583
+ },
20584
+ /* @__PURE__ */ React.createElement(MenuDotsIcon, { color: getContrastColor(headerConfig.background_color || "#111827"), size: isMobile ? 22 : 22 })
20585
+ ),
20586
+ showMenu && /* @__PURE__ */ React.createElement(
20587
+ "div",
20588
+ {
20589
+ className: "livechat-menu-popup absolute left-3 top-12 bg-white rounded shadow-lg border",
20590
+ style: {
20591
+ minWidth: isMobile ? "132px" : "120px",
20592
+ top: isMobile ? "calc(50% + 18px)" : "calc(50% + 16px)",
20593
+ left: isMobile ? "8px" : "12px",
20594
+ zIndex: 30,
20595
+ boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
20596
+ border: "1px solid #e5e7eb",
20597
+ padding: "6px 0",
20598
+ color: "#111827",
20599
+ fontSize: isMobile ? "16px" : "15px",
20600
+ fontWeight: 500
20601
+ }
20602
+ },
20603
+ /* @__PURE__ */ React.createElement(
20604
+ "button",
20605
+ {
20606
+ ref: endChatButtonRef,
20607
+ className: "transition-all duration-200 hover:bg-red-50",
20608
+ type: "button",
20609
+ tabIndex: "0",
20610
+ style: {
20611
+ background: "none",
20612
+ border: "none",
20613
+ width: "100%",
20614
+ cursor: "pointer",
20615
+ padding: isMobile ? "8px 12px" : "6px 12px",
20616
+ minHeight: "32px",
20617
+ fontSize: isMobile ? "14px" : "13px",
20618
+ color: "#DC2626",
20619
+ fontWeight: "500",
20620
+ borderRadius: "6px",
20621
+ margin: "0",
20622
+ display: "flex",
20623
+ alignItems: "center",
20624
+ justifyContent: "center",
20625
+ userSelect: "none"
20626
+ },
20627
+ onClick: (e) => {
20628
+ var _a2, _b2;
20629
+ e.preventDefault();
20630
+ e.stopPropagation();
20631
+ (_b2 = (_a2 = e.nativeEvent) == null ? void 0 : _a2.stopImmediatePropagation) == null ? void 0 : _b2.call(_a2);
20632
+ handleEndChat();
20633
+ setTimeout(() => setShowMenu(false), 0);
20634
+ }
20635
+ },
20636
+ "End Chat"
20637
+ )
20638
+ ),
20495
20639
  /* @__PURE__ */ React.createElement(
20496
20640
  "button",
20497
20641
  {
@@ -20666,7 +20810,7 @@
20666
20810
  })()
20667
20811
  )),
20668
20812
  showContactFields && /* @__PURE__ */ React.createElement("div", { className: "p-3 border rounded-lg mt-2", style: {
20669
- borderColor: showContactErrors && (!contactName.trim() || !contactEmail.trim()) ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20813
+ borderColor: showContactErrors && (!contactName.trim() || !contactEmail.trim() || !isValidEmail(contactEmail)) || emailIsInvalid ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20670
20814
  backgroundColor: inputAreaConfig.background_color || "#FFF"
20671
20815
  } }, /* @__PURE__ */ React.createElement("div", { className: "text-sm font-semibold mb-2", style: { color: inputAreaConfig.text_color || "#111827" } }, "How should we reach you?"), /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement(
20672
20816
  "input",
@@ -20698,13 +20842,13 @@
20698
20842
  },
20699
20843
  className: "w-full px-3 py-1.5 border rounded-md",
20700
20844
  style: {
20701
- borderColor: showContactErrors && !contactEmail.trim() ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20845
+ borderColor: showContactErrors && !contactEmail.trim() || emailIsInvalid ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20702
20846
  color: inputAreaConfig.text_color || "#111827",
20703
20847
  fontSize: "13px",
20704
20848
  backgroundColor: inputAreaConfig.background_color || "#FFF"
20705
20849
  }
20706
20850
  }
20707
- ), showContactErrors && (!contactName.trim() || !contactEmail.trim()) && /* @__PURE__ */ React.createElement("div", { className: "text-xs", style: { color: "#EF4444" } }, `${!contactName.trim() ? "Name is required. " : ""}${!contactEmail.trim() ? "Email is required." : ""}`)))
20851
+ ), showContactErrors && (!contactName.trim() || !contactEmail.trim() || !isValidEmail(contactEmail)) && /* @__PURE__ */ React.createElement("div", { className: "text-xs", style: { color: "#EF4444" } }, `${!contactName.trim() ? "Name is required. " : ""}${!contactEmail.trim() ? "Email is required. " : ""}${contactEmail.trim() && !isValidEmail(contactEmail) ? "Enter a valid email address." : ""}`)))
20708
20852
  ),
20709
20853
  inputAreaConfig.show_branding !== false && /* @__PURE__ */ React.createElement(
20710
20854
  "div",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getwidgets/live-chat-widget",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "main": "dist/live-chat-widget.umd.js",
5
5
  "unpkg": "dist/live-chat-widget.umd.js",
6
6
  "type": "module",