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