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