UNPKG

@cometchat/chat-uikit-react-native

Version:

Ready-to-use Chat UI Components for React Native

410 lines 14.8 kB
import { CometChat } from "@cometchat/chat-sdk-react-native"; import React from "react"; import { Text } from "react-native"; import { CometChatUIKit } from "../../CometChatUiKit"; import { MentionsTargetElement, MentionsType, MentionsVisibility, } from "../../constants/UIKitConstants"; import { CometChatUIEventHandler, CometChatUIEvents } from "../../events"; import { localize } from "../../resources"; import { SuggestionItem } from "../../views/CometChatSuggestionList"; import { CometChatTextFormatter } from "../CometChatTextFormatter"; /** * Represents the CometChatMentionsFormatter class. * This class extends the CometChatTextFormatter class and provides methods for handling mentions in text. * @extends CometChatTextFormatter */ export class CometChatMentionsFormatter extends CometChatTextFormatter { /** * List of users for mentions. */ SuggestionItems = []; /** * List of searched data. */ searchData = []; /** * Stores the formatting style for mentions. */ mentionsStyle; /** * Default search request object to fetch users or group members. */ searchRequest; /** * Custom request object to fetch users or group members. */ customRequest; /** * Limit of unique users to be added in the composer. */ limit = 10; /** * visibleIn property to determine where the mentions should be visible. * @type {MentionsVisibility} * @default MentionsVisibility.both */ visibleIn = MentionsVisibility.both; /** * type property to determine the type of mention list. * @type {MentionsType} * @default MentionsType.usersAndGroupMembers */ type = MentionsType.usersAndGroupMembers; /** * type property to determine the type of mention list. * @type {MentionsType} * @default MentionsType.usersAndGroupMembers */ target = MentionsTargetElement.textbubble; textStyle = {}; /** * Initializes a new CometChatMentionsFormatter. * @param {CometChat.User} loggedInUser - The user who is currently logged in. */ constructor(loggedInUser) { super(); this.regexPattern = /<@uid:(.*?)>/g; this.trackCharacter = "@"; this.loggedInUser = loggedInUser; } /** * Sets the message object. * * @param {CometChat.BaseMessage} messageObject - The message object to be set. */ setMessage(messageObject) { this.messageObject = messageObject; let mentionedUsers = (messageObject?.getMentionedUsers && messageObject?.getMentionedUsers()) || []; let cometchatUIUserArray = this.convertCCUsersToSuggestionsItem(mentionedUsers); this.setSuggestionItems(cometchatUIUserArray); } setTargetElement(target) { this.target = target; } setTextStyle(textStyle) { this.textStyle = textStyle; } handlePreMessageSend(message) { let CCUsers = this.getSuggestionItems().map((item) => { let user = new CometChat.User(item.id); user.setAvatar(item?.leadingIconUrl); user.setName(item?.name); return user; }); message.setMentionedUsers(CCUsers); return message; } handleComposerPreview(message) { let users = this.convertCCUsersToSuggestionsItem(message.getMentionedUsers()); this.setSuggestionItems(users); } convertCCUsersToSuggestionsItem(users) { return users.map((item) => { return new SuggestionItem({ id: item?.getUid(), name: item?.getName(), promptText: "@" + item?.getName(), trackingCharacter: "@", underlyingText: `<@uid:${item?.getUid()}>`, leadingIconUrl: item?.getAvatar(), hideLeadingIcon: false, }); }); } /** * Sets the search request builder. * @param requestBuilder - The request builder to set. */ setSearchRequestBuilder(requestBuilder) { this.customRequest = requestBuilder; } shouldLoadLocalData(searchKey) { if (this.getUniqueUsersList().size >= this.limit) { let data = searchKey ? [...this.SuggestionItems].filter((item) => item.name?.toLowerCase().includes(searchKey.trim().toLowerCase()) || item.id.toLowerCase().includes(searchKey.trim().toLowerCase())) : [...this.SuggestionItems]; this.searchData = [...data]; this.setSearchData(this.searchData); return true; } return false; } search(searchKey) { if (this.shouldLoadLocalData(searchKey)) return; let requestBuilder = this.customRequest || (this.group && this.type === MentionsType.usersAndGroupMembers ? new CometChat.GroupMembersRequestBuilder(this.group.getGuid()) : new CometChat.UsersRequestBuilder()); this.searchRequest = requestBuilder.setLimit(10).setSearchKeyword(searchKey).build(); this.searchData = []; this.fetchNext(true); } fetchNext(freshCall) { if (this.getUniqueUsersList().size >= this.limit) return; this.searchRequest?.fetchNext && this.searchRequest ?.fetchNext() .then((users) => { let structuredData = this.convertCCUsersToSuggestionsItem(users); this.searchData = freshCall ? [...structuredData] : [...this.searchData, ...structuredData]; this.setSearchData(this.searchData); }) .catch((err) => { console.log("searchRequest fetchNext failed:", err); this.setSearchData(this.searchData); }); } setSearchData(data) { this.searchData = [...data]; CometChatUIEventHandler.emitUIEvent(CometChatUIEvents.ccSuggestionData, { id: this.composerId, data: [...this.searchData], }); } /** * Sets the limit of unique users to be added in the composer. */ setLimit(limit) { this.limit = limit; } /** * Retrieves the limit of unique users to be added in the composer. */ getLimit() { return this.limit; } /** * Retrieves the unique users list. */ getUniqueUsersList() { // A Set to store unique user IDs const uniqueUserIds = new Set(); // Populate the Set with user IDs from the existing user list this.SuggestionItems.forEach((user) => uniqueUserIds.add(user.id)); return uniqueUserIds; } /** * Retrieves the message object. * * @returns {CometChat.BaseMessage} - The current message object. */ getMessage() { return this.messageObject; } /** * Sets the regex pattern for matching text. * * @param {<RegExp>} regexPattern - Regex patterns. */ setRegexPattern = (regexPattern) => { this.regexPattern = regexPattern; }; /** * Gets the regex pattern for matching text. */ getRegexPattern = () => { return this.regexPattern; }; /** * Retrieves the SuggestionItems. * * @returns {Array<SuggestionItem>} - The current SuggestionItems. */ getSuggestionItems() { return this.SuggestionItems; } /** * Sets the SuggestionItems. * * @param {Array<SuggestionItem>} SuggestionItems - The SuggestionItems to be set. */ setSuggestionItems(SuggestionItems) { this.SuggestionItems = [...SuggestionItems]; } /** * Retrieves the mentions style. * * @returns {CometChatTheme["mentionsStyle"]} - The current mentions style. */ getMentionsStyle() { return this.mentionsStyle; } /** * Sets the mentions style. * * @param {CometChatTheme["mentionsStyle"]} mentionsStyle - The mentions style to be set. */ setMentionsStyle(mentionsStyle) { this.mentionsStyle = mentionsStyle; } getFormattedText(inputText, textStyle) { if (!inputText) { return ""; } let formattedText = this.addMentionsView(inputText, textStyle); return formattedText; } temp; setOnMentionClick(callBack) { // callBack(this.messageObject, "uid"); this.temp = callBack; } /** * Emits the event for mention click. * @param {any} event - The event object. * @param {string} uid - The user id. */ onMentionClick = (event, uid) => { if (this.temp) { this.temp(this.messageObject, uid); return; } // let obj = { uid, trackCharacter: this.trackCharacter }; // CometChatUIEventHandler.emitUIEvent(CometChatUIEvents.ccMentionClick, { // item: { // body: { // CometChatUserGroupMembersObject: obj, // message: this.messageObject ?? null, // id: uid, // }, // // event, // source: "mentions", //add through enum // } // }); }; /** * This function adds the mention view to the input text. * * @param {string} inputText - The input text where the view needs to be added. * @returns {string} - The modified input text. */ addMentionsView(inputText, textStyle = {}) { if (typeof inputText === "string") { let mentions = []; if (this.SuggestionItems) { const userRegistry = {}; for (let i = 0; i < this.SuggestionItems?.length; i++) { const userUid = this.SuggestionItems[i].id; const userName = this.SuggestionItems[i].promptText; userRegistry[userUid] = userName; } // Define the regex pattern const regex = this.getRegexPattern(); // Break the string into segments split by the regex let match; let lastIndex = 0; let segments = []; while ((match = regex.exec(inputText)) !== null) { // Add preceding non-UID segment, if any if (match.index > lastIndex) { segments.push(inputText.slice(lastIndex, match.index)); } // Add UID segment segments.push(match[1]); // Update lastIndex lastIndex = match.index + match[0].length; } // Append trailing non-UID segment, if any if (lastIndex < inputText.length) { segments.push(inputText.slice(lastIndex)); } // Now create an array of JSX elements from the segments const elements = segments.map((segment, index) => { // Check if segment is a UID if (userRegistry.hasOwnProperty(segment)) { let _loggedInUser = this.loggedInUser || CometChatUIKit.loggedInUser; let textStyle = _loggedInUser?.getUid() == segment ? this.getMentionsStyle()?.selfTextStyle : this.getMentionsStyle()?.textStyle; let onPressProp = this.temp ? { onPress: (event) => this.onMentionClick(event, segment) } : {}; if (this.target === MentionsTargetElement.textbubble) { return ( // <View> <Text suppressHighlighting={true} key={index} {...onPressProp} style={[textStyle]}> {userRegistry[segment]} </Text> // </View> ); } //conv return (<Text suppressHighlighting={true} key={index} {...onPressProp} style={[textStyle]}> {userRegistry[segment]} </Text>); } else { if (this.target === MentionsTargetElement.textbubble) return ( // <View> <Text key={index} style={{ ...this.textStyle }}> {segment} </Text> // </View> ); //conv return (<Text key={index} style={{ ...this.textStyle }}> {segment} </Text>); } }); if (elements.length > 0) return <Text style={textStyle}>{elements.map((item) => item)}</Text>; } return inputText; } else if (React.isValidElement(inputText)) { // inputText is a React element if (inputText.props.children) { // If the React element have children, we map over these children // and call addMentionsView recursively for each child. return React.cloneElement(inputText, { children: React.Children.map(inputText.props.children, (child) => { return this.addMentionsView(child); }), }); } else { // If the React element does not have children, return it as is return inputText; } } else { throw new Error(`Unsupported inputText type: ${typeof inputText}`); } } /** * Sets the type of mention list. * @param type - The type of mention list. */ setType(type) { this.type = type; } /** * Sets the visibleIn property to determine where the mentions should be visible. * @param visibleIn - The visibleIn property to set. */ setVisibleIn(visibleIn) { this.visibleIn = visibleIn; } /** * Retrieves the visibleIn property to determine where the mentions should be visible. */ getVisibleIn() { return this.visibleIn; } /** * Retrieves the type of mention list. */ getType() { return this.type; } getErrorString() { return `${localize("MENTION_UPTO")} ${this.limit} ${this.limit === 1 ? localize("TIME") : localize("TIMES")} ${localize("AT_A_TIME")}.`; } } //# sourceMappingURL=CometChatMentionsFormatter.js.map