Skip to content

Instantly share code, notes, and snippets.

@sajjadjaved01
Last active July 21, 2023 11:57
Show Gist options
  • Save sajjadjaved01/82c3569a5fc4fe588aed6b4034d014c3 to your computer and use it in GitHub Desktop.
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.
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;
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);
@sajjadjaved01
Copy link
Author

Added Ref to show close and check if reactions is visible.

@sajjadjaved01
Copy link
Author

add main ref as example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment