Introduces Home component redesign
This commit is contained in:
@@ -6,10 +6,16 @@ import Link from './link'
|
|||||||
|
|
||||||
import { Colors, Typography } from '../../styles/redesign'
|
import { Colors, Typography } from '../../styles/redesign'
|
||||||
|
|
||||||
export default function AppText({ children, onPress, numberOfLines, style}) {
|
export default function AppText({
|
||||||
|
children,
|
||||||
|
linkStyle,
|
||||||
|
onPress,
|
||||||
|
numberOfLines,
|
||||||
|
style
|
||||||
|
}) {
|
||||||
// we parse for links in case the text contains any
|
// we parse for links in case the text contains any
|
||||||
return (
|
return (
|
||||||
<Link>
|
<Link style={linkStyle}>
|
||||||
<Text style={[styles.text, style]}
|
<Text style={[styles.text, style]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
numberOfLines={numberOfLines}
|
numberOfLines={numberOfLines}
|
||||||
@@ -22,6 +28,7 @@ export default function AppText({ children, onPress, numberOfLines, style}) {
|
|||||||
|
|
||||||
AppText.propTypes = {
|
AppText.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
|
linkStyle: PropTypes.object,
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
numberOfLines: PropTypes.number,
|
numberOfLines: PropTypes.number,
|
||||||
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
|
|||||||
+21
-10
@@ -7,7 +7,7 @@ import AppText from './app-text'
|
|||||||
import { Colors, Fonts, Spacing } from '../../styles/redesign'
|
import { Colors, Fonts, Spacing } from '../../styles/redesign'
|
||||||
|
|
||||||
const Button = ({ children, isCTA, onPress, testID }) => {
|
const Button = ({ children, isCTA, onPress, testID }) => {
|
||||||
const buttonStyle = isCTA ? styles.orange : {}
|
const buttonStyle = isCTA ? styles.cta : styles.regular
|
||||||
const textStyle = isCTA ? styles.buttonTextBold : styles.buttonTextRegular
|
const textStyle = isCTA ? styles.buttonTextBold : styles.buttonTextRegular
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={onPress} style={buttonStyle} testID={testID}>
|
<TouchableOpacity onPress={onPress} style={buttonStyle} testID={testID}>
|
||||||
@@ -23,24 +23,35 @@ Button.propTypes = {
|
|||||||
testID: PropTypes.string
|
testID: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
const button = {
|
const text = {
|
||||||
paddingHorizontal: Spacing.large,
|
padding: Spacing.base,
|
||||||
paddingVertical: Spacing.base,
|
|
||||||
textTransform: 'uppercase'
|
textTransform: 'uppercase'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const button = {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: Spacing.base
|
||||||
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
orange: {
|
regular: {
|
||||||
|
...button
|
||||||
|
},
|
||||||
|
cta: {
|
||||||
backgroundColor: Colors.orange,
|
backgroundColor: Colors.orange,
|
||||||
borderRadius: 25
|
borderRadius: 25,
|
||||||
|
...button
|
||||||
},
|
},
|
||||||
buttonTextBold: {
|
buttonTextBold: {
|
||||||
fontFamily: Fonts.main,
|
color: 'white',
|
||||||
...button
|
fontFamily: Fonts.bold,
|
||||||
|
...text
|
||||||
},
|
},
|
||||||
buttonTextRegular: {
|
buttonTextRegular: {
|
||||||
fontFamily: Fonts.bold,
|
color: Colors.greyDark,
|
||||||
...button
|
fontFamily: Fonts.main,
|
||||||
|
...text
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import { Colors, Typography } from '../../styles/redesign'
|
|||||||
|
|
||||||
import links from '../../i18n/en/links'
|
import links from '../../i18n/en/links'
|
||||||
|
|
||||||
const Link = ({ children }) => {
|
const Link = ({ children, style }) => {
|
||||||
return (
|
return (
|
||||||
<Hyperlink
|
<Hyperlink
|
||||||
linkStyle={styles.link}
|
linkStyle={[styles.link, style]}
|
||||||
linkText={replaceUrlWithText}
|
linkText={replaceUrlWithText}
|
||||||
linkDefault
|
linkDefault
|
||||||
>
|
>
|
||||||
@@ -20,7 +20,8 @@ const Link = ({ children }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Link.propTypes = {
|
Link.propTypes = {
|
||||||
children: PropTypes.node
|
children: PropTypes.node,
|
||||||
|
style: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Icon = createIconSetFromIcoMoon(iconConfig, '', 'Menu')
|
|||||||
const MenuIcon = ({ isActive, name }) => {
|
const MenuIcon = ({ isActive, name }) => {
|
||||||
const color = isActive ? Colors.greyDark : Colors.grey
|
const color = isActive ? Colors.greyDark : Colors.grey
|
||||||
|
|
||||||
return <Icon name={name} size={Sizes.icon} color={color} />
|
return <Icon name={name} size={Sizes.huge} color={color} />
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuIcon.propTypes = {
|
MenuIcon.propTypes = {
|
||||||
|
|||||||
@@ -62,3 +62,10 @@ export function getBleedingPredictionRange(prediction) {
|
|||||||
}
|
}
|
||||||
return (daysToEnd === 0 ? '0' : `0 - ${daysToEnd}`)
|
return (daysToEnd === 0 ? '0' : `0 - ${daysToEnd}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dateEnding = {
|
||||||
|
'1': 'st',
|
||||||
|
'2': 'nd',
|
||||||
|
'3': 'rd',
|
||||||
|
'default': 'th'
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import { View } from 'react-native'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import Button from './common/button'
|
|
||||||
|
|
||||||
import styles from '../styles'
|
|
||||||
|
|
||||||
const HomeElement = ({ children, onPress, buttonColor, buttonLabel }) => {
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
onPress={ onPress }
|
|
||||||
style={ styles.homeElement }
|
|
||||||
>
|
|
||||||
<View style={styles.homeIconAndText}>
|
|
||||||
{children[0]}
|
|
||||||
{children[1]}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{paddingLeft: 15}}>
|
|
||||||
{children.slice(2)}
|
|
||||||
<Button
|
|
||||||
style={styles.homeButton}
|
|
||||||
onPress={ onPress }
|
|
||||||
backgroundColor={ buttonColor }>
|
|
||||||
{ buttonLabel }
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
HomeElement.propTypes = {
|
|
||||||
buttonColor: PropTypes.string,
|
|
||||||
buttonLabel: PropTypes.string,
|
|
||||||
children: PropTypes.node,
|
|
||||||
onPress: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomeElement
|
|
||||||
+99
-98
@@ -1,54 +1,51 @@
|
|||||||
import { LocalDate } from 'js-joda'
|
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { ScrollView, View } from 'react-native'
|
import { ScrollView, StyleSheet, View } from 'react-native'
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
import { LocalDate } from 'js-joda'
|
||||||
|
|
||||||
|
import { connect } from 'react-redux'
|
||||||
import { navigate } from '../slices/navigation'
|
import { navigate } from '../slices/navigation'
|
||||||
import { getDate, setDate } from '../slices/date'
|
import { getDate, setDate } from '../slices/date'
|
||||||
|
|
||||||
import DripHomeIcon from '../assets/drip-home-icons'
|
|
||||||
|
|
||||||
import AppText from './common/app-text'
|
import AppText from './common/app-text'
|
||||||
import IconText from './icon-text'
|
import Button from './common/button'
|
||||||
import HomeElement from './home-element'
|
|
||||||
|
|
||||||
import { home as labels } from '../i18n/en/labels'
|
|
||||||
import links from '../i18n/en/links'
|
|
||||||
|
|
||||||
import cycleModule from '../lib/cycle'
|
import cycleModule from '../lib/cycle'
|
||||||
import { getFertilityStatusForDay } from '../lib/sympto-adapter'
|
import { getFertilityStatusForDay } from '../lib/sympto-adapter'
|
||||||
import {
|
import { determinePredictionText, dateEnding } from './helpers/home'
|
||||||
determinePredictionText,
|
|
||||||
getBleedingPredictionRange
|
|
||||||
} from './helpers/home'
|
|
||||||
|
|
||||||
import styles, { cycleDayColor, periodColor, secondaryColor } from '../styles'
|
import { Colors, Fonts, Sizes, Spacing } from '../styles/redesign'
|
||||||
|
import { homeRedesign as labels, home as cycle } from '../i18n/en/labels'
|
||||||
|
|
||||||
class Home extends Component {
|
class Home extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigate: PropTypes.func,
|
navigate: PropTypes.func,
|
||||||
setDate: PropTypes.func,
|
setDate: PropTypes.func
|
||||||
// The following are not being used,
|
|
||||||
// we could see if it's possible to not pass them from the <App />
|
|
||||||
cycleDay: PropTypes.object,
|
|
||||||
date: PropTypes.string,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
|
const today = LocalDate.now()
|
||||||
|
this.todayDateString = today.toString()
|
||||||
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
|
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
|
||||||
|
|
||||||
this.todayDateString = LocalDate.now().toString()
|
|
||||||
this.cycleDayNumber = getCycleDayNumber(this.todayDateString)
|
this.cycleDayNumber = getCycleDayNumber(this.todayDateString)
|
||||||
|
const {status, phase, statusText} =
|
||||||
|
getFertilityStatusForDay(this.todayDateString)
|
||||||
const prediction = getPredictedMenses()
|
const prediction = getPredictedMenses()
|
||||||
this.predictionText = determinePredictionText(prediction)
|
|
||||||
this.bleedingPredictionRange = getBleedingPredictionRange(prediction)
|
|
||||||
|
|
||||||
this.fertilityStatus = getFertilityStatusForDay(this.todayDateString)
|
this.cycleDayText = !this.cycleDayNumber ? cycle.cycleDayNotEnoughInfo
|
||||||
|
: `${this.cycleDayNumber}${dateEnding[this.cycleDayNumber] || dateEnding['default']}`
|
||||||
|
this.phase = phase
|
||||||
|
this.phaseText = !phase ? statusText
|
||||||
|
: `${phase}${dateEnding[phase] || dateEnding['default']}`
|
||||||
|
this.prediction = determinePredictionText(prediction)
|
||||||
|
this.status = status
|
||||||
|
this.statusText = statusText
|
||||||
|
this.title = `${today.dayOfMonth()} ${today.month()}`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToCycleDayView = () => {
|
navigateToCycleDayView = () => {
|
||||||
@@ -56,88 +53,92 @@ class Home extends Component {
|
|||||||
this.props.navigate('CycleDay')
|
this.props.navigate('CycleDay')
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToBleedingEditView = () => {
|
|
||||||
this.props.setDate(this.todayDateString)
|
|
||||||
this.props.navigate('BleedingEditView')
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateToChart = () => {
|
|
||||||
this.props.navigate('Chart')
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
cycleDayNumber,
|
cycleDayText,
|
||||||
predictionText,
|
phase,
|
||||||
bleedingPredictionRange,
|
phaseText,
|
||||||
|
prediction,
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
title
|
||||||
} = this
|
} = this
|
||||||
|
|
||||||
const { phase, status, statusText } = this.fertilityStatus
|
|
||||||
|
|
||||||
const cycleDayMoreText = cycleDayNumber ?
|
|
||||||
labels.cycleDayKnown(cycleDayNumber) :
|
|
||||||
labels.cycleDayNotEnoughInfo
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View flex={1}>
|
<ScrollView
|
||||||
<ScrollView>
|
style={styles.container}
|
||||||
<View style={styles.homeView}>
|
contentContainerStyle={styles.contentContainer}
|
||||||
<HomeElement
|
>
|
||||||
onPress={this.navigateToCycleDayView}
|
<AppText style={styles.title}>{title}</AppText>
|
||||||
buttonColor={ cycleDayColor }
|
<View style={styles.line}>
|
||||||
buttonLabel={ labels.editToday }
|
{this.cycleDayNumber && (
|
||||||
>
|
<React.Fragment>
|
||||||
<View>
|
<AppText style={styles.whiteText}>{cycleDayText}</AppText>
|
||||||
<DripHomeIcon name="circle" size={80} color={cycleDayColor}/>
|
<AppText>{labels.cycleDay}</AppText>
|
||||||
</View>
|
</React.Fragment>
|
||||||
<IconText>{cycleDayNumber || labels.unknown}</IconText>
|
)}
|
||||||
|
{!this.cycleDayNumber && <AppText>{cycleDayText}</AppText>}
|
||||||
<AppText style={styles.homeDescriptionText}>
|
</View>
|
||||||
{cycleDayMoreText}
|
<View style={styles.line}>
|
||||||
</AppText>
|
{!phase && <AppText>{phaseText}</AppText>}
|
||||||
</HomeElement>
|
{phase && (
|
||||||
|
<React.Fragment>
|
||||||
<HomeElement
|
<AppText style={styles.whiteText}>{phaseText}</AppText>
|
||||||
onPress={this.navigateToBleedingEditView}
|
<AppText>{labels.cyclePhase}</AppText>
|
||||||
buttonColor={ periodColor }
|
<AppText>{status}</AppText>
|
||||||
buttonLabel={ labels.trackPeriod }
|
<Asterisk />
|
||||||
>
|
</React.Fragment>
|
||||||
<DripHomeIcon name="drop" size={100} color={periodColor} />
|
)}
|
||||||
|
</View>
|
||||||
<IconText wrapperStyles={{ top: '45%' }}>
|
<View style={styles.line}>
|
||||||
{bleedingPredictionRange}
|
<AppText>{prediction}</AppText>
|
||||||
</IconText>
|
</View>
|
||||||
|
<Button onPress={this.navigateToCycleDayView} isCTA>
|
||||||
<AppText style={styles.homeDescriptionText}>
|
{labels.addData}
|
||||||
{predictionText}
|
</Button>
|
||||||
</AppText>
|
{phase && (
|
||||||
</HomeElement>
|
<View style={styles.line}>
|
||||||
|
<Asterisk />
|
||||||
<HomeElement
|
<AppText linkStyle={styles.whiteText}>{statusText}</AppText>
|
||||||
onPress={this.navigateToChart}
|
|
||||||
buttonColor={ secondaryColor }
|
|
||||||
buttonLabel={ labels.checkFertility }
|
|
||||||
>
|
|
||||||
<View style={styles.homeCircle}/>
|
|
||||||
|
|
||||||
<IconText>{ phase ? phase.toString() : labels.unknown }</IconText>
|
|
||||||
|
|
||||||
{ phase &&
|
|
||||||
<AppText style={styles.homeDescriptionText}>
|
|
||||||
{`${labels.phase(phase)} (${status})`}
|
|
||||||
</AppText>
|
|
||||||
}
|
|
||||||
<AppText style={styles.homeDescriptionText}>
|
|
||||||
{ `${statusText} Visit ${links.wiki.url}.` }
|
|
||||||
</AppText>
|
|
||||||
</HomeElement>
|
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
)}
|
||||||
</View>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Asterisk = () => {
|
||||||
|
return <AppText style={styles.asterisk}>*</AppText>
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
asterisk: {
|
||||||
|
color: Colors.orange,
|
||||||
|
paddingRight: Spacing.base
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
backgroundColor: Colors.purple,
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
contentContainer: {
|
||||||
|
padding: Spacing.base
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
marginBottom: Spacing.tiny
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: Colors.purpleLight,
|
||||||
|
fontFamily: Fonts.bold,
|
||||||
|
fontSize: Sizes.huge,
|
||||||
|
marginVertical: Spacing.base,
|
||||||
|
},
|
||||||
|
whiteText: {
|
||||||
|
color: 'white'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
return({
|
return({
|
||||||
date: getDate(state),
|
date: getDate(state),
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import { View } from 'react-native'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import AppText from './common/app-text'
|
|
||||||
|
|
||||||
import styles from '../styles'
|
|
||||||
|
|
||||||
const IconText = ({ children, wrapperStyles }) => {
|
|
||||||
return (
|
|
||||||
<View style={[ styles.homeIconTextWrapper, wrapperStyles ]}>
|
|
||||||
<AppText style={styles.iconText}>
|
|
||||||
{ children }
|
|
||||||
</AppText>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
IconText.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
wrapperStyles: PropTypes.object,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IconText
|
|
||||||
+7
-1
@@ -1,6 +1,12 @@
|
|||||||
import labels from './settings'
|
import labels from './settings'
|
||||||
const settingsTitles = labels.menuItems
|
const settingsTitles = labels.menuItems
|
||||||
|
|
||||||
|
export const homeRedesign = {
|
||||||
|
cycleDay: ' day of your cycle',
|
||||||
|
cyclePhase: ' cycle phase - ',
|
||||||
|
addData: 'add data for today'
|
||||||
|
}
|
||||||
|
|
||||||
export const shared = {
|
export const shared = {
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
@@ -113,7 +119,7 @@ export const fertilityStatus = {
|
|||||||
fertileUntilEvening: 'Fertile phase ends in the evening',
|
fertileUntilEvening: 'Fertile phase ends in the evening',
|
||||||
unknown: 'We cannot show any cycle information because no period data has been added.',
|
unknown: 'We cannot show any cycle information because no period data has been added.',
|
||||||
preOvuText: "With NFP rules, you may assume 5 days of infertility at the beginning of your cycle, provided you don't observe any fertile cervical mucus or cervix values.",
|
preOvuText: "With NFP rules, you may assume 5 days of infertility at the beginning of your cycle, provided you don't observe any fertile cervical mucus or cervix values.",
|
||||||
periOvuText: "We have not been able to detect both a temperature shift and cervical mucus or cervix shift. Please find more information on NFP rules here:",
|
periOvuText: "We have not been able to detect both a temperature shift and cervical mucus or cervix shift. Please find more information on NFP rules here: https://gitlab.com/bloodyhealth/drip/wikis/home",
|
||||||
postOvuText: tempRule => {
|
postOvuText: tempRule => {
|
||||||
return (
|
return (
|
||||||
'We have detected a temperature shift (' + ['regular', '1st exception', '2nd exception'][tempRule] +
|
'We have detected a temperature shift (' + ['regular', '1st exception', '2nd exception'][tempRule] +
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
|
tiny: 4,
|
||||||
small: 10,
|
small: 10,
|
||||||
base: 16,
|
base: 16,
|
||||||
large: 20
|
large: 20
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const sizes = {
|
|||||||
base: 18,
|
base: 18,
|
||||||
subtitle: 22,
|
subtitle: 22,
|
||||||
title: 24,
|
title: 24,
|
||||||
icon: 40
|
huge: 40
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = {
|
const title = {
|
||||||
|
|||||||
Reference in New Issue
Block a user