Introduces Home component redesign
This commit is contained in:
@@ -6,10 +6,16 @@ import Link from './link'
|
||||
|
||||
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
|
||||
return (
|
||||
<Link>
|
||||
<Link style={linkStyle}>
|
||||
<Text style={[styles.text, style]}
|
||||
onPress={onPress}
|
||||
numberOfLines={numberOfLines}
|
||||
@@ -22,6 +28,7 @@ export default function AppText({ children, onPress, numberOfLines, style}) {
|
||||
|
||||
AppText.propTypes = {
|
||||
children: PropTypes.node,
|
||||
linkStyle: PropTypes.object,
|
||||
onPress: PropTypes.func,
|
||||
numberOfLines: PropTypes.number,
|
||||
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'
|
||||
|
||||
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
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress} style={buttonStyle} testID={testID}>
|
||||
@@ -23,24 +23,35 @@ Button.propTypes = {
|
||||
testID: PropTypes.string
|
||||
}
|
||||
|
||||
const button = {
|
||||
paddingHorizontal: Spacing.large,
|
||||
paddingVertical: Spacing.base,
|
||||
const text = {
|
||||
padding: Spacing.base,
|
||||
textTransform: 'uppercase'
|
||||
}
|
||||
|
||||
const button = {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: Spacing.base
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
orange: {
|
||||
regular: {
|
||||
...button
|
||||
},
|
||||
cta: {
|
||||
backgroundColor: Colors.orange,
|
||||
borderRadius: 25
|
||||
borderRadius: 25,
|
||||
...button
|
||||
},
|
||||
buttonTextBold: {
|
||||
fontFamily: Fonts.main,
|
||||
...button
|
||||
color: 'white',
|
||||
fontFamily: Fonts.bold,
|
||||
...text
|
||||
},
|
||||
buttonTextRegular: {
|
||||
fontFamily: Fonts.bold,
|
||||
...button
|
||||
color: Colors.greyDark,
|
||||
fontFamily: Fonts.main,
|
||||
...text
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ import { Colors, Typography } from '../../styles/redesign'
|
||||
|
||||
import links from '../../i18n/en/links'
|
||||
|
||||
const Link = ({ children }) => {
|
||||
const Link = ({ children, style }) => {
|
||||
return (
|
||||
<Hyperlink
|
||||
linkStyle={styles.link}
|
||||
linkStyle={[styles.link, style]}
|
||||
linkText={replaceUrlWithText}
|
||||
linkDefault
|
||||
>
|
||||
@@ -20,7 +20,8 @@ const Link = ({ children }) => {
|
||||
}
|
||||
|
||||
Link.propTypes = {
|
||||
children: PropTypes.node
|
||||
children: PropTypes.node,
|
||||
style: PropTypes.object
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -10,7 +10,7 @@ const Icon = createIconSetFromIcoMoon(iconConfig, '', 'Menu')
|
||||
const MenuIcon = ({ isActive, name }) => {
|
||||
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 = {
|
||||
|
||||
@@ -62,3 +62,10 @@ export function getBleedingPredictionRange(prediction) {
|
||||
}
|
||||
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
|
||||
+96
-95
@@ -1,54 +1,51 @@
|
||||
import { LocalDate } from 'js-joda'
|
||||
import React, { Component } from 'react'
|
||||
import { ScrollView, View } from 'react-native'
|
||||
import { connect } from 'react-redux'
|
||||
import { ScrollView, StyleSheet, View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { LocalDate } from 'js-joda'
|
||||
|
||||
import { connect } from 'react-redux'
|
||||
import { navigate } from '../slices/navigation'
|
||||
import { getDate, setDate } from '../slices/date'
|
||||
|
||||
import DripHomeIcon from '../assets/drip-home-icons'
|
||||
|
||||
import AppText from './common/app-text'
|
||||
import IconText from './icon-text'
|
||||
import HomeElement from './home-element'
|
||||
|
||||
import { home as labels } from '../i18n/en/labels'
|
||||
import links from '../i18n/en/links'
|
||||
import Button from './common/button'
|
||||
|
||||
import cycleModule from '../lib/cycle'
|
||||
import { getFertilityStatusForDay } from '../lib/sympto-adapter'
|
||||
import {
|
||||
determinePredictionText,
|
||||
getBleedingPredictionRange
|
||||
} from './helpers/home'
|
||||
import { determinePredictionText, dateEnding } 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 {
|
||||
|
||||
static propTypes = {
|
||||
navigate: 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,
|
||||
setDate: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
const today = LocalDate.now()
|
||||
this.todayDateString = today.toString()
|
||||
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
|
||||
|
||||
this.todayDateString = LocalDate.now().toString()
|
||||
this.cycleDayNumber = getCycleDayNumber(this.todayDateString)
|
||||
|
||||
const {status, phase, statusText} =
|
||||
getFertilityStatusForDay(this.todayDateString)
|
||||
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 = () => {
|
||||
@@ -56,88 +53,92 @@ class Home extends Component {
|
||||
this.props.navigate('CycleDay')
|
||||
}
|
||||
|
||||
navigateToBleedingEditView = () => {
|
||||
this.props.setDate(this.todayDateString)
|
||||
this.props.navigate('BleedingEditView')
|
||||
}
|
||||
|
||||
navigateToChart = () => {
|
||||
this.props.navigate('Chart')
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
cycleDayNumber,
|
||||
predictionText,
|
||||
bleedingPredictionRange,
|
||||
cycleDayText,
|
||||
phase,
|
||||
phaseText,
|
||||
prediction,
|
||||
status,
|
||||
statusText,
|
||||
title
|
||||
} = this
|
||||
|
||||
const { phase, status, statusText } = this.fertilityStatus
|
||||
|
||||
const cycleDayMoreText = cycleDayNumber ?
|
||||
labels.cycleDayKnown(cycleDayNumber) :
|
||||
labels.cycleDayNotEnoughInfo
|
||||
|
||||
return (
|
||||
<View flex={1}>
|
||||
<ScrollView>
|
||||
<View style={styles.homeView}>
|
||||
<HomeElement
|
||||
onPress={this.navigateToCycleDayView}
|
||||
buttonColor={ cycleDayColor }
|
||||
buttonLabel={ labels.editToday }
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
contentContainerStyle={styles.contentContainer}
|
||||
>
|
||||
<View>
|
||||
<DripHomeIcon name="circle" size={80} color={cycleDayColor}/>
|
||||
<AppText style={styles.title}>{title}</AppText>
|
||||
<View style={styles.line}>
|
||||
{this.cycleDayNumber && (
|
||||
<React.Fragment>
|
||||
<AppText style={styles.whiteText}>{cycleDayText}</AppText>
|
||||
<AppText>{labels.cycleDay}</AppText>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{!this.cycleDayNumber && <AppText>{cycleDayText}</AppText>}
|
||||
</View>
|
||||
<IconText>{cycleDayNumber || labels.unknown}</IconText>
|
||||
|
||||
<AppText style={styles.homeDescriptionText}>
|
||||
{cycleDayMoreText}
|
||||
</AppText>
|
||||
</HomeElement>
|
||||
|
||||
<HomeElement
|
||||
onPress={this.navigateToBleedingEditView}
|
||||
buttonColor={ periodColor }
|
||||
buttonLabel={ labels.trackPeriod }
|
||||
>
|
||||
<DripHomeIcon name="drop" size={100} color={periodColor} />
|
||||
|
||||
<IconText wrapperStyles={{ top: '45%' }}>
|
||||
{bleedingPredictionRange}
|
||||
</IconText>
|
||||
|
||||
<AppText style={styles.homeDescriptionText}>
|
||||
{predictionText}
|
||||
</AppText>
|
||||
</HomeElement>
|
||||
|
||||
<HomeElement
|
||||
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 style={styles.line}>
|
||||
{!phase && <AppText>{phaseText}</AppText>}
|
||||
{phase && (
|
||||
<React.Fragment>
|
||||
<AppText style={styles.whiteText}>{phaseText}</AppText>
|
||||
<AppText>{labels.cyclePhase}</AppText>
|
||||
<AppText>{status}</AppText>
|
||||
<Asterisk />
|
||||
</React.Fragment>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.line}>
|
||||
<AppText>{prediction}</AppText>
|
||||
</View>
|
||||
<Button onPress={this.navigateToCycleDayView} isCTA>
|
||||
{labels.addData}
|
||||
</Button>
|
||||
{phase && (
|
||||
<View style={styles.line}>
|
||||
<Asterisk />
|
||||
<AppText linkStyle={styles.whiteText}>{statusText}</AppText>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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) => {
|
||||
return({
|
||||
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'
|
||||
const settingsTitles = labels.menuItems
|
||||
|
||||
export const homeRedesign = {
|
||||
cycleDay: ' day of your cycle',
|
||||
cyclePhase: ' cycle phase - ',
|
||||
addData: 'add data for today'
|
||||
}
|
||||
|
||||
export const shared = {
|
||||
cancel: 'Cancel',
|
||||
save: 'Save',
|
||||
@@ -113,7 +119,7 @@ export const fertilityStatus = {
|
||||
fertileUntilEvening: 'Fertile phase ends in the evening',
|
||||
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.",
|
||||
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 => {
|
||||
return (
|
||||
'We have detected a temperature shift (' + ['regular', '1st exception', '2nd exception'][tempRule] +
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default {
|
||||
tiny: 4,
|
||||
small: 10,
|
||||
base: 16,
|
||||
large: 20
|
||||
|
||||
@@ -11,7 +11,7 @@ export const sizes = {
|
||||
base: 18,
|
||||
subtitle: 22,
|
||||
title: 24,
|
||||
icon: 40
|
||||
huge: 40
|
||||
}
|
||||
|
||||
const title = {
|
||||
|
||||
Reference in New Issue
Block a user