react-native-free-template
Version:
React Native template for a quick start with javascript
305 lines (288 loc) • 8.7 kB
JavaScript
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {View, Image, TouchableOpacity, ImageBackground} from 'react-native';
import {assets} from '../../assets';
export default class StarReview extends Component {
constructor(props) {
super(props);
// 'value' and 'rating' are deprecated and have become 'display' and 'default'
this.displayValue = props.display || props.value;
this.defaultRating = props.default || props.rating;
this.state = {
rating: this.defaultRating,
};
this.isReactElement = React.isValidElement;
}
componentDidUpdate(prevProps) {
let previousDefaultRating = prevProps.rating || prevProps.default;
let defaultRating = this.props.rating || this.props.default;
if (previousDefaultRating !== defaultRating) {
this.setState({
rating: defaultRating,
});
}
}
createPartialStar(partial, blockStyle, emptyBlockStyle, starStyle) {
return this.props.opacity ? (
this.isReactElement(this.props.fullStar) ? (
<View style={{opacity: partial}}>{this.props.fullStar}</View>
) : (
<ImageBackground style={starStyle} source={this.props.emptyStar}>
<Image
style={{
height: this.props.starSize,
width: this.props.starSize,
opacity: partial,
backgroundColor: 'transparent',
}}
source={this.props.fullStar}
/>
</ImageBackground>
)
) : this.isReactElement(this.props.fullStar) ? (
<View style={{flexDirection: 'row'}}>
<View>{this.props.emptyStar}</View>
<View
style={{
maxWidth: `${Math.round(partial * 100)}%`,
overflow: 'hidden',
position: 'absolute',
}}>
{this.props.fullStar}
</View>
</View>
) : (
<ImageBackground style={starStyle} source={this.props.emptyStar}>
<View style={{flexDirection: 'row'}}>
<View style={blockStyle}>
<Image
style={{
height: this.props.starSize,
width: this.props.starSize,
backgroundColor: 'transparent',
position: 'absolute',
}}
source={this.props.fullStar}
/>
</View>
<View style={emptyBlockStyle}></View>
</View>
</ImageBackground>
);
}
displayMode() {
const partial = this.displayValue - Math.floor(this.displayValue);
const emptyBlockStyle = {
height: this.props.starSize,
width: this.props.starSize * (1.0 - partial),
backgroundColor: 'transparent',
};
const blockStyle = {
height: this.props.starSize,
width: this.props.starSize * partial,
backgroundColor: 'transparent',
overflow: 'hidden',
};
const starStyle = {
height: this.props.starSize,
width: this.props.starSize,
backgroundColor: this.props.backingColor,
};
const spacingStyle = {
paddingLeft: this.props.spacing / 2,
paddingRight: this.props.spacing / 2,
};
const stars = [];
for (let i = 1; i < this.props.count + 1; i++) {
if (i == Math.floor(this.displayValue) + 1) {
//partial star
const partialStarComponent = (
<View key={i} style={spacingStyle}>
{this.createPartialStar(
partial,
blockStyle,
emptyBlockStyle,
starStyle,
)}
</View>
);
stars.push(partialStarComponent);
} else if (i > Math.floor(this.displayValue) + 1) {
//empty stars
const emptyStarComponent = this.isReactElement(this.props.emptyStar) ? (
<View style={spacingStyle} key={i}>
{this.props.emptyStar}
</View>
) : (
<View key={i} style={spacingStyle}>
<Image style={starStyle} source={this.props.emptyStar} />
</View>
);
stars.push(emptyStarComponent);
} else {
//filled stars
const starComponent = this.isReactElement(this.props.fullStar) ? (
<View style={spacingStyle} key={i}>
{this.props.fullStar}
</View>
) : (
<View key={i} style={spacingStyle}>
<Image style={starStyle} source={this.props.fullStar} />
</View>
);
stars.push(starComponent);
}
}
return (
<View>
<View style={{flexDirection: 'row', justifyContent: 'center'}}>
{stars}
</View>
</View>
);
}
createHalfStarMember(index, star, halfStar) {
// if not a halfStar, either fullStar or emptyStar
let starComponent = halfStar || star;
starComponent = this.isReactElement(starComponent) ? (
starComponent
) : (
<ImageBackground
style={{width: this.props.starSize, height: this.props.starSize}}
source={star}>
<Image
style={{width: this.props.starSize, height: this.props.starSize}}
source={halfStar}
/>
</ImageBackground>
);
return (
<View
key={index}
style={{
paddingLeft: this.props.spacing / 2,
paddingRight: this.props.spacing / 2,
}}>
{starComponent}
<View style={{flexDirection: 'row', position: 'absolute'}}>
<TouchableOpacity
style={{
height: this.props.starSize,
width: this.props.starSize / 2,
}}
disabled={this.props.disabled}
onPress={() => {
this.setState({rating: index - 0.5});
this.props.update(index - 0.5);
}}
/>
<TouchableOpacity
style={{
height: this.props.starSize,
width: this.props.starSize / 2,
}}
disabled={this.props.disabled}
onPress={() => {
this.setState({rating: index});
this.props.update(index);
}}
/>
</View>
</View>
);
}
halfRatingMode() {
const stars = [];
for (let i = 1; i < this.props.count + 1; i++) {
const star =
i <= this.state.rating ? this.props.fullStar : this.props.emptyStar;
const halfStar =
this.state.rating + 0.5 == i ? this.props.halfStar : null;
stars.push(this.createHalfStarMember(i, star, halfStar));
}
return (
<View style={{flexDirection: 'row', justifyContent: 'center'}}>
{stars}
</View>
);
}
createFullStarMember(index, star) {
const starComponent = this.isReactElement(star) ? (
star
) : (
<Image
style={{width: this.props.starSize, height: this.props.starSize}}
source={star}
/>
);
return (
<View
key={index}
style={{
paddingLeft: this.props.spacing / 2,
paddingRight: this.props.spacing / 2,
}}>
<TouchableOpacity
disabled={this.props.disabled}
onPress={() => {
this.setState({rating: index});
this.props.update(index);
}}>
{starComponent}
</TouchableOpacity>
</View>
);
}
fullRatingMode() {
const stars = [];
for (let i = 1; i < this.props.count + 1; i++) {
const star =
i <= this.state.rating ? this.props.fullStar : this.props.emptyStar;
stars.push(this.createFullStarMember(i, star));
}
return (
<View style={{flexDirection: 'row', justifyContent: 'center'}}>
{stars}
</View>
);
}
render() {
const view =
this.displayValue == null
? this.props.half
? this.halfRatingMode()
: this.fullRatingMode()
: this.displayMode();
return <View>{view}</View>;
}
}
StarReview.propTypes = {
display: PropTypes.number,
count: PropTypes.number,
default: PropTypes.number,
emptyStar: PropTypes.oneOfType([PropTypes.number, PropTypes.object])
.isRequired,
fullStar: PropTypes.oneOfType([PropTypes.number, PropTypes.object])
.isRequired,
halfStar: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
update: PropTypes.func,
starSize: PropTypes.number,
opacity: PropTypes.bool,
half: PropTypes.bool,
spacing: PropTypes.number,
disabled: PropTypes.bool,
};
StarReview.defaultProps = {
fullStar: assets.StarFilled,
halfStar: assets.StarHalf,
emptyStar: assets.StarEmpty,
disabled: false,
display: null,
count: 5,
default: 0,
starSize: 30,
update: () => {},
opacity: false,
half: false,
spacing: 0,
};