import React , { Component } from 'react' ; import { Linking , Modal , Platform , Text , View } from 'react-native' ; import { AirbnbRating } from 'react-native-ratings' ; import { RateModalStyles } from '../Assets/Styles/RateModal' ; import { Button } from './Button' ; import { ButtonContainer } from './ButtonContainer' ; import { TextBox } from './TextBox' ; import { IProps , IState } from '../Interfaces/IRateModal' ; let prevIsModalOpen = false ; export class RateModal extends Component < IProps , IState > { public static defaultProps = { modalTitle : 'How many stars do you give to this app?' , cancelBtnText : 'Cancel' , totalStarCount : 5 , defaultStars : 5 , emptyCommentErrorMessage : 'Please specify your opinion.' , isVisible : true , isModalOpen : false , commentPlaceholderText : 'You can type your comments here ...' , rateBtnText : 'Rate' , sendBtnText : 'Send' , storeRedirectThreshold : 3 , starLabels : [ 'Terrible' , 'Bad' , 'Okay' , 'Good' , 'Great' ] , isTransparent : true , styles : { } , ratingProps : { } , ratingComponent : AirbnbRating , modalProps : { } , onSendReview : ( ) => true , } ; constructor ( props ) { super ( props ) ; this . state = { rating : props . defaultStars , review : '' , reviewError : false , showContactForm : false , } ; const { OS } = Platform ; const { totalStarCount , isVisible , starLabels , playStoreUrl , iTunesStoreUrl } = props ; if ( isVisible && starLabels . length !== totalStarCount ) { throw new Error ( `You should define at least ${ starLabels . length } review values` ) ; } else if ( OS === 'android' && ! playStoreUrl ) { throw new Error ( 'Enter a valid store url' ) ; } else if ( OS === 'ios' && ! iTunesStoreUrl ) { throw new Error ( 'Enter a valid store url' ) ; } } public render ( ) { const { onClosed , isTransparent , modalProps , isModalOpen } = this . props ; return ( < Modal transparent = { isTransparent } visible = { isModalOpen } onRequestClose = { onClosed } { ... modalProps } > { this . renderRateModal ( ) } < /Modal>); } public static getDerivedStateFromProps ( nextProps ) { const { isModalOpen , defaultStars } = nextProps ; const isMounting = isModalOpen && ! prevIsModalOpen ; prevIsModalOpen = isModalOpen ; if ( isMounting ) { return { rating : defaultStars , showContactForm : false , } ; } return null ; } private onStarSelected ( e ) { const { onStarSelected } = this . props ; if ( onStarSelected ) { onStarSelected ( e ) ; } this . setState ( { rating : e } ) ; } private renderRateModal ( ) { const { modalContainer , modalWrapper } = RateModalStyles ; const { style , styles } = this . props ; return ( < View style = { [ modalWrapper , style , styles . modalWrapper ] } > < View style = { [ modalContainer , styles . modalContainer ] } > { ! this . state . showContactForm && this . renderRatingView ( ) } { this . state . showContactForm && this . renderContactFormView ( ) } < /View> < /View>); } private renderRatingView ( ) { const { title } = RateModalStyles ; const { modalTitle , styles } = this . props ; return ( < React . Fragment > < Text style = { [ title , styles . title ] } > { modalTitle } < /Text> { this . renderRating ( ) } < ButtonContainer styles = { styles } > { this . renderCancelButton ( ) } { this . renderRateButton ( ) } < /ButtonContainer> < /React.Fragment>); } private renderContactFormView ( ) { const { styles } = this . props ; return ( < React . Fragment > { this . renderContactForm ( ) } < View > { this . state . reviewError && this . renderReviewError ( ) } < /View> < ButtonContainer styles = { styles } > { this . renderCancelButton ( ) } { this . renderSendButton ( ) } < /ButtonContainer> < /React.Fragment>); } private renderRating ( ) { const { ratingProps , ratingComponent , starLabels , isVisible , totalStarCount , defaultStars } = this . props ; const RatingComponent = ratingComponent ; return ( < RatingComponent count = { totalStarCount } defaultRating = { defaultStars } showRating = { isVisible } reviews = { starLabels } onFinishRating = { ( e ) => this . onStarSelected ( e ) } { ... ratingProps } />); } private renderContactForm ( ) { const { commentPlaceholderText , styles } = this . props ; return ( < TextBox containerStyle = { [ RateModalStyles . textBox , styles . textBox ] } textStyle = { { paddingVertical : 5 } } value = { this . state . review } placeholder = { commentPlaceholderText } multiline autoFocus onChangeText = { ( value ) => this . setState ( { review : value , reviewError : false } ) } />); } private renderCancelButton ( ) { const { button , buttonCancel , buttonCancelText } = RateModalStyles ; const { styles , cancelBtnText } = this . props ; return ( < Button text = { cancelBtnText } containerStyle = { [ button , buttonCancel , styles . button , styles . buttonCancel , ] } textStyle = { [ buttonCancelText , styles . buttonText , styles . buttonCancelText ] } onPress = { this . handleCancel . bind ( this ) } / > ) ; } private renderRateButton ( ) { const { button } = RateModalStyles ; const { rateBtnText , styles } = this . props ; return ( < Button text = { rateBtnText } containerStyle = { [ button , styles . button ] } textStyle = { styles . buttonText } onPress = { this . sendRate . bind ( this ) } / > ) ; } private renderSendButton ( ) { const { button } = RateModalStyles ; const { sendBtnText , styles } = this . props ; const { review } = this . state ; return ( < Button text = { sendBtnText } disabled = { review === '' && typeof styles . buttonDisabled !== 'undefined' } containerStyle = { [ button , styles . button , ... ( review === '' ? [ styles . buttonDisabled ] : [ ] ) , ] } textStyle = { styles . buttonText } onPress = { this . sendContactUsForm . bind ( this ) } / > ) ; } private renderReviewError ( ) { const { errorText } = RateModalStyles ; const { emptyCommentErrorMessage , styles } = this . props ; return ( < Text style = { [ errorText , styles . errorText ] } > { emptyCommentErrorMessage } < /Text>); } private handleCancel ( ) { this . props . onClosed ( ) ; } private sendRate ( ) { const { storeRedirectThreshold , playStoreUrl , iTunesStoreUrl , onSendReview , onClosed } = this . props ; if ( this . state . rating > storeRedirectThreshold ) { Platform . OS === 'ios' ? Linking . openURL ( iTunesStoreUrl ) : Linking . openURL ( playStoreUrl ) ; onSendReview ( { ... this . state } ) ; onClosed ( ) ; } else { this . setState ( { showContactForm : true } ) ; } } private sendContactUsForm ( ) { const { sendContactUsForm , onClosed } = this . props ; if ( this . state . review . length > 0 ) { if ( sendContactUsForm && typeof sendContactUsForm === 'function' ) { this . setState ( { review : '' , } ) ; sendContactUsForm ( { ... this . state } ) ; onClosed ( ) ; } else { throw new Error ( 'You should generate sendContactUsForm function' ) ; } } else { this . setState ( { reviewError : true } ) ; } } }