@yassirbenmoussa/aicommerce-sdk 1.8.0 → 1.9.0
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/ai-commerce.min.js +390 -78
- package/dist/index.cjs +455 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +455 -55
- package/dist/index.mjs.map +1 -1
- package/dist/widget.min.js +382 -70
- package/dist/widget.min.js.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -902,17 +902,21 @@ function createWidgetStyles(config) {
|
|
|
902
902
|
}
|
|
903
903
|
|
|
904
904
|
/* ============================================
|
|
905
|
-
Embedded Mode Styles
|
|
905
|
+
Embedded Mode Styles - ChatGPT Style
|
|
906
906
|
============================================ */
|
|
907
907
|
|
|
908
|
-
/* Embedded container -
|
|
908
|
+
/* Embedded container - fit content with max height */
|
|
909
909
|
#aicommerce-widget.aicommerce-embedded {
|
|
910
910
|
position: relative;
|
|
911
911
|
bottom: auto;
|
|
912
912
|
left: auto;
|
|
913
913
|
right: auto;
|
|
914
914
|
width: 100%;
|
|
915
|
-
height:
|
|
915
|
+
height: auto;
|
|
916
|
+
max-height: var(--aic-max-height, 600px);
|
|
917
|
+
display: flex;
|
|
918
|
+
flex-direction: column;
|
|
919
|
+
background: transparent;
|
|
916
920
|
}
|
|
917
921
|
|
|
918
922
|
/* Embedded mode: hide launcher button */
|
|
@@ -920,17 +924,30 @@ function createWidgetStyles(config) {
|
|
|
920
924
|
display: none !important;
|
|
921
925
|
}
|
|
922
926
|
|
|
923
|
-
/* Embedded mode:
|
|
927
|
+
/* Embedded mode: hide the header completely */
|
|
928
|
+
.aicommerce-embedded .aicommerce-header {
|
|
929
|
+
display: none !important;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/* Embedded mode: hide close button */
|
|
933
|
+
.aicommerce-embedded .aicommerce-close {
|
|
934
|
+
display: none !important;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/* Embedded mode: chat fills container with transparent background */
|
|
924
938
|
.aicommerce-embedded .aicommerce-chat {
|
|
925
939
|
position: relative;
|
|
926
940
|
width: 100%;
|
|
927
|
-
height:
|
|
941
|
+
height: auto;
|
|
928
942
|
max-width: 100%;
|
|
929
|
-
|
|
930
|
-
|
|
943
|
+
border-radius: 0;
|
|
944
|
+
background: transparent;
|
|
945
|
+
box-shadow: none;
|
|
931
946
|
transform: none !important;
|
|
932
947
|
opacity: 1 !important;
|
|
933
948
|
pointer-events: auto !important;
|
|
949
|
+
display: flex;
|
|
950
|
+
flex-direction: column;
|
|
934
951
|
}
|
|
935
952
|
|
|
936
953
|
/* Embedded mode: no open/close animations */
|
|
@@ -940,22 +957,244 @@ function createWidgetStyles(config) {
|
|
|
940
957
|
pointer-events: auto !important;
|
|
941
958
|
}
|
|
942
959
|
|
|
943
|
-
/* Embedded mode: messages area
|
|
960
|
+
/* Embedded mode: messages area - messages start from bottom, grow upward */
|
|
944
961
|
.aicommerce-embedded .aicommerce-messages {
|
|
962
|
+
display: flex;
|
|
963
|
+
flex-direction: column;
|
|
964
|
+
justify-content: flex-end;
|
|
965
|
+
overflow-y: auto;
|
|
966
|
+
max-height: calc(var(--aic-max-height, 600px) - 100px);
|
|
967
|
+
padding: 16px;
|
|
968
|
+
max-width: 700px;
|
|
969
|
+
margin: 0 auto;
|
|
970
|
+
width: 100%;
|
|
971
|
+
background: transparent;
|
|
972
|
+
gap: 12px;
|
|
973
|
+
scrollbar-width: thin;
|
|
974
|
+
scrollbar-color: var(--aic-border) transparent;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/* Embedded mode: custom scrollbar for webkit browsers */
|
|
978
|
+
.aicommerce-embedded .aicommerce-messages::-webkit-scrollbar {
|
|
979
|
+
width: 6px;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.aicommerce-embedded .aicommerce-messages::-webkit-scrollbar-track {
|
|
983
|
+
background: transparent;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.aicommerce-embedded .aicommerce-messages::-webkit-scrollbar-thumb {
|
|
987
|
+
background-color: var(--aic-border);
|
|
988
|
+
border-radius: 3px;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
.aicommerce-embedded .aicommerce-messages::-webkit-scrollbar-thumb:hover {
|
|
992
|
+
background-color: var(--aic-text-secondary);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/* Embedded mode: messages have different styling */
|
|
996
|
+
.aicommerce-embedded .aicommerce-message {
|
|
997
|
+
max-width: 100%;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.aicommerce-embedded .aicommerce-message-content {
|
|
1001
|
+
background: var(--aic-bg);
|
|
1002
|
+
border: 1px solid var(--aic-border);
|
|
1003
|
+
border-radius: 12px;
|
|
1004
|
+
padding: 12px 16px;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.aicommerce-embedded .aicommerce-user .aicommerce-message-content {
|
|
1008
|
+
background: var(--aic-primary);
|
|
1009
|
+
color: white;
|
|
1010
|
+
border-color: var(--aic-primary);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/* Embedded mode: input container wrapper - always at bottom */
|
|
1014
|
+
.aicommerce-embedded .aicommerce-input-wrapper {
|
|
1015
|
+
width: 100%;
|
|
1016
|
+
display: flex;
|
|
1017
|
+
flex-direction: column;
|
|
1018
|
+
align-items: center;
|
|
1019
|
+
padding: 16px;
|
|
1020
|
+
flex-shrink: 0;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/* Embedded mode: input container styled like ChatGPT */
|
|
1024
|
+
.aicommerce-embedded .aicommerce-input-container {
|
|
1025
|
+
width: 100%;
|
|
1026
|
+
max-width: 700px;
|
|
1027
|
+
background: var(--aic-bg);
|
|
1028
|
+
border: 1px solid var(--aic-border);
|
|
1029
|
+
border-radius: 24px;
|
|
1030
|
+
padding: 8px 12px;
|
|
1031
|
+
display: flex;
|
|
1032
|
+
align-items: flex-end;
|
|
1033
|
+
gap: 8px;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/* Embedded mode: textarea field styling - auto-grow */
|
|
1037
|
+
.aicommerce-embedded .aicommerce-input {
|
|
945
1038
|
flex: 1;
|
|
946
|
-
min-
|
|
1039
|
+
min-width: 0;
|
|
1040
|
+
border: none;
|
|
1041
|
+
background: transparent;
|
|
1042
|
+
padding: 8px 4px;
|
|
1043
|
+
font-size: 16px;
|
|
1044
|
+
font-family: inherit;
|
|
1045
|
+
color: var(--aic-text);
|
|
1046
|
+
outline: none;
|
|
1047
|
+
resize: none;
|
|
1048
|
+
min-height: 24px;
|
|
1049
|
+
max-height: 150px;
|
|
1050
|
+
line-height: 1.5;
|
|
1051
|
+
overflow-y: auto;
|
|
947
1052
|
}
|
|
948
1053
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1054
|
+
.aicommerce-embedded .aicommerce-input::placeholder {
|
|
1055
|
+
color: var(--aic-text-secondary);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/* Embedded mode: buttons styling - smaller, no overflow */
|
|
1059
|
+
.aicommerce-embedded .aicommerce-mic,
|
|
1060
|
+
.aicommerce-embedded .aicommerce-send {
|
|
1061
|
+
flex-shrink: 0;
|
|
1062
|
+
width: 36px;
|
|
1063
|
+
height: 36px;
|
|
1064
|
+
min-width: 36px;
|
|
1065
|
+
border-radius: 50%;
|
|
1066
|
+
background: var(--aic-primary);
|
|
1067
|
+
color: white;
|
|
1068
|
+
border: none;
|
|
1069
|
+
display: flex;
|
|
1070
|
+
align-items: center;
|
|
1071
|
+
justify-content: center;
|
|
1072
|
+
cursor: pointer;
|
|
1073
|
+
transition: all 0.2s ease;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
.aicommerce-embedded .aicommerce-mic:hover,
|
|
1077
|
+
.aicommerce-embedded .aicommerce-send:hover {
|
|
1078
|
+
opacity: 0.9;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
.aicommerce-embedded .aicommerce-mic {
|
|
1082
|
+
background: transparent;
|
|
1083
|
+
color: var(--aic-text-secondary);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
.aicommerce-embedded .aicommerce-mic:hover {
|
|
1087
|
+
background: rgba(0, 0, 0, 0.05);
|
|
1088
|
+
color: var(--aic-text);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/* Embedded mode: product cards styling */
|
|
1092
|
+
.aicommerce-embedded .aicommerce-products {
|
|
1093
|
+
display: flex;
|
|
1094
|
+
flex-wrap: wrap;
|
|
1095
|
+
gap: 12px;
|
|
1096
|
+
margin-top: 12px;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
.aicommerce-embedded .aicommerce-product-card {
|
|
1100
|
+
background: var(--aic-bg);
|
|
1101
|
+
border: 1px solid var(--aic-border);
|
|
1102
|
+
border-radius: 12px;
|
|
1103
|
+
max-width: 180px;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/* Embedded mode: typing indicator */
|
|
1107
|
+
.aicommerce-embedded .aicommerce-typing {
|
|
1108
|
+
background: var(--aic-bg);
|
|
1109
|
+
border: 1px solid var(--aic-border);
|
|
1110
|
+
border-radius: 12px;
|
|
1111
|
+
padding: 12px 16px;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/* Embedded mode responsive - mobile fixes */
|
|
1115
|
+
@media (max-width: 640px) {
|
|
1116
|
+
.aicommerce-embedded .aicommerce-input-container {
|
|
1117
|
+
padding: 6px 10px;
|
|
1118
|
+
gap: 6px;
|
|
1119
|
+
border-radius: 20px;
|
|
953
1120
|
}
|
|
954
1121
|
|
|
955
|
-
.aicommerce-embedded .aicommerce-
|
|
956
|
-
|
|
1122
|
+
.aicommerce-embedded .aicommerce-mic,
|
|
1123
|
+
.aicommerce-embedded .aicommerce-send {
|
|
1124
|
+
width: 32px;
|
|
1125
|
+
height: 32px;
|
|
1126
|
+
min-width: 32px;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
.aicommerce-embedded .aicommerce-mic svg,
|
|
1130
|
+
.aicommerce-embedded .aicommerce-send svg {
|
|
1131
|
+
width: 16px;
|
|
1132
|
+
height: 16px;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
.aicommerce-embedded .aicommerce-input {
|
|
1136
|
+
font-size: 16px;
|
|
1137
|
+
padding: 6px 4px;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
.aicommerce-embedded .aicommerce-messages {
|
|
1141
|
+
padding: 12px;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
.aicommerce-embedded .aicommerce-input-wrapper {
|
|
1145
|
+
padding: 12px;
|
|
957
1146
|
}
|
|
958
1147
|
}
|
|
1148
|
+
|
|
1149
|
+
/* ============================================
|
|
1150
|
+
Add to Cart Button Styles
|
|
1151
|
+
============================================ */
|
|
1152
|
+
|
|
1153
|
+
.aicommerce-add-to-cart {
|
|
1154
|
+
width: 100%;
|
|
1155
|
+
padding: 8px 12px;
|
|
1156
|
+
background: var(--aic-primary);
|
|
1157
|
+
color: white;
|
|
1158
|
+
border: none;
|
|
1159
|
+
border-radius: 6px;
|
|
1160
|
+
font-size: 12px;
|
|
1161
|
+
font-weight: 500;
|
|
1162
|
+
cursor: pointer;
|
|
1163
|
+
margin-top: 8px;
|
|
1164
|
+
transition: all 0.2s;
|
|
1165
|
+
display: flex;
|
|
1166
|
+
align-items: center;
|
|
1167
|
+
justify-content: center;
|
|
1168
|
+
gap: 6px;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
.aicommerce-add-to-cart:hover {
|
|
1172
|
+
opacity: 0.9;
|
|
1173
|
+
transform: translateY(-1px);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
.aicommerce-add-to-cart:active {
|
|
1177
|
+
transform: translateY(0);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
.aicommerce-add-to-cart:disabled {
|
|
1181
|
+
opacity: 0.7;
|
|
1182
|
+
cursor: not-allowed;
|
|
1183
|
+
transform: none;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
.aicommerce-add-to-cart svg {
|
|
1187
|
+
flex-shrink: 0;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/* Spinner animation for loading state */
|
|
1191
|
+
@keyframes aicommerce-spin {
|
|
1192
|
+
to { transform: rotate(360deg); }
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
.aicommerce-spinner {
|
|
1196
|
+
animation: aicommerce-spin 1s linear infinite;
|
|
1197
|
+
}
|
|
959
1198
|
`;
|
|
960
1199
|
}
|
|
961
1200
|
function injectStyles(css) {
|
|
@@ -1034,7 +1273,8 @@ function createWidget(config) {
|
|
|
1034
1273
|
baseUrl: config.baseUrl || detectBaseUrl(),
|
|
1035
1274
|
displayMode,
|
|
1036
1275
|
container: config.container,
|
|
1037
|
-
|
|
1276
|
+
maxHeight: config.maxHeight || "600px",
|
|
1277
|
+
placeholder: config.placeholder || "Ask me anything about our products...",
|
|
1038
1278
|
position: config.position || "bottom-right",
|
|
1039
1279
|
theme: config.theme || "auto",
|
|
1040
1280
|
primaryColor: config.primaryColor || state.storeConfig?.primaryColor || "#6366f1",
|
|
@@ -1043,9 +1283,11 @@ function createWidget(config) {
|
|
|
1043
1283
|
zIndex: config.zIndex || 9999,
|
|
1044
1284
|
buttonText: config.buttonText || "\u{1F4AC}",
|
|
1045
1285
|
hideLauncher: config.hideLauncher || false,
|
|
1286
|
+
addToCartText: config.addToCartText,
|
|
1046
1287
|
onOpen: config.onOpen,
|
|
1047
1288
|
onClose: config.onClose,
|
|
1048
1289
|
onProductClick: config.onProductClick,
|
|
1290
|
+
onAddToCart: config.onAddToCart,
|
|
1049
1291
|
onMessage: config.onMessage
|
|
1050
1292
|
};
|
|
1051
1293
|
const styles = createWidgetStyles(resolvedConfig);
|
|
@@ -1064,7 +1306,7 @@ function createWidget(config) {
|
|
|
1064
1306
|
container = document.createElement("div");
|
|
1065
1307
|
container.id = "aicommerce-widget";
|
|
1066
1308
|
container.className = `aicommerce-widget aicommerce-embedded aicommerce-theme-${resolvedConfig.theme}`;
|
|
1067
|
-
container.style.setProperty("--aic-height", resolvedConfig.
|
|
1309
|
+
container.style.setProperty("--aic-max-height", resolvedConfig.maxHeight);
|
|
1068
1310
|
targetContainer.appendChild(container);
|
|
1069
1311
|
state.isOpen = true;
|
|
1070
1312
|
} else {
|
|
@@ -1074,16 +1316,78 @@ function createWidget(config) {
|
|
|
1074
1316
|
document.body.appendChild(container);
|
|
1075
1317
|
}
|
|
1076
1318
|
render();
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1319
|
+
if (!isEmbedded) {
|
|
1320
|
+
state.messages.push({
|
|
1321
|
+
role: "assistant",
|
|
1322
|
+
content: resolvedConfig.welcomeMessage
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1081
1325
|
state.isLoading = false;
|
|
1082
1326
|
render();
|
|
1083
1327
|
}
|
|
1328
|
+
async function addToShopifyCart(variantId, quantity = 1) {
|
|
1329
|
+
const response = await fetch("/cart/add.js", {
|
|
1330
|
+
method: "POST",
|
|
1331
|
+
headers: {
|
|
1332
|
+
"Content-Type": "application/json"
|
|
1333
|
+
},
|
|
1334
|
+
body: JSON.stringify({
|
|
1335
|
+
id: variantId,
|
|
1336
|
+
quantity
|
|
1337
|
+
})
|
|
1338
|
+
});
|
|
1339
|
+
if (!response.ok) {
|
|
1340
|
+
throw new Error("Failed to add to cart");
|
|
1341
|
+
}
|
|
1342
|
+
document.dispatchEvent(new CustomEvent("cart:refresh"));
|
|
1343
|
+
}
|
|
1084
1344
|
function render() {
|
|
1085
1345
|
if (!container) return;
|
|
1086
1346
|
const isEmbedded = resolvedConfig.displayMode === "embedded";
|
|
1347
|
+
const hasUserMessages = state.messages.some((m) => m.role === "user");
|
|
1348
|
+
if (isEmbedded) {
|
|
1349
|
+
container.classList.remove("aicommerce-no-messages", "aicommerce-has-messages");
|
|
1350
|
+
container.classList.add(hasUserMessages ? "aicommerce-has-messages" : "aicommerce-no-messages");
|
|
1351
|
+
}
|
|
1352
|
+
const placeholder = resolvedConfig.placeholder || "Ask me anything about our products...";
|
|
1353
|
+
const inputContainerHtml = `
|
|
1354
|
+
<div class="aicommerce-input-container">
|
|
1355
|
+
${isEmbedded ? `
|
|
1356
|
+
<textarea
|
|
1357
|
+
class="aicommerce-input"
|
|
1358
|
+
placeholder="${placeholder}"
|
|
1359
|
+
rows="1"
|
|
1360
|
+
${state.isLoading || state.isRecording ? "disabled" : ""}
|
|
1361
|
+
></textarea>
|
|
1362
|
+
` : `
|
|
1363
|
+
<input
|
|
1364
|
+
type="text"
|
|
1365
|
+
class="aicommerce-input"
|
|
1366
|
+
placeholder="${placeholder}"
|
|
1367
|
+
${state.isLoading || state.isRecording ? "disabled" : ""}
|
|
1368
|
+
/>
|
|
1369
|
+
`}
|
|
1370
|
+
<button class="aicommerce-mic ${state.isRecording ? "aicommerce-recording" : ""}" ${state.isLoading ? "disabled" : ""} aria-label="${state.isRecording ? "Stop recording" : "Voice input"}">
|
|
1371
|
+
${state.isRecording ? `
|
|
1372
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
|
1373
|
+
<rect x="6" y="6" width="12" height="12" rx="2"/>
|
|
1374
|
+
</svg>
|
|
1375
|
+
` : `
|
|
1376
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1377
|
+
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
|
|
1378
|
+
<path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
|
|
1379
|
+
<line x1="12" y1="19" x2="12" y2="23"/>
|
|
1380
|
+
<line x1="8" y1="23" x2="16" y2="23"/>
|
|
1381
|
+
</svg>
|
|
1382
|
+
`}
|
|
1383
|
+
</button>
|
|
1384
|
+
<button class="aicommerce-send" ${state.isLoading || state.isRecording ? "disabled" : ""} aria-label="Send message">
|
|
1385
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1386
|
+
<path d="M22 2L11 13M22 2L15 22L11 13M22 2L2 9L11 13"/>
|
|
1387
|
+
</svg>
|
|
1388
|
+
</button>
|
|
1389
|
+
</div>
|
|
1390
|
+
`;
|
|
1087
1391
|
const html = `
|
|
1088
1392
|
${!isEmbedded && !resolvedConfig.hideLauncher ? `
|
|
1089
1393
|
<button class="aicommerce-launcher ${state.isOpen ? "aicommerce-hidden" : ""}" aria-label="Open chat">
|
|
@@ -1092,6 +1396,7 @@ function createWidget(config) {
|
|
|
1092
1396
|
` : ""}
|
|
1093
1397
|
|
|
1094
1398
|
<div class="aicommerce-chat ${state.isOpen ? "aicommerce-open" : "aicommerce-closed"}">
|
|
1399
|
+
${!isEmbedded ? `
|
|
1095
1400
|
<div class="aicommerce-header">
|
|
1096
1401
|
<div class="aicommerce-header-info">
|
|
1097
1402
|
<div class="aicommerce-avatar">
|
|
@@ -1102,9 +1407,11 @@ function createWidget(config) {
|
|
|
1102
1407
|
<span class="aicommerce-status">Online</span>
|
|
1103
1408
|
</div>
|
|
1104
1409
|
</div>
|
|
1105
|
-
|
|
1410
|
+
<button class="aicommerce-close" aria-label="Close chat">\u2715</button>
|
|
1106
1411
|
</div>
|
|
1412
|
+
` : ""}
|
|
1107
1413
|
|
|
1414
|
+
${isEmbedded && hasUserMessages ? `
|
|
1108
1415
|
<div class="aicommerce-messages">
|
|
1109
1416
|
${state.messages.map((msg, index) => {
|
|
1110
1417
|
const isRtl = isArabic(msg.content);
|
|
@@ -1143,34 +1450,61 @@ function createWidget(config) {
|
|
|
1143
1450
|
</div>
|
|
1144
1451
|
` : ""}
|
|
1145
1452
|
</div>
|
|
1453
|
+
` : ""}
|
|
1146
1454
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1455
|
+
${!isEmbedded ? `
|
|
1456
|
+
<div class="aicommerce-messages">
|
|
1457
|
+
${state.messages.map((msg, index) => {
|
|
1458
|
+
const isRtl = isArabic(msg.content);
|
|
1459
|
+
const isUser = msg.role === "user";
|
|
1460
|
+
return `
|
|
1461
|
+
<div class="aicommerce-message aicommerce-${msg.role}">
|
|
1462
|
+
<div class="aicommerce-message-content ${isRtl ? "aicommerce-rtl" : "aicommerce-ltr"}">
|
|
1463
|
+
${msg.audioUrl ? renderAudioPlayer(msg, index, isUser) : escapeHtml(msg.content)}
|
|
1464
|
+
</div>
|
|
1465
|
+
${msg.products && msg.products.length > 0 ? `
|
|
1466
|
+
<div class="aicommerce-products">
|
|
1467
|
+
${msg.products.map((product) => `
|
|
1468
|
+
<div class="aicommerce-product-card" data-product-id="${product.id}" data-variant-id="${product.variantId || ""}">
|
|
1469
|
+
${product.image || product.imageUrl ? `
|
|
1470
|
+
<img src="${product.image || product.imageUrl}" alt="${escapeHtml(product.name)}" class="aicommerce-product-image" />
|
|
1471
|
+
` : `
|
|
1472
|
+
<div class="aicommerce-product-placeholder">\u{1F4E6}</div>
|
|
1473
|
+
`}
|
|
1474
|
+
<div class="aicommerce-product-info">
|
|
1475
|
+
<span class="aicommerce-product-name" title="${escapeHtml(product.name)}">${escapeHtml(product.name)}</span>
|
|
1476
|
+
${product.description ? `<p class="aicommerce-product-desc">${escapeHtml(product.description)}</p>` : ""}
|
|
1477
|
+
<span class="aicommerce-product-price">${formatPrice(product.price, product.currency)}</span>
|
|
1478
|
+
<button class="aicommerce-add-to-cart" data-product-id="${product.id}">
|
|
1479
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1480
|
+
<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/>
|
|
1481
|
+
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>
|
|
1482
|
+
</svg>
|
|
1483
|
+
${resolvedConfig.addToCartText || "Add to Cart"}
|
|
1484
|
+
</button>
|
|
1485
|
+
</div>
|
|
1486
|
+
</div>
|
|
1487
|
+
`).join("")}
|
|
1488
|
+
</div>
|
|
1489
|
+
` : ""}
|
|
1490
|
+
</div>
|
|
1491
|
+
`;
|
|
1492
|
+
}).join("")}
|
|
1493
|
+
${state.isLoading ? `
|
|
1494
|
+
<div class="aicommerce-message aicommerce-assistant">
|
|
1495
|
+
<div class="aicommerce-typing">
|
|
1496
|
+
<span></span><span></span><span></span>
|
|
1497
|
+
</div>
|
|
1498
|
+
</div>
|
|
1499
|
+
` : ""}
|
|
1500
|
+
</div>
|
|
1501
|
+
` : ""}
|
|
1502
|
+
|
|
1503
|
+
${isEmbedded ? `
|
|
1504
|
+
<div class="aicommerce-input-wrapper">
|
|
1505
|
+
${inputContainerHtml}
|
|
1173
1506
|
</div>
|
|
1507
|
+
` : inputContainerHtml}
|
|
1174
1508
|
</div>
|
|
1175
1509
|
`;
|
|
1176
1510
|
container.innerHTML = html;
|
|
@@ -1214,18 +1548,40 @@ function createWidget(config) {
|
|
|
1214
1548
|
const inputEl = container.querySelector(".aicommerce-input");
|
|
1215
1549
|
const sendEl = container.querySelector(".aicommerce-send");
|
|
1216
1550
|
if (inputEl) {
|
|
1217
|
-
inputEl.addEventListener("
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1551
|
+
inputEl.addEventListener("keydown", (e) => {
|
|
1552
|
+
const keyEvent = e;
|
|
1553
|
+
if (keyEvent.key === "Enter") {
|
|
1554
|
+
const isTextarea = inputEl instanceof HTMLTextAreaElement;
|
|
1555
|
+
if (isTextarea && keyEvent.shiftKey) {
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
e.preventDefault();
|
|
1559
|
+
const value = inputEl.value.trim();
|
|
1560
|
+
if (value) {
|
|
1561
|
+
handleSend(value);
|
|
1562
|
+
inputEl.value = "";
|
|
1563
|
+
if (isTextarea) {
|
|
1564
|
+
inputEl.style.height = "auto";
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1221
1567
|
}
|
|
1222
1568
|
});
|
|
1569
|
+
if (inputEl instanceof HTMLTextAreaElement) {
|
|
1570
|
+
inputEl.addEventListener("input", () => {
|
|
1571
|
+
inputEl.style.height = "auto";
|
|
1572
|
+
inputEl.style.height = Math.min(inputEl.scrollHeight, 150) + "px";
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1223
1575
|
}
|
|
1224
1576
|
if (sendEl && inputEl) {
|
|
1225
1577
|
sendEl.addEventListener("click", () => {
|
|
1226
|
-
|
|
1227
|
-
|
|
1578
|
+
const value = inputEl.value.trim();
|
|
1579
|
+
if (value) {
|
|
1580
|
+
handleSend(value);
|
|
1228
1581
|
inputEl.value = "";
|
|
1582
|
+
if (inputEl instanceof HTMLTextAreaElement) {
|
|
1583
|
+
inputEl.style.height = "auto";
|
|
1584
|
+
}
|
|
1229
1585
|
}
|
|
1230
1586
|
});
|
|
1231
1587
|
}
|
|
@@ -1235,7 +1591,8 @@ function createWidget(config) {
|
|
|
1235
1591
|
}
|
|
1236
1592
|
const productCards = container.querySelectorAll(".aicommerce-product-card");
|
|
1237
1593
|
productCards.forEach((card) => {
|
|
1238
|
-
card.addEventListener("click", () => {
|
|
1594
|
+
card.addEventListener("click", (e) => {
|
|
1595
|
+
if (e.target.closest(".aicommerce-add-to-cart")) return;
|
|
1239
1596
|
const productId = card.getAttribute("data-product-id");
|
|
1240
1597
|
const product = state.messages.flatMap((m) => m.products || []).find((p) => p.id === productId);
|
|
1241
1598
|
if (product) {
|
|
@@ -1247,6 +1604,49 @@ function createWidget(config) {
|
|
|
1247
1604
|
}
|
|
1248
1605
|
});
|
|
1249
1606
|
});
|
|
1607
|
+
const addToCartBtns = container.querySelectorAll(".aicommerce-add-to-cart");
|
|
1608
|
+
addToCartBtns.forEach((btn) => {
|
|
1609
|
+
btn.addEventListener("click", async (e) => {
|
|
1610
|
+
e.stopPropagation();
|
|
1611
|
+
const button = btn;
|
|
1612
|
+
const productCard = button.closest(".aicommerce-product-card");
|
|
1613
|
+
const productId = productCard?.getAttribute("data-product-id");
|
|
1614
|
+
const variantId = productCard?.getAttribute("data-variant-id");
|
|
1615
|
+
const product = state.messages.flatMap((m) => m.products || []).find((p) => p.id === productId);
|
|
1616
|
+
if (!product) return;
|
|
1617
|
+
const originalText = button.innerHTML;
|
|
1618
|
+
button.disabled = true;
|
|
1619
|
+
button.innerHTML = `
|
|
1620
|
+
<svg class="aicommerce-spinner" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1621
|
+
<circle cx="12" cy="12" r="10" stroke-dasharray="32" stroke-dashoffset="32"/>
|
|
1622
|
+
</svg>
|
|
1623
|
+
Adding...
|
|
1624
|
+
`;
|
|
1625
|
+
try {
|
|
1626
|
+
if (resolvedConfig.onAddToCart) {
|
|
1627
|
+
await resolvedConfig.onAddToCart(product);
|
|
1628
|
+
} else if (variantId && window.Shopify) {
|
|
1629
|
+
await addToShopifyCart(variantId);
|
|
1630
|
+
} else if (product.url) {
|
|
1631
|
+
window.open(product.url, "_blank", "noopener,noreferrer");
|
|
1632
|
+
}
|
|
1633
|
+
button.innerHTML = `
|
|
1634
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1635
|
+
<polyline points="20 6 9 17 4 12"/>
|
|
1636
|
+
</svg>
|
|
1637
|
+
Added!
|
|
1638
|
+
`;
|
|
1639
|
+
setTimeout(() => {
|
|
1640
|
+
button.innerHTML = originalText;
|
|
1641
|
+
button.disabled = false;
|
|
1642
|
+
}, 2e3);
|
|
1643
|
+
} catch (error) {
|
|
1644
|
+
console.error("[AI Commerce] Add to cart failed:", error);
|
|
1645
|
+
button.innerHTML = originalText;
|
|
1646
|
+
button.disabled = false;
|
|
1647
|
+
}
|
|
1648
|
+
});
|
|
1649
|
+
});
|
|
1250
1650
|
const sliders = container.querySelectorAll(".aicommerce-products");
|
|
1251
1651
|
sliders.forEach((slider) => {
|
|
1252
1652
|
let isDown = false;
|