Skip to content

Instantly share code, notes, and snippets.

@lucianomlima
Forked from AlexBrasileiro/index.js
Created September 25, 2018 22:29
Show Gist options
  • Save lucianomlima/e0a5b15dd0c865306901c39bd2e8be66 to your computer and use it in GitHub Desktop.
Save lucianomlima/e0a5b15dd0c865306901c39bd2e8be66 to your computer and use it in GitHub Desktop.
ShareYourFeedback
// inspiration: https://dribbble.com/shots/4370657-Share-Your-Feedback
import React, { Component, Fragment } from "react";
import { Animated, StyleSheet, Text, View, TouchableOpacity, Dimensions, Platform, Easing, TextInput, KeyboardAvoidingView, Image } from "react-native";
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
const { width: windowWidth } = Dimensions.get('window');
const Icon = (props) => <FontAwesome5 {...props} />
export default class ShareYourFeedback extends Component {
state = {
withTimer: true,
activeOpacity: .7,
animations: {
envelopeAnimation: new Animated.Value(0),
envelopeWidthAnimation: new Animated.Value(0),
iconAnimation: new Animated.Value(1),
buttonsAnimation: new Animated.Value(0),
feedbackWrapperAnimation: new Animated.Value(0),
feedbackHeightWrapperAnimation: new Animated.Value(0),
formWrapperAnimation: new Animated.Value(0),
closeFeedbackWrapperOpactiy: new Animated.Value(1),
titleThankyouOpactiy: new Animated.Value(0)
},
changeZindex: {
buttonsWrapper: undefined
},
feedbackType: 'Feedback',
smiles: [
['sad-tear', '#e74c3c'],
['frown', '#e67e22'],
['meh', '#f1c40f'],
['smile', '#1abc9c'],
['kiss-wink-heart', '#2ecc71']
],
feedbackSmiles: undefined,
}
componentDidMount() {
this.handleEnvelopeAnimate()
}
handleEnvelopeAnimate = () => {
this.state.withTimer
? setTimeout(() => {
Animated.timing(this.state.animations.envelopeAnimation, {
toValue: 1,
duration: this.state.duration === 0 ? 0 : this.state.duration,
easing: Easing.elastic()
}).start()
}, 1500)
: Animated.timing(this.state.animations.envelopeAnimation, {
toValue: 1,
duration: this.state.duration === 0 ? 0 : this.state.duration,
easing: Easing.elastic()
}).start()
}
handleEnvelopePress = () => {
Animated.parallel([
Animated.spring(this.state.animations.envelopeWidthAnimation, {
toValue: 1,
}),
Animated.timing(this.state.animations.iconAnimation, {
toValue: 0,
duration: 300
}),
Animated.timing(this.state.animations.buttonsAnimation, {
toValue: 1,
duration: 1000
})
]).start(() => {
this.setState({
changeZindex: {
buttonsWrapper: 2
}
})
})
}
handleFeedbackPress = () => {
Animated.parallel([
Animated.timing(this.state.animations.envelopeAnimation, {
toValue: 0,
duration: 300
}),
Animated.spring(this.state.animations.feedbackWrapperAnimation, {
toValue: 1,
friction: 5
}),
]).start()
}
handleBugPress = () => {
// something for Bugs
}
handleSmilePress = (smile) => {
Animated.parallel([
Animated.timing(this.state.animations.feedbackHeightWrapperAnimation, {
toValue: 1,
duration: 250
}),
Animated.timing(this.state.animations.formWrapperAnimation, {
toValue: 1,
duration: 300
})
]).start()
this.setState({
feedbackSmiles: smile
})
}
handleFormSubmitPress = () => {
Animated.parallel([
Animated.timing(this.state.animations.feedbackHeightWrapperAnimation, {
toValue: 2,
duration: 500
}),
Animated.timing(this.state.animations.closeFeedbackWrapperOpactiy, {
toValue: 0,
duration: 100
}),
Animated.timing(this.state.animations.titleThankyouOpactiy, {
toValue: 1,
duration: 500
})
]).start(() => {
Animated.timing(this.state.animations.feedbackWrapperAnimation, {
toValue: 3,
duration: 3000,
easing: Easing.elastic()
}).start()
});
}
render() {
const { app, envelope, envelopeAnimatedWrapperStyles, row, buttonsWrapper, buttons, iconsStyle, iconEnvelope, feedbackWrapper, title, question, formWrapper, formInput, formButton, formButtonText, feedbackWrapperKeyboard, titleThankyou, logo } = styles;
const envelopeAnimatedInterpolate = this.state.animations.envelopeAnimation.interpolate({
inputRange: [0, 1],
outputRange: [55, 0]
})
const envelopeWidthAnimatedInterpolate = this.state.animations.envelopeWidthAnimation.interpolate({
inputRange: [0, 1],
outputRange: [55, (windowWidth * .8)]
})
const feedbackWrapperAnimatedInterpolate = this.state.animations.feedbackWrapperAnimation.interpolate({
inputRange: [0, 1, 2, 3],
outputRange: [150, -10, -10, 300]
})
const feedbackHeightWrapperAnimatedInterpolate = this.state.animations.feedbackHeightWrapperAnimation.interpolate({
inputRange: [0, 1, 2],
outputRange: [150, 360, 55]
})
const envelopeAnimatedStyles = {
transform: [
{
translateY: envelopeAnimatedInterpolate
}
],
width: envelopeWidthAnimatedInterpolate
}
const iconAnimatedStyles = {
opacity: this.state.animations.iconAnimation
}
const buttonsAnimatedStyles = {
opacity: this.state.animations.buttonsAnimation
}
const feedbackWrapperAnimatedStyles = {
transform: [
{
translateY: feedbackWrapperAnimatedInterpolate
}
],
height: feedbackHeightWrapperAnimatedInterpolate
}
const formWrapperAnimatedStyles = {
opacity: this.state.animations.formWrapperAnimation
}
const closeFeedbackWrapperAnimatedStyles = {
opacity: this.state.animations.closeFeedbackWrapperOpactiy
}
const titleThankyouAnimatedStyles = {
opacity: this.state.animations.titleThankyouOpactiy
}
return (
<View style={app}>
<Animated.View style={[envelopeAnimatedWrapperStyles, envelopeAnimatedStyles]}>
<TouchableOpacity activeOpacity={this.state.activeOpacity} style={envelope} onPress={this.handleEnvelopePress}>
<Animated.View style={[iconEnvelope, iconAnimatedStyles]}>
<Icon name={'envelope-open'} size={20} color='#000' solid />
</Animated.View>
<Animated.View style={[row, buttonsWrapper, buttonsAnimatedStyles, { zIndex: this.state.changeZindex.buttonsWrapper }]}>
<TouchableOpacity activeOpacity={this.state.activeOpacity} style={[row, buttons, { backgroundColor: 'rgba(0,0,0,.05)' }]} onPress={this.handleFeedbackPress}>
<Icon style={iconsStyle} name={'comments'} size={20} color='#000' solid />
<Text>Feedback</Text>
</TouchableOpacity>
<TouchableOpacity activeOpacity={this.state.activeOpacity} style={[row, buttons]} onPress={this.handleBugPress}>
<Icon style={iconsStyle} name={'bug'} size={20} color='#000' solid />
<Text>Bug</Text>
</TouchableOpacity>
</Animated.View>
</TouchableOpacity>
</Animated.View>
<KeyboardAvoidingView style={feedbackWrapperKeyboard} behavior="padding">
<Animated.View style={[feedbackWrapper, feedbackWrapperAnimatedStyles]}>
<Animated.View style={closeFeedbackWrapperAnimatedStyles}>
<Text style={title}>Share your {this.state.feedbackType}</Text>
{
this.state.feedbackType === 'Feedback'
? (
<Fragment>
<Text style={question}>How satisfied are you with AwesomeApp?</Text>
<View style={[row, { justifyContent: 'space-between' }]}>
{
this.state.smiles.map(smile =>
<TouchableOpacity key={smile[0]} activeOpacity={this.state.activeOpacity} onPress={() => this.handleSmilePress(smile[0])}>
<Icon name={smile[0]} size={40} color={!this.state.feedbackSmiles || this.state.feedbackSmiles !== smile[0] ? 'rgba(0,0,0,.33)' : this.state.smiles.filter(smile => smile[0] === this.state.feedbackSmiles)[0][1]} />
</TouchableOpacity>
)
}
</View>
</Fragment>
) : (
null
)
}
<Animated.View style={[formWrapper, formWrapperAnimatedStyles]}>
<TextInput style={formInput} multiline placeholder='How can we improve?' />
<TouchableOpacity onPress={this.handleFormSubmitPress} style={[formButton, { backgroundColor: !this.state.feedbackSmiles ? 'rgba(0,0,0,.33)' : this.state.smiles.filter(smile => smile[0] === this.state.feedbackSmiles)[0][1] }]}>
<Text style={formButtonText}>Send</Text>
</TouchableOpacity>
</Animated.View>
</Animated.View>
<Animated.Text style={[title, titleThankyou, titleThankyouAnimatedStyles]}>! Thank You !</Animated.Text>
</Animated.View>
</KeyboardAvoidingView>
<Image style={logo} resizeMode='stretch' source={require('./logo.png')} />
</View>
);
}
}
const styles = StyleSheet.create({
app: {
backgroundColor: "#FFC764",
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
row: {
flexDirection: 'row',
},
envelopeAnimatedWrapperStyles: {
position: 'absolute',
bottom: 0,
right: '10%',
zIndex: 1,
},
envelope: {
width: '100%',
height: 55,
backgroundColor: 'white',
alignItems: 'flex-end',
justifyContent: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 0 },
shadowOpacity: .33,
shadowRadius: 5,
elevation: Platform.OS === 'android' ? 5 : undefined,
borderTopLeftRadius: 3,
borderTopRightRadius: 3,
},
iconEnvelope: {
position: 'absolute',
right: 0,
zIndex: 1,
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
maxWidth: 55,
},
buttonsWrapper: {
width: '100%',
height: '100%',
justifyContent: 'space-between',
},
buttons: {
width: '50%',
alignItems: 'center',
justifyContent: 'center'
},
iconsStyle: {
marginRight: 10
},
feedbackWrapperKeyboard: {
alignSelf: 'center',
position: 'absolute',
bottom: 0,
width: '80%',
},
feedbackWrapper: {
backgroundColor: '#fff',
borderRadius: 3,
shadowColor: '#000',
shadowOffset: { width: 0, height: 0 },
shadowOpacity: .33,
shadowRadius: 5,
elevation: Platform.OS === 'android' ? 5 : undefined,
padding: 20,
overflow: 'hidden'
},
title: {
fontWeight: '600',
textTransform: 'uppercase',
fontSize: 16,
marginBottom: 20
},
question: {
fontWeight: '100',
fontSize: 13,
marginBottom: 15
},
formWrapper: {
width: '100%',
marginTop: 20,
alignItems: 'flex-end'
},
formInput: {
width: '100%',
padding: 10,
borderWidth: 1,
borderColor: '#EDEDED',
height: 130,
marginBottom: 20,
},
formButton: {
width: 63,
height: 37,
alignItems: 'center',
justifyContent: 'center',
},
formButtonText: {
color: '#fff',
fontWeight: '600',
textTransform: 'uppercase',
},
titleThankyou: {
position: 'absolute',
textAlign: 'center',
top: 0,
right: 0,
left: 0,
marginBottom: 0,
lineHeight: 55,
},
logo:{
zIndex: -1,
opacity: .5
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment