-
-
Save rafaeluzzi/0e4c9a2bcf49134fa172a2d2d3daea24 to your computer and use it in GitHub Desktop.
ShareYourFeedback
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
// 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