wealth-alpha-chat-widget 1.0.2 → 1.0.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.
- package/dist/index.cjs +155 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1294 -25
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +155 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -683,6 +683,9 @@ function useSession(opts = {}) {
|
|
|
683
683
|
// src/styles/chat.module.css
|
|
684
684
|
var chat_default = {
|
|
685
685
|
root: "chat_root",
|
|
686
|
+
headerTitle: "chat_headerTitle",
|
|
687
|
+
menuItemTitle: "chat_menuItemTitle",
|
|
688
|
+
markdown: "chat_markdown",
|
|
686
689
|
floatingButton: "chat_floatingButton",
|
|
687
690
|
positionRight: "chat_positionRight",
|
|
688
691
|
positionLeft: "chat_positionLeft",
|
|
@@ -690,25 +693,27 @@ var chat_default = {
|
|
|
690
693
|
popupBubbleLeft: "chat_popupBubbleLeft",
|
|
691
694
|
popupBubbleRight: "chat_popupBubbleRight",
|
|
692
695
|
header: "chat_header",
|
|
693
|
-
headerTitle: "chat_headerTitle",
|
|
694
696
|
headerMeta: "chat_headerMeta",
|
|
695
697
|
headerActions: "chat_headerActions",
|
|
696
698
|
iconButton: "chat_iconButton",
|
|
697
699
|
body: "chat_body",
|
|
698
700
|
bubble: "chat_bubble",
|
|
699
|
-
markdown: "chat_markdown",
|
|
700
701
|
bubbleBot: "chat_bubbleBot",
|
|
701
702
|
bubbleUser: "chat_bubbleUser",
|
|
703
|
+
bubbleCard: "chat_bubbleCard",
|
|
704
|
+
bubbleMeta: "chat_bubbleMeta",
|
|
702
705
|
chipRow: "chat_chipRow",
|
|
703
706
|
chip: "chat_chip",
|
|
704
707
|
chipActive: "chat_chipActive",
|
|
705
708
|
chipDisabled: "chat_chipDisabled",
|
|
706
709
|
typing: "chat_typing",
|
|
707
710
|
typingDot: "chat_typingDot",
|
|
711
|
+
wacBlink: "chat_wacBlink",
|
|
708
712
|
input: "chat_input",
|
|
709
713
|
inputBox: "chat_inputBox",
|
|
710
714
|
sendButton: "chat_sendButton",
|
|
711
715
|
hiddenFileInput: "chat_hiddenFileInput",
|
|
716
|
+
csvButton: "chat_csvButton",
|
|
712
717
|
authGate: "chat_authGate",
|
|
713
718
|
authGateIcon: "chat_authGateIcon",
|
|
714
719
|
authGateTitle: "chat_authGateTitle",
|
|
@@ -718,7 +723,22 @@ var chat_default = {
|
|
|
718
723
|
authGateDisclaimerTitle: "chat_authGateDisclaimerTitle",
|
|
719
724
|
errorBanner: "chat_errorBanner",
|
|
720
725
|
popupBubble: "chat_popupBubble",
|
|
721
|
-
|
|
726
|
+
wacPopIn: "chat_wacPopIn",
|
|
727
|
+
popupDismiss: "chat_popupDismiss",
|
|
728
|
+
menuGrid: "chat_menuGrid",
|
|
729
|
+
menuItem: "chat_menuItem",
|
|
730
|
+
menuItemIcon: "chat_menuItemIcon",
|
|
731
|
+
menuItemSvg: "chat_menuItemSvg",
|
|
732
|
+
menuItemSub: "chat_menuItemSub",
|
|
733
|
+
menuIconGreen: "chat_menuIconGreen",
|
|
734
|
+
menuIconBlue: "chat_menuIconBlue",
|
|
735
|
+
menuIconLeaf: "chat_menuIconLeaf",
|
|
736
|
+
menuIconRed: "chat_menuIconRed",
|
|
737
|
+
menuIconOrange: "chat_menuIconOrange",
|
|
738
|
+
menuIconGold: "chat_menuIconGold",
|
|
739
|
+
menuIconTeal: "chat_menuIconTeal",
|
|
740
|
+
menuIconPurple: "chat_menuIconPurple",
|
|
741
|
+
chat_bubbleBot: "chat_chat_bubbleBot"
|
|
722
742
|
};
|
|
723
743
|
function AuthGate({ brandName, loginUrl, onLoginClick }) {
|
|
724
744
|
const handleClick = () => {
|
|
@@ -790,9 +810,10 @@ var ALLOWED_TAGS = [
|
|
|
790
810
|
"ol",
|
|
791
811
|
"li",
|
|
792
812
|
"blockquote",
|
|
793
|
-
"span"
|
|
813
|
+
"span",
|
|
814
|
+
"div"
|
|
794
815
|
];
|
|
795
|
-
var ALLOWED_ATTR = ["href", "target", "rel", "class"];
|
|
816
|
+
var ALLOWED_ATTR = ["href", "target", "rel", "class", "style", "data-wa-gauge-pct"];
|
|
796
817
|
var SANITIZE_CFG = {
|
|
797
818
|
ALLOWED_TAGS,
|
|
798
819
|
ALLOWED_ATTR,
|
|
@@ -803,28 +824,116 @@ var SANITIZE_CFG = {
|
|
|
803
824
|
function inlineMarkdownToHtml(text) {
|
|
804
825
|
return text.replace(/^[ \t]*#{1,6}[ \t]+(.+?)[ \t]*$/gm, "<b>$1</b>").replace(/\*\*([^\n<>]+?)\*\*/g, "<b>$1</b>").replace(/__([^\n<>]+?)__/g, "<b>$1</b>").replace(/(?<!\*)\*([^\n*<>]+?)\*(?!\*)/g, "<b>$1</b>").replace(/(?<![_a-zA-Z0-9])_([^\n_<>]+?)_(?![_a-zA-Z0-9])/g, "<i>$1</i>");
|
|
805
826
|
}
|
|
827
|
+
function stripCardDateTime(html) {
|
|
828
|
+
return html.replace(
|
|
829
|
+
/(<span class="wa-card-date">)([^<]*)(<\/span>)/g,
|
|
830
|
+
(_m, open, content, close) => open + content.replace(/,\s*\d{1,2}:\d{2}.*$/, "").trim() + close
|
|
831
|
+
);
|
|
832
|
+
}
|
|
806
833
|
function renderMarkdown(text) {
|
|
807
834
|
if (!text) return "";
|
|
808
835
|
const inlined = inlineMarkdownToHtml(text);
|
|
836
|
+
if (/<div[\s>]/i.test(inlined)) {
|
|
837
|
+
return DOMPurify__default.default.sanitize(stripCardDateTime(inlined), SANITIZE_CFG);
|
|
838
|
+
}
|
|
809
839
|
const paragraphs = inlined.split(/\n{2,}/).map((para) => para.replace(/\n/g, "<br>")).filter((p) => p.length > 0);
|
|
810
840
|
const html = paragraphs.length > 1 ? paragraphs.map((p) => `<p>${p}</p>`).join("") : paragraphs[0] ?? "";
|
|
811
|
-
return DOMPurify__default.default.sanitize(html, SANITIZE_CFG);
|
|
841
|
+
return DOMPurify__default.default.sanitize(stripCardDateTime(html), SANITIZE_CFG);
|
|
842
|
+
}
|
|
843
|
+
var ROOT_MENU_CHIP_IDS = /* @__PURE__ */ new Set([
|
|
844
|
+
"stock_analysis",
|
|
845
|
+
"stock_discovery",
|
|
846
|
+
"new_listings",
|
|
847
|
+
"portfolio_risk",
|
|
848
|
+
"market_forecast",
|
|
849
|
+
"crypto",
|
|
850
|
+
"tradable_picks",
|
|
851
|
+
"peer_compare"
|
|
852
|
+
]);
|
|
853
|
+
var MENU_SUBTITLES = {
|
|
854
|
+
stock_analysis: "Fundamental & technical",
|
|
855
|
+
stock_discovery: "Find promising stocks",
|
|
856
|
+
new_listings: "Track IPOs & new stocks",
|
|
857
|
+
portfolio_risk: "Analyze your portfolio",
|
|
858
|
+
market_forecast: "Outlook & key events",
|
|
859
|
+
crypto: "BTC, ETH & trends",
|
|
860
|
+
tradable_picks: "Short-term setups",
|
|
861
|
+
peer_compare: "Compare peer stocks"
|
|
862
|
+
};
|
|
863
|
+
var MENU_ICON_KEY = {
|
|
864
|
+
stock_analysis: "menuIconGreen",
|
|
865
|
+
stock_discovery: "menuIconBlue",
|
|
866
|
+
new_listings: "menuIconLeaf",
|
|
867
|
+
portfolio_risk: "menuIconRed",
|
|
868
|
+
market_forecast: "menuIconOrange",
|
|
869
|
+
crypto: "menuIconGold",
|
|
870
|
+
tradable_picks: "menuIconTeal",
|
|
871
|
+
peer_compare: "menuIconPurple"
|
|
872
|
+
};
|
|
873
|
+
var MENU_ICON_SVG = {
|
|
874
|
+
stock_analysis: ' <path d="M4 16L9 11L13 15L20 8" /> <path d="M20 8V13" /> <path d="M20 8H15" />',
|
|
875
|
+
stock_discovery: '<circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/>',
|
|
876
|
+
new_listings: '<rect x="5" y="5" width="14" height="14" rx="3"/><path d="M12 8v8"/> <path d="M8 12h8"/>',
|
|
877
|
+
portfolio_risk: '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z"/>',
|
|
878
|
+
market_forecast: '<path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z"/>',
|
|
879
|
+
crypto: '<path d="M4 20V10M10 20V4M16 20v-7M22 20v-4"/>',
|
|
880
|
+
tradable_picks: '<circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/>',
|
|
881
|
+
peer_compare: '<path d="M12 3v18"/><path d="M5 8l-3 6h6z"/><path d="M19 8l-3 6h6z"/>'
|
|
882
|
+
};
|
|
883
|
+
function isRootMenuChips(chips) {
|
|
884
|
+
return chips.length > 0 && chips.every((c) => ROOT_MENU_CHIP_IDS.has(c.id));
|
|
812
885
|
}
|
|
813
886
|
function MessageBubble({ message, onChipClick }) {
|
|
814
887
|
const isBot = message.role === "bot";
|
|
815
|
-
const
|
|
888
|
+
const isCard = isBot && message.content.includes("<div");
|
|
889
|
+
const bubbleClass = isBot ? `${chat_default.bubble} ${isCard ? chat_default.bubbleCard : chat_default.bubbleBot}` : `${chat_default.bubble} ${chat_default.bubbleUser}`;
|
|
890
|
+
const handleMarkdownClick = (e) => {
|
|
891
|
+
const anchor = e.target.closest("a");
|
|
892
|
+
if (!anchor?.href) return;
|
|
893
|
+
e.preventDefault();
|
|
894
|
+
window.location.assign(anchor.href);
|
|
895
|
+
};
|
|
896
|
+
const chips = message.chips ?? [];
|
|
897
|
+
const showMenuGrid = isBot && message.chipsActive && isRootMenuChips(chips);
|
|
816
898
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
|
|
817
899
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: bubbleClass, children: isBot ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
818
900
|
"div",
|
|
819
901
|
{
|
|
820
902
|
className: chat_default.markdown,
|
|
821
|
-
dangerouslySetInnerHTML: { __html: renderMarkdown(message.content) }
|
|
903
|
+
dangerouslySetInnerHTML: { __html: renderMarkdown(message.content) },
|
|
904
|
+
onClick: handleMarkdownClick
|
|
822
905
|
}
|
|
823
906
|
) : message.content }),
|
|
824
|
-
|
|
907
|
+
showMenuGrid ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.menuGrid, children: chips.map((chip) => {
|
|
908
|
+
const iconKey = MENU_ICON_KEY[chip.id];
|
|
909
|
+
const iconClass = iconKey && chat_default[iconKey] || "";
|
|
910
|
+
const svgIcon = MENU_ICON_SVG[chip.id];
|
|
911
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
912
|
+
"button",
|
|
913
|
+
{
|
|
914
|
+
type: "button",
|
|
915
|
+
className: chat_default.menuItem,
|
|
916
|
+
onClick: () => onChipClick(chip),
|
|
917
|
+
children: [
|
|
918
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${chat_default.menuItemIcon} ${iconClass}`, children: svgIcon ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
919
|
+
"svg",
|
|
920
|
+
{
|
|
921
|
+
className: chat_default.menuItemSvg,
|
|
922
|
+
viewBox: "0 0 24 24",
|
|
923
|
+
"aria-hidden": "true",
|
|
924
|
+
dangerouslySetInnerHTML: { __html: svgIcon }
|
|
925
|
+
}
|
|
926
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: chip.icon }) }),
|
|
927
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.menuItemTitle, children: chip.label }),
|
|
928
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.menuItemSub, children: MENU_SUBTITLES[chip.id] ?? "" })
|
|
929
|
+
]
|
|
930
|
+
},
|
|
931
|
+
chip.id
|
|
932
|
+
);
|
|
933
|
+
}) }) : isBot && chips.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
825
934
|
ChipRow,
|
|
826
935
|
{
|
|
827
|
-
chips
|
|
936
|
+
chips,
|
|
828
937
|
disabled: !message.chipsActive,
|
|
829
938
|
onClick: onChipClick
|
|
830
939
|
}
|
|
@@ -873,18 +982,6 @@ function ChatBody({
|
|
|
873
982
|
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: endRef })
|
|
874
983
|
] });
|
|
875
984
|
}
|
|
876
|
-
|
|
877
|
-
// src/utils/time.ts
|
|
878
|
-
function formatCountdown(remainingMs) {
|
|
879
|
-
if (remainingMs <= 0) return "expired";
|
|
880
|
-
const totalSeconds = Math.floor(remainingMs / 1e3);
|
|
881
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
882
|
-
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
883
|
-
const seconds = totalSeconds % 60;
|
|
884
|
-
if (hours > 0) return `${hours}h ${minutes}m left`;
|
|
885
|
-
if (minutes > 0) return `${minutes}m ${seconds}s left`;
|
|
886
|
-
return `${seconds}s left`;
|
|
887
|
-
}
|
|
888
985
|
function ChatHeader({
|
|
889
986
|
brandName,
|
|
890
987
|
remainingMs,
|
|
@@ -893,13 +990,7 @@ function ChatHeader({
|
|
|
893
990
|
onClear
|
|
894
991
|
}) {
|
|
895
992
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chat_default.header, children: [
|
|
896
|
-
/* @__PURE__ */ jsxRuntime.
|
|
897
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.headerTitle, children: brandName }),
|
|
898
|
-
showCountdown && remainingMs > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chat_default.headerMeta, children: [
|
|
899
|
-
"Session: ",
|
|
900
|
-
formatCountdown(remainingMs)
|
|
901
|
-
] }) : null
|
|
902
|
-
] }),
|
|
993
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: chat_default.headerTitle, children: brandName }) }),
|
|
903
994
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: chat_default.headerActions, children: [
|
|
904
995
|
onClear ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
905
996
|
"button",
|
|
@@ -1015,15 +1106,20 @@ var DEFAULT_BRAND_NAME = "Wealth Alpha AI";
|
|
|
1015
1106
|
var DEFAULT_BRAND_COLOR = "#1a2d5a";
|
|
1016
1107
|
var DEFAULT_AUTH_CHECK = "/me";
|
|
1017
1108
|
var DEFAULT_GREETING = "Hi! I'm your Wealth Alpha AI assistant. How can I help you?";
|
|
1018
|
-
var
|
|
1019
|
-
var CTA_LINE = "Select a quick command below \u2014 or type your query to ask our AI Research Analyst directly.";
|
|
1109
|
+
var CTA_LINE = "Select a quick command below";
|
|
1020
1110
|
var PORTFOLIO_CSV_CHIP_ID = "__portfolio_csv_upload";
|
|
1111
|
+
var UPGRADE_PREMIUM_CHIP_ID = "__upgrade_premium__";
|
|
1112
|
+
function resolvePricingUrl(upgradeUrl) {
|
|
1113
|
+
if (upgradeUrl) return upgradeUrl;
|
|
1114
|
+
if (typeof window !== "undefined") {
|
|
1115
|
+
return `${window.location.origin}/pricing`;
|
|
1116
|
+
}
|
|
1117
|
+
return "";
|
|
1118
|
+
}
|
|
1021
1119
|
function buildWelcome(name, plan) {
|
|
1022
1120
|
const greeting = name ? `Welcome back, ${name}! You have ${plan ? plan : "Premium"} access.` : `Welcome! You have ${plan ? plan : "Premium"} access.`;
|
|
1023
1121
|
return `${greeting}
|
|
1024
1122
|
|
|
1025
|
-
${DISCLAIMER_BLOCK}
|
|
1026
|
-
|
|
1027
1123
|
${CTA_LINE}`;
|
|
1028
1124
|
}
|
|
1029
1125
|
function WealthChat(props) {
|
|
@@ -1051,6 +1147,16 @@ function WealthChat(props) {
|
|
|
1051
1147
|
react.useEffect(() => {
|
|
1052
1148
|
setMounted(true);
|
|
1053
1149
|
}, []);
|
|
1150
|
+
react.useEffect(() => {
|
|
1151
|
+
if (typeof document === "undefined") return;
|
|
1152
|
+
const id = "wac-google-fonts";
|
|
1153
|
+
if (document.getElementById(id)) return;
|
|
1154
|
+
const link = document.createElement("link");
|
|
1155
|
+
link.id = id;
|
|
1156
|
+
link.rel = "stylesheet";
|
|
1157
|
+
link.href = "https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@600;700;800&display=swap";
|
|
1158
|
+
document.head.appendChild(link);
|
|
1159
|
+
}, []);
|
|
1054
1160
|
react.useEffect(() => {
|
|
1055
1161
|
if (!mounted || open || popupShownRef.current) return;
|
|
1056
1162
|
const timer = setTimeout(() => {
|
|
@@ -1135,16 +1241,30 @@ function WealthChat(props) {
|
|
|
1135
1241
|
csvFileRef.current?.click();
|
|
1136
1242
|
return;
|
|
1137
1243
|
}
|
|
1244
|
+
if (chip.id === UPGRADE_PREMIUM_CHIP_ID) {
|
|
1245
|
+
appendUserMessage(chip.label);
|
|
1246
|
+
const pricingUrl = resolvePricingUrl(user?.upgradeUrl);
|
|
1247
|
+
if (pricingUrl && typeof window !== "undefined") {
|
|
1248
|
+
window.location.assign(pricingUrl);
|
|
1249
|
+
}
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1138
1252
|
appendUserMessage(chip.label);
|
|
1139
1253
|
setTyping(true);
|
|
1140
1254
|
try {
|
|
1141
1255
|
const resp = await callChip(chip);
|
|
1142
|
-
if (resp)
|
|
1256
|
+
if (!resp) return;
|
|
1257
|
+
const redirectUrl = resp.metadata?.redirectUrl;
|
|
1258
|
+
if (typeof redirectUrl === "string" && redirectUrl && typeof window !== "undefined") {
|
|
1259
|
+
window.location.assign(redirectUrl);
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
appendBotResponse(resp);
|
|
1143
1263
|
} finally {
|
|
1144
1264
|
setTyping(false);
|
|
1145
1265
|
}
|
|
1146
1266
|
},
|
|
1147
|
-
[touch, deactivatePriorChips, appendUserMessage, callChip, setTyping, appendBotResponse]
|
|
1267
|
+
[touch, deactivatePriorChips, appendUserMessage, callChip, setTyping, appendBotResponse, user?.upgradeUrl]
|
|
1148
1268
|
);
|
|
1149
1269
|
const handleCsvFileSelected = react.useCallback(
|
|
1150
1270
|
(e) => {
|