@getwidgets/live-chat-widget 1.1.2 → 1.1.3

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,7 @@
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);
19755
19756
  const [config, setConfig] = reactExports.useState(null);
19756
19757
  const [messages, setMessages] = reactExports.useState([]);
19757
19758
  const [inputMessage, setInputMessage] = reactExports.useState("");
@@ -20235,13 +20236,10 @@
20235
20236
  if (isMobile2) {
20236
20237
  return {
20237
20238
  width: "95vw",
20238
- height: "85vh",
20239
- // Changed from 60vh to 85vh for better mobile experience
20239
+ height: "85dvh",
20240
20240
  maxWidth: "95vw",
20241
- maxHeight: "95vh",
20242
- bottom: "0",
20243
- right: "0",
20244
- borderRadius: "12px 12px 0 0"
20241
+ maxHeight: "calc(100dvh - 24px)",
20242
+ borderRadius: appearanceConfig.border_radius || "12px"
20245
20243
  };
20246
20244
  }
20247
20245
  return {
@@ -20255,19 +20253,16 @@
20255
20253
  const position2 = appearanceConfig.position || "bottom-right";
20256
20254
  const isMobile2 = windowWidth < 768;
20257
20255
  const baseStyles = { position: "fixed", zIndex: 9999 };
20258
- if (isMobile2) {
20259
- return { ...baseStyles, left: 0, right: 0, bottom: 0 };
20260
- }
20261
- const desktopSpacing = "20px";
20256
+ const edgeSpacing = isMobile2 ? "12px" : "20px";
20262
20257
  switch (position2) {
20263
20258
  case "bottom-left":
20264
- return { ...baseStyles, left: desktopSpacing, bottom: desktopSpacing };
20259
+ return { ...baseStyles, left: edgeSpacing, bottom: edgeSpacing };
20265
20260
  case "top-left":
20266
- return { ...baseStyles, left: desktopSpacing, top: desktopSpacing };
20261
+ return { ...baseStyles, left: edgeSpacing, top: edgeSpacing };
20267
20262
  case "top-right":
20268
- return { ...baseStyles, right: desktopSpacing, top: desktopSpacing };
20263
+ return { ...baseStyles, right: edgeSpacing, top: edgeSpacing };
20269
20264
  default:
20270
- return { ...baseStyles, right: desktopSpacing, bottom: desktopSpacing };
20265
+ return { ...baseStyles, right: edgeSpacing, bottom: edgeSpacing };
20271
20266
  }
20272
20267
  };
20273
20268
  const responsiveDimensions = getResponsiveDimensions();
@@ -20313,7 +20308,12 @@
20313
20308
  setShowContactFields(false);
20314
20309
  }
20315
20310
  }, [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());
