@yassirbenmoussa/aicommerce-sdk 1.7.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 +431 -63
- package/dist/index.cjs +523 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +20 -2
- package/dist/index.d.ts +20 -2
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +523 -42
- package/dist/index.mjs.map +1 -1
- package/dist/widget.min.js +423 -55
- package/dist/widget.min.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -902,6 +902,301 @@ function createWidgetStyles(config) {
|
|
|
902
902
|
.aicommerce-messages::-webkit-scrollbar-thumb:hover {
|
|
903
903
|
background: var(--aic-text-secondary);
|
|
904
904
|
}
|
|
905
|
+
|
|
906
|
+
/* ============================================
|
|
907
|
+
Embedded Mode Styles - ChatGPT Style
|
|
908
|
+
============================================ */
|
|
909
|
+
|
|
910
|
+
/* Embedded container - fit content with max height */
|
|
911
|
+
#aicommerce-widget.aicommerce-embedded {
|
|
912
|
+
position: relative;
|
|
913
|
+
bottom: auto;
|
|
914
|
+
left: auto;
|
|
915
|
+
right: auto;
|
|
916
|
+
width: 100%;
|
|
917
|
+
height: auto;
|
|
918
|
+
max-height: var(--aic-max-height, 600px);
|
|
919
|
+
display: flex;
|
|
920
|
+
flex-direction: column;
|
|
921
|
+
background: transparent;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/* Embedded mode: hide launcher button */
|
|
925
|
+
.aicommerce-embedded .aicommerce-launcher {
|
|
926
|
+
display: none !important;
|
|
927
|
+
}
|
|
928
|
+
|
|
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 */
|
|
940
|
+
.aicommerce-embedded .aicommerce-chat {
|
|
941
|
+
position: relative;
|
|
942
|
+
width: 100%;
|
|
943
|
+
height: auto;
|
|
944
|
+
max-width: 100%;
|
|
945
|
+
border-radius: 0;
|
|
946
|
+
background: transparent;
|
|
947
|
+
box-shadow: none;
|
|
948
|
+
transform: none !important;
|
|
949
|
+
opacity: 1 !important;
|
|
950
|
+
pointer-events: auto !important;
|
|
951
|
+
display: flex;
|
|
952
|
+
flex-direction: column;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/* Embedded mode: no open/close animations */
|
|
956
|
+
.aicommerce-embedded .aicommerce-chat.aicommerce-closed {
|
|
957
|
+
opacity: 1 !important;
|
|
958
|
+
transform: none !important;
|
|
959
|
+
pointer-events: auto !important;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/* Embedded mode: messages area - messages start from bottom, grow upward */
|
|
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 {
|
|
1040
|
+
flex: 1;
|
|
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;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
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;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
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;
|
|
1148
|
+
}
|
|
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
|
+
}
|
|
905
1200
|
`;
|
|
906
1201
|
}
|
|
907
1202
|
function injectStyles(css) {
|
|
@@ -972,10 +1267,16 @@ function createWidget(config) {
|
|
|
972
1267
|
}
|
|
973
1268
|
async function initialize() {
|
|
974
1269
|
state.storeConfig = await fetchStoreConfig();
|
|
1270
|
+
const displayMode = config.displayMode || "widget";
|
|
1271
|
+
const isEmbedded = displayMode === "embedded";
|
|
975
1272
|
resolvedConfig = {
|
|
976
1273
|
apiKey: config.apiKey,
|
|
977
1274
|
storeId: config.storeId,
|
|
978
1275
|
baseUrl: config.baseUrl || detectBaseUrl(),
|
|
1276
|
+
displayMode,
|
|
1277
|
+
container: config.container,
|
|
1278
|
+
maxHeight: config.maxHeight || "600px",
|
|
1279
|
+
placeholder: config.placeholder || "Ask me anything about our products...",
|
|
979
1280
|
position: config.position || "bottom-right",
|
|
980
1281
|
theme: config.theme || "auto",
|
|
981
1282
|
primaryColor: config.primaryColor || state.storeConfig?.primaryColor || "#6366f1",
|
|
@@ -984,35 +1285,120 @@ function createWidget(config) {
|
|
|
984
1285
|
zIndex: config.zIndex || 9999,
|
|
985
1286
|
buttonText: config.buttonText || "\u{1F4AC}",
|
|
986
1287
|
hideLauncher: config.hideLauncher || false,
|
|
1288
|
+
addToCartText: config.addToCartText,
|
|
987
1289
|
onOpen: config.onOpen,
|
|
988
1290
|
onClose: config.onClose,
|
|
989
1291
|
onProductClick: config.onProductClick,
|
|
1292
|
+
onAddToCart: config.onAddToCart,
|
|
990
1293
|
onMessage: config.onMessage
|
|
991
1294
|
};
|
|
992
1295
|
const styles = createWidgetStyles(resolvedConfig);
|
|
993
1296
|
styleElement = injectStyles(styles);
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1297
|
+
if (isEmbedded) {
|
|
1298
|
+
let targetContainer = null;
|
|
1299
|
+
if (typeof config.container === "string") {
|
|
1300
|
+
targetContainer = document.querySelector(config.container);
|
|
1301
|
+
} else if (config.container instanceof HTMLElement) {
|
|
1302
|
+
targetContainer = config.container;
|
|
1303
|
+
}
|
|
1304
|
+
if (!targetContainer) {
|
|
1305
|
+
console.error("[AI Commerce] Embedded mode requires a valid container element or selector");
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
container = document.createElement("div");
|
|
1309
|
+
container.id = "aicommerce-widget";
|
|
1310
|
+
container.className = `aicommerce-widget aicommerce-embedded aicommerce-theme-${resolvedConfig.theme}`;
|
|
1311
|
+
container.style.setProperty("--aic-max-height", resolvedConfig.maxHeight);
|
|
1312
|
+
targetContainer.appendChild(container);
|
|
1313
|
+
state.isOpen = true;
|
|
1314
|
+
} else {
|
|
1315
|
+
container = document.createElement("div");
|
|
1316
|
+
container.id = "aicommerce-widget";
|
|
1317
|
+
container.className = `aicommerce-widget aicommerce-${resolvedConfig.position} aicommerce-theme-${resolvedConfig.theme}`;
|
|
1318
|
+
document.body.appendChild(container);
|
|
1319
|
+
}
|
|
998
1320
|
render();
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1321
|
+
if (!isEmbedded) {
|
|
1322
|
+
state.messages.push({
|
|
1323
|
+
role: "assistant",
|
|
1324
|
+
content: resolvedConfig.welcomeMessage
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1003
1327
|
state.isLoading = false;
|
|
1004
1328
|
render();
|
|
1005
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
|
+
}
|
|
1006
1346
|
function render() {
|
|
1007
1347
|
if (!container) return;
|
|
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
|
+
`;
|
|
1008
1393
|
const html = `
|
|
1009
|
-
${!resolvedConfig.hideLauncher ? `
|
|
1394
|
+
${!isEmbedded && !resolvedConfig.hideLauncher ? `
|
|
1010
1395
|
<button class="aicommerce-launcher ${state.isOpen ? "aicommerce-hidden" : ""}" aria-label="Open chat">
|
|
1011
1396
|
<span class="aicommerce-launcher-icon">${resolvedConfig.buttonText}</span>
|
|
1012
1397
|
</button>
|
|
1013
1398
|
` : ""}
|
|
1014
1399
|
|
|
1015
1400
|
<div class="aicommerce-chat ${state.isOpen ? "aicommerce-open" : "aicommerce-closed"}">
|
|
1401
|
+
${!isEmbedded ? `
|
|
1016
1402
|
<div class="aicommerce-header">
|
|
1017
1403
|
<div class="aicommerce-header-info">
|
|
1018
1404
|
<div class="aicommerce-avatar">
|
|
@@ -1025,7 +1411,9 @@ function createWidget(config) {
|
|
|
1025
1411
|
</div>
|
|
1026
1412
|
<button class="aicommerce-close" aria-label="Close chat">\u2715</button>
|
|
1027
1413
|
</div>
|
|
1414
|
+
` : ""}
|
|
1028
1415
|
|
|
1416
|
+
${isEmbedded && hasUserMessages ? `
|
|
1029
1417
|
<div class="aicommerce-messages">
|
|
1030
1418
|
${state.messages.map((msg, index) => {
|
|
1031
1419
|
const isRtl = isArabic(msg.content);
|
|
@@ -1064,34 +1452,61 @@ function createWidget(config) {
|
|
|
1064
1452
|
</div>
|
|
1065
1453
|
` : ""}
|
|
1066
1454
|
</div>
|
|
1455
|
+
` : ""}
|
|
1067
1456
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
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}
|
|
1094
1508
|
</div>
|
|
1509
|
+
` : inputContainerHtml}
|
|
1095
1510
|
</div>
|
|
1096
1511
|
`;
|
|
1097
1512
|
container.innerHTML = html;
|
|
@@ -1135,18 +1550,40 @@ function createWidget(config) {
|
|
|
1135
1550
|
const inputEl = container.querySelector(".aicommerce-input");
|
|
1136
1551
|
const sendEl = container.querySelector(".aicommerce-send");
|
|
1137
1552
|
if (inputEl) {
|
|
1138
|
-
inputEl.addEventListener("
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
+
}
|
|
1142
1569
|
}
|
|
1143
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
|
+
}
|
|
1144
1577
|
}
|
|
1145
1578
|
if (sendEl && inputEl) {
|
|
1146
1579
|
sendEl.addEventListener("click", () => {
|
|
1147
|
-
|
|
1148
|
-
|
|
1580
|
+
const value = inputEl.value.trim();
|
|
1581
|
+
if (value) {
|
|
1582
|
+
handleSend(value);
|
|
1149
1583
|
inputEl.value = "";
|
|
1584
|
+
if (inputEl instanceof HTMLTextAreaElement) {
|
|
1585
|
+
inputEl.style.height = "auto";
|
|
1586
|
+
}
|
|
1150
1587
|
}
|
|
1151
1588
|
});
|
|
1152
1589
|
}
|
|
@@ -1156,7 +1593,8 @@ function createWidget(config) {
|
|
|
1156
1593
|
}
|
|
1157
1594
|
const productCards = container.querySelectorAll(".aicommerce-product-card");
|
|
1158
1595
|
productCards.forEach((card) => {
|
|
1159
|
-
card.addEventListener("click", () => {
|
|
1596
|
+
card.addEventListener("click", (e) => {
|
|
1597
|
+
if (e.target.closest(".aicommerce-add-to-cart")) return;
|
|
1160
1598
|
const productId = card.getAttribute("data-product-id");
|
|
1161
1599
|
const product = state.messages.flatMap((m) => m.products || []).find((p) => p.id === productId);
|
|
1162
1600
|
if (product) {
|
|
@@ -1168,6 +1606,49 @@ function createWidget(config) {
|
|
|
1168
1606
|
}
|
|
1169
1607
|
});
|
|
1170
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
|
+
});
|
|
1171
1652
|
const sliders = container.querySelectorAll(".aicommerce-products");
|
|
1172
1653
|
sliders.forEach((slider) => {
|
|
1173
1654
|
let isDown = false;
|