UNPKG

react-native-chating-ui-kit

Version:

CometChat React Native UI Kit is a collection of custom UI Components designed to build text , chat and calling features in your application. The UI Kit is developed to keep developers in mind and aims to reduce development efforts significantly

348 lines (347 loc) 19.5 kB
import React from "react"; import { View, Text, Alert, TouchableOpacity, Image, Modal } from "react-native"; import { downArrowIcon, rightTickIcon } from "./resources"; import { AvatarStyle, CometChatContext, ListItemStyle, StatusIndicatorStyle } from "../shared"; import { GroupMembersStyle } from "./GroupMemberStyle"; //@ts-ignore import { CometChat } from "@cometchat-pro/react-native-chat"; import { CometChatListItem } from "../shared"; import { CometChatList } from "../shared"; import { BorderStyle, FontStyle } from "../shared"; import { getDefaultGroupMemberOptions, validateGroupMemberOptions } from "../shared/utils/DetailsUtils/DetailsUtils"; import { GroupMemberOptionConstants, MessageTypeConstants } from "../shared/constants/UIKitConstants"; import { localize } from "../shared"; import { Style } from "./style"; import { GroupScopeStyle } from "./GroupScopeStyle"; import { CometChatGroupsEvents } from "../shared/events"; import { getUnixTimestamp } from "../shared/utils/CometChatMessageHelper"; import { CometChatUIEventHandler } from "../shared/events/CometChatUIEventHandler/CometChatUIEventHandler"; const groupListenerId = "grouplist_" + new Date().getTime(); export const CometChatGroupsMembers = (props) => { const { SubtitleView, ListItemView, AppBarOptions, options, hideSeparator, searchPlaceholderText, backButtonIcon, showBackButton, selectionMode = "multiple", onSelection, searchBoxIcon, hideSearch, title = localize("MEMBERS"), EmptyStateView, emptyStateText, ErrorStateView, errorStateText, LoadingStateView, groupMemberRequestBuilder, searchRequestBuilder, group, hideError, onItemPress, onItemLongPress, onError, onBack, groupMemberStyle, listItemStyle, avatarStyle, statusIndicatorStyle, groupScopeStyle, TailView, selectionIcon } = props; const { theme } = React.useContext(CometChatContext); const _groupMemberStyle = new GroupMembersStyle({ backgroundColor: theme?.palette.getBackgroundColor(), backIconTint: theme?.palette.getPrimary(), emptyTextColor: theme?.palette.getAccent400(), emptyTextFont: theme?.typography.caption2, errorTextColor: theme?.palette.getError(), errorTextFont: theme?.typography.subtitle1, searchBackgroundColor: theme?.palette.getAccent600(), searchIconTint: theme?.palette.getAccent600(), searchTextColor: theme?.palette.getAccent(), searchTextFont: theme?.typography.caption1, separatorColor: theme?.palette.getAccent100(), titleColor: theme?.palette.getAccent(), titleFont: theme?.typography.title1, onlineStatusColor: theme?.palette.getSuccess(), ...groupMemberStyle }); const _avatarStyle = new AvatarStyle({ backgroundColor: theme?.palette.getSecondary(), nameTextColor: theme?.palette.getAccent(), nameTextFont: theme?.typography.title1, ...avatarStyle }); const _statusIndicatorStyle = new StatusIndicatorStyle(statusIndicatorStyle || {}); const _listItemStyle = new ListItemStyle({ backgroundColor: theme?.palette?.getBackgroundColor(), titleColor: theme?.palette.getAccent(), titleFont: theme?.typography.name, ...listItemStyle }); const _groupScopeStyle = new GroupScopeStyle({ backgroundColor: theme?.palette.getBackgroundColor(), arrowIconTint: theme?.palette.getPrimary(), optionTextColor: theme?.palette.getAccent(), selectedOptionBackgroundColor: theme?.palette.getAccent400(), optionTextFont: theme?.typography.text1, selectedOptionTextColor: theme?.palette.getAccent(), selectedOptionTextFont: theme?.typography.text1, ...groupScopeStyle }); const groupMemberListenerId = 'groupMemberList_' + new Date().getTime(); const groupRef = React.useRef(null); const itemRef = React.useRef(null); const loggedInUser = React.useRef(null); const [selecting, setSelecting] = React.useState(selectionMode ? true : false); const [selectedMembers, setSelectedMembers] = React.useState([]); const swipeOptions = (member, onKick, onBan) => { let arr = getDefaultGroupMemberOptions(group, member, theme); return arr.map(option => { if (option.id == GroupMemberOptionConstants.kick) option.onPress = onKick; if (option.id == GroupMemberOptionConstants.ban) option.onPress = onBan; return option; }); }; const banUser = (user) => { //logic to ban user CometChat.banGroupMember(group['guid'], user.uid) .then((response) => { groupRef.current && groupRef.current.removeItemFromList(user.uid); let action = new CometChat.Action(group['guid'], MessageTypeConstants.groupMember, CometChat.RECEIVER_TYPE.GROUP, CometChat.CATEGORY_ACTION); action.setActionBy(loggedInUser.current); action.setActionOn(user); action.setActionFor(group); action.setMessage(`${loggedInUser.current.name} banned ${user.name}`); action.setSentAt(getUnixTimestamp()); action.setMuid(String(getUnixTimestamp())); action.setSender(loggedInUser.current); action.setReceiver(group); //reducing members count by one group.setMembersCount(group.getMembersCount() - 1); CometChatUIEventHandler.emitGroupEvent(CometChatGroupsEvents.ccGroupMemberBanned, { message: action, kickedUser: user, kickedBy: loggedInUser.current, kickedFrom: group }); }) .catch((err) => { console.log("ban user", err); onError(err); }); }; const kickUser = (id, user) => { //logic to kick user CometChat.kickGroupMember(group['guid'], id) .then((response) => { groupRef.current && groupRef.current.removeItemFromList(id); //reducing members count by one group.setMembersCount(group.getMembersCount() - 1); let action = new CometChat.Action(group['guid'], MessageTypeConstants.groupActions, CometChat.RECEIVER_TYPE.GROUP, CometChat.CATEGORY_ACTION); action.setActionBy(loggedInUser.current); action.setActionOn(user); action.setActionFor(group); action.setMessage(`${loggedInUser.current.name} kicked ${user.name}`); action.setSentAt(getUnixTimestamp()); action.setMuid(String(getUnixTimestamp())); action.setSender(loggedInUser.current); action.setReceiver(group); CometChatUIEventHandler.emitGroupEvent(CometChatGroupsEvents.ccGroupMemberKicked, { message: action, kickedUser: user, kickedBy: loggedInUser.current, kickedFrom: group }); }) .catch((err) => { console.log("kick user", err); onError(err); }); }; const itemPress = (item) => { if (!selecting) return; if (selectionMode == "single") setSelectedMembers([item]); if (selectionMode == "multiple") setSelectedMembers([...selectedMembers, item]); }; const itemLongPress = (item) => { if (!selecting) setSelecting(true); if (selectionMode == "single") { if (selectedMembers.length > 0 && selectedMembers[0].uid == item.uid) setSelectedMembers([]); else setSelectedMembers([item]); return; } const index = selectedMembers.findIndex((value) => value.uid == item.uid); if (index >= 0) { let tmp = [...selectedMembers]; tmp.splice(index, 1); setSelectedMembers([...tmp]); } else { setSelectedMembers([...selectedMembers, group]); } return; }; const ItemView = ({ item: member, ...props }) => { if (ListItemView) return <ListItemView {...member}/>; let image, backgroundColor; if (selecting) { let index = selectedMembers.findIndex((value) => value.uid == member.uid); if (index >= 0) { image = rightTickIcon; backgroundColor = theme?.palette.getBackgroundColor(); } } //Note: Check props which are need here return <CometChatListItem id={member.uid} onPress={itemPress.bind(this, member)} onLongPress={itemLongPress.bind(this, member)} SubtitleView={SubtitleView ? () => <SubtitleView {...member}/> : null} //Note: should return prop to SubtitleView statusIndicatorIcon={image} statusIndicatorColor={backgroundColor} title={member.uid == loggedInUser.current.uid ? "You" : member.name} avatarName={member.name} avatarURL={member.avatar} listItemStyle={_listItemStyle} avatarStyle={_avatarStyle} statusIndicatorStyle={_statusIndicatorStyle} TailView={TailView ? () => <TailView {...member}/> : ScopeChangeUI.bind(this, member, groupScopeStyle)} //Note: should return prop to TailView options={() => (options && options(member)) || swipeOptions(member, (id) => kickUser(id, member), () => banUser(member))} //Note: should have options />; }; const ScopeChangeUI = (member, style) => { const [showChangeScope, setShowChangeScope] = React.useState(false); const { height = "100%", width = "100%", backgroundColor = _groupMemberStyle.backgroundColor, border = new BorderStyle({}), borderRadius = 4, titleTextFont = new FontStyle({ fontSize: 14 }), } = style || {}; const onOptionSelection = (newScope) => { if (member['scope'] == group['scope'] && group['owner'] == member['uid']) { Alert.alert("you can not remove yourself from admin as Transfer Ownership is not yet done."); return; } CometChat.updateGroupMemberScope(group['guid'], member.uid, newScope) .then((res) => { let updatedMember = { ...member, scope: newScope }; groupRef.current?.updateList(updatedMember); setShowChangeScope(false); let action = new CometChat.Action(group['guid'], "groupMember", CometChat.RECEIVER_TYPE.GROUP, CometChat.CATEGORY_ACTION); action.setActionBy(loggedInUser.current); action.setActionOn(member); action.setActionFor(group); action.setMessage(`${loggedInUser.current.name} made ${member.name} ${newScope}`); action.setSentAt(getUnixTimestamp()); action.setMuid(String(getUnixTimestamp())); action.setSender(loggedInUser.current); action.setReceiver(group); CometChatUIEventHandler.emitGroupEvent(CometChatGroupsEvents.ccGroupMemberScopeChanged, { action, updatedUser: updatedMember, scopeChangedTo: newScope, scopeChangedFrom: member.scope, group }); }) .catch(err => { console.log("Error:", err); setShowChangeScope(false); onError && onError(err); }); }; const OptionButton = ({ title, isCurrent }) => { return <TouchableOpacity style={{ flexDirection: "row", justifyContent: "center", width: "100%", backgroundColor: _groupScopeStyle.optionBackgroundColor, borderRadius: _groupScopeStyle.optionBorderRadius, ..._groupScopeStyle.optionBorder }} activeOpacity={1} onPress={onOptionSelection.bind(this, title)}> <Text style={[ Style.optionTextStyle, { ...isCurrent && _groupScopeStyle.selectedOptionTextFont || _groupScopeStyle.optionTextFont, color: isCurrent && _groupScopeStyle.selectedOptionTextColor || _groupScopeStyle.optionTextColor, backgroundColor: isCurrent && _groupScopeStyle.selectedOptionBackgroundColor || _groupScopeStyle.backgroundColor || "transparent", borderRadius: isCurrent && _groupScopeStyle.selectedOptionBorderRadius || _groupScopeStyle.optionBorderRadius, } ]}>{title}</Text> </TouchableOpacity>; }; let changeScopeOptions = validateGroupMemberOptions(group['scope'], member['scope'], GroupMemberOptionConstants.changeScope); const ChangeScopeDialog = () => { return <Modal transparent> <TouchableOpacity activeOpacity={1} style={[Style.changeDialogContainer, { backgroundColor: theme.palette.getAccent200() }]} onPress={() => setShowChangeScope(false)}> <View style={[ Style.changeDialogView, { backgroundColor: _groupScopeStyle.backgroundColor } ]}> <Text style={[Style.changeDialogTitle, { color: _groupScopeStyle.optionTextColor }]}>{localize("CHANGE_SCOPE")}</Text> <View style={{ width: _groupScopeStyle.width, backgroundColor: _groupScopeStyle.backgroundColor, borderRadius: _groupMemberStyle.borderRadius, ..._groupScopeStyle.border, }}> {changeScopeOptions.map(option => { return <OptionButton key={option} title={option} isCurrent={member['scope'] == option}/>; })} </View> </View> </TouchableOpacity> </Modal>; }; if (member['scope'] == group['scope'] && group['owner'] == member['uid']) { return <Text style={{ ...titleTextFont, color: _groupScopeStyle.optionTextColor }}>{localize("OWNER")}</Text>; } return <View style={{ height, width, alignItems: "center", justifyContent: "center", backgroundColor: backgroundColor, ...border, borderRadius: borderRadius }}> {showChangeScope ? <ChangeScopeDialog /> : null} <TouchableOpacity ref={itemRef} activeOpacity={1} onPress={() => setShowChangeScope(changeScopeOptions?.length > 0 ? !showChangeScope : false)}> <View style={{ flexDirection: "row" }}> <Text style={{ ...titleTextFont, color: _groupScopeStyle.optionTextColor }}>{group['owner'] == member.uid ? "owner" : member.scope}</Text> {changeScopeOptions?.length > 0 ? <Image style={{ height: 16, width: 16, tintColor: _groupScopeStyle.arrowIconTint }} source={downArrowIcon}/> : null} </View> </TouchableOpacity> </View>; }; const onSelectionClicked = () => { onSelection && onSelection(selectedMembers); setSelectedMembers([]); setSelecting(false); }; /** * * Listener callback when a member is kicked from / has left the group */ const handleGroupMemberRemoval = (...options) => { const groupMember = options[1]; groupRef.current.removeItemFromList(groupMember.uid); }; /** * * Listener callback when a member is banned from the group */ const handleGroupMemberBan = (...options) => { const groupMember = options[1]; groupRef.current.removeItemFromList(groupMember.uid); }; /** * * Listener callback when a user joins/added to the group */ const handleGroupMemberAddition = (...options) => { const groupMember = options[1]; let newGroupMember = { ...groupMember, scope: CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT }; groupRef.current.addItemToList(newGroupMember); }; /** * * Listener callback when a group member scope is updated */ const handleGroupMemberScopeChange = (...options) => { const groupMember = options[1]; let newScope = { ...groupMember, scope: options[2] }; groupRef.current.updateList(newScope); }; React.useEffect(() => { CometChat.getLoggedinUser() .then(u => loggedInUser.current = u) .catch(e => console.log(e)); CometChat.addUserListener(groupMemberListenerId, new CometChat.UserListener({ onUserOnline: (onlineUser) => { /* when someuser/friend comes online, user will be received here */ groupRef.current.updateUser(onlineUser); }, onUserOffline: (offlineUser) => { /* when someuser/friend went offline, user will be received here */ groupRef.current.updateUser(offlineUser); }, })); CometChat.addGroupListener(groupListenerId, new CometChat.GroupListener({ onGroupMemberScopeChanged: (message, changedUser, newScope, oldScope, changedGroup) => { handleGroupMemberScopeChange(message, changedUser, newScope, oldScope, changedGroup); }, onGroupMemberKicked: (message, kickedUser, kickedBy, kickedFrom) => { handleGroupMemberRemoval(message, kickedUser, kickedBy, kickedFrom); }, onGroupMemberLeft: (message, leavingUser, group) => { handleGroupMemberRemoval(message, leavingUser, null, group); }, onGroupMemberBanned: (message, bannedUser, bannedBy, bannedFrom) => { handleGroupMemberBan(message, bannedUser, bannedBy, bannedFrom); }, onMemberAddedToGroup: (message, userAdded, userAddedBy, userAddedIn) => { handleGroupMemberAddition(message, userAdded, userAddedBy, userAddedIn); }, onGroupMemberJoined: (message, joinedUser, joinedGroup) => { handleGroupMemberAddition(message, joinedUser, null, joinedGroup); }, })); return () => { CometChat.removeGroupListener(groupListenerId); CometChat.removeUserListener(groupMemberListenerId); }; }, []); return <CometChatList ref={groupRef} listItemKey={"uid"} SubtitleView={SubtitleView} AppBarOptions={AppBarOptions} hideSeparator={hideSeparator || true} searchPlaceholderText={searchPlaceholderText} backButtonIcon={backButtonIcon} showBackButton={showBackButton || true} ListItemView={ItemView} selectionMode={selecting ? selectionMode : "none"} onSelection={onSelectionClicked} searchBoxIcon={searchBoxIcon} hideSearch={hideSearch} title={title || localize("MEMBERS")} EmptyStateView={EmptyStateView} emptyStateText={emptyStateText} ErrorStateView={ErrorStateView} errorStateText={errorStateText} LoadingStateView={LoadingStateView} searchRequestBuilder={searchRequestBuilder} requestBuilder={groupMemberRequestBuilder || new CometChat.GroupMembersRequestBuilder(group['guid']).setLimit(30)} hideError={hideError} onItemPress={onItemPress} onItemLongPress={onItemLongPress} onError={onError} onBack={onBack} listStyle={{ ..._groupMemberStyle, background: _groupMemberStyle.backgroundColor }} listItemStyle={listItemStyle} avatarStyle={avatarStyle} statusIndicatorStyle={statusIndicatorStyle} selectionIcon={selectionIcon}/>; }; //# sourceMappingURL=CometChatGroupMembers.js.map