communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
275 lines • 12.5 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
import { _IMAGE_ATTRIBUTE_INLINE_IMAGE_FILE_NAME_KEY } from "../../../../../acs-ui-common/src";
/* @conditional-compile-remove(rich-text-editor-image-upload) */
import { AttachmentUploadActionType } from '../file-sharing/AttachmentUpload';
/* @conditional-compile-remove(rich-text-editor-image-upload) */
import { _DEFAULT_INLINE_IMAGE_FILE_NAME, SEND_BOX_UPLOADS_KEY_VALUE } from '../../common/constants';
/* @conditional-compile-remove(rich-text-editor-image-upload) */
import { nanoid } from 'nanoid';
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const MAX_INLINE_IMAGE_UPLOAD_SIZE_MB = 20;
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const fetchBlobData = (resource, options) => __awaiter(void 0, void 0, void 0, function* () {
// default timeout is 30 seconds
const { timeout = 30000, abortController } = options;
const id = setTimeout(() => {
abortController.abort();
}, timeout);
const response = yield fetch(resource, Object.assign(Object.assign({}, options), { signal: abortController.signal }));
clearTimeout(id);
return response;
});
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @private
*/
export const getInlineImageData = (image) => __awaiter(void 0, void 0, void 0, function* () {
if (image.startsWith('blob') || image.startsWith('http')) {
try {
const res = yield fetchBlobData(image, { abortController: new AbortController() });
const blobImage = yield res.blob();
return blobImage;
}
catch (error) {
console.error('Error fetching image data', error);
return;
}
}
return;
});
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const getEditBoxMessagesInlineImages = (editBoxInlineImageUploads) => {
if (!editBoxInlineImageUploads) {
return;
}
const messagesInlineImagesWithProgress = {};
Object.entries(editBoxInlineImageUploads || {}).map(([messageId, attachmentUploads]) => {
const messageUploads = attachmentUploads.map((upload) => {
return upload.metadata;
});
messagesInlineImagesWithProgress[messageId] = messageUploads;
});
return messagesInlineImagesWithProgress;
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const getSendBoxInlineImages = (sendBoxInlineImageUploads) => {
var _a;
if (!sendBoxInlineImageUploads) {
return;
}
return (_a = sendBoxInlineImageUploads[SEND_BOX_UPLOADS_KEY_VALUE]) === null || _a === void 0 ? void 0 : _a.map((upload) => upload.metadata);
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const inlineImageUploadHandler = (uploadTasks, adapter, strings) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c;
for (const task of uploadTasks) {
const uploadTask = task;
const image = uploadTask.image;
if (!image) {
uploadTask.notifyUploadFailed(strings.uploadImageDataNotProvided);
continue;
}
if (image && image.size > MAX_INLINE_IMAGE_UPLOAD_SIZE_MB * 1024 * 1024) {
uploadTask.notifyUploadFailed(strings.uploadImageIsTooLarge.replace('{maxImageSize}', `${MAX_INLINE_IMAGE_UPLOAD_SIZE_MB}`));
continue;
}
const SUPPORTED_FILES = ['jpg', 'jpeg', 'png', 'gif', 'heic', 'webp'];
const imageExtension = (_b = (_a = task.metadata) === null || _a === void 0 ? void 0 : _a.name.split('.').pop()) !== null && _b !== void 0 ? _b : '';
if (!SUPPORTED_FILES.includes(imageExtension)) {
uploadTask.notifyUploadFailed(strings.uploadImageExtensionIsNotAllowed.replace('{imageExtension}', imageExtension));
continue;
}
try {
const response = yield adapter.uploadImage(image, (_c = task.metadata) === null || _c === void 0 ? void 0 : _c.name);
// Use response id as the image src because we need to keep the original image id as a reference to find the image.
// Also the html content we send to ChatSDK does not need image src,
// it only need the response id to match the uploaded image, url is not needed.
uploadTask.notifyUploadCompleted(task.metadata.id, response.id);
}
catch (error) {
console.error(error);
uploadTask.notifyUploadFailed(strings.uploadImageFailed);
}
}
});
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const generateUploadTask = (imageAttributes, fileName, messageId, inlineImageUploadActionHandler) => __awaiter(void 0, void 0, void 0, function* () {
if (!imageAttributes.src) {
console.error('Cannot upload image - Image src is not provided');
return;
}
if (!imageAttributes.id) {
console.error('Cannot upload image - Image id is not provided');
return;
}
const imageData = yield getInlineImageData(imageAttributes.src);
if (!imageData) {
return;
}
const taskId = nanoid();
const uploadTask = {
image: imageData,
taskId,
metadata: {
id: imageAttributes.id,
name: fileName,
url: imageAttributes.src,
progress: 0
},
notifyUploadProgressChanged: (value) => {
inlineImageUploadActionHandler({
type: AttachmentUploadActionType.Progress,
taskId,
progress: value,
messageId
});
},
notifyUploadCompleted: (id, url) => {
inlineImageUploadActionHandler({
type: AttachmentUploadActionType.Completed,
taskId,
id,
url,
messageId
});
},
notifyUploadFailed: (message) => {
inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Failed, taskId, message, messageId });
// remove the failed upload task when error banner is auto dismissed after 10 seconds
// so the banner won't be shown again on UI re-rendering.
setTimeout(() => {
inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Remove, id: taskId, messageId });
}, 10 * 1000);
}
};
return uploadTask;
});
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const onInsertInlineImageForEditBox = (imageAttributes, fileName, messageId, adapter, handleEditBoxInlineImageUploadAction, chatCompositeStrings) => __awaiter(void 0, void 0, void 0, function* () {
const uploadTask = yield generateUploadTask(imageAttributes, fileName, messageId, handleEditBoxInlineImageUploadAction);
if (!uploadTask) {
return;
}
handleEditBoxInlineImageUploadAction({
type: AttachmentUploadActionType.Set,
newUploads: [uploadTask],
messageId
});
inlineImageUploadHandler([uploadTask], adapter, chatCompositeStrings);
});
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const onInsertInlineImageForSendBox = (imageAttributes, fileName, adapter, handleSendBoxInlineImageUploadAction, chatCompositeStrings) => __awaiter(void 0, void 0, void 0, function* () {
const uploadTask = yield generateUploadTask(imageAttributes, fileName, SEND_BOX_UPLOADS_KEY_VALUE, handleSendBoxInlineImageUploadAction);
if (!uploadTask) {
return;
}
handleSendBoxInlineImageUploadAction({
type: AttachmentUploadActionType.Set,
newUploads: [uploadTask],
messageId: SEND_BOX_UPLOADS_KEY_VALUE
});
inlineImageUploadHandler([uploadTask], adapter, chatCompositeStrings);
});
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const cancelInlineImageUpload = (imageAttributes, imageUploads, messageId, inlineImageUploadActionHandler, adapter) => {
var _a;
if (!imageAttributes.id) {
console.error('Cannot cancel image upload - Image id is not provided');
return;
}
if (!imageUploads || !imageUploads[messageId]) {
deleteExistingInlineImageForEditBox(imageAttributes.id, messageId, adapter);
return;
}
const imageUpload = (_a = imageUploads[messageId]) === null || _a === void 0 ? void 0 : _a.find((upload) => upload.metadata.id === imageAttributes.id);
if (!imageUpload || !(imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.id)) {
deleteExistingInlineImageForEditBox(imageAttributes.id, messageId, adapter);
return;
}
inlineImageUploadActionHandler({
type: AttachmentUploadActionType.Remove,
id: imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.id,
messageId
});
if ((imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.progress) === 1 && (imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.url)) {
// The image id that we got back from the ChatSDK response is stored in the image src attribute,
// while the metadata id is the internal image id that we assigned to the image when it was pasted in.
deleteInlineImageFromServer(imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.url, adapter);
}
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const deleteInlineImageFromServer = (imageId, adapter) => {
try {
adapter.deleteImage(imageId);
}
catch (error) {
console.error(error);
}
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
// This function is used to delete the inline image that existed before editing starts
const deleteExistingInlineImageForEditBox = (imageId, messageId, adapter) => {
if (messageId !== SEND_BOX_UPLOADS_KEY_VALUE) {
deleteInlineImageFromServer(imageId, adapter);
}
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const updateContentStringWithUploadedInlineImages = (content, imageUploads, messageId = SEND_BOX_UPLOADS_KEY_VALUE) => {
if (!imageUploads || !imageUploads[messageId]) {
return content;
}
const messageUploads = imageUploads[messageId];
const document = new DOMParser().parseFromString(content !== null && content !== void 0 ? content : '', 'text/html');
document.querySelectorAll('img').forEach((img) => {
var _a;
const uploadInlineImage = messageUploads === null || messageUploads === void 0 ? void 0 : messageUploads.find((upload) => !upload.metadata.error && upload.metadata.progress === 1 && upload.metadata.id === img.id);
if (uploadInlineImage) {
// ChatSDK uses the respond id provided by the upload response. We store the response id in the image src attribute previously.
img.id = (_a = uploadInlineImage.metadata.url) !== null && _a !== void 0 ? _a : img.id;
img.src = '';
}
});
content = document.body.innerHTML;
return content;
};
/* @conditional-compile-remove(rich-text-editor-image-upload) */
/**
* @internal
*/
export const getImageFileNameFromAttributes = (imageAttributes) => {
const fileName = imageAttributes[_IMAGE_ATTRIBUTE_INLINE_IMAGE_FILE_NAME_KEY];
if (!fileName || fileName === '' || fileName === 'undefined' || fileName === 'null') {
return _DEFAULT_INLINE_IMAGE_FILE_NAME;
}
return fileName;
};
//# sourceMappingURL=ImageUploadUtils.js.map