20311
+ const isValidEmail = (value) => {
20312
+ if (!value) return false;
20313
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value).trim());
20314
+ };
20315
+ const emailIsInvalid = showContactFields && contactEmail.trim() && !isValidEmail(contactEmail);
20316
+ const isContactValid = !(inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) || (!showContactFields ? true : contactName.trim() && contactEmail.trim() && isValidEmail(contactEmail));
20317
20317
  const createAndStoreAuthToken = () => {
20318
20318
  const payload = { name: contactName.trim(), email: contactEmail.trim(), unique_id };
20319
20319
  const token = buildUnsignedJwt(payload);
@@ -20328,7 +20328,8 @@
20328
20328
  if ((inputAreaConfig == null ? void 0 : inputAreaConfig.allow_chat_with_email) && !authToken) {
20329
20329
  const missingName = !contactName.trim();
20330
20330
  const missingEmail = !contactEmail.trim();
20331
- if (missingName || missingEmail) {
20331
+ const invalidEmail = !missingEmail && !isValidEmail(contactEmail);
20332
+ if (missingName || missingEmail || invalidEmail) {
20332
20333
  setShowContactErrors(true);
20333
20334
  return;
20334
20335
  }
@@ -20337,7 +20338,45 @@
20337
20338
  }
20338
20339
  await performSend();
20339
20340
  };
20341
+ reactExports.useEffect(() => {
20342
+ if (!showMenu) return;
20343
+ const handler = (e) => {
20344
+ if (!e.target.closest(".livechat-menu-trigger") && !e.target.closest(".livechat-menu-popup")) {
20345
+ setShowMenu(false);
20346
+ }
20347
+ };
20348
+ document.addEventListener("mousedown", handler);
20349
+ return () => document.removeEventListener("mousedown", handler);
20350
+ }, [showMenu]);
20340
20351
  if (!config) return null;
20352
+ const handleStartNewChat = () => {
20353
+ try {
20354
+ const newSessionId = v4();
20355
+ if (wsRef.current) {
20356
+ try {
20357
+ wsRef.current.close();
20358
+ } catch (e) {
20359
+ }
20360
+ wsRef.current = null;
20361
+ }
20362
+ localStorage.setItem("live-chat-widget/session-id", newSessionId);
20363
+ setSessionId(newSessionId);
20364
+ setHasCheckedSession(false);
20365
+ setIsConnecting(false);
20366
+ setLocalLoading(false);
20367
+ setAuthToken(null);
20368
+ setMessages([]);
20369
+ setLocalMessages([]);
20370
+ setInputMessage("");
20371
+ setIsSessionInitialized(false);
20372
+ setShowMenu(false);
20373
+ } catch (e) {
20374
+ }
20375
+ };
20376
+ const handleEndChat = () => {
20377
+ handleStartNewChat();
20378
+ };
20379
+ 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
20380
  return /* @__PURE__ */ React.createElement("div", { style: getPositionStyles() }, !isOpen && showNotificationPreview && /* @__PURE__ */ React.createElement(
20342
20381
  "div",
20343
20382
  {
@@ -20492,6 +20531,69 @@
20492
20531
  minHeight: "auto"
20493
20532
  }
20494
20533
  },
20534
+ /* @__PURE__ */ React.createElement(
20535
+ "button",
20536
+ {
20537
+ className: "livechat-menu-trigger absolute left-3 top-1/2 transform -translate-y-1/2 hover:opacity-80 transition-opacity",
20538
+ style: {
20539
+ background: "none",
20540
+ border: "none",
20541
+ cursor: "pointer",
20542
+ width: isMobile ? "40px" : "36px",
20543
+ height: isMobile ? "40px" : "36px",
20544
+ display: "flex",
20545
+ alignItems: "center",
20546
+ justifyContent: "center",
20547
+ padding: 0,
20548
+ zIndex: 20
20549
+ },
20550
+ onClick: (e) => {
20551
+ e.stopPropagation();
20552
+ setShowMenu((v2) => !v2);
20553
+ },
20554
+ "aria-label": "Open menu"
20555
+ },
20556
+ /* @__PURE__ */ React.createElement(MenuDotsIcon, { color: getContrastColor(headerConfig.background_color || "#111827"), size: isMobile ? 22 : 22 })
20557
+ ),
20558
+ showMenu && /* @__PURE__ */ React.createElement(
20559
+ "div",
20560
+ {
20561
+ className: "livechat-menu-popup absolute left-3 top-12 bg-white rounded shadow-lg border",
20562
+ style: {
20563
+ minWidth: isMobile ? "132px" : "120px",
20564
+ top: isMobile ? "calc(50% + 18px)" : "calc(50% + 16px)",
20565
+ left: isMobile ? "8px" : "12px",
20566
+ zIndex: 30,
20567
+ boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
20568
+ border: "1px solid #e5e7eb",
20569
+ padding: "6px 0",
20570
+ color: "#111827",
20571
+ fontSize: isMobile ? "16px" : "15px",
20572
+ fontWeight: 500
20573
+ }
20574
+ },
20575
+ /* @__PURE__ */ React.createElement(
20576
+ "button",
20577
+ {
20578
+ className: "transition-all duration-200 hover:bg-red-50",
20579
+ style: {
20580
+ background: "none",
20581
+ border: "none",
20582
+ width: "100%",
20583
+ cursor: "pointer",
20584
+ // padding: isMobile ? '8px 12px' : '6px 12px',
20585
+ minHeight: "auto",
20586
+ fontSize: isMobile ? "14px" : "13px",
20587
+ color: "#DC2626",
20588
+ fontWeight: "500",
20589
+ borderRadius: "6px"
20590
+ // margin: '4px 0'
20591
+ },
20592
+ onClick: handleEndChat
20593
+ },
20594
+ "End Chat"
20595
+ )
20596
+ ),
20495
20597
  /* @__PURE__ */ React.createElement(
20496
20598
  "button",
20497
20599
  {
@@ -20666,7 +20768,7 @@
20666
20768
  })()
20667
20769
  )),
20668
20770
  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",
20771
+ borderColor: showContactErrors && (!contactName.trim() || !contactEmail.trim() || !isValidEmail(contactEmail)) || emailIsInvalid ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20670
20772
  backgroundColor: inputAreaConfig.background_color || "#FFF"
20671
20773
  } }, /* @__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
20774
  "input",
@@ -20698,13 +20800,13 @@
20698
20800
  },
20699
20801
  className: "w-full px-3 py-1.5 border rounded-md",
20700
20802
  style: {
20701
- borderColor: showContactErrors && !contactEmail.trim() ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20803
+ borderColor: showContactErrors && !contactEmail.trim() || emailIsInvalid ? "#EF4444" : inputAreaConfig.border_color || "#D1D5DB",
20702
20804
  color: inputAreaConfig.text_color || "#111827",
20703
20805
  fontSize: "13px",
20704
20806
  backgroundColor: inputAreaConfig.background_color || "#FFF"
20705
20807
  }
20706
20808
  }
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." : ""}`)))
20809
+ ), 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
20810
  ),
20709
20811
  inputAreaConfig.show_branding !== false && /* @__PURE__ */ React.createElement(
20710
20812
  "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.3",
4
4
  "main": "dist/live-chat-widget.umd.js",
5
5
  "unpkg": "dist/live-chat-widget.umd.js",
6
6
  "type": "module",