@aslaluroba/help-center-react 3.2.3 → 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/index.js CHANGED
@@ -38390,6 +38390,7 @@ var ChatWindowFooter = props => {
38390
38390
  var fileInputRef = React.useRef(null);
38391
38391
  var [selectedFiles, setSelectedFiles] = React.useState([]);
38392
38392
  var [previewImage, setPreviewImage] = React.useState(null);
38393
+ var [isSending, setIsSending] = React.useState(false);
38393
38394
  var handleAttachClick = React.useCallback(() => {
38394
38395
  var _a;
38395
38396
  (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
@@ -38425,106 +38426,112 @@ var ChatWindowFooter = props => {
38425
38426
  }, []);
38426
38427
  var handleSendMessageWithAttachments = React.useCallback(/*#__PURE__*/_asyncToGenerator(function* () {
38427
38428
  // Prevent sending if already loading
38428
- if (props.isLoading) {
38429
+ if (props.isLoading || isSending) {
38429
38430
  return;
38430
38431
  }
38431
- // Get files that need to be uploaded (those without uploadedId)
38432
- var filesToUpload = selectedFiles.filter(f => f.uploadedId === null && !f.error);
38433
- var alreadyUploadedIds = selectedFiles.filter(f => f.uploadedId !== null).map(f => f.uploadedId);
38434
- // Declare uploadedIds outside the if block so it's accessible later
38435
- var uploadedIds = [];
38436
- // If there are files to upload, upload them first
38437
- if (filesToUpload.length > 0) {
38438
- // Get session ID - only use existing, never create new one
38439
- var sessionId = null;
38440
- try {
38441
- // Only use existing sessionId, never call onEnsureSession
38442
- if (props.sessionId) {
38443
- sessionId = props.sessionId;
38444
- } else {
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);
38445
38453
  // Mark all files as error
38446
38454
  setSelectedFiles(prev => prev.map(f => filesToUpload.some(ftl => ftl.previewUrl === f.previewUrl) ? _objectSpread2(_objectSpread2({}, f), {}, {
38447
- error: 'No session available',
38455
+ error: 'Failed to initialize session',
38448
38456
  uploading: false
38449
38457
  }) : f));
38458
+ setIsSending(false);
38450
38459
  return;
38451
38460
  }
38452
- } catch (error) {
38453
- console.error('[ChatWindowFooter] Failed to get sessionId for file upload:', error);
38454
- // Mark all files as error
38455
- setSelectedFiles(prev => prev.map(f => filesToUpload.some(ftl => ftl.previewUrl === f.previewUrl) ? _objectSpread2(_objectSpread2({}, f), {}, {
38456
- error: 'Failed to initialize session',
38457
- uploading: false
38458
- }) : f));
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)
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));
38480
38484
  }
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));
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;
38501
38511
  }
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
- return;
38510
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);
38511
38525
  }
38512
- // Get all successfully uploaded file IDs (already uploaded + newly uploaded)
38513
- // Use uploadedIds from the upload loop instead of reading from state
38514
- var allAttachmentIds = [...alreadyUploadedIds, ...uploadedIds];
38515
- // Call the original send message with attachment IDs
38516
- props.handleSendMessage(allAttachmentIds);
38517
- // Clear selected files and revoke URLs
38518
- selectedFiles.forEach(f => URL.revokeObjectURL(f.previewUrl));
38519
- setSelectedFiles([]);
38520
- }), [selectedFiles, props, i18n.language]);
38526
+ }), [selectedFiles, props, i18n.language, isSending]);
38521
38527
  // Check if any files are currently uploading
38522
38528
  var hasUploadingFiles = selectedFiles.some(f => f.uploading);
38523
38529
  // Check if there are files with errors
38524
38530
  var hasFileErrors = selectedFiles.some(f => f.error !== null);
38525
38531
  // Allow sending if there's text OR files selected (files will be uploaded on send)
38526
38532
  var hasContentToSend = props.inputMessage.trim() !== '' || selectedFiles.length > 0;
38527
- var isSendDisabled = props.isLoading || !hasContentToSend || hasUploadingFiles || hasFileErrors;
38533
+ var isSendDisabled = props.isLoading || isSending || !hasContentToSend || hasUploadingFiles || hasFileErrors;
38534
+ var showLoading = props.isLoading || isSending || hasUploadingFiles;
38528
38535
  var handleKeyDown = React.useCallback(e => {
38529
38536
  if (e.key === 'Enter' && !e.shiftKey) {
38530
38537
  e.preventDefault();
@@ -38598,10 +38605,12 @@ var ChatWindowFooter = props => {
38598
38605
  size: 'icon',
38599
38606
  onClick: handleSendMessageWithAttachments,
38600
38607
  disabled: isSendDisabled,
38601
- 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',
38602
38609
  type: 'button',
38603
- children: jsxRuntime.jsx(EnvelopeIcon, {
38604
- className: "babylai-w-4 babylai-h-4 ".concat(dir === 'rtl' ? 'babylai-rotate-270' : '')
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' : '')
38605
38614
  })
38606
38615
  })]
38607
38616
  }), previewImage && jsxRuntime.jsx(ImagePreviewDialog, {
@@ -38690,7 +38699,7 @@ var MessageComponent = /*#__PURE__*/React__default["default"].memo(_ref => {
38690
38699
  var textDirection = message.senderType === 1 ? 'babylai-justify-end' : 'babylai-justify-start';
38691
38700
  var handleImageClick = React.useCallback(clickedIndex => {
38692
38701
  // Use attachmentUrls if available (from Ably), otherwise use attachmentIds (user-sent)
38693
- var attachments = message.attachmentUrls || message.attachmentIds || [];
38702
+ var attachments = message.attachmentUrls || [];
38694
38703
  if (attachments.length > 0) {
38695
38704
  onImageClick(attachments, clickedIndex);
38696
38705
  }