From 29d76d19b11e9fd94a6fd76e563108e5a16200d8 Mon Sep 17 00:00:00 2001 From: mashazyu <mariya.z@gmail.com> Date: Tue, 24 Mar 2020 20:15:01 +0100 Subject: [PATCH] Introduces Home component redesign --- components/common/app-text.js | 11 +- components/common/button.js | 31 ++++-- components/common/link.js | 7 +- components/common/menu-icon.js | 2 +- components/helpers/home.js | 7 ++ components/home-element.js | 40 ------- components/home.js | 197 +++++++++++++++++---------------- components/icon-text.js | 24 ---- i18n/en/labels.js | 8 +- styles/spacing.js | 1 + styles/typography.js | 2 +- 11 files changed, 150 insertions(+), 180 deletions(-) delete mode 100644 components/home-element.js delete mode 100644 components/icon-text.js diff --git a/components/common/app-text.js b/components/common/app-text.js index e7c1270d..d431466a 100644 --- a/components/common/app-text.js +++ b/components/common/app-text.js @@ -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]), diff --git a/components/common/button.js b/components/common/button.js index afd57e52..fd2213f6 100644 --- a/components/common/button.js +++ b/components/common/button.js @@ -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 } }) diff --git a/components/common/link.js b/components/common/link.js index 8b1293f0..c2213613 100644 --- a/components/common/link.js +++ b/components/common/link.js @@ -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({ diff --git a/components/common/menu-icon.js b/components/common/menu-icon.js index 636235ec..abe7f837 100644 --- a/components/common/menu-icon.js +++ b/components/common/menu-icon.js @@ -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 = { diff --git a/components/helpers/home.js b/components/helpers/home.js index 98e9f200..1da85165 100644 --- a/components/helpers/home.js +++ b/components/helpers/home.js @@ -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' +} diff --git a/components/home-element.js b/components/home-element.js deleted file mode 100644 index 7f50f351..00000000 --- a/components/home-element.js +++ /dev/null @@ -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 diff --git a/components/home.js b/components/home.js index b76bfd68..7cc52a0f 100644 --- a/components/home.js +++ b/components/home.js @@ -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 } - > - <View> - <DripHomeIcon name="circle" size={80} color={cycleDayColor}/> - </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> + <ScrollView + style={styles.container} + contentContainerStyle={styles.contentContainer} + > + <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> + <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> + )} + </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) => { return({ date: getDate(state), diff --git a/components/icon-text.js b/components/icon-text.js deleted file mode 100644 index be3b4063..00000000 --- a/components/icon-text.js +++ /dev/null @@ -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 diff --git a/i18n/en/labels.js b/i18n/en/labels.js index 7aec163f..4dd59fe3 100644 --- a/i18n/en/labels.js +++ b/i18n/en/labels.js @@ -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] + diff --git a/styles/spacing.js b/styles/spacing.js index 9b2a0b54..32c57974 100644 --- a/styles/spacing.js +++ b/styles/spacing.js @@ -1,4 +1,5 @@ export default { + tiny: 4, small: 10, base: 16, large: 20 diff --git a/styles/typography.js b/styles/typography.js index 82527a84..4dcf274b 100644 --- a/styles/typography.js +++ b/styles/typography.js @@ -11,7 +11,7 @@ export const sizes = { base: 18, subtitle: 22, title: 24, - icon: 40 + huge: 40 } const title = { -- GitLab