@sendbird/uikit-react
Version:
Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
338 lines (331 loc) • 16 kB
JavaScript
import { e as __extends, _ as __assign } from '../chunks/bundle-DlZj_j5B.js';
import React__default, { Component, useState, useEffect } from 'react';
import { z as getClassName } from '../chunks/bundle-C5Cl3Igw.js';
import { O as Or, M as MessageTemplate } from '../chunks/bundle-ChE9cvzN.js';
import { FallbackTemplateMessageItemBody } from './FallbackTemplateMessageItemBody.tsx.js';
import { LoadingTemplateMessageItemBody } from './LoadingTemplateMessageItemBody.tsx.js';
import { M as MESSAGE_TEMPLATE_KEY } from '../chunks/bundle-C8kxBudB.js';
import { u as useSendbird } from '../chunks/bundle-BnaoVUUl.js';
import '@sendbird/chat/groupChannel';
import '../utils/message/getOutgoingMessageState.js';
import '../chunks/bundle-OJHU7Q3U.js';
import '../chunks/bundle-DZaN4z9l.js';
import '../chunks/bundle-0bJlK18Z.js';
import '../chunks/bundle-DxLnjDoJ.js';
import '../chunks/bundle-Dhutxl0X.js';
import '../chunks/bundle-D89Qj0P4.js';
import '../chunks/bundle-FZ_FdxZT.js';
import './Loader.js';
import './Icon.js';
import '../chunks/bundle-CaW4IP0_.js';
import '../chunks/bundle-C1jTnXNH.js';
import '@sendbird/chat';
import '@sendbird/chat/openChannel';
var MessageTemplateWrapper = function (_a) {
var message = _a.message, templateVersion = _a.templateVersion, templateItems = _a.templateItems;
return React__default.createElement(Or, { message: message },
React__default.createElement(MessageTemplate, { templateVersion: templateVersion, templateItems: templateItems }));
};
var splitColorVariables = function (colorVariables) {
var light = {};
var dark = {};
for (var key in colorVariables) {
if (Object.prototype.hasOwnProperty.call(colorVariables, key)) {
var value = colorVariables[key];
if (typeof value === 'object' && value !== null) {
var _a = splitColorVariables(value), nestedLight = _a[0], nestedDark = _a[1];
light[key] = nestedLight;
dark[key] = nestedDark;
}
else if (typeof value === 'string') {
var _b = value.split(','), lightColor = _b[0], darkColor = _b[1];
light[key] = lightColor;
dark[key] = darkColor || lightColor; // when dark color is not provided, use light color
}
else {
light[key] = value;
dark[key] = value;
}
}
}
return [light, dark];
};
function selectColorVariablesByTheme(_a) {
var colorVariables = _a.colorVariables, theme = _a.theme;
var _b = splitColorVariables(colorVariables), light = _b[0], dark = _b[1];
return theme === 'light' ? light : dark;
}
var MessageTemplateErrorBoundary = /** @class */ (function (_super) {
__extends(MessageTemplateErrorBoundary, _super);
function MessageTemplateErrorBoundary(props) {
var _this = _super.call(this, props) || this;
_this.state = { hasError: false };
return _this;
}
MessageTemplateErrorBoundary.getDerivedStateFromError = function () {
return { hasError: true };
};
MessageTemplateErrorBoundary.prototype.componentDidCatch = function (error, errorInfo) {
var _a;
(_a = this.props.logger) === null || _a === void 0 ? void 0 : _a.error('Error caught by ErrorBoundary: ', error, errorInfo);
};
MessageTemplateErrorBoundary.prototype.render = function () {
if (this.state.hasError) {
return this.props.fallbackMessage;
}
return this.props.children;
};
return MessageTemplateErrorBoundary;
}(Component));
var flattenObjectHelper = function (currentObject, flattenObject, parentKeyPath) {
if (parentKeyPath === void 0) { parentKeyPath = ''; }
for (var _i = 0, _a = Object.entries(currentObject); _i < _a.length; _i++) {
var _b = _a[_i], key = _b[0], value = _b[1];
var currentKeyPath = parentKeyPath ? "".concat(parentKeyPath, ".").concat(key) : key;
if (value && typeof value === 'object') {
flattenObjectHelper(value, flattenObject, currentKeyPath);
}
else {
flattenObject[currentKeyPath] = value;
}
}
};
/**
* Returns flattened object.
* ex.
* given { key-1: { key-1.1: 'value-1.1' }, key-2: 'value-2' }
* returns { key-1.key-1.1: 'value-1.1', key-2: 'value-2' }
*/
function flattenObject(object) {
var result = {};
flattenObjectHelper(object, result);
return result;
}
var TEMPLATE_FETCH_RETRY_BUFFER_TIME_IN_MILLIES = 500; // It takes about 450ms for isError update
var replaceVariablesInTemplateString = function (_a) {
var template = _a.template, _b = _a.templateData, templateData = _b === void 0 ? {} : _b, colorVariables = _a.colorVariables, theme = _a.theme;
var selectedThemeColorVariables = {};
if (colorVariables && theme) {
selectedThemeColorVariables = selectColorVariablesByTheme({
colorVariables: colorVariables,
theme: theme,
});
}
var source = __assign(__assign({}, templateData), selectedThemeColorVariables);
var flattenedSource = flattenObject(source);
var replaced = template;
Object.entries(flattenedSource).forEach(function (_a) {
var key = _a[0], val = _a[1];
var pattern = "\\{".concat(key, "\\}");
var regex = new RegExp(pattern, 'g');
replaced = replaced.replace(regex, val);
});
return replaced;
};
function TemplateMessageItemBody(_a) {
var _b;
var _c = _a.className, className = _c === void 0 ? '' : _c, message = _a.message, _d = _a.isByMe, isByMe = _d === void 0 ? false : _d, _e = _a.theme, theme = _e === void 0 ? 'light' : _e;
var templateData = (_b = message.extendedMessagePayload) === null || _b === void 0 ? void 0 : _b[MESSAGE_TEMPLATE_KEY];
var getFailedBody = function () {
return React__default.createElement(FallbackTemplateMessageItemBody, { className: className, message: message, isByMe: isByMe });
};
if (!(templateData === null || templateData === void 0 ? void 0 : templateData.key)) {
return getFailedBody();
}
var templateKey = templateData.key;
var state = useSendbird().state;
if (!state) {
return getFailedBody();
}
var logger = state.config.logger;
var _f = state.utils, getCachedTemplate = _f.getCachedTemplate, updateMessageTemplatesInfo = _f.updateMessageTemplatesInfo;
var waitingTemplateKeysMap = state.stores.appInfoStore.waitingTemplateKeysMap;
var waitingTemplateKeysMapString = Object.entries(waitingTemplateKeysMap)
.map(function (_a) {
var key = _a[0], value = _a[1];
return [key, value.requestedAt, value.erroredMessageIds.join(',')].join('-');
}).join('_');
var _g = useState(getFilledMessageTemplateItems()), renderData = _g[0], setRenderData = _g[1];
function findSubstrings(input, matchString) {
var indices = [];
var startIndex = 0;
while ((startIndex = input.indexOf(matchString, startIndex)) !== -1) {
indices.push({ start: startIndex, end: startIndex + matchString.length });
startIndex += matchString.length;
}
return indices;
}
function replaceAtIndices(input, indices, replacement) {
var result = '';
var lastIndex = 0;
indices.forEach(function (_a) {
var start = _a.start, end = _a.end;
result += input.slice(lastIndex, start) + replacement;
lastIndex = end;
});
// Add any remaining part of the string after the last match
result += input.slice(lastIndex);
return result;
}
function replaceReservationKeys(templateString, reservationKey, replacement) {
var indices = findSubstrings(templateString, reservationKey);
return replaceAtIndices(templateString, indices, replacement);
}
/**
* Returns filled rootTemplate. Given rootTemplate,
* 1. replace any reservation key with matching cached template,
* 2. fill variables and view_variables.
*
* Assume below facts:
* - carousel type template cannot have a carousel typed template in any
* depth of items.
* - However, box type template can have a carousel typed template in any
* depth of items.
*
* @param rootTemplate
*/
function getFilledRootTemplate(rootTemplate) {
var rootTemplateString = replaceVariablesInTemplateString({
template: rootTemplate.uiTemplate,
templateData: templateData.variables,
colorVariables: rootTemplate.colorVariables,
theme: theme,
});
if (templateData.view_variables) {
var reservationKeyToItems_1 = {};
Object.entries(templateData.view_variables).forEach(function (_a) {
var reservationKey = _a[0], simpleTemplateDataList = _a[1];
var filledSimpleTemplates = [];
simpleTemplateDataList.forEach(function (simpleTemplateData) {
var simpleTemplateKey = simpleTemplateData === null || simpleTemplateData === void 0 ? void 0 : simpleTemplateData.key;
if (simpleTemplateKey) {
var cachedTemplate = getCachedTemplate(simpleTemplateKey);
if (!cachedTemplate) {
logger.error('TemplateMessageItemBody | simple template is expected to be cached: ', simpleTemplateKey);
}
var items = replaceVariablesInTemplateString({
template: cachedTemplate.uiTemplate,
templateData: simpleTemplateData.variables,
colorVariables: cachedTemplate.colorVariables,
theme: theme,
});
filledSimpleTemplates.push({
version: cachedTemplate.version,
body: {
items: JSON.parse(items),
},
});
reservationKeyToItems_1[reservationKey] = JSON.stringify(filledSimpleTemplates);
}
});
});
Object.entries(reservationKeyToItems_1).forEach(function (_a) {
var reservationKey = _a[0], filledSimpleTemplates = _a[1];
rootTemplateString = replaceReservationKeys(rootTemplateString, "\"@{".concat(reservationKey, "}\""), filledSimpleTemplates);
});
}
return JSON.parse(rootTemplateString);
}
function getFilledMessageTemplateItems() {
var result = {
filledMessageTemplateItemsList: [],
isErrored: false,
};
var nonCachedTemplateKeys = [];
var cachedTemplate = getCachedTemplate(templateKey);
if (!cachedTemplate) {
nonCachedTemplateKeys.push(templateKey);
}
if (templateData === null || templateData === void 0 ? void 0 : templateData.view_variables) {
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Object.entries(templateData.view_variables).forEach(function (_a) {
var _ = _a[0], simpleTemplateDataList = _a[1];
simpleTemplateDataList.forEach(function (simpleTemplateData) {
var simpleTemplateKey = simpleTemplateData === null || simpleTemplateData === void 0 ? void 0 : simpleTemplateData.key;
if (simpleTemplateKey
&& !getCachedTemplate(simpleTemplateKey)
&& !nonCachedTemplateKeys.includes(simpleTemplateKey)) {
nonCachedTemplateKeys.push(simpleTemplateKey);
}
});
});
}
catch (e) {
logger.error('TemplateMessageItemBody | received view_variables is malformed: ', templateData);
result.isErrored = true;
return result;
}
}
try {
if (nonCachedTemplateKeys.length > 0) {
tryFetchTemplateByKey(nonCachedTemplateKeys);
}
else if (cachedTemplate) {
var items = getFilledRootTemplate(cachedTemplate);
result.filledMessageTemplateItemsList.push({
version: cachedTemplate.version,
items: items,
});
}
}
catch (e) {
logger.error('TemplateMessageItemBody | fetching non-cached templates by given template keys failed: ', e);
result.isErrored = true;
}
return result;
}
useEffect(function () {
if (!renderData.isErrored && renderData.filledMessageTemplateItemsList.length === 0) {
var newRenderData = getFilledMessageTemplateItems();
setRenderData(newRenderData);
}
}, [templateData.key, waitingTemplateKeysMapString]);
/**
* Attempt GET template by key IFF one of below cases is met:
* 1. This is the first GET call for the template key.
* 2. Minimum buffer time has passed since the previous GET error.
*/
function tryFetchTemplateByKey(templateKeys) {
if (templateKeys.length > 0) {
var waitingTemplateKeyDataList_1 = [];
templateKeys.forEach(function (templateKey) {
var waitingTemplateKeyData = waitingTemplateKeysMap[templateKey];
waitingTemplateKeyDataList_1.push([templateKey, waitingTemplateKeyData]);
});
var requestedAt_1 = Date.now();
var keysToUpdate_1 = [];
waitingTemplateKeyDataList_1.forEach(function (_a) {
var templateKey = _a[0], waitingTemplateKeyData = _a[1];
if (!waitingTemplateKeyData
|| (waitingTemplateKeyData.erroredMessageIds.indexOf(message.messageId) === -1
&& requestedAt_1 > waitingTemplateKeyData.requestedAt + TEMPLATE_FETCH_RETRY_BUFFER_TIME_IN_MILLIES)) {
keysToUpdate_1.push(templateKey);
}
else if (waitingTemplateKeyData.erroredMessageIds.indexOf(message.messageId) > -1) {
throw new Error("TemplateMessageItemBody | fetching template key ".concat(templateKey, " for messageId: ").concat(message.messageId, " has failed."));
}
});
if (keysToUpdate_1.length > 0) {
updateMessageTemplatesInfo(keysToUpdate_1, message.messageId, requestedAt_1);
}
}
}
if (renderData.isErrored) {
return getFailedBody();
}
if (renderData.filledMessageTemplateItemsList.length === 0) {
return React__default.createElement(LoadingTemplateMessageItemBody, { className: className, isByMe: isByMe });
}
return (React__default.createElement("div", { className: getClassName([
className,
isByMe ? 'outgoing' : 'incoming',
'sendbird-template-message-item-body',
]) },
React__default.createElement(MessageTemplateErrorBoundary, { fallbackMessage: React__default.createElement(FallbackTemplateMessageItemBody, { className: className, message: message, isByMe: isByMe }), logger: logger }, renderData.filledMessageTemplateItemsList.map(function (filledMessageTemplateItem, i) {
var _a;
return (React__default.createElement(MessageTemplateWrapper, { key: i, message: message, templateVersion: (_a = filledMessageTemplateItem.version) !== null && _a !== void 0 ? _a : 0, templateItems: filledMessageTemplateItem.items }));
}))));
}
export { TemplateMessageItemBody, TemplateMessageItemBody as default, replaceVariablesInTemplateString };
//# sourceMappingURL=TemplateMessageItemBody.js.map