wealth-alpha-chat-widget 1.0.2 → 1.0.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.
package/dist/index.cjs CHANGED
@@ -699,16 +699,19 @@ var chat_default = {
699
699
  markdown: "chat_markdown",
700
700
  bubbleBot: "chat_bubbleBot",
701
701
  bubbleUser: "chat_bubbleUser",
702
+ bubbleMeta: "chat_bubbleMeta",
702
703
  chipRow: "chat_chipRow",
703
704
  chip: "chat_chip",
704
705
  chipActive: "chat_chipActive",
705
706
  chipDisabled: "chat_chipDisabled",
706
707
  typing: "chat_typing",
707
708
  typingDot: "chat_typingDot",
709
+ wacBlink: "chat_wacBlink",
708
710
  input: "chat_input",
709
711
  inputBox: "chat_inputBox",
710
712
  sendButton: "chat_sendButton",
711
713
  hiddenFileInput: "chat_hiddenFileInput",
714
+ csvButton: "chat_csvButton",
712
715
  authGate: "chat_authGate",
713
716
  authGateIcon: "chat_authGateIcon",
714
717
  authGateTitle: "chat_authGateTitle",
@@ -718,7 +721,21 @@ var chat_default = {
718
721
  authGateDisclaimerTitle: "chat_authGateDisclaimerTitle",
719
722
  errorBanner: "chat_errorBanner",
720
723
  popupBubble: "chat_popupBubble",
721
- popupDismiss: "chat_popupDismiss"
724
+ wacPopIn: "chat_wacPopIn",
725
+ popupDismiss: "chat_popupDismiss",
726
+ menuGrid: "chat_menuGrid",
727
+ menuItem: "chat_menuItem",
728
+ menuItemIcon: "chat_menuItemIcon",
729
+ menuItemTitle: "chat_menuItemTitle",
730
+ menuItemSub: "chat_menuItemSub",
731
+ menuIconGreen: "chat_menuIconGreen",
732
+ menuIconBlue: "chat_menuIconBlue",
733
+ menuIconLeaf: "chat_menuIconLeaf",
734
+ menuIconRed: "chat_menuIconRed",
735
+ menuIconOrange: "chat_menuIconOrange",
736
+ menuIconGold: "chat_menuIconGold",
737
+ menuIconTeal: "chat_menuIconTeal",
738
+ menuIconPurple: "chat_menuIconPurple"
722
739
  };
723
740
  function AuthGate({ brandName, loginUrl, onLoginClick }) {
724
741
  const handleClick = () => {
@@ -790,9 +807,10 @@ var ALLOWED_TAGS = [
790
807
  "ol",
791
808
  "li",
792
809
  "blockquote",
793
- "span"
810
+ "span",
811
+ "div"
794
812
  ];
795
- var ALLOWED_ATTR = ["href", "target", "rel", "class"];
813
+ var ALLOWED_ATTR = ["href", "target", "rel", "class", "style", "data-wa-gauge-pct"];
796
814
  var SANITIZE_CFG = {
797
815
  ALLOWED_TAGS,
798
816
  ALLOWED_ATTR,
@@ -806,25 +824,87 @@ function inlineMarkdownToHtml(text) {
806
824
  function renderMarkdown(text) {
807
825
  if (!text) return "";
808
826
  const inlined = inlineMarkdownToHtml(text);
827
+ if (/<div[\s>]/i.test(inlined)) {
828
+ return DOMPurify__default.default.sanitize(inlined, SANITIZE_CFG);
829
+ }
809
830
  const paragraphs = inlined.split(/\n{2,}/).map((para) => para.replace(/\n/g, "<br>")).filter((p) => p.length > 0);
810
831
  const html = paragraphs.length > 1 ? paragraphs.map((p) => `<p>${p}</p>`).join("") : paragraphs[0] ?? "";
811
832
  return DOMPurify__default.default.sanitize(html, SANITIZE_CFG);
812
833
  }
834
+ var ROOT_MENU_CHIP_IDS = /* @__PURE__ */ new Set([
835
+ "stock_analysis",
836
+ "stock_discovery",
837
+ "new_listings",
838
+ "portfolio_risk",
839
+ "market_forecast",
840
+ "crypto",
841
+ "tradable_picks",
842
+ "peer_compare"
843
+ ]);
844
+ var MENU_SUBTITLES = {
845
+ stock_analysis: "Fundamental & technical",
846
+ stock_discovery: "Find promising stocks",
847
+ new_listings: "Track IPOs & new stocks",
848
+ portfolio_risk: "Analyze your portfolio",
849
+ market_forecast: "Outlook & key events",
850
+ crypto: "BTC, ETH & trends",
851
+ tradable_picks: "Short-term setups",
852
+ peer_compare: "Compare peer stocks"
853
+ };
854
+ var MENU_ICON_KEY = {
855
+ stock_analysis: "menuIconGreen",
856
+ stock_discovery: "menuIconBlue",
857
+ new_listings: "menuIconLeaf",
858
+ portfolio_risk: "menuIconRed",
859
+ market_forecast: "menuIconOrange",
860
+ crypto: "menuIconGold",
861
+ tradable_picks: "menuIconTeal",
862
+ peer_compare: "menuIconPurple"
863
+ };
864
+ function isRootMenuChips(chips) {
865
+ return chips.some((c) => ROOT_MENU_CHIP_IDS.has(c.id));
866
+ }
813
867
  function MessageBubble({ message, onChipClick }) {
814
868
  const isBot = message.role === "bot";
815
869
  const bubbleClass = isBot ? `${chat_default.bubble} ${chat_default.bubbleBot}` : `${chat_default.bubble} ${chat_default.bubbleUser}`;
870
+ const handleMarkdownClick = (e) => {
871
+ const anchor = e.target.closest("a");
872
+ if (!anchor?.href) return;
873
+ e.preventDefault();
874
+ window.location.assign(anchor.href);
875
+ };
876
+ const chips = message.chips ?? [];
877
+ const showMenuGrid = isBot && message.chipsActive && isRootMenuChips(chips);
816
878
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
817
879
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: bubbleClass, children: isBot ? /* @__PURE__ */ jsxRuntime.jsx(
818
880
  "div",
819
881
  {
820
882
  className: chat_default.markdown,
821
- dangerouslySetInnerHTML: { __html: renderMarkdown(message.content) }
883
+ dangerouslySetInnerHTML: { __html: renderMarkdown(message.content) },
884
+ onClick: handleMarkdownClick
822
885
  }
823
886
  ) : message.content }),
824
- isBot && message.chips && message.chips.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
887
+ showMenuGrid ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.menuGrid, children: chips.map((chip) => {
888
+ const iconKey = MENU_ICON_KEY[chip.id];
889
+ const iconClass = iconKey && chat_default[iconKey] || "";
890
+ return /* @__PURE__ */ jsxRuntime.jsxs(
891
+ "button",
892
+ {
893
+ type: "button",
894
+ className: chat_default.menuItem,
895
+ onClick: () => onChipClick(chip),
896
+ children: [
897
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${chat_default.menuItemIcon} ${iconClass}`, children: chip.icon }),
898
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.menuItemTitle, children: chip.label }),
899
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.menuItemSub, children: MENU_SUBTITLES[chip.id] ?? "" })
900
+ ]
901
+ },
902
+ chip.id
903
+ );
904
+ }) }) : isBot && chips.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
825
905
  ChipRow,
826
906
  {
827
- chips: message.chips,
907
+ chips,
828
908
  disabled: !message.chipsActive,
829
909
  onClick: onChipClick
830
910
  }
@@ -1015,15 +1095,20 @@ var DEFAULT_BRAND_NAME = "Wealth Alpha AI";
1015
1095
  var DEFAULT_BRAND_COLOR = "#1a2d5a";
1016
1096
  var DEFAULT_AUTH_CHECK = "/me";
1017
1097
  var DEFAULT_GREETING = "Hi! I'm your Wealth Alpha AI assistant. How can I help you?";
1018
- var DISCLAIMER_BLOCK = "DISCLAIMER:\n\u2022 AI-assisted analysis for educational purposes only.\n\u2022 Not financial advice. Markets involve risk.\n\u2022 Consult a SEBI-registered advisor before investing.";
1019
- var CTA_LINE = "Select a quick command below \u2014 or type your query to ask our AI Research Analyst directly.";
1098
+ var CTA_LINE = "Select a quick command below";
1020
1099
  var PORTFOLIO_CSV_CHIP_ID = "__portfolio_csv_upload";
1100
+ var UPGRADE_PREMIUM_CHIP_ID = "__upgrade_premium__";
1101
+ function resolvePricingUrl(upgradeUrl) {
1102
+ if (upgradeUrl) return upgradeUrl;
1103
+ if (typeof window !== "undefined") {
1104
+ return `${window.location.origin}/pricing`;
1105
+ }
1106
+ return "";
1107
+ }
1021
1108
  function buildWelcome(name, plan) {
1022
1109
  const greeting = name ? `Welcome back, ${name}! You have ${plan ? plan : "Premium"} access.` : `Welcome! You have ${plan ? plan : "Premium"} access.`;
1023
1110
  return `${greeting}
1024
1111
 
1025
- ${DISCLAIMER_BLOCK}
1026
-
1027
1112
  ${CTA_LINE}`;
1028
1113
  }
1029
1114
  function WealthChat(props) {
@@ -1135,16 +1220,30 @@ function WealthChat(props) {
1135
1220
  csvFileRef.current?.click();
1136
1221
  return;
1137
1222
  }
1223
+ if (chip.id === UPGRADE_PREMIUM_CHIP_ID) {
1224
+ appendUserMessage(chip.label);
1225
+ const pricingUrl = resolvePricingUrl(user?.upgradeUrl);
1226
+ if (pricingUrl && typeof window !== "undefined") {
1227
+ window.location.assign(pricingUrl);
1228
+ }
1229
+ return;
1230
+ }
1138
1231
  appendUserMessage(chip.label);
1139
1232
  setTyping(true);
1140
1233
  try {
1141
1234
  const resp = await callChip(chip);
1142
- if (resp) appendBotResponse(resp);
1235
+ if (!resp) return;
1236
+ const redirectUrl = resp.metadata?.redirectUrl;
1237
+ if (typeof redirectUrl === "string" && redirectUrl && typeof window !== "undefined") {
1238
+ window.location.assign(redirectUrl);
1239
+ return;
1240
+ }
1241
+ appendBotResponse(resp);
1143
1242
  } finally {
1144
1243
  setTyping(false);
1145
1244
  }
1146
1245
  },
1147
- [touch, deactivatePriorChips, appendUserMessage, callChip, setTyping, appendBotResponse]
1246
+ [touch, deactivatePriorChips, appendUserMessage, callChip, setTyping, appendBotResponse, user?.upgradeUrl]
1148
1247
  );
1149
1248
  const handleCsvFileSelected = react.useCallback(
1150
1249
  (e) => {