@aslaluroba/help-center-react 3.2.1 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/image-attachment.d.ts +2 -1
- package/dist/index.css +1 -1
- package/dist/index.esm.js +352 -173
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +352 -173
- package/dist/index.js.map +1 -1
- package/dist/lib/types.d.ts +1 -0
- package/dist/services.esm.js +71 -14
- package/dist/services.esm.js.map +1 -1
- package/dist/services.js +71 -14
- package/dist/services.js.map +1 -1
- package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +1 -0
- package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/ui/agent-response/agent-response.tsx +5 -3
- package/src/components/ui/image-attachment.tsx +29 -17
- package/src/components/ui/image-preview-dialog.tsx +46 -0
- package/src/core/AblyService.ts +59 -12
- package/src/core/api.ts +0 -1
- package/src/lib/custom-hooks/useTypewriter.ts +5 -3
- package/src/lib/types.ts +2 -1
- package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +133 -95
- package/src/ui/chatbot-popup/chat-window-screen/index.tsx +69 -18
- package/src/ui/help-center.tsx +13 -8
- package/src/ui/help-popup.tsx +3 -1
package/dist/index.js
CHANGED
|
@@ -16271,10 +16271,19 @@ class ClientAblyService {
|
|
|
16271
16271
|
token: ablyToken,
|
|
16272
16272
|
autoConnect: true
|
|
16273
16273
|
});
|
|
16274
|
+
_this.client.connection.on('failed', stateChange => {
|
|
16275
|
+
var _a;
|
|
16276
|
+
console.error('[AblyService] Connection state: failed', {
|
|
16277
|
+
reason: (_a = stateChange.reason) === null || _a === void 0 ? void 0 : _a.message,
|
|
16278
|
+
error: stateChange.reason
|
|
16279
|
+
});
|
|
16280
|
+
});
|
|
16274
16281
|
// Wait for connection to be established
|
|
16275
16282
|
yield new Promise((resolve, reject) => {
|
|
16276
16283
|
if (!_this.client) {
|
|
16277
|
-
|
|
16284
|
+
var error = new Error('Failed to initialize Ably client');
|
|
16285
|
+
console.error('[AblyService]', error);
|
|
16286
|
+
reject(error);
|
|
16278
16287
|
return;
|
|
16279
16288
|
}
|
|
16280
16289
|
_this.client.connection.once('connected', () => {
|
|
@@ -16283,23 +16292,38 @@ class ClientAblyService {
|
|
|
16283
16292
|
resolve();
|
|
16284
16293
|
});
|
|
16285
16294
|
_this.client.connection.once('failed', stateChange => {
|
|
16286
|
-
var _a;
|
|
16287
|
-
|
|
16295
|
+
var _a, _b;
|
|
16296
|
+
var error = new Error("Ably connection failed: ".concat(((_a = stateChange.reason) === null || _a === void 0 ? void 0 : _a.message) || 'Unknown error'));
|
|
16297
|
+
console.error('[AblyService] Connection failed', {
|
|
16298
|
+
reason: (_b = stateChange.reason) === null || _b === void 0 ? void 0 : _b.message,
|
|
16299
|
+
error: stateChange.reason
|
|
16300
|
+
});
|
|
16301
|
+
reject(error);
|
|
16288
16302
|
});
|
|
16289
16303
|
_this.client.connection.once('disconnected', stateChange => {
|
|
16290
|
-
var _a;
|
|
16291
|
-
|
|
16304
|
+
var _a, _b;
|
|
16305
|
+
var error = new Error("Ably connection disconnected: ".concat(((_a = stateChange.reason) === null || _a === void 0 ? void 0 : _a.message) || 'Unknown error'));
|
|
16306
|
+
console.error('[AblyService] Connection disconnected', {
|
|
16307
|
+
reason: (_b = stateChange.reason) === null || _b === void 0 ? void 0 : _b.message
|
|
16308
|
+
});
|
|
16309
|
+
reject(error);
|
|
16292
16310
|
});
|
|
16293
16311
|
// Set a timeout for connection
|
|
16294
16312
|
setTimeout(() => {
|
|
16295
16313
|
if (!_this.isConnected) {
|
|
16296
|
-
|
|
16314
|
+
var _error = new Error('Ably connection timeout');
|
|
16315
|
+
console.error('[AblyService] Connection timeout after 10 seconds');
|
|
16316
|
+
reject(_error);
|
|
16297
16317
|
}
|
|
16298
16318
|
}, 10000);
|
|
16299
16319
|
});
|
|
16300
16320
|
// Subscribe to the session room
|
|
16301
16321
|
yield _this.joinChannel(sessionId, onMessageReceived, tenantId);
|
|
16302
16322
|
} catch (error) {
|
|
16323
|
+
console.error('[AblyService] Error in startConnection', {
|
|
16324
|
+
error,
|
|
16325
|
+
sessionId
|
|
16326
|
+
});
|
|
16303
16327
|
_this.isConnected = false;
|
|
16304
16328
|
_this.sessionId = null;
|
|
16305
16329
|
throw error;
|
|
@@ -16310,23 +16334,53 @@ class ClientAblyService {
|
|
|
16310
16334
|
var _this2 = this;
|
|
16311
16335
|
return _asyncToGenerator(function* () {
|
|
16312
16336
|
if (!_this2.client) {
|
|
16313
|
-
|
|
16337
|
+
var error = new Error('Chat client not initialized');
|
|
16338
|
+
console.error('[AblyService] joinChannel error:', error);
|
|
16339
|
+
throw error;
|
|
16314
16340
|
}
|
|
16315
16341
|
var roomName = "session:".concat(tenantId, ":").concat(sessionId);
|
|
16316
16342
|
// Set up raw channel subscription for server messages
|
|
16317
16343
|
if (_this2.client) {
|
|
16318
16344
|
_this2.channel = _this2.client.channels.get(roomName);
|
|
16345
|
+
_this2.channel.on('failed', stateChange => {
|
|
16346
|
+
var _a;
|
|
16347
|
+
console.error('[AblyService] Channel failed', {
|
|
16348
|
+
roomName,
|
|
16349
|
+
reason: (_a = stateChange.reason) === null || _a === void 0 ? void 0 : _a.message,
|
|
16350
|
+
error: stateChange.reason
|
|
16351
|
+
});
|
|
16352
|
+
});
|
|
16319
16353
|
// Subscribe to assistant/system responses
|
|
16320
16354
|
_this2.channel.subscribe('ReceiveMessage', message => {
|
|
16321
|
-
var _a, _b, _c, _d, _e, _f;
|
|
16355
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
16322
16356
|
try {
|
|
16323
|
-
|
|
16324
|
-
var
|
|
16325
|
-
var
|
|
16326
|
-
var
|
|
16327
|
-
|
|
16357
|
+
// Ensure messageContent is always a string (default to empty string if undefined)
|
|
16358
|
+
var messageContent = typeof message.data === 'string' ? message.data : (_d = (_b = (_a = message.data) === null || _a === void 0 ? void 0 : _a.content) !== null && _b !== void 0 ? _b : (_c = message.data) === null || _c === void 0 ? void 0 : _c.message) !== null && _d !== void 0 ? _d : '';
|
|
16359
|
+
var senderType = ((_e = message.data) === null || _e === void 0 ? void 0 : _e.senderType) || 3; // Assistant
|
|
16360
|
+
var needsAgent = ((_f = message.data) === null || _f === void 0 ? void 0 : _f.needsAgent) || ((_g = message.data) === null || _g === void 0 ? void 0 : _g.actionType) == 'needs_agent' || false;
|
|
16361
|
+
var attachments = ((_h = message.data) === null || _h === void 0 ? void 0 : _h.attachments) || [];
|
|
16362
|
+
// Extract downloadUrl from attachments (Ably now returns downloadUrl directly)
|
|
16363
|
+
// Attachments can be: strings (URLs), objects with downloadUrl, or objects with id
|
|
16364
|
+
var attachmentUrls = attachments.map(attachment => {
|
|
16365
|
+
if (typeof attachment === 'string') {
|
|
16366
|
+
// If it's already a string, it's a URL
|
|
16367
|
+
return attachment;
|
|
16368
|
+
} else if (attachment === null || attachment === void 0 ? void 0 : attachment.downloadUrl) {
|
|
16369
|
+
// If it's an object with downloadUrl, use that
|
|
16370
|
+
return attachment.downloadUrl;
|
|
16371
|
+
} else if (attachment === null || attachment === void 0 ? void 0 : attachment.url) {
|
|
16372
|
+
// Fallback to url property
|
|
16373
|
+
return attachment.url;
|
|
16374
|
+
}
|
|
16375
|
+
// If it's an object with id, we'll need to keep it for backward compatibility
|
|
16376
|
+
return null;
|
|
16377
|
+
}).filter(url => url !== null);
|
|
16378
|
+
onMessageReceived(messageContent, senderType, needsAgent, attachmentUrls);
|
|
16328
16379
|
} catch (error) {
|
|
16329
|
-
|
|
16380
|
+
console.error('[AblyService] Error processing message', {
|
|
16381
|
+
error,
|
|
16382
|
+
message
|
|
16383
|
+
});
|
|
16330
16384
|
}
|
|
16331
16385
|
});
|
|
16332
16386
|
yield _this2.channel.attach();
|
|
@@ -16356,6 +16410,9 @@ class ClientAblyService {
|
|
|
16356
16410
|
_this3.isConnected = false;
|
|
16357
16411
|
_this3.sessionId = null;
|
|
16358
16412
|
} catch (error) {
|
|
16413
|
+
console.error('[AblyService] Error in stopConnection', {
|
|
16414
|
+
error
|
|
16415
|
+
});
|
|
16359
16416
|
// Reset state even if there's an error
|
|
16360
16417
|
_this3.isConnected = false;
|
|
16361
16418
|
_this3.sessionId = null;
|
|
@@ -16508,19 +16565,21 @@ function useTypewriter(text) {
|
|
|
16508
16565
|
var onType = arguments.length > 2 ? arguments[2] : undefined;
|
|
16509
16566
|
var [displayedText, setDisplayedText] = React.useState('');
|
|
16510
16567
|
React.useEffect(() => {
|
|
16568
|
+
// Ensure text is always a string to prevent errors
|
|
16569
|
+
var safeText = text !== null && text !== void 0 ? text : '';
|
|
16511
16570
|
var index = 0;
|
|
16512
16571
|
setDisplayedText('');
|
|
16513
16572
|
var interval = setInterval(() => {
|
|
16514
16573
|
setDisplayedText(() => {
|
|
16515
|
-
var next =
|
|
16574
|
+
var next = safeText.slice(0, index + 1);
|
|
16516
16575
|
index++;
|
|
16517
16576
|
if (onType) onType();
|
|
16518
|
-
if (index >=
|
|
16577
|
+
if (index >= safeText.length) clearInterval(interval);
|
|
16519
16578
|
return next;
|
|
16520
16579
|
});
|
|
16521
16580
|
}, speed);
|
|
16522
16581
|
return () => clearInterval(interval);
|
|
16523
|
-
}, [text]);
|
|
16582
|
+
}, [text, onType]);
|
|
16524
16583
|
return displayedText;
|
|
16525
16584
|
}
|
|
16526
16585
|
|
|
@@ -34307,11 +34366,13 @@ var AgentResponse = _ref => {
|
|
|
34307
34366
|
messageId,
|
|
34308
34367
|
onType
|
|
34309
34368
|
} = _ref;
|
|
34369
|
+
// Ensure messageContent is always a string to prevent errors
|
|
34370
|
+
var safeMessageContent = messageContent !== null && messageContent !== void 0 ? messageContent : '';
|
|
34310
34371
|
var shouldAnimate = (senderType === 2 || senderType === 3) && !seenMessagesRef.has(messageId);
|
|
34311
|
-
var animatedText = useTypewriter(
|
|
34312
|
-
var finalMessage = shouldAnimate ? animatedText :
|
|
34372
|
+
var animatedText = useTypewriter(safeMessageContent, 20, onType);
|
|
34373
|
+
var finalMessage = shouldAnimate ? animatedText : safeMessageContent;
|
|
34313
34374
|
// Mark message as "seen" after full animation
|
|
34314
|
-
if (shouldAnimate && finalMessage ===
|
|
34375
|
+
if (shouldAnimate && finalMessage === safeMessageContent) {
|
|
34315
34376
|
seenMessagesRef.add(messageId);
|
|
34316
34377
|
}
|
|
34317
34378
|
return jsxRuntime.jsx("div", {
|
|
@@ -34461,6 +34522,32 @@ var ImagePreviewDialog = _ref => {
|
|
|
34461
34522
|
y: 0
|
|
34462
34523
|
});
|
|
34463
34524
|
}, []);
|
|
34525
|
+
var handleDownload = React.useCallback(/*#__PURE__*/_asyncToGenerator(function* () {
|
|
34526
|
+
if (!currentImageUrl) return;
|
|
34527
|
+
try {
|
|
34528
|
+
// Fetch the image as a blob
|
|
34529
|
+
var response = yield fetch(currentImageUrl);
|
|
34530
|
+
var blob = yield response.blob();
|
|
34531
|
+
// Create a temporary URL for the blob
|
|
34532
|
+
var blobUrl = URL.createObjectURL(blob);
|
|
34533
|
+
// Extract filename from URL or use a default
|
|
34534
|
+
var urlParts = currentImageUrl.split('/');
|
|
34535
|
+
var filename = urlParts[urlParts.length - 1].split('?')[0] || 'image.png';
|
|
34536
|
+
// Create a temporary anchor element and trigger download
|
|
34537
|
+
var link = document.createElement('a');
|
|
34538
|
+
link.href = blobUrl;
|
|
34539
|
+
link.download = filename;
|
|
34540
|
+
document.body.appendChild(link);
|
|
34541
|
+
link.click();
|
|
34542
|
+
// Cleanup
|
|
34543
|
+
document.body.removeChild(link);
|
|
34544
|
+
URL.revokeObjectURL(blobUrl);
|
|
34545
|
+
} catch (error) {
|
|
34546
|
+
console.error('Failed to download image:', error);
|
|
34547
|
+
// Fallback: open in new tab if download fails
|
|
34548
|
+
window.open(currentImageUrl, '_blank');
|
|
34549
|
+
}
|
|
34550
|
+
}), [currentImageUrl]);
|
|
34464
34551
|
var handleClose = React.useCallback(() => {
|
|
34465
34552
|
setZoomLevel(1);
|
|
34466
34553
|
setImagePosition({
|
|
@@ -34661,6 +34748,27 @@ var ImagePreviewDialog = _ref => {
|
|
|
34661
34748
|
"aria-label": 'Reset zoom',
|
|
34662
34749
|
type: 'button',
|
|
34663
34750
|
children: "Reset"
|
|
34751
|
+
}), jsxRuntime.jsx("div", {
|
|
34752
|
+
className: 'babylai-h-9 babylai-w-px babylai-bg-white/20 babylai-mx-1'
|
|
34753
|
+
}), jsxRuntime.jsx(Button, {
|
|
34754
|
+
variant: 'ghost',
|
|
34755
|
+
size: 'icon',
|
|
34756
|
+
onClick: handleDownload,
|
|
34757
|
+
className: 'babylai-text-white hover:babylai-text-white/80 hover:babylai-bg-white/10 babylai-h-9 babylai-w-9',
|
|
34758
|
+
"aria-label": 'Download image',
|
|
34759
|
+
type: 'button',
|
|
34760
|
+
children: jsxRuntime.jsx("svg", {
|
|
34761
|
+
className: 'babylai-w-5 babylai-h-5',
|
|
34762
|
+
fill: 'none',
|
|
34763
|
+
stroke: 'currentColor',
|
|
34764
|
+
viewBox: '0 0 24 24',
|
|
34765
|
+
children: jsxRuntime.jsx("path", {
|
|
34766
|
+
strokeLinecap: 'round',
|
|
34767
|
+
strokeLinejoin: 'round',
|
|
34768
|
+
strokeWidth: 2,
|
|
34769
|
+
d: 'M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4'
|
|
34770
|
+
})
|
|
34771
|
+
})
|
|
34664
34772
|
})]
|
|
34665
34773
|
}), hasMultipleImages && jsxRuntime.jsx("div", {
|
|
34666
34774
|
className: cn('babylai-absolute babylai-top-4 babylai-z-[60]', 'babylai-bg-black/50 babylai-backdrop-blur-sm babylai-rounded-lg babylai-px-4 babylai-py-2', dir === 'rtl' ? 'babylai-right-1/2 babylai-translate-x-1/2' : 'babylai-left-1/2 -babylai-translate-x-1/2'),
|
|
@@ -34694,6 +34802,7 @@ ImagePreviewDialog.displayName = 'ImagePreviewDialog';
|
|
|
34694
34802
|
var ImageAttachment = _ref => {
|
|
34695
34803
|
var {
|
|
34696
34804
|
fileId,
|
|
34805
|
+
imageUrl: propImageUrl,
|
|
34697
34806
|
className,
|
|
34698
34807
|
enablePreview = true,
|
|
34699
34808
|
onClick
|
|
@@ -34701,30 +34810,39 @@ var ImageAttachment = _ref => {
|
|
|
34701
34810
|
var {
|
|
34702
34811
|
i18n
|
|
34703
34812
|
} = useLocalTranslation();
|
|
34704
|
-
var [imageUrl, setImageUrl] = React.useState(null);
|
|
34705
|
-
var [loading, setLoading] = React.useState(
|
|
34813
|
+
var [imageUrl, setImageUrl] = React.useState(propImageUrl || null);
|
|
34814
|
+
var [loading, setLoading] = React.useState(!propImageUrl && !!fileId);
|
|
34706
34815
|
var [error, setError] = React.useState(false);
|
|
34707
34816
|
var [isPreviewOpen, setIsPreviewOpen] = React.useState(false);
|
|
34708
34817
|
React.useEffect(() => {
|
|
34709
|
-
|
|
34710
|
-
|
|
34711
|
-
|
|
34712
|
-
|
|
34713
|
-
|
|
34714
|
-
|
|
34715
|
-
|
|
34716
|
-
|
|
34717
|
-
|
|
34718
|
-
|
|
34719
|
-
|
|
34720
|
-
|
|
34721
|
-
|
|
34722
|
-
|
|
34723
|
-
|
|
34724
|
-
|
|
34725
|
-
|
|
34726
|
-
|
|
34727
|
-
|
|
34818
|
+
// If we have a direct URL, use it immediately
|
|
34819
|
+
if (propImageUrl) {
|
|
34820
|
+
setImageUrl(propImageUrl);
|
|
34821
|
+
setLoading(false);
|
|
34822
|
+
return;
|
|
34823
|
+
}
|
|
34824
|
+
// If we only have a fileId, fetch the URL using presignDownload
|
|
34825
|
+
if (fileId) {
|
|
34826
|
+
var fetchImageUrl = /*#__PURE__*/function () {
|
|
34827
|
+
var _ref2 = _asyncToGenerator(function* () {
|
|
34828
|
+
try {
|
|
34829
|
+
setLoading(true);
|
|
34830
|
+
setError(false);
|
|
34831
|
+
var response = yield presignDownload(fileId, i18n.language);
|
|
34832
|
+
setImageUrl(response.downloadUrl);
|
|
34833
|
+
} catch (err) {
|
|
34834
|
+
setError(true);
|
|
34835
|
+
} finally {
|
|
34836
|
+
setLoading(false);
|
|
34837
|
+
}
|
|
34838
|
+
});
|
|
34839
|
+
return function fetchImageUrl() {
|
|
34840
|
+
return _ref2.apply(this, arguments);
|
|
34841
|
+
};
|
|
34842
|
+
}();
|
|
34843
|
+
fetchImageUrl();
|
|
34844
|
+
}
|
|
34845
|
+
}, [fileId, propImageUrl, i18n.language]);
|
|
34728
34846
|
var handleImageClick = () => {
|
|
34729
34847
|
if (onClick) {
|
|
34730
34848
|
onClick();
|
|
@@ -38272,95 +38390,31 @@ var ChatWindowFooter = props => {
|
|
|
38272
38390
|
var fileInputRef = React.useRef(null);
|
|
38273
38391
|
var [selectedFiles, setSelectedFiles] = React.useState([]);
|
|
38274
38392
|
var [previewImage, setPreviewImage] = React.useState(null);
|
|
38393
|
+
var [isSending, setIsSending] = React.useState(false);
|
|
38275
38394
|
var handleAttachClick = React.useCallback(() => {
|
|
38276
38395
|
var _a;
|
|
38277
38396
|
(_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
38278
38397
|
}, []);
|
|
38279
|
-
var handleFileSelect = React.useCallback(
|
|
38280
|
-
var
|
|
38281
|
-
|
|
38282
|
-
|
|
38283
|
-
|
|
38284
|
-
|
|
38285
|
-
|
|
38286
|
-
|
|
38287
|
-
|
|
38288
|
-
|
|
38289
|
-
|
|
38290
|
-
|
|
38291
|
-
|
|
38292
|
-
|
|
38293
|
-
|
|
38294
|
-
|
|
38295
|
-
|
|
38296
|
-
|
|
38297
|
-
|
|
38298
|
-
|
|
38299
|
-
yield handleUploadFiles(newFiles);
|
|
38300
|
-
});
|
|
38301
|
-
return function (_x) {
|
|
38302
|
-
return _ref.apply(this, arguments);
|
|
38303
|
-
};
|
|
38304
|
-
}(), []);
|
|
38305
|
-
var handleUploadFiles = React.useCallback(/*#__PURE__*/function () {
|
|
38306
|
-
var _ref2 = _asyncToGenerator(function* (filesToUpload) {
|
|
38307
|
-
// Get session ID
|
|
38308
|
-
var sessionId;
|
|
38309
|
-
try {
|
|
38310
|
-
sessionId = yield props.onEnsureSession();
|
|
38311
|
-
} catch (error) {
|
|
38312
|
-
// Mark all files as error
|
|
38313
|
-
setSelectedFiles(prev => prev.map(f => filesToUpload.some(ftl => ftl.previewUrl === f.previewUrl) ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38314
|
-
error: 'Failed to initialize session',
|
|
38315
|
-
uploading: false
|
|
38316
|
-
}) : f));
|
|
38317
|
-
return;
|
|
38318
|
-
}
|
|
38319
|
-
// Upload each file
|
|
38320
|
-
var _loop = function* _loop(fileDto) {
|
|
38321
|
-
try {
|
|
38322
|
-
// Mark as uploading
|
|
38323
|
-
setSelectedFiles(prev => prev.map(f => f.previewUrl === fileDto.previewUrl ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38324
|
-
uploading: true,
|
|
38325
|
-
error: null
|
|
38326
|
-
}) : f));
|
|
38327
|
-
// Get presigned URL
|
|
38328
|
-
var presignResponse = yield presignUpload(sessionId, fileDto.file, i18n.language);
|
|
38329
|
-
// Upload file to presigned URL using axios
|
|
38330
|
-
// Important: Content-Type must match the file type (e.g., 'image/png'), not 'multipart/form-data'
|
|
38331
|
-
var uploadResponse = yield axios$1.put(presignResponse.uploadUrl, fileDto.file, {
|
|
38332
|
-
headers: {
|
|
38333
|
-
'Content-Type': fileDto.file.type
|
|
38334
|
-
},
|
|
38335
|
-
onUploadProgress: () => {
|
|
38336
|
-
// Upload progress tracking (silent)
|
|
38337
|
-
}
|
|
38338
|
-
});
|
|
38339
|
-
if (uploadResponse.status !== 200 && uploadResponse.status !== 204) {
|
|
38340
|
-
throw new Error("Upload failed with status ".concat(uploadResponse.status));
|
|
38341
|
-
}
|
|
38342
|
-
// Update with uploaded ID
|
|
38343
|
-
setSelectedFiles(prev => prev.map(f => f.previewUrl === fileDto.previewUrl ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38344
|
-
uploading: false,
|
|
38345
|
-
uploadedId: presignResponse.id,
|
|
38346
|
-
error: null
|
|
38347
|
-
}) : f));
|
|
38348
|
-
} catch (error) {
|
|
38349
|
-
setSelectedFiles(prev => prev.map(f => f.previewUrl === fileDto.previewUrl ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38350
|
-
uploading: false,
|
|
38351
|
-
error: 'Upload failed',
|
|
38352
|
-
uploadedId: null
|
|
38353
|
-
}) : f));
|
|
38354
|
-
}
|
|
38355
|
-
};
|
|
38356
|
-
for (var fileDto of filesToUpload) {
|
|
38357
|
-
yield* _loop(fileDto);
|
|
38358
|
-
}
|
|
38359
|
-
});
|
|
38360
|
-
return function (_x2) {
|
|
38361
|
-
return _ref2.apply(this, arguments);
|
|
38362
|
-
};
|
|
38363
|
-
}(), [props.onEnsureSession, i18n.language]);
|
|
38398
|
+
var handleFileSelect = React.useCallback(e => {
|
|
38399
|
+
var files = Array.from(e.target.files || []);
|
|
38400
|
+
// Validate that all files are images
|
|
38401
|
+
var imageFiles = files.filter(file => file.type.startsWith('image/'));
|
|
38402
|
+
// Create preview URLs and add to selected files (don't upload yet)
|
|
38403
|
+
var newFiles = imageFiles.map(file => ({
|
|
38404
|
+
file,
|
|
38405
|
+
previewUrl: URL.createObjectURL(file),
|
|
38406
|
+
uploading: false,
|
|
38407
|
+
uploadedId: null,
|
|
38408
|
+
error: null
|
|
38409
|
+
}));
|
|
38410
|
+
setSelectedFiles(prev => [...prev, ...newFiles]);
|
|
38411
|
+
// Clear the input
|
|
38412
|
+
if (fileInputRef.current) {
|
|
38413
|
+
fileInputRef.current.value = '';
|
|
38414
|
+
}
|
|
38415
|
+
// Don't upload files immediately - wait for send button click
|
|
38416
|
+
}, []);
|
|
38417
|
+
// Removed handleUploadFiles - files are now uploaded in handleSendMessageWithAttachments
|
|
38364
38418
|
var handleRemoveFile = React.useCallback(previewUrl => {
|
|
38365
38419
|
setSelectedFiles(prev => {
|
|
38366
38420
|
var fileToRemove = prev.find(f => f.previewUrl === previewUrl);
|
|
@@ -38370,29 +38424,114 @@ var ChatWindowFooter = props => {
|
|
|
38370
38424
|
return prev.filter(f => f.previewUrl !== previewUrl);
|
|
38371
38425
|
});
|
|
38372
38426
|
}, []);
|
|
38373
|
-
var handleSendMessageWithAttachments = React.useCallback(()
|
|
38374
|
-
//
|
|
38375
|
-
|
|
38376
|
-
|
|
38377
|
-
|
|
38378
|
-
|
|
38379
|
-
|
|
38380
|
-
|
|
38381
|
-
|
|
38382
|
-
|
|
38383
|
-
|
|
38384
|
-
|
|
38385
|
-
|
|
38386
|
-
|
|
38427
|
+
var handleSendMessageWithAttachments = React.useCallback(/*#__PURE__*/_asyncToGenerator(function* () {
|
|
38428
|
+
// Prevent sending if already loading
|
|
38429
|
+
if (props.isLoading || isSending) {
|
|
38430
|
+
return;
|
|
38431
|
+
}
|
|
38432
|
+
setIsSending(true);
|
|
38433
|
+
try {
|
|
38434
|
+
// Get files that need to be uploaded (those without uploadedId)
|
|
38435
|
+
var filesToUpload = selectedFiles.filter(f => f.uploadedId === null && !f.error);
|
|
38436
|
+
var alreadyUploadedIds = selectedFiles.filter(f => f.uploadedId !== null).map(f => f.uploadedId);
|
|
38437
|
+
// Declare uploadedIds outside the if block so it's accessible later
|
|
38438
|
+
var uploadedIds = [];
|
|
38439
|
+
// If there are files to upload, upload them first
|
|
38440
|
+
if (filesToUpload.length > 0) {
|
|
38441
|
+
// Get session ID - ensure session exists if needed (for image-only messages)
|
|
38442
|
+
var sessionId = null;
|
|
38443
|
+
try {
|
|
38444
|
+
// Use existing sessionId if available, otherwise ensure session is created
|
|
38445
|
+
if (props.sessionId) {
|
|
38446
|
+
sessionId = props.sessionId;
|
|
38447
|
+
} else {
|
|
38448
|
+
// Ensure session exists before uploading files (allows starting chat with image only)
|
|
38449
|
+
sessionId = yield props.onEnsureSession();
|
|
38450
|
+
}
|
|
38451
|
+
} catch (error) {
|
|
38452
|
+
console.error('[ChatWindowFooter] Failed to get sessionId for file upload:', error);
|
|
38453
|
+
// Mark all files as error
|
|
38454
|
+
setSelectedFiles(prev => prev.map(f => filesToUpload.some(ftl => ftl.previewUrl === f.previewUrl) ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38455
|
+
error: 'Failed to initialize session',
|
|
38456
|
+
uploading: false
|
|
38457
|
+
}) : f));
|
|
38458
|
+
setIsSending(false);
|
|
38459
|
+
return;
|
|
38460
|
+
}
|
|
38461
|
+
// Upload each file and collect uploaded IDs
|
|
38462
|
+
uploadedIds = [];
|
|
38463
|
+
var hasUploadErrors = false;
|
|
38464
|
+
var _loop = function* _loop(fileDto) {
|
|
38465
|
+
try {
|
|
38466
|
+
// Mark as uploading
|
|
38467
|
+
setSelectedFiles(prev => prev.map(f => f.previewUrl === fileDto.previewUrl ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38468
|
+
uploading: true,
|
|
38469
|
+
error: null
|
|
38470
|
+
}) : f));
|
|
38471
|
+
// Get presigned URL
|
|
38472
|
+
var presignResponse = yield presignUpload(sessionId, fileDto.file, i18n.language);
|
|
38473
|
+
// Upload file to presigned URL using axios
|
|
38474
|
+
var uploadResponse = yield axios$1.put(presignResponse.uploadUrl, fileDto.file, {
|
|
38475
|
+
headers: {
|
|
38476
|
+
'Content-Type': fileDto.file.type
|
|
38477
|
+
},
|
|
38478
|
+
onUploadProgress: () => {
|
|
38479
|
+
// Upload progress tracking (silent)
|
|
38480
|
+
}
|
|
38481
|
+
});
|
|
38482
|
+
if (uploadResponse.status !== 200 && uploadResponse.status !== 204) {
|
|
38483
|
+
throw new Error("Upload failed with status ".concat(uploadResponse.status));
|
|
38484
|
+
}
|
|
38485
|
+
// Collect uploaded ID
|
|
38486
|
+
uploadedIds.push(presignResponse.id);
|
|
38487
|
+
// Update with uploaded ID
|
|
38488
|
+
setSelectedFiles(prev => prev.map(f => f.previewUrl === fileDto.previewUrl ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38489
|
+
uploading: false,
|
|
38490
|
+
uploadedId: presignResponse.id,
|
|
38491
|
+
error: null
|
|
38492
|
+
}) : f));
|
|
38493
|
+
} catch (error) {
|
|
38494
|
+
console.error('[ChatWindowFooter] File upload failed:', error);
|
|
38495
|
+
hasUploadErrors = true;
|
|
38496
|
+
setSelectedFiles(prev => prev.map(f => f.previewUrl === fileDto.previewUrl ? _objectSpread2(_objectSpread2({}, f), {}, {
|
|
38497
|
+
uploading: false,
|
|
38498
|
+
error: 'Upload failed',
|
|
38499
|
+
uploadedId: null
|
|
38500
|
+
}) : f));
|
|
38501
|
+
}
|
|
38502
|
+
};
|
|
38503
|
+
for (var fileDto of filesToUpload) {
|
|
38504
|
+
yield* _loop(fileDto);
|
|
38505
|
+
}
|
|
38506
|
+
// If any uploads failed, don't send the message
|
|
38507
|
+
if (hasUploadErrors) {
|
|
38508
|
+
console.error('[ChatWindowFooter] Some files failed to upload, not sending message');
|
|
38509
|
+
setIsSending(false);
|
|
38510
|
+
return;
|
|
38511
|
+
}
|
|
38512
|
+
}
|
|
38513
|
+
// Get all successfully uploaded file IDs (already uploaded + newly uploaded)
|
|
38514
|
+
// Use uploadedIds from the upload loop instead of reading from state
|
|
38515
|
+
var allAttachmentIds = [...alreadyUploadedIds, ...uploadedIds];
|
|
38516
|
+
// Call the original send message with attachment IDs
|
|
38517
|
+
props.handleSendMessage(allAttachmentIds);
|
|
38518
|
+
// Clear selected files and revoke URLs
|
|
38519
|
+
selectedFiles.forEach(f => URL.revokeObjectURL(f.previewUrl));
|
|
38520
|
+
setSelectedFiles([]);
|
|
38521
|
+
setIsSending(false);
|
|
38522
|
+
} catch (error) {
|
|
38523
|
+
console.error('[ChatWindowFooter] Error sending message:', error);
|
|
38524
|
+
setIsSending(false);
|
|
38525
|
+
}
|
|
38526
|
+
}), [selectedFiles, props, i18n.language, isSending]);
|
|
38387
38527
|
// Check if any files are currently uploading
|
|
38388
38528
|
var hasUploadingFiles = selectedFiles.some(f => f.uploading);
|
|
38389
|
-
// Check if there are files
|
|
38390
|
-
|
|
38391
|
-
|
|
38392
|
-
|
|
38393
|
-
var
|
|
38394
|
-
var
|
|
38395
|
-
var isSendDisabled = props.isLoading || props.inputMessage.trim() === '' || hasUploadingFiles || hasPendingFiles || allFilesHaveErrors;
|
|
38529
|
+
// Check if there are files with errors
|
|
38530
|
+
var hasFileErrors = selectedFiles.some(f => f.error !== null);
|
|
38531
|
+
// Allow sending if there's text OR files selected (files will be uploaded on send)
|
|
38532
|
+
var hasContentToSend = props.inputMessage.trim() !== '' || selectedFiles.length > 0;
|
|
38533
|
+
var isSendDisabled = props.isLoading || isSending || !hasContentToSend || hasUploadingFiles || hasFileErrors;
|
|
38534
|
+
var showLoading = props.isLoading || isSending || hasUploadingFiles;
|
|
38396
38535
|
var handleKeyDown = React.useCallback(e => {
|
|
38397
38536
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
38398
38537
|
e.preventDefault();
|
|
@@ -38466,10 +38605,12 @@ var ChatWindowFooter = props => {
|
|
|
38466
38605
|
size: 'icon',
|
|
38467
38606
|
onClick: handleSendMessageWithAttachments,
|
|
38468
38607
|
disabled: isSendDisabled,
|
|
38469
|
-
className: 'babylai-rounded-full babylai-bg-primary-500 babylai-hover:babylai-bg-purple-600 babylai-w-8 babylai-h-8 disabled:babylai-opacity-50',
|
|
38608
|
+
className: 'babylai-rounded-full babylai-bg-primary-500 babylai-hover:babylai-bg-purple-600 babylai-w-8 babylai-h-8 !babylai-p-0 babylai-flex babylai-items-center babylai-justify-center disabled:babylai-opacity-50',
|
|
38470
38609
|
type: 'button',
|
|
38471
|
-
children: jsxRuntime.jsx(
|
|
38472
|
-
className:
|
|
38610
|
+
children: showLoading ? jsxRuntime.jsx("div", {
|
|
38611
|
+
className: 'babylai-inline-block babylai-animate-spin babylai-rounded-full babylai-h-4 babylai-w-4 babylai-aspect-square babylai-border-2 babylai-border-white babylai-border-t-transparent babylai-box-border'
|
|
38612
|
+
}) : jsxRuntime.jsx(EnvelopeIcon, {
|
|
38613
|
+
className: "babylai-w-4 babylai-h-4 babylai-flex-shrink-0 ".concat(dir === 'rtl' ? 'babylai-rotate-270' : '')
|
|
38473
38614
|
})
|
|
38474
38615
|
})]
|
|
38475
38616
|
}), previewImage && jsxRuntime.jsx(ImagePreviewDialog, {
|
|
@@ -38557,10 +38698,12 @@ var MessageComponent = /*#__PURE__*/React__default["default"].memo(_ref => {
|
|
|
38557
38698
|
var isFirstHumanAgentMessage = index === firstHumanAgentIndex && message.senderType === 2;
|
|
38558
38699
|
var textDirection = message.senderType === 1 ? 'babylai-justify-end' : 'babylai-justify-start';
|
|
38559
38700
|
var handleImageClick = React.useCallback(clickedIndex => {
|
|
38560
|
-
if (
|
|
38561
|
-
|
|
38701
|
+
// Use attachmentUrls if available (from Ably), otherwise use attachmentIds (user-sent)
|
|
38702
|
+
var attachments = message.attachmentUrls || [];
|
|
38703
|
+
if (attachments.length > 0) {
|
|
38704
|
+
onImageClick(attachments, clickedIndex);
|
|
38562
38705
|
}
|
|
38563
|
-
}, [message.attachmentIds, onImageClick]);
|
|
38706
|
+
}, [message.attachmentIds, message.attachmentUrls, onImageClick]);
|
|
38564
38707
|
return jsxRuntime.jsxs("div", {
|
|
38565
38708
|
children: [isFirstHumanAgentMessage && jsxRuntime.jsx("div", {
|
|
38566
38709
|
className: 'babylai-flex babylai-justify-center babylai-items-center babylai-my-4',
|
|
@@ -38583,14 +38726,21 @@ var MessageComponent = /*#__PURE__*/React__default["default"].memo(_ref => {
|
|
|
38583
38726
|
className: 'babylai-flex-shrink-0 babylai-me-3 babylai-w-8'
|
|
38584
38727
|
}), jsxRuntime.jsxs("div", {
|
|
38585
38728
|
className: 'babylai-flex babylai-flex-col babylai-gap-2',
|
|
38586
|
-
children: [message.
|
|
38729
|
+
children: [message.attachmentUrls && message.attachmentUrls.length > 0 && jsxRuntime.jsx("div", {
|
|
38730
|
+
className: 'babylai-flex babylai-flex-row babylai-flex-wrap babylai-gap-2 babylai-max-w-full',
|
|
38731
|
+
children: message.attachmentUrls.map((attachmentUrl, imgIndex) => jsxRuntime.jsx(ImageAttachment, {
|
|
38732
|
+
imageUrl: attachmentUrl,
|
|
38733
|
+
enablePreview: false,
|
|
38734
|
+
onClick: () => handleImageClick(imgIndex)
|
|
38735
|
+
}, attachmentUrl))
|
|
38736
|
+
}), message.attachmentIds && message.attachmentIds.length > 0 && jsxRuntime.jsx("div", {
|
|
38587
38737
|
className: 'babylai-flex babylai-flex-row babylai-flex-wrap babylai-gap-2 babylai-max-w-full',
|
|
38588
38738
|
children: message.attachmentIds.map((attachmentId, imgIndex) => jsxRuntime.jsx(ImageAttachment, {
|
|
38589
38739
|
fileId: attachmentId,
|
|
38590
38740
|
enablePreview: false,
|
|
38591
38741
|
onClick: () => handleImageClick(imgIndex)
|
|
38592
38742
|
}, attachmentId))
|
|
38593
|
-
}), jsxRuntime.jsx(AgentResponse$1, {
|
|
38743
|
+
}), message.messageContent && message.messageContent.trim() !== '' && jsxRuntime.jsx(AgentResponse$1, {
|
|
38594
38744
|
messageContent: message.messageContent,
|
|
38595
38745
|
senderType: message.senderType,
|
|
38596
38746
|
messageId: message.id,
|
|
@@ -38635,7 +38785,8 @@ var ChatWindow = /*#__PURE__*/React__default["default"].memo(_ref3 => {
|
|
|
38635
38785
|
onEnsureSession,
|
|
38636
38786
|
messages,
|
|
38637
38787
|
assistantStatus = 'loading',
|
|
38638
|
-
needsAgent
|
|
38788
|
+
needsAgent,
|
|
38789
|
+
sessionId
|
|
38639
38790
|
} = _ref3;
|
|
38640
38791
|
var {
|
|
38641
38792
|
i18n
|
|
@@ -38678,7 +38829,8 @@ var ChatWindow = /*#__PURE__*/React__default["default"].memo(_ref3 => {
|
|
|
38678
38829
|
};
|
|
38679
38830
|
}, []);
|
|
38680
38831
|
var handleSendMessage = React.useCallback(attachmentIds => {
|
|
38681
|
-
if
|
|
38832
|
+
// Allow sending if there's text OR attachments
|
|
38833
|
+
if (inputMessage.trim() || attachmentIds.length > 0) {
|
|
38682
38834
|
onSendMessage(inputMessage, attachmentIds);
|
|
38683
38835
|
setInputMessage('');
|
|
38684
38836
|
}
|
|
@@ -38689,13 +38841,32 @@ var ChatWindow = /*#__PURE__*/React__default["default"].memo(_ref3 => {
|
|
|
38689
38841
|
}, [messages]);
|
|
38690
38842
|
// Handle image gallery opening
|
|
38691
38843
|
var handleImageClick = React.useCallback(/*#__PURE__*/function () {
|
|
38692
|
-
var _ref4 = _asyncToGenerator(function* (
|
|
38693
|
-
|
|
38844
|
+
var _ref4 = _asyncToGenerator(function* (attachmentIdsOrUrls, clickedIndex) {
|
|
38845
|
+
var _a, _b;
|
|
38846
|
+
if (!attachmentIdsOrUrls || attachmentIdsOrUrls.length === 0) {
|
|
38694
38847
|
return;
|
|
38695
38848
|
}
|
|
38696
38849
|
try {
|
|
38697
|
-
//
|
|
38698
|
-
|
|
38850
|
+
// Check if the first item is a URL (starts with http:// or https://)
|
|
38851
|
+
// If so, they're all URLs from Ably and can be used directly
|
|
38852
|
+
var isUrl = ((_a = attachmentIdsOrUrls[0]) === null || _a === void 0 ? void 0 : _a.startsWith('http://')) || ((_b = attachmentIdsOrUrls[0]) === null || _b === void 0 ? void 0 : _b.startsWith('https://'));
|
|
38853
|
+
var imageUrls;
|
|
38854
|
+
if (isUrl) {
|
|
38855
|
+
// These are already URLs from Ably, use them directly (no async needed)
|
|
38856
|
+
imageUrls = attachmentIdsOrUrls.filter(url => url !== null && url.length > 0);
|
|
38857
|
+
// Open gallery immediately with URLs
|
|
38858
|
+
if (imageUrls.length > 0) {
|
|
38859
|
+
var _adjustedIndex = Math.max(0, Math.min(clickedIndex, imageUrls.length - 1));
|
|
38860
|
+
setGalleryState({
|
|
38861
|
+
isOpen: true,
|
|
38862
|
+
imageUrls,
|
|
38863
|
+
initialIndex: _adjustedIndex
|
|
38864
|
+
});
|
|
38865
|
+
}
|
|
38866
|
+
return; // Exit early since we don't need to fetch anything
|
|
38867
|
+
}
|
|
38868
|
+
// These are file IDs, need to fetch URLs using presignDownload
|
|
38869
|
+
var imageUrlPromises = attachmentIdsOrUrls.map(fileId => {
|
|
38699
38870
|
if (!fileId || typeof fileId !== 'string') {
|
|
38700
38871
|
return Promise.resolve(null);
|
|
38701
38872
|
}
|
|
@@ -38709,7 +38880,7 @@ var ChatWindow = /*#__PURE__*/React__default["default"].memo(_ref3 => {
|
|
|
38709
38880
|
return null;
|
|
38710
38881
|
});
|
|
38711
38882
|
});
|
|
38712
|
-
|
|
38883
|
+
imageUrls = (yield Promise.all(imageUrlPromises)).filter(url => url !== null && url.length > 0);
|
|
38713
38884
|
if (imageUrls.length === 0) {
|
|
38714
38885
|
return;
|
|
38715
38886
|
}
|
|
@@ -38771,7 +38942,8 @@ var ChatWindow = /*#__PURE__*/React__default["default"].memo(_ref3 => {
|
|
|
38771
38942
|
handleSendMessage: handleSendMessage,
|
|
38772
38943
|
setInputMessage: setInputMessage,
|
|
38773
38944
|
isLoading: isLoading,
|
|
38774
|
-
onEnsureSession: onEnsureSession
|
|
38945
|
+
onEnsureSession: onEnsureSession,
|
|
38946
|
+
sessionId: sessionId
|
|
38775
38947
|
}), galleryState.isOpen && galleryState.imageUrls.length > 0 && jsxRuntime.jsx(ImagePreviewDialog, {
|
|
38776
38948
|
imageUrls: galleryState.imageUrls,
|
|
38777
38949
|
initialIndex: galleryState.initialIndex,
|
|
@@ -39390,7 +39562,8 @@ var HelpPopup = _ref => {
|
|
|
39390
39562
|
}
|
|
39391
39563
|
}, [onStartChat, setSelectedOption, sessionId, setStartNewChatConfirmation, setTempSelectedOption]);
|
|
39392
39564
|
var handleSendMessage = React.useCallback((message, attachmentIds) => {
|
|
39393
|
-
if
|
|
39565
|
+
// Allow sending if there's text OR attachments
|
|
39566
|
+
if (message.trim() || attachmentIds.length > 0) {
|
|
39394
39567
|
onSendMessage(message.trim(), attachmentIds);
|
|
39395
39568
|
}
|
|
39396
39569
|
}, [onSendMessage]);
|
|
@@ -39446,7 +39619,8 @@ var HelpPopup = _ref => {
|
|
|
39446
39619
|
messages: memoizedMessages,
|
|
39447
39620
|
assistantStatus: assistantStatus,
|
|
39448
39621
|
needsAgent: needsAgent,
|
|
39449
|
-
isAblyConnected: isAblyConnected
|
|
39622
|
+
isAblyConnected: isAblyConnected,
|
|
39623
|
+
sessionId: sessionId
|
|
39450
39624
|
})]
|
|
39451
39625
|
});
|
|
39452
39626
|
}
|
|
@@ -39585,7 +39759,7 @@ var HelpCenterContent = _ref => {
|
|
|
39585
39759
|
sentAt: new Date(),
|
|
39586
39760
|
isSeen: true
|
|
39587
39761
|
}, attachments.length > 0 && {
|
|
39588
|
-
|
|
39762
|
+
attachmentUrls: attachments
|
|
39589
39763
|
});
|
|
39590
39764
|
return [...prevMessages, newMessage];
|
|
39591
39765
|
});
|
|
@@ -39714,10 +39888,11 @@ var HelpCenterContent = _ref => {
|
|
|
39714
39888
|
var handleEnsureSession = /*#__PURE__*/function () {
|
|
39715
39889
|
var _ref7 = _asyncToGenerator(function* () {
|
|
39716
39890
|
// If we already have a session ID and connection, return it
|
|
39717
|
-
if
|
|
39891
|
+
// NEVER create a new session if one already exists
|
|
39892
|
+
if (sessionId) {
|
|
39718
39893
|
return sessionId;
|
|
39719
39894
|
}
|
|
39720
|
-
//
|
|
39895
|
+
// Only create a new session if we don't have one and have a selected option
|
|
39721
39896
|
if (selectedOption) {
|
|
39722
39897
|
var newSessionId = yield startNewChatSession(selectedOption);
|
|
39723
39898
|
return newSessionId;
|
|
@@ -39731,28 +39906,32 @@ var HelpCenterContent = _ref => {
|
|
|
39731
39906
|
var handleSendMessage = /*#__PURE__*/function () {
|
|
39732
39907
|
var _ref8 = _asyncToGenerator(function* (message) {
|
|
39733
39908
|
var attachmentIds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
39734
|
-
|
|
39909
|
+
// Allow sending if there's text OR attachments
|
|
39910
|
+
if (message.trim() !== '' || attachmentIds.length > 0) {
|
|
39735
39911
|
try {
|
|
39736
39912
|
setAssistantStatus('typing');
|
|
39737
39913
|
var userMessage = {
|
|
39738
39914
|
id: Date.now(),
|
|
39739
39915
|
senderType: 1,
|
|
39740
|
-
messageContent: message,
|
|
39916
|
+
messageContent: message || '',
|
|
39917
|
+
// Use empty string if message is empty but attachments exist
|
|
39741
39918
|
sentAt: new Date(),
|
|
39742
39919
|
isSeen: false,
|
|
39743
39920
|
attachmentIds: attachmentIds.length > 0 ? attachmentIds : undefined
|
|
39744
39921
|
};
|
|
39745
39922
|
setMessages(prevMessages => [...prevMessages, userMessage]);
|
|
39746
|
-
// Handle session creation if needed
|
|
39923
|
+
// Handle session creation if needed - only create if no session exists
|
|
39747
39924
|
var currentSessionId = sessionId;
|
|
39748
|
-
if
|
|
39925
|
+
// Only create a new session if we don't have one and we have a selected option
|
|
39926
|
+
// This ensures session is only created once with the first message
|
|
39927
|
+
if (!currentSessionId && !isAblyConnected && selectedOption) {
|
|
39749
39928
|
currentSessionId = yield startNewChatSession(selectedOption);
|
|
39750
39929
|
}
|
|
39751
39930
|
if (!currentSessionId) {
|
|
39752
39931
|
throw new Error('No active session available');
|
|
39753
39932
|
}
|
|
39754
39933
|
var messageDto = _objectSpread2({
|
|
39755
|
-
messageContent: message
|
|
39934
|
+
messageContent: message || ''
|
|
39756
39935
|
}, attachmentIds.length > 0 && {
|
|
39757
39936
|
attachmentIds
|
|
39758
39937
|
});
|