UNPKG

@rohitninawe/chat-uikit-react-native

Version:

Ready-to-use Chat UI Components for React Native

242 lines (239 loc) 12.5 kB
import { View, Text, ScrollView, TouchableOpacity, FlatList, Image } from 'react-native'; import React, { useState, useEffect, useContext, useRef, useCallback } from 'react'; import { CometChat } from '@cometchat/chat-sdk-react-native'; import { CometChatListItem } from '../CometChatListItem'; import { CometChatContext } from '../../CometChatContext'; import { ReactionListStyle } from './ReactionListStyle'; import { localize } from '../../resources'; import { LoadingIcon } from './resources'; import { CommonUtils } from '../../utils/CommonUtils'; export const CometChatReactionList = (props) => { const { messageObject, onPress, reactionRequestBuilder, avatarStyle, listItemStyle, selectedReaction, reactionListStyle, ErrorStateView, errorStateText, loadingIconURL, LoadingStateView, } = props; const { theme } = useContext(CometChatContext); const [messageReactions, setMessageReactions] = useState(messageObject?.getReactions() || []); const [currentSelectedReaction, setCurrentSelectedReaction] = useState(selectedReaction || "All"); const [reactionList, setReactionList] = useState([]); const [state, setState] = useState("loading"); const loggedInUser = useRef(); const newMessageObj = useRef(CommonUtils.clone(messageObject)); let requestBuilderMap = useRef({}); let reactionListMap = useRef({}); const _style = new ReactionListStyle({ subtitleColor: reactionListStyle?.subtitleColor || theme.palette.getAccent600(), subtitleFont: reactionListStyle?.subtitleFont || theme.typography.subtitle2, activeEmojiBackgroundColor: reactionListStyle?.activeEmojiBackgroundColor || theme.palette.getAccent100(), sliderEmojiCountColor: reactionListStyle?.sliderEmojiCountColor || theme.palette.getAccent700(), tailViewFont: reactionListStyle?.tailViewFont || theme.typography.title1, sliderEmojiCountFont: reactionListStyle?.sliderEmojiCountFont || theme.typography.subtitle1, sliderEmojiFont: reactionListStyle?.sliderEmojiFont || theme.typography.subtitle1, errorTextColor: reactionListStyle?.errorTextColor || theme?.palette?.getError(), errorTextFont: reactionListStyle?.errorTextFont || theme?.typography?.subtitle1, loadingTint: reactionListStyle?.loadingTint || theme?.palette.getAccent700(), separatorColor: reactionListStyle?.separatorColor || theme.palette.getAccent100(), ...reactionListStyle, }); const { subtitleColor, subtitleFont, activeEmojiBackgroundColor, sliderEmojiCountColor, tailViewFont, sliderEmojiCountFont, sliderEmojiFont, errorTextColor, errorTextFont, loadingTint, separatorColor, } = _style; useEffect(() => { CometChat.getLoggedinUser() .then(user => loggedInUser.current = user) .catch(rej => { loggedInUser.current = null; // onError && onError(rej); }); showReactions(true); let newMessageReactions = messageObject?.getReactions() || []; _setAllReactions(newMessageReactions); }, []); useEffect(() => { showReactions(); }, [currentSelectedReaction]); const _setAllReactions = (_messageReactions) => { let totalCount = _messageReactions.reduce((acc, curr) => acc + curr.count, 0); setMessageReactions([{ reaction: "All", count: totalCount }, ..._messageReactions]); }; const showReactions = async (firstFetch) => { const requestBuilder = getRequestBuilder(currentSelectedReaction); const list = await getReactionList(requestBuilder, currentSelectedReaction); if (firstFetch && currentSelectedReaction !== "All") { await getReactionList(getRequestBuilder("All"), "All"); } setReactionList(list); }; const getRequestBuilder = (reaction) => { let requestBuilder; if (requestBuilderMap.current[reaction]) { return requestBuilderMap.current[reaction]; } requestBuilder = reactionRequestBuilder || new CometChat.ReactionsRequestBuilder(); requestBuilder.setLimit(10).setMessageId(messageObject?.getId()); if (reaction !== "All") { requestBuilder.setReaction(reaction); } const request = requestBuilder.build(); requestBuilderMap.current[reaction] = request; return request; }; const getReactionList = async (requestBuilder, reaction) => { setState("loading"); if (reactionListMap.current[reaction]) { setState("done"); let list = reactionListMap.current[reaction]; return list; } try { const list = await requestBuilder.fetchNext(); reactionListMap.current[reaction] = list; setState("done"); return list; } catch (error) { console.log("error while fetching reactions", error); if (error?.code === "REQUEST_IN_PROGRESS") return; setState("error"); return []; } }; const fetchNext = async () => { try { const requestBuilder = getRequestBuilder(currentSelectedReaction); if (reactionListMap.current[currentSelectedReaction]?.length === 0) { return; } else { const newList = await requestBuilder.fetchNext(); reactionListMap.current[currentSelectedReaction] = [ ...(reactionListMap.current?.[currentSelectedReaction] || []), ...newList, ]; setReactionList(reactionListMap.current[currentSelectedReaction]); } setState("done"); } catch (error) { console.log("error while fetching next reactions", error); if (error?.code === "REQUEST_IN_PROGRESS") return; setState("error"); } }; const removeReaction = (reactionObj) => { let reactedByMe = loggedInUser.current.uid === reactionObj?.getReactedBy()?.getUid(); if (reactedByMe) { if (onPress) { onPress(reactionObj, newMessageObj.current); } // const messageId = messageObject?.getId(); // const emoji = reactionObj?.reaction; // CometChat.removeReaction(messageId, emoji) // .then((message) => { // CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageEdited, { message: message, status: messageStatus.success }); let newReactionList = [...reactionList]?.filter(reaction => reaction?.id !== reactionObj?.id); setReactionList(newReactionList); if (currentSelectedReaction === "All") { reactionListMap.current[currentSelectedReaction] = [...newReactionList]; reactionListMap.current[reactionObj?.reaction] = reactionListMap.current[reactionObj?.reaction]?.filter((reaction) => reaction?.id !== reactionObj?.id); } else { reactionListMap.current[currentSelectedReaction] = [...newReactionList]; reactionListMap.current['All'] = reactionListMap.current['All']?.filter((reaction) => reaction?.id !== reactionObj?.id); } let newMessageReactions = [...messageReactions]; let messageReactionIndex = newMessageReactions.findIndex(reaction => reaction?.reaction === reactionObj?.reaction); if (messageReactionIndex > -1) { if (newMessageReactions[messageReactionIndex]?.getCount() > 1) { newMessageReactions[messageReactionIndex].setCount(newMessageReactions[messageReactionIndex].getCount() - 1); newMessageReactions[messageReactionIndex].setReactedByMe(false); newMessageReactions.shift(); _setAllReactions(newMessageReactions); } else { newMessageReactions.splice(messageReactionIndex, 1); newMessageReactions.shift(); _setAllReactions(newMessageReactions); setCurrentSelectedReaction("All"); } } newMessageObj.current.setReactions(newMessageReactions); // }) // .catch(err => console.log("Some error occured in removing reaction", err)); } }; const subtitleView = useCallback((item) => { let reactedByMe = loggedInUser.current.uid === item?.reactedBy?.uid; return (reactedByMe ? <Text style={[{ color: subtitleColor }, subtitleFont]}> {localize("TAP_TO_REMOVE")} </Text> : null); }, []); const _render = ({ item, index }) => { function getName() { let reactedByMe = loggedInUser.current.uid === item?.reactedBy?.uid; return reactedByMe ? localize("YOU") : item?.reactedBy?.name; } return (<> <CometChatListItem id={item?.id || index} title={getName()} avatarStyle={avatarStyle} avatarName={item?.reactedBy?.name} avatarURL={item?.reactedBy?.avatar ? { uri: item?.reactedBy?.avatar } : undefined} SubtitleView={() => subtitleView(item)} TailView={() => <Text style={[tailViewFont, { color: theme?.palette?.getPrimary() }]}>{item?.reaction}</Text>} listItemStyle={{ height: 60, ...listItemStyle }} onPress={(id) => removeReaction(item)}/> <View style={{ height: 1, backgroundColor: separatorColor }}/> </>); }; const ErrorView = () => { if (ErrorStateView) return <ErrorStateView />; return <View style={{ marginTop: 100, justifyContent: "center", alignItems: "center", }}> <Text style={[{ color: errorTextColor, ...errorTextFont }]}>{errorStateText || localize("SOMETHING_WRONG")}</Text> </View>; }; const LoadingView = () => { if (LoadingStateView) return <LoadingStateView />; return <View style={{ marginTop: 100, justifyContent: "center", alignItems: "center", }}> <Image source={loadingIconURL || LoadingIcon} style={[{ height: 24, width: 24, alignSelf: "center", tintColor: loadingTint }]}/> </View>; }; return (<View> {/* Slider for reactions */} <ScrollView style={{ paddingBottom: 5 }} contentContainerStyle={{ paddingLeft: 5, }} showsHorizontalScrollIndicator={false} horizontal={true}> {messageReactions?.length > 0 && messageReactions.map((reactionObject, index) => (<TouchableOpacity style={[{ paddingHorizontal: 10, flexDirection: "row", marginRight: 5, backgroundColor: currentSelectedReaction === reactionObject?.reaction ? activeEmojiBackgroundColor : undefined, borderRadius: 20, alignItems: "center", justifyContent: "center" }]} key={index} onPress={() => setCurrentSelectedReaction(reactionObject?.reaction)}> <Text style={[{ borderWidth: .5, borderColor: "transparent", paddingVertical: 5, marginRight: 4, color: reactionObject?.reaction === "All" ? sliderEmojiCountColor : theme?.palette?.getPrimary() }, sliderEmojiFont]}>{reactionObject?.reaction === "All" ? localize("ALL") : reactionObject?.reaction}</Text> <Text style={[{ color: sliderEmojiCountColor }, sliderEmojiCountFont]}>{reactionObject?.count}</Text> </TouchableOpacity>))} </ScrollView> {state === "error" ? <ErrorView /> : state === "loading" ? <LoadingView /> : <FlatList data={reactionList} keyExtractor={(item, index) => index.toString()} renderItem={_render} onEndReached={({ distanceFromEnd }) => { if (distanceFromEnd < 0) return; fetchNext(); }} onEndReachedThreshold={0.1} contentContainerStyle={{ paddingBottom: 25, paddingHorizontal: 5, }}/>} </View>); }; //# sourceMappingURL=CometChatReactionList.js.map