diff --git a/components/common/app-page.js b/components/common/app-page.js index f8b3e93..a7b5a49 100644 --- a/components/common/app-page.js +++ b/components/common/app-page.js @@ -4,7 +4,7 @@ import { ScrollView, StyleSheet } from 'react-native' import AppText from '../common/app-text' -import { Colors, Fonts, Sizes, Spacing, Typography } from '../../styles/redesign' +import { Colors, Typography } from '../../styles/redesign' const AppPage = ({ children, title }) => { return( @@ -26,11 +26,6 @@ const styles = StyleSheet.create({ flex: 1 }, title: { - alignSelf: 'center', - fontFamily: Fonts.bold, - fontWeight: '700', - fontSize: Sizes.title, - marginHorizontal: Spacing.base, ...Typography.title } }) diff --git a/components/common/segment.js b/components/common/segment.js index edc525e..5037c5b 100644 --- a/components/common/segment.js +++ b/components/common/segment.js @@ -4,7 +4,7 @@ import { StyleSheet, View } from 'react-native' import AppText from './app-text' -import { Containers, Spacing, Sizes, Typography } from '../../styles/redesign' +import { Containers, Spacing, Typography } from '../../styles/redesign' const Segment = ({ children, last, title }) => { const containerStyle = last ? styles.containerLast : styles.container @@ -37,8 +37,7 @@ const styles = StyleSheet.create({ ...segmentContainer }, title: { - fontSize: Sizes.subtitle, - ...Typography.title + ...Typography.subtitle } }) diff --git a/components/header/delete-icon.js b/components/header/delete-icon.js deleted file mode 100644 index 1b67001..0000000 --- a/components/header/delete-icon.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import { TouchableOpacity } from 'react-native' -import PropTypes from 'prop-types' - -import Icon from 'react-native-vector-icons/AntDesign' - -import styles, { iconStyles } from '../../styles' - -export default function DeleteIcon({ handleDelete }) { - - return ( - - - - ) -} - -DeleteIcon.propTypes = { - handleDelete: PropTypes.func, -} diff --git a/components/header/index.js b/components/header/index.js index 885eec3..13cb88b 100644 --- a/components/header/index.js +++ b/components/header/index.js @@ -1,36 +1,78 @@ -import React from 'react' -import { View } from 'react-native' +import React, { Component } from 'react' +import { StyleSheet, TouchableOpacity, View } from 'react-native' import PropTypes from 'prop-types' -import Title from './title' -import NavigationArrow from './navigation-arrow' -import DeleteIcon from './delete-icon' +import AppText from '../common/app-text' +import SideMenu from './side-menu' -import styles from '../../styles' +import { connect } from 'react-redux' +import { navigate } from '../../slices/navigation' -export default function Header({ - handleBack, - handleNext, - handleDelete, - title, - subtitle, -}) { +import { Colors, Containers, Fonts, Sizes } from '../../styles/redesign' - return ( - - - { handleBack && } - - { handleNext && <NavigationArrow handleNext={handleNext} /> } - { handleDelete && <DeleteIcon handleDelete={handleDelete} /> } - </View > +class Header extends Component { + + static propTypes = { + navigate: PropTypes.func.isRequired + } + + constructor(props) { + super(props) + + this.state = { shouldShowMenu: false } + } + + toggleMenu = () => { + this.setState({ shouldShowMenu: !this.state.shouldShowMenu}) + } + + render() { + const { shouldShowMenu } = this.state + + return ( + <View style={styles.header}> + <DripIcon navigate={this.props.navigate}/> + <SideMenu + shouldShowMenu={shouldShowMenu} + onPress={this.toggleMenu} + /> + </View > + ) + } +} + +const DripIcon = ({ navigate }) => { + return( + <TouchableOpacity onPress={() => navigate('Home')}> + <AppText style={styles.icon}>drip.</AppText> + </TouchableOpacity> ) } -Header.propTypes = { - handleBack: PropTypes.func, - handleDelete: PropTypes.func, - handleNext: PropTypes.func, - subtitle: PropTypes.string, - title: PropTypes.string.isRequired +DripIcon.propTypes = { + navigate: PropTypes.func.isRequired } + +const styles = StyleSheet.create({ + header: { + backgroundColor: Colors.purple, + padding: Sizes.base, + ...Containers.rowContainer + }, + icon: { + color: Colors.tourquiseDark, + fontFamily: Fonts.bold, + fontSize: Sizes.title + } +}) + +const mapDispatchToProps = (dispatch) => { + return({ + navigate: (page) => dispatch(navigate(page)), + }) +} + +export default connect( + null, + mapDispatchToProps, +)(Header) \ No newline at end of file diff --git a/components/header/navigation-arrow.js b/components/header/navigation-arrow.js deleted file mode 100644 index 7675893..0000000 --- a/components/header/navigation-arrow.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react' -import { TouchableOpacity } from 'react-native' -import PropTypes from 'prop-types' -import Icon from 'react-native-vector-icons/Entypo' - -import styles, { iconStyles } from '../../styles' - -export default function NavigationArrow({ handleBack, handleNext }) { - const navigationDirection = handleBack ? 'Left' : 'Right' - return ( - <TouchableOpacity - style={[ - styles.navigationArrow, - styles[`navigationArrow${navigationDirection}`] - ]} - onPress={ handleBack || handleNext } - testID={ handleBack ? 'backButton' : 'nextButton'} - > - <Icon - name={`chevron-thin-${navigationDirection.toLowerCase()}`} - {...iconStyles.navigationArrow} - /> - </TouchableOpacity> - ) -} - -NavigationArrow.propTypes = { - handleBack: PropTypes.func, - handleNext: PropTypes.func, -} \ No newline at end of file diff --git a/components/header/side-menu.js b/components/header/side-menu.js new file mode 100644 index 0000000..0b48e3e --- /dev/null +++ b/components/header/side-menu.js @@ -0,0 +1,114 @@ +import React from 'react' +import { Modal, StyleSheet, TouchableOpacity, View } from 'react-native' +import PropTypes from 'prop-types' + +import AppIcon from '../common/app-icon' +import AppText from '../common/app-text' + +import { connect } from 'react-redux' +import { navigate } from '../../slices/navigation' + +import { Sizes, Typography } from '../../styles/redesign' +import settingsLabels from '../../i18n/en/settings' + +const { menuItems } = settingsLabels + +const settingsMenuItems = [ + {name: menuItems.settings, component: 'SettingsMenu'}, + {name: menuItems.about, component: 'About'}, + {name: menuItems.license, component: 'License'}, +] + +const SideMenu = ({ navigate, onPress, shouldShowMenu }) => { + const navigateMenuItem = (page) => { + onPress() + navigate(page) + } + + return( + <React.Fragment> + {!shouldShowMenu && + <TouchableOpacity onPress={onPress}> + <AppIcon name={'dots-three-vertical'} isCTA/> + </TouchableOpacity> + } + {shouldShowMenu && + <Modal + animationType='fade' + onRequestClose={onPress} + transparent={true} + visible={shouldShowMenu} + > + <View style={styles.blackBackground}></View> + <View style={styles.menu}> + <TouchableOpacity onPress={onPress} style={styles.iconContainer}> + <AppIcon name={'cross'}/> + </TouchableOpacity> + {settingsMenuItems.map(item => + <MenuItem + item={item} + key={item.name} + navigate={navigateMenuItem} + /> + )} + </View> + </Modal> + } + </React.Fragment> + ) +} + +SideMenu.propTypes = { + navigate: PropTypes.func.isRequired, + onPress: PropTypes.func, + shouldShowMenu: PropTypes.bool.isRequired +} + +const MenuItem = ({ item, navigate }) => { + return( + <View style={styles.menuItem}> + <TouchableOpacity onPress={() => navigate(item.component)}> + <AppText style={styles.text}>{item.name}</AppText> + </TouchableOpacity> + </View> + ) +} + +MenuItem.propTypes = { + item: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, +} + +const styles = StyleSheet.create({ + blackBackground: { + backgroundColor: 'black', + flex: 1, + opacity: 0.65, + }, + iconContainer: { + alignSelf: 'flex-end', + marginBottom: Sizes.base + }, + menu: { + alignSelf: 'flex-end', + backgroundColor: 'white', + height: '100%', + padding: Sizes.base, + position: 'absolute', + width: '60%' + }, + text: { + ...Typography.subtitle + } +}) + +const mapDispatchToProps = (dispatch) => { + return({ + navigate: (page) => dispatch(navigate(page)), + }) +} + +export default connect( + null, + mapDispatchToProps, +)(SideMenu) diff --git a/components/header/title.js b/components/header/title.js deleted file mode 100644 index f667ded..0000000 --- a/components/header/title.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import { View, Text} from 'react-native' -import PropTypes from 'prop-types' - -import styles from '../../styles' - -export default function Title({ title, subtitle }) { - - if (subtitle !== undefined) { - return ( - <View> - <Text style={styles.dateHeader} testID='headerTitle'> - { // design wants everyhting lowercased, but we don't - // have CSS pseudo properties - title.toLowerCase()} - </Text> - { subtitle && - <Text style={styles.cycleDayNumber} testID='headerSubtitle'> - {subtitle.toLowerCase()} - </Text> - } - </View> - ) - } - - return ( - <Text testID='headerTitle' style={styles.headerText}> - {title.toLowerCase()} - </Text> - ) -} - -Title.propTypes = { - title: PropTypes.string, - subtitle: PropTypes.string, -} diff --git a/i18n/en/settings.js b/i18n/en/settings.js index c1f6ec6..ca83862 100644 --- a/i18n/en/settings.js +++ b/i18n/en/settings.js @@ -20,7 +20,10 @@ export default { password: { name:'Password', text: '' - } + }, + about: 'About', + license: 'License', + settings: 'Settings' }, export: { errors: { diff --git a/styles/containers.js b/styles/containers.js index 78194a4..37af327 100644 --- a/styles/containers.js +++ b/styles/containers.js @@ -12,5 +12,10 @@ export default { alignItems: 'center', flex: 1, justifyContent: 'center' + }, + rowContainer: { + alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between' } } \ No newline at end of file diff --git a/styles/typography.js b/styles/typography.js index 5539b6a..effa01c 100644 --- a/styles/typography.js +++ b/styles/typography.js @@ -12,13 +12,26 @@ export const sizes = { title: 24 } +const title = { + color: Colors.purple, + marginVertical: Spacing.large +} + export default { mainText: { fontFamily: fonts.main, fontSize: sizes.base }, + subtitle: { + fontSize: sizes.subtitle, + ...title + }, title: { - color: Colors.purple, - marginVertical: Spacing.large + alignSelf: 'center', + fontFamily: fonts.bold, + fontWeight: '700', + fontSize: sizes.title, + marginHorizontal: Spacing.base, + ...title } }