Skip to content

Instantly share code, notes, and snippets.

@dilipsuthar97
Created September 22, 2021 10:29
Show Gist options
  • Save dilipsuthar97/bf546531b8a0c789f64618756769dbfc to your computer and use it in GitHub Desktop.
Save dilipsuthar97/bf546531b8a0c789f64618756769dbfc to your computer and use it in GitHub Desktop.
import * as React from 'react';
import { View, Text, Image, StyleSheet, Animated } from 'react-native';
import { Matrics, Colors, Icons, Fonts } from '../CommonConfig';
import { Tools } from '../Helpers';
import Bounceable from './Bounceable';
/**
* 'reactionFlag' value is same as in DB
* it's useful during sending data with API request
*/
const reactionTypes = [
{
reactionType: 0,
reactionName: 'like',
reactionFlag: 'is_like',
},
{
reactionType: 3,
reactionName: 'prais_the_lord',
reactionFlag: 'is_prais_the_lord',
},
{
reactionType: 1,
reactionName: 'amen',
reactionFlag: 'is_amen',
},
{
reactionType: 2,
reactionName: 'hallelujah',
reactionFlag: 'is_hallelujah',
},
];
export default ({ onPress, style, reactionCounts = [0, 0, 0, 0] }) => {
const uiData = [
{
lable: 'Like',
icon: Icons.IC_LIKE,
color: Colors.LIKE_1,
colorBg: Colors.LIKE_BG_1,
ref: React.createRef(),
},
{
lable: 'Prais The Lord',
icon: Icons.IC_LIKE_2,
color: Colors.LIKE_2,
colorBg: Colors.LIKE_BG_2,
ref: React.createRef(),
},
{
lable: 'Amen',
icon: Icons.IC_LIKE_3,
color: Colors.LIKE_3,
colorBg: Colors.LIKE_BG_3,
ref: React.createRef(),
},
{
lable: 'Hallelujah',
icon: Icons.IC_LIKE_4,
color: Colors.LIKE_4,
colorBg: Colors.LIKE_BG_4,
ref: React.createRef(),
},
];
const containerRef = React.useRef();
const hoverViewRef = React.useRef();
const [activeIndex, setActiveIndex] = React.useState(0);
/**
* Function to perform action when user presses on any reaction
*
* @param {Object} value
*/
const onPressReaction = (value) => {
if (onPress)
onPress({
reactionType: value.reactionType,
reactionName: value.reactionName,
reactionFlag: value.reactionFlag,
});
};
const getMeasurement = (index) => {
return new Promise((resolve, reject) => {
uiData[index].ref.current.measureLayout(
containerRef.current,
(x, y, width, height) => {
resolve({
x,
width,
});
},
);
});
};
const onLongPressIn = async (index) => {
setActiveIndex(index);
const options = await getMeasurement(index);
hoverViewRef.current.show(options);
};
const onLongPressOut = () => {
hoverViewRef.current.hide();
};
return (
<View ref={containerRef} style={[styles.main.container, style]}>
{reactionTypes.map((value, i) => (
<Bounceable
key={`like-${i}`}
activeOpacity={0.5}
delayPressIn={0}
delayLongPress={150}
onPress={() => onPressReaction(value)}
onLongPressIn={() => onLongPressIn(i)}
onLongPressOut={() => onLongPressOut()}
style={styles.main.button}>
<View
ref={uiData[i].ref}
style={[
styles.main.wrapper,
{ backgroundColor: uiData[i].colorBg },
]}>
<Image
style={styles.main.icon}
source={uiData[i].icon}
resizeMode={'contain'}
/>
<Text
style={[
styles.main.count,
{ color: uiData[i].color },
]}>
{Tools.formatLongNumbers(reactionCounts[i])}
</Text>
</View>
</Bounceable>
))}
<HoverView
ref={hoverViewRef}
data={uiData}
index={activeIndex}
containerRef={containerRef}
/>
</View>
);
};
const HoverView = React.forwardRef(({ data, index, containerRef }, ref) => {
const hoverRef = React.useRef();
const hoverHeight = React.useRef(0);
React.useImperativeHandle(ref, () => ({
show: showAnimation,
hide: hideAnimation,
}));
const animations = {
translateX: React.useRef(new Animated.Value(0)).current,
anim: React.useRef(new Animated.Value(0)).current,
};
const animationStyles = {
container: {
transform: [
{
translateX: animations.translateX,
},
{
translateY: animations.anim.interpolate({
inputRange: [0, 1],
outputRange: [0, -hoverHeight.current],
}),
},
{
scale: animations.anim,
},
],
opacity: animations.anim,
},
};
const onLayout = ({ nativeEvent }) => {
hoverHeight.current = nativeEvent.layout.height;
};
const getMeasurement = () => {
return new Promise((resolve) => {
hoverRef.current.measureLayout(
containerRef.current,
(x, y, width, height) => {
resolve({
width,
});
},
);
});
};
const getTranslateXValue = async (options) => {
const { width } = await getMeasurement();
let toValue = options.x;
if (width < options.width) {
toValue = options.x + (options.width - width) / 2;
} else if (width > options.width) {
toValue = options.x - (width - options.width) / 2;
}
return toValue;
};
const showAnimation = async (options) => {
let toValue = await getTranslateXValue(options);
Animated.sequence([
Animated.timing(animations.translateX, {
toValue,
duration: 1,
useNativeDriver: true,
}),
Animated.spring(animations.anim, {
toValue: 1,
useNativeDriver: true,
}),
]).start();
};
const hideAnimation = () => {
Animated.spring(animations.anim, {
toValue: 0,
useNativeDriver: true,
}).start();
};
return (
<Animated.View
onLayout={onLayout}
style={[styles.hover.container, animationStyles.container]}>
<Animated.View
ref={hoverRef}
style={[
styles.hover.wrapper,
{ borderColor: data[index].colorBg },
]}>
<Image
style={styles.hover.icon}
source={data[index].icon}
resizeMode={'contain'}
/>
<Text
style={[styles.hover.lable, { color: data[index].color }]}>
{data[index].lable}
</Text>
</Animated.View>
<View
style={[
styles.hover.triangle,
styles.hover.arrowDown,
{ borderTopColor: data[index].colorBg },
]}
/>
</Animated.View>
);
});
const styles = {
main: StyleSheet.create({
container: {
flexDirection: 'row',
paddingHorizontal: Matrics.mvs(16),
paddingVertical: Matrics.mvs(8),
justifyContent: 'space-between',
width: '100%',
},
button: {
width: '23%',
justifyContent: 'center',
},
wrapper: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 100,
},
icon: {
width: Matrics.mvs(18),
height: Matrics.mvs(18),
},
count: {
fontSize: Matrics.mvs(12),
fontFamily: Fonts.Regular,
padding: Matrics.mvs(8),
},
}),
hover: StyleSheet.create({
container: {
position: 'absolute',
alignSelf: 'center',
alignItems: 'center',
},
wrapper: {
borderRadius: Matrics.mvs(6),
paddingHorizontal: Matrics.s(8),
paddingVertical: Matrics.vs(6),
backgroundColor: Colors.WHITE,
borderWidth: 1.5,
flexDirection: 'row',
alignItems: 'center',
},
icon: {
width: Matrics.mvs(16),
height: Matrics.mvs(16),
},
lable: {
fontSize: Matrics.mvs(12),
fontFamily: Fonts.Regular,
marginLeft: Matrics.s(6),
},
triangle: {
width: 0,
height: 0,
backgroundColor: 'transparent',
borderStyle: 'solid',
marginTop: -1,
},
arrowDown: {
borderTopWidth: 6,
borderRightWidth: 5,
borderBottomWidth: 0,
borderLeftWidth: 5,
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderLeftColor: 'transparent',
},
}),
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment