From 7b9293f7a250c5c75199ce0bd8d4e0431fd74444 Mon Sep 17 00:00:00 2001 From: Maria Zadnepryanets Date: Mon, 26 Sep 2022 17:19:23 +0000 Subject: [PATCH] Feature: add stats explainer take2 --- components/Home.js | 2 +- components/common/Footnote.js | 17 +- components/common/app-modal.js | 61 ++++-- components/cycle-day/symptom-edit-view.js | 200 ++++++++---------- .../{StatsTable.js => PeriodDetailsModal.js} | 37 ++-- components/stats/StatsOverview.js | 8 +- components/stats/index.js | 74 ++++--- .../__snapshots__/Footnote.spec.js.snap | 6 +- 8 files changed, 224 insertions(+), 181 deletions(-) rename components/stats/{StatsTable.js => PeriodDetailsModal.js} (75%) diff --git a/components/Home.js b/components/Home.js index 0ad6949..820dc22 100644 --- a/components/Home.js +++ b/components/Home.js @@ -71,7 +71,7 @@ const Home = ({ navigate, setDate }) => { - {phase && {statusText}} + {phase && {statusText}} ) } diff --git a/components/common/Footnote.js b/components/common/Footnote.js index 2e1ff22..2749b75 100644 --- a/components/common/Footnote.js +++ b/components/common/Footnote.js @@ -7,13 +7,16 @@ import Asterisk from '../common/Asterisk' import { Colors, Spacing } from '../../styles' -const Footnote = ({ children }) => { +const Footnote = ({ children, colorLabel }) => { if (!children) return false return ( - + {children} @@ -22,6 +25,11 @@ const Footnote = ({ children }) => { Footnote.propTypes = { children: PropTypes.node, + colorLabel: PropTypes.string, +} + +Footnote.defaultProps = { + colorLabel: 'greyDark', } const styles = StyleSheet.create({ @@ -29,14 +37,13 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignContent: 'flex-start', marginBottom: Spacing.tiny, - marginTop: Spacing.small, + marginTop: Spacing.base, }, link: { color: 'white', }, text: { - color: Colors.greyLight, - paddingLeft: Spacing.base, + paddingLeft: Spacing.small, }, }) diff --git a/components/common/app-modal.js b/components/common/app-modal.js index 6b33fd9..c559ac5 100644 --- a/components/common/app-modal.js +++ b/components/common/app-modal.js @@ -1,20 +1,33 @@ import React from 'react' -import { Modal, StyleSheet, TouchableOpacity } from 'react-native' +import { + Dimensions, + Modal, + StyleSheet, + TouchableOpacity, + View, +} from 'react-native' import PropTypes from 'prop-types' -const AppModal = ({ children, onClose }) => { - return ( - - +import CloseIcon from './close-icon' + +import { Sizes, Spacing } from '../../styles' + +const AppModal = ({ children, onClose }) => ( + + + + + + {children} - - ) -} + + +) AppModal.propTypes = { children: PropTypes.node, @@ -27,6 +40,28 @@ const styles = StyleSheet.create({ flex: 1, opacity: 0.5, }, + headerContainer: { + flexDirection: 'row', + justifyContent: 'flex-end', + paddingTop: Spacing.base, + paddingHorizontal: Spacing.base, + position: 'absolute', + width: '100%', + zIndex: 3, // works on ios + elevation: 3, // works on android + }, + modalWindow: { + alignSelf: 'center', + backgroundColor: 'white', + borderRadius: 10, + marginTop: Sizes.huge * 2, + paddingVertical: Spacing.large * 2, + position: 'absolute', + maxHeight: Dimensions.get('window').height * 0.7, + zIndex: 2, // works on ios + elevation: 2, // works on android + minWidth: '80%', + }, }) export default AppModal diff --git a/components/cycle-day/symptom-edit-view.js b/components/cycle-day/symptom-edit-view.js index d487054..64090a4 100644 --- a/components/cycle-day/symptom-edit-view.js +++ b/components/cycle-day/symptom-edit-view.js @@ -1,13 +1,12 @@ import React, { useState } from 'react' import PropTypes from 'prop-types' -import { Dimensions, ScrollView, StyleSheet, View } from 'react-native' +import { ScrollView, StyleSheet, View } from 'react-native' import AppModal from '../common/app-modal' import AppSwitch from '../common/app-switch' import AppText from '../common/app-text' import AppTextInput from '../common/app-text-input' import Button from '../common/button' -import CloseIcon from '../common/close-icon' import Segment from '../common/segment' import SelectBoxGroup from './select-box-group' import SelectTabGroup from './select-tab-group' @@ -119,99 +118,94 @@ const SymptomEditView = ({ date, onClose, symptom, symptomData }) => { return ( - - - - - - {symptom === 'temperature' && ( - onSaveTemperature(value, field)} - /> - )} - {shouldShow(symptomConfig.selectTabGroups) && - symtomPage[symptom].selectTabGroups.map((group) => { - return ( - - {group.title} - onSelectTab(group, value)} - /> - - ) - })} - {shouldShow(symptomConfig.selectBoxGroups) && - symtomPage[symptom].selectBoxGroups.map((group) => { - const isOtherSelected = - data['other'] !== null && - data['other'] !== false && - Object.keys(group.options).includes('other') + + {symptom === 'temperature' && ( + onSaveTemperature(value, field)} + /> + )} + {shouldShow(symptomConfig.selectTabGroups) && + symtomPage[symptom].selectTabGroups.map((group) => { + return ( + + {group.title} + onSelectTab(group, value)} + /> + + ) + })} + {shouldShow(symptomConfig.selectBoxGroups) && + symtomPage[symptom].selectBoxGroups.map((group) => { + const isOtherSelected = + data['other'] !== null && + data['other'] !== false && + Object.keys(group.options).includes('other') - return ( - - {group.title} - onSelectBox(value)} - optionsState={data} + return ( + + {group.title} + onSelectBox(value)} + optionsState={data} + /> + {isOtherSelected && ( + onSelectBoxNote(value)} /> - {isOtherSelected && ( - onSelectBoxNote(value)} - /> - )} - - ) - })} - {shouldShow(symptomConfig.excludeText) && ( - - - - )} - {shouldShow(symptomConfig.note) && ( - - {symtomPage[symptom].note} - - - )} - - - - - - {shouldShowInfo && ( - - {info[symptom].text} - - )} - - + )} + + ) + })} + {shouldShow(symptomConfig.excludeText) && ( + + + + )} + {shouldShow(symptomConfig.note) && ( + + {symtomPage[symptom].note} + + + )} + + + + + + {shouldShowInfo && ( + + {info[symptom].text} + + )} + ) } @@ -229,32 +223,12 @@ const styles = StyleSheet.create({ paddingHorizontal: Spacing.base, paddingBottom: Spacing.base, }, - headerContainer: { - flexDirection: 'row', - justifyContent: 'flex-end', - paddingTop: Spacing.base, - paddingHorizontal: Spacing.base, - position: 'absolute', - width: '100%', - zIndex: 3, // works on ios - elevation: 3, // works on android - }, input: { height: Sizes.base * 5, }, modalContainer: { paddingHorizontal: Spacing.base, }, - modalWindow: { - alignSelf: 'center', - backgroundColor: 'white', - borderRadius: 10, - marginTop: Sizes.huge * 2, - paddingTop: Spacing.large * 2, - position: 'absolute', - minHeight: '40%', - maxHeight: Dimensions.get('window').height * 0.7, - }, segmentBorder: { borderBottomColor: Colors.greyLight, }, diff --git a/components/stats/StatsTable.js b/components/stats/PeriodDetailsModal.js similarity index 75% rename from components/stats/StatsTable.js rename to components/stats/PeriodDetailsModal.js index 88bc33b..fca8d5f 100644 --- a/components/stats/StatsTable.js +++ b/components/stats/PeriodDetailsModal.js @@ -3,6 +3,7 @@ import { FlatList, StyleSheet, View } from 'react-native' import PropTypes from 'prop-types' import { useTranslation } from 'react-i18next' +import AppModal from '../common/app-modal' import AppText from '../common/app-text' import cycleModule from '../../lib/cycle' @@ -35,26 +36,34 @@ Item.propTypes = { data: PropTypes.object.isRequired, } -const StatsTable = () => { +const PeriodDetailsModal = ({ onClose }) => { const renderItem = ({ item }) => const data = cycleModule().getStats() if (!data || data.length === 0) return false return ( - item.date} - ItemSeparatorComponent={ItemDivider} - ListHeaderComponent={FlatListHeader} - ListHeaderComponentStyle={styles.headerDivider} - stickyHeaderIndices={[0]} - contentContainerStyle={styles.container} - /> + + + item.date} + ItemSeparatorComponent={ItemDivider} + ListHeaderComponent={FlatListHeader} + ListHeaderComponentStyle={styles.headerDivider} + stickyHeaderIndices={[0]} + contentContainerStyle={styles.container} + /> + + ) } +PeriodDetailsModal.propTypes = { + onClose: PropTypes.func, +} + const ItemDivider = () => const FlatListHeader = () => ( @@ -89,7 +98,7 @@ const styles = StyleSheet.create({ flexDirection: 'row', justifyContent: 'space-between', paddingVertical: Spacing.tiny, - backgroundColor: Colors.turquoiseLight, + backgroundColor: 'white', }, cell: { flex: 2, @@ -100,8 +109,10 @@ const styles = StyleSheet.create({ justifyContent: 'center', }, container: { + minHeight: '40%', + minWidth: '95%', paddingHorizontal: Spacing.base, }, }) -export default StatsTable +export default PeriodDetailsModal diff --git a/components/stats/StatsOverview.js b/components/stats/StatsOverview.js index a6317f6..6eb1081 100644 --- a/components/stats/StatsOverview.js +++ b/components/stats/StatsOverview.js @@ -15,10 +15,12 @@ StatsOverview.propTypes = { } const Row = ({ rowContent }) => { + const isStandardDeviation = rowContent[1].includes('deviation') + return ( - + ) } @@ -27,7 +29,7 @@ Row.propTypes = { rowContent: PropTypes.array.isRequired, } -const Cell = ({ content, isLeft }) => { +const Cell = ({ content, isLeft, hasAsterisk }) => { const styleContainer = isLeft ? styles.cellLeft : styles.cellRight const styleText = isLeft ? styles.accentPurpleBig : styles.accentOrange const numberOfLines = isLeft ? 1 : 2 @@ -41,6 +43,7 @@ const Cell = ({ content, isLeft }) => { style={styleText} > {content} + {hasAsterisk && *} ) @@ -49,6 +52,7 @@ const Cell = ({ content, isLeft }) => { Cell.propTypes = { content: PropTypes.node.isRequired, isLeft: PropTypes.bool, + hasAsterisk: PropTypes.bool, } const styles = StyleSheet.create({ diff --git a/components/stats/index.js b/components/stats/index.js index 29b4bc5..2f4a2c2 100644 --- a/components/stats/index.js +++ b/components/stats/index.js @@ -1,11 +1,13 @@ -import React from 'react' -import { ImageBackground, View } from 'react-native' +import React, { useState } from 'react' +import { ImageBackground, SafeAreaView, ScrollView, View } from 'react-native' import { ScaledSheet } from 'react-native-size-matters' import { useTranslation } from 'react-i18next' import AppText from '../common/app-text' +import Button from '../common/button' +import Footnote from '../common/Footnote' import StatsOverview from './StatsOverview' -import StatsTable from './StatsTable' +import PeriodDetailsModal from './PeriodDetailsModal' import cycleModule from '../../lib/cycle' import { getCycleLengthStats as getCycleInfo } from '../../lib/cycle-length' @@ -15,6 +17,8 @@ import { Containers, Sizes, Spacing, Typography } from '../../styles' const image = require('../../assets/cycle-icon.png') const Stats = () => { + const [isStatsVisible, setIsStatsVisible] = useState(false) + const { t } = useTranslation(null, { keyPrefix: 'stats' }) const cycleLengths = cycleModule().getAllCycleLengths() @@ -34,42 +38,50 @@ const Stats = () => { ] return ( - - + + {t('intro')} {numberOfCycles === 0 ? ( {t('noData')} ) : ( - - - - + + + - {cycleData.mean} + + {cycleData.mean} + + + {t('overview.days')} + + + + {t('overview.average')} - - {t('overview.days')} - - - - {t('overview.average')} - + + + + - - - - + + {isStatsVisible && ( + setIsStatsVisible(false)} /> + )} + {t('footnote')} + )} - - - + + ) } diff --git a/test/components/common/__snapshots__/Footnote.spec.js.snap b/test/components/common/__snapshots__/Footnote.spec.js.snap index 07c0e5e..68b5474 100644 --- a/test/components/common/__snapshots__/Footnote.spec.js.snap +++ b/test/components/common/__snapshots__/Footnote.spec.js.snap @@ -7,7 +7,7 @@ exports[`Footnote component when children are present, renders them 1`] = ` "alignContent": "flex-start", "flexDirection": "row", "marginBottom": 8.571428571428571, - "marginTop": 21.428571428571427, + "marginTop": 34.285714285714285, } } > @@ -41,8 +41,8 @@ exports[`Footnote component when children are present, renders them 1`] = ` "fontSize": 34.285714285714285, }, Object { - "color": "#CCC", - "paddingLeft": 34.285714285714285, + "color": "#555", + "paddingLeft": 21.428571428571427, }, ] }