Last active
July 21, 2023 11:57
-
-
Save sajjadjaved01/82c3569a5fc4fe588aed6b4034d014c3 to your computer and use it in GitHub Desktop.
A React Native component that renders a set of animated reactions for a chat message. The component uses the Animated API to fade in/out the reactions, and allows the user to select a reaction by tapping on it. The selected reaction is then sent to the server to update the message's reactions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Main = () => { | |
const cuteReactionsRefs = useRef<React.RefObject<CuteReactionsRef>[]>([]); | |
// for show using ref | |
cuteReactionsRefs.current[message._id]?.current?.showReactions(); | |
const check = () => { | |
if (!cuteReactionsRefs.current[props.currentMessage?._id]) { | |
cuteReactionsRefs.current[props.currentMessage?._id] = | |
useRef<CuteReactionsRef>(null); | |
} | |
return ( | |
<CuteReactions | |
key={props.position?.toString()} | |
{...props} | |
ref={cuteReactionsRefs.current[props.currentMessage?._id]}> | |
<Block card flex={0} black={isMine}> | |
<Text white={isMine}>{props?.currentMessage?.text}</Text> | |
</Block> | |
</CuteReactions>) | |
} | |
} | |
export default Main; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Linking from 'expo-linking'; | |
import React, { | |
ForwardedRef, | |
forwardRef, | |
useEffect, | |
useImperativeHandle, | |
useRef, | |
useState, | |
} from 'react'; | |
import {Pressable, FlatList, TouchableOpacity} from 'react-native'; | |
import Animated, {EasingNode, Layout} from 'react-native-reanimated'; | |
import {Text} from '../components/'; | |
import {useTheme} from '../hooks'; | |
import {useUserStore} from '../store'; | |
import {requestHandler} from '../utils/requestHandlet'; | |
export interface CuteReactionsRef { | |
showReactions: () => void; | |
closeReactions: () => void; | |
isShowing: boolean; | |
test: () => void; | |
getAlert: () => void; | |
} | |
const CuteReactions = (props: any, ref: ForwardedRef<CuteReactionsRef>) => { | |
const {assets, colors, gradients, sizes, icons} = useTheme(); | |
const [user] = useUserStore((state) => [state.user, state.setUser]); | |
const [isShowing, setIsShowing] = useState(false); | |
const [ReactionsItems, setReactionsItems] = useState<EmojiItemProp[]>([ | |
{ | |
id: 0, | |
emoji: '👍', | |
title: 'like', | |
}, | |
{ | |
id: 1, | |
emoji: '🥰', | |
title: 'love', | |
}, | |
{ | |
id: 2, | |
emoji: '🤗', | |
title: 'care', | |
}, | |
{ | |
id: 3, | |
emoji: '😘', | |
title: 'kiss', | |
}, | |
{ | |
id: 4, | |
emoji: '😆', | |
title: 'laugh', | |
}, | |
{ | |
id: 5, | |
emoji: '😄', | |
title: 'smile', | |
}, | |
{ | |
id: 6, | |
emoji: '😢', | |
title: 'sad', | |
}, | |
{ | |
id: 7, | |
emoji: '😡', | |
title: 'angry', | |
}, | |
{ | |
id: 8, | |
emoji: '😮', | |
title: 'surprised', | |
}, | |
]); | |
interface EmojiItemProp { | |
id: number; | |
emoji: React.ReactNode | string | number; | |
title: string; | |
} | |
const isMine = props?.currentMessage?.user?._id === user?.id; | |
const [selectedEmoji, setSelectedEmoji] = useState<EmojiItemProp>(); | |
const fadeAnim = useRef(new Animated.Value(0)).current; | |
useImperativeHandle(ref, () => ({ | |
showReactions() { | |
show(); | |
}, | |
closeReactions, | |
isShowing, | |
test() { | |
console.log('test'); | |
}, | |
getAlert() { | |
alert('getAlert from Child'); | |
}, | |
})); | |
const closeReactions = () => { | |
Animated.timing(fadeAnim, { | |
toValue: 0, | |
duration: 120, | |
easing: EasingNode.linear, | |
}).start(); | |
}; | |
useEffect(() => { | |
if ( | |
props.currentMessage.reactions != undefined && | |
props.currentMessage.reactions != null && | |
JSON.parse(props.currentMessage.reactions).length > 0 | |
) { | |
const fg: [] = JSON.parse(props.currentMessage.reactions); | |
if (fg.length > 0) { | |
setSelectedEmoji(ReactionsItems.find((r) => r.emoji === fg[0].emoji)); | |
} | |
} | |
}, []); | |
useEffect(() => { | |
if (!isShowing) { | |
closeReactions(); | |
} | |
}, [isShowing]); | |
const show = () => { | |
Animated.timing(fadeAnim, { | |
toValue: 1, | |
duration: 200, | |
easing: EasingNode.elastic(1), | |
}).start(() => setIsShowing(!isShowing)); | |
}; | |
const parseTags = (text: string) => { | |
if (/#(\w+)/.test(text)) { | |
console.log('hashtag', text); | |
} else if (/@(\w+)/.test(text)) { | |
console.log('mention', text); | |
} else if (/(https?:\/\/[^\s]+)/g.test(text)) { | |
Linking.openURL(text); | |
} else if (/(https?:\/\/[^\s]+)/g.test(text)) { | |
Linking.openURL(text); | |
} else { | |
show(); | |
} | |
}; | |
return ( | |
<Pressable | |
onPress={() => parseTags(props.currentMessage.text)} | |
style={{ | |
alignItems: isMine ? 'flex-end' : 'flex-start', | |
justifyContent: 'center', | |
width: 150, | |
}}> | |
<Animated.View | |
layout={Layout.springify()} | |
style={{ | |
opacity: fadeAnim, | |
marginVertical: 4, | |
paddingHorizontal: 10, | |
paddingVertical: 6, | |
flexDirection: 'row', | |
borderRadius: 22, | |
backgroundColor: colors.white, | |
}}> | |
<FlatList | |
horizontal | |
showsHorizontalScrollIndicator={false} | |
data={ReactionsItems} | |
renderItem={({item, index}) => ( | |
<TouchableOpacity | |
key={index.toString()} | |
onPress={() => { | |
setSelectedEmoji(item); | |
closeReactions(); | |
const body = { | |
reactions: [ | |
{ | |
emoji: item.emoji, | |
users: [ | |
{ | |
id: props.currentMessage.user._id, | |
timestamp: Date.now(), | |
}, | |
], | |
timestamp: Date.now(), | |
count: 1, | |
}, | |
], | |
id: props.currentMessage._id, | |
}; | |
requestHandler({ | |
type: 'put', | |
route: 'chat/update-reactions', | |
body, | |
}); | |
}} | |
style={{marginHorizontal: 2}} | |
key={item.id}> | |
<Text h4 size={20}> | |
{item.emoji} | |
</Text> | |
</TouchableOpacity> | |
)} | |
/> | |
</Animated.View> | |
{props.children} | |
{selectedEmoji && <Text h5>{selectedEmoji?.emoji}</Text>} | |
</Pressable> | |
); | |
}; | |
export default forwardRef<CuteReactionsRef, any>(CuteReactions); |
add main ref as example
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added Ref to show close and check if reactions is visible.