Chore/make function components 3

This commit is contained in:
Maria Zadnepryanets
2022-09-11 15:35:16 +00:00
parent 8404a3bbe8
commit 9202945e9c
4 changed files with 134 additions and 222 deletions
+24 -64
View File
@@ -1,4 +1,4 @@
import React, { Component } from 'react' import React, { useState, useEffect } from 'react'
import { BackHandler, StyleSheet, View } from 'react-native' import { BackHandler, StyleSheet, View } from 'react-native'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
@@ -7,99 +7,59 @@ import { LocalDate } from '@js-joda/core'
import Header from './header' import Header from './header'
import Menu from './menu' import Menu from './menu'
import { viewsList } from './views' import { viewsList } from './views'
import { isSettingsView, pages } from './pages' import { pages } from './pages'
import { headerTitles } from '../i18n/en/labels'
import setupNotifications from '../lib/notifications' import setupNotifications from '../lib/notifications'
import { closeDb } from '../db' import { closeDb } from '../db'
class App extends Component { const App = ({ restartApp }) => {
static propTypes = { const [date, setDate] = useState(LocalDate.now().toString())
date: PropTypes.string, const [currentPage, setCurrentPage] = useState('Home')
navigate: PropTypes.func, const goBack = () => {
setDate: PropTypes.func,
goBack: PropTypes.func,
restartApp: PropTypes.func,
}
constructor(props) {
super(props)
this.backHandler = BackHandler.addEventListener(
'hardwareBackPress',
this.goBack
)
this.state = {
date: LocalDate.now().toString(),
currentPage: 'Home',
}
setupNotifications(this.navigate, this.setDate)
}
navigate = (page) => {
this.setState({ currentPage: page })
}
setDate = (date) => {
this.setState({ date })
}
goBack = () => {
const { currentPage } = this.state
if (currentPage === 'Home') { if (currentPage === 'Home') {
closeDb() closeDb()
BackHandler.exitApp() BackHandler.exitApp()
} else { } else {
const { parent } = pages.find((p) => p.component === currentPage) const { parent } = pages.find((p) => p.component === currentPage)
this.navigate(parent)
setCurrentPage(parent)
} }
return true return true
} }
componentWillUnmount() { useEffect(() => {
this.backHandler.remove() const backHandler = BackHandler.addEventListener(
} 'hardwareBackPress',
goBack
)
render() { return () => backHandler.remove()
const { goBack, restartApp } = this.props })
const { date, currentPage } = this.state
const { navigate } = this
if (!currentPage) { useEffect(() => setupNotifications(setCurrentPage, setDate), [])
return false
}
const Page = viewsList[currentPage] const Page = viewsList[currentPage]
const title = headerTitles[currentPage]
const isSettingsSubView = isSettingsView(currentPage)
const isTemperatureEditView = currentPage === 'TemperatureEditView' const isTemperatureEditView = currentPage === 'TemperatureEditView'
const headerProps = { navigate: setCurrentPage }
const headerProps = {
title,
handleBack: isSettingsSubView ? goBack : null,
navigate,
}
const pageProps = { const pageProps = {
date, date,
setDate: this.setDate, setDate,
isTemperatureEditView, isTemperatureEditView,
navigate, navigate: setCurrentPage,
} }
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Header {...headerProps} /> <Header {...headerProps} />
<Page {...pageProps} restartApp={restartApp} /> <Page {...pageProps} restartApp={restartApp} />
<Menu currentPage={currentPage} navigate={navigate} /> <Menu currentPage={currentPage} navigate={setCurrentPage} />
</View> </View>
) )
} }
App.propTypes = {
restartApp: PropTypes.func,
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
+16 -48
View File
@@ -1,11 +1,10 @@
import React, { Component } from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { StyleSheet, View } from 'react-native' import { StyleSheet, View } from 'react-native'
import { CalendarList } from 'react-native-calendars' import { CalendarList } from 'react-native-calendars'
import { getBleedingDaysSortedByDate } from '../db' import { getBleedingDaysSortedByDate } from '../db'
import cycleModule from '../lib/cycle' import cycleModule from '../lib/cycle'
import nothingChanged from '../db/db-unchanged'
import { import {
calendarTheme, calendarTheme,
predictionToCalFormat, predictionToCalFormat,
@@ -13,55 +12,20 @@ import {
todayToCalFormat, todayToCalFormat,
} from './helpers/calendar' } from './helpers/calendar'
class CalendarView extends Component { const CalendarView = ({ setDate, navigate }) => {
static propTypes = { const bleedingDays = getBleedingDaysSortedByDate()
setDate: PropTypes.func.isRequired,
navigate: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
this.bleedingDays = getBleedingDaysSortedByDate()
const predictedMenses = cycleModule().getPredictedMenses() const predictedMenses = cycleModule().getPredictedMenses()
this.state = {
bleedingDaysInCalFormat: toCalFormat(this.bleedingDays), const passDateToDayView = ({ dateString }) => {
predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses), setDate(dateString)
todayInCalFormat: todayToCalFormat(), navigate('CycleDay')
} }
this.bleedingDays.addListener(this.setStateWithCalFormattedDays)
}
setStateWithCalFormattedDays = (_, changes) => {
if (nothingChanged(changes)) return
const predictedMenses = cycleModule().getPredictedMenses()
this.setState({
bleedingDaysInCalFormat: toCalFormat(this.bleedingDays),
predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses),
todayInCalFormat: todayToCalFormat(),
})
}
componentWillUnmount() {
this.bleedingDays.removeListener(this.setStateWithCalFormattedDays)
}
passDateToDayView = (result) => {
this.props.setDate(result.dateString)
this.props.navigate('CycleDay')
}
render() {
const {
todayInCalFormat,
bleedingDaysInCalFormat,
predictedBleedingDaysInCalFormat,
} = this.state
const markedDates = Object.assign( const markedDates = Object.assign(
{}, {},
todayInCalFormat, todayToCalFormat(),
bleedingDaysInCalFormat, toCalFormat(bleedingDays),
predictedBleedingDaysInCalFormat predictionToCalFormat(predictedMenses)
) )
return ( return (
@@ -69,7 +33,7 @@ class CalendarView extends Component {
<CalendarList <CalendarList
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday. // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1} firstDay={1}
onDayPress={this.passDateToDayView.bind(this)} onDayPress={passDateToDayView}
markedDates={markedDates} markedDates={markedDates}
markingType="custom" markingType="custom"
theme={calendarTheme} theme={calendarTheme}
@@ -78,11 +42,15 @@ class CalendarView extends Component {
/> />
</View> </View>
) )
}
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { flex: 1 }, container: { flex: 1 },
}) })
CalendarView.propTypes = {
setDate: PropTypes.func.isRequired,
navigate: PropTypes.func.isRequired,
}
export default CalendarView export default CalendarView
-3
View File
@@ -3,9 +3,6 @@ import settingsViews from './settings'
import settingsLabels from '../i18n/en/settings' import settingsLabels from '../i18n/en/settings'
const labels = settingsLabels.menuItems const labels = settingsLabels.menuItems
export const isSettingsView = (page) =>
Object.keys(settingsViews).includes(page)
export const pages = [ export const pages = [
{ {
component: 'Home', component: 'Home',
+45 -58
View File
@@ -1,4 +1,4 @@
import React, { Component } from 'react' import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Alert, StyleSheet, View } from 'react-native' import { Alert, StyleSheet, View } from 'react-native'
import nodejs from 'nodejs-mobile-react-native' import nodejs from 'nodejs-mobile-react-native'
@@ -15,97 +15,82 @@ import { Containers, Spacing } from '../styles'
const cancelButton = { text: shared.cancel, style: 'cancel' } const cancelButton = { text: shared.cancel, style: 'cancel' }
export default class PasswordPrompt extends Component { const PasswordPrompt = ({ enableShowApp }) => {
static propTypes = { const [password, setPassword] = useState(null)
enableShowApp: PropTypes.func.isRequired, const unlockApp = () => requestHash('check-pw', password)
} const isPasswordEntered = Boolean(password)
const passHashToDb = async (hash) => {
constructor(props) {
super(props)
this.state = { password: null }
nodejs.channel.addListener('check-pw', this.passHashToDb, this)
}
componentWillUnmount() {
nodejs.channel.removeListener('check-pw', this.passHashToDb)
}
onConfirmDeletion = async () => {
Alert.alert(labels.deleteDatabaseTitle, labels.deleteDatabaseExplainer, [
cancelButton,
{ text: labels.deleteData, onPress: this.onDeleteData },
])
}
onDeleteData = () => {
Alert.alert(labels.areYouSureTitle, labels.areYouSure, [
cancelButton,
{
text: labels.reallyDeleteData,
onPress: this.onDeleteDataConfirmation,
},
])
}
onDeleteDataConfirmation = async () => {
await deleteDbAndOpenNew()
await saveEncryptionFlag(false)
this.props.enableShowApp()
}
passHashToDb = async (hash) => {
const connected = await openDb(hash) const connected = await openDb(hash)
if (!connected) { if (!connected) {
Alert.alert(shared.incorrectPassword, shared.incorrectPasswordMessage, [ Alert.alert(shared.incorrectPassword, shared.incorrectPasswordMessage, [
{ {
text: shared.tryAgain, text: shared.tryAgain,
onPress: () => this.setState({ password: null }), onPress: () => setPassword(null),
}, },
]) ])
return return
} }
this.props.enableShowApp()
enableShowApp()
} }
unlockApp = () => { useEffect(() => {
requestHash('check-pw', this.state.password) nodejs.channel.addListener('check-pw', passHashToDb, this)
return () => nodejs.channel.remove('check-pw', passHashToDb)
}, [])
const onDeleteDataConfirmation = async () => {
await deleteDbAndOpenNew()
await saveEncryptionFlag(false)
enableShowApp()
} }
setPassword = (password) => { const onDeleteData = () => {
this.setState({ password }) Alert.alert(labels.areYouSureTitle, labels.areYouSure, [
cancelButton,
{
text: labels.reallyDeleteData,
onPress: onDeleteDataConfirmation,
},
])
} }
render() { const onConfirmDeletion = async () => {
const { password } = this.state Alert.alert(labels.deleteDatabaseTitle, labels.deleteDatabaseExplainer, [
const isPasswordEntered = Boolean(password) cancelButton,
{ text: labels.deleteData, onPress: onDeleteData },
])
}
return ( return (
<React.Fragment> <>
<Header isStatic /> <Header isStatic />
<AppPage contentContainerStyle={styles.contentContainer}> <AppPage contentContainerStyle={styles.contentContainer}>
<AppTextInput <AppTextInput
isKeyboardOffset={false} isKeyboardOffset={false}
onChangeText={this.setPassword} onChangeText={setPassword}
secureTextEntry={true} secureTextEntry={true}
placeholder={labels.enterPassword} placeholder={labels.enterPassword}
/> />
<View style={styles.containerButtons}> <View style={styles.containerButtons}>
<Button onPress={this.onConfirmDeletion}> <Button onPress={onConfirmDeletion}>{labels.forgotPassword}</Button>
{labels.forgotPassword}
</Button>
<Button <Button
disabled={!isPasswordEntered} disabled={!isPasswordEntered}
isCTA={isPasswordEntered} isCTA={isPasswordEntered}
onPress={this.unlockApp} onPress={unlockApp}
> >
{labels.title} {labels.title}
</Button> </Button>
</View> </View>
</AppPage> </AppPage>
</React.Fragment> </>
) )
} }
PasswordPrompt.propTypes = {
enableShowApp: PropTypes.func.isRequired,
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@@ -119,3 +104,5 @@ const styles = StyleSheet.create({
justifyContent: 'space-around', justifyContent: 'space-around',
}, },
}) })
export default PasswordPrompt