Compare commits

...

6 Commits

Author SHA1 Message Date
tina a4e0fa64e9 calculates cycle days for headaches 2024-10-15 17:52:38 +02:00
tina fd6f39fbc4 first exploration of place of feature and how to access data 2024-10-15 14:47:42 +02:00
wunderfisch d492a27797 Merge branch '723-feature-link-faq-in-app' into 'main'
adds a button leading to faq on website to about section in the app

Closes #723

See merge request bloodyhealth/drip!684
2024-10-03 16:35:28 +00:00
wunderfisch 22a451d4e6 Merge branch 'chore/add-condriputers' into 'main'
addding condriputers

See merge request bloodyhealth/drip!682
2024-10-03 16:35:10 +00:00
wunderfisch 86bdb8a1f8 adds a button leading to faq on website to about section in the app 2024-09-09 21:00:21 +02:00
wunderfisch 4212906917 addding condriputers 2024-02-29 17:54:25 +01:00
8 changed files with 188 additions and 3 deletions
+4
View File
@@ -18,6 +18,10 @@ const AboutSection = () => {
<AppPage title={t('title')}>
<Segment>
<AppText>{t('intro.text')}</AppText>
<Button isCTA isSmall onPress={() => Linking.openURL(links.faq.url)}>
{t('intro.faq')}
</Button>
<AppText>{t('intro.contact')}</AppText>
<ButtonRow>
{[links.email, links.gitlab, links.website].map((link) => (
<Button
+89
View File
@@ -0,0 +1,89 @@
import React from 'react'
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 symOccModule from '../../lib/sympto-occurance'
import { Spacing, Typography, Colors } from '../../styles'
// const { t } = useTranslation(null, { keyPrefix: 'stats' })
const SymptomOccurance = ({ onClose }) => {
const cycleDays = symOccModule().getCycleStartsOfLastYear()
if (!cycleDays || cycleDays.length === 0) return false
console.log('cycle starts:', cycleDays)
const headacheDays = symOccModule().getPainDaysOfLastYear()
console.log('pain', headacheDays)
const cycleDaysOfPain = symOccModule().getCycleDayForPainDays(
cycleDays,
headacheDays
)
console.log('cycle days of pain', cycleDaysOfPain)
return (
<AppModal onClose={onClose}>
<View>
<FlatList
ListHeaderComponent={FlatListHeader}
contentContainerStyle={styles.container}
/>
</View>
</AppModal>
)
}
SymptomOccurance.propTypes = {
onClose: PropTypes.func,
}
const FlatListHeader = () => (
<View style={styles.row}>
<View style={styles.accentCell}>
<AppText style={styles.header}>
{'When did you experience headaches in the last year?'}
</AppText>
</View>
</View>
)
const styles = StyleSheet.create({
divider: {
height: 1,
width: '100%',
backgroundColor: Colors.grey,
},
header: {
...Typography.accentOrange,
paddingVertical: Spacing.small,
},
headerDivider: {
borderBottomColor: Colors.purple,
borderBottomWidth: 2,
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingVertical: Spacing.tiny,
backgroundColor: 'white',
},
cell: {
flex: 2,
justifyContent: 'center',
},
accentCell: {
flex: 3,
justifyContent: 'center',
},
container: {
minHeight: '40%',
minWidth: '95%',
paddingHorizontal: Spacing.base,
},
})
export default SymptomOccurance
+11
View File
@@ -8,6 +8,7 @@ import Button from '../common/button'
import Footnote from '../common/Footnote'
import StatsOverview from './StatsOverview'
import PeriodDetailsModal from './PeriodDetailsModal'
import SymptomOccurance from './SymptomOccurance'
import cycleModule from '../../lib/cycle'
import { getCycleLengthStats as getCycleInfo } from '../../lib/cycle-length'
@@ -19,6 +20,8 @@ const image = require('../../assets/cycle-icon.png')
const Stats = () => {
const [isStatsVisible, setIsStatsVisible] = useState(false)
const [isSymptomOccuranceVisible, setIsSymptomOccuranceVisible] =
useState(false)
const { t } = useTranslation(null, { keyPrefix: 'stats' })
@@ -83,6 +86,14 @@ const Stats = () => {
{isStatsVisible && (
<PeriodDetailsModal onClose={() => setIsStatsVisible(false)} />
)}
<Button isCTA onPress={() => setIsSymptomOccuranceVisible(true)}>
{t('showSymptomOccurance')}
</Button>
{isSymptomOccuranceVisible && (
<SymptomOccurance
onClose={() => setIsSymptomOccuranceVisible(false)}
/>
)}
<Footnote>{t('footnote')}</Footnote>
</>
)}
+3
View File
@@ -73,6 +73,9 @@ export function getTemperatureDaysSortedByDate() {
.filtered('temperature != null')
.sorted('date', true)
}
export function getPainDaysSortedByDate() {
return db.objects('CycleDay').filtered('pain != null').sorted('date', true)
}
export function getCycleDaysSortedByDate() {
const cycleDays = db.objects('CycleDay').sorted('date', true)
+5 -2
View File
@@ -45,7 +45,9 @@
"text": "The drips are developing this app on a volunteer basis. We are always grateful for support. This could mean condriputing to the code, giving feedback, suggesting improvements or features, testing or donating. It helps and motivates us maintaining this app and developing new features. Thank you for your support!"
},
"intro": {
"text": "Please note that your data is stored locally on your phone and not on a server. This means your data cannot be read by anyone else unless they have access to your phone. We want to ensure that you stay in control of your own data. If you are planning to switch or reset your phone, please remember to export your data before doing so. You can reinstall the app afterwards and import your data.\n\nIf you encounter any technical issues, don't hesitate to contact us via email. You can also contribute to the code base on Gitlab and visit our website."
"text": "Please note that your data is stored locally on your phone and not on a server. This means your data cannot be read by anyone else unless they have access to your phone. We want to ensure that you stay in control of your own data. If you are planning to switch or reset your phone, please remember to export your data before doing so. You can reinstall the app afterwards and import your data.\n\nIf you encounter any issues, please take a look at our Frequently Asked Questions page.",
"faq": "FAQ",
"contact": "\nIf your issue is not listed, don't hesitate to contact us via email. You can also contribute to the code base on Gitlab and visit our website."
},
"philosophy": {
"title": "Remember to think for yourself",
@@ -154,7 +156,8 @@
"cycleLength": "Cycle length",
"bleedingDays": "Bleeding"
},
"footnote": "Based on the standard deviation of all your tracked periods drip. calculates a range for the starting day of the upcoming 3 periods. The range will be 3 days if your standard deviation is smaller than 1.5 and 5 days if the value is bigger.\n\nThe standard deviation tells you how much the length of your periods vary, 0 means all your periods are exactly the same length and the bigger the value the more the period length varies."
"footnote": "Based on the standard deviation of all your tracked periods drip. calculates a range for the starting day of the upcoming 3 periods. The range will be 3 days if your standard deviation is smaller than 1.5 and 5 days if the value is bigger.\n\nThe standard deviation tells you how much the length of your periods vary, 0 means all your periods are exactly the same length and the bigger the value the more the period length varies.",
"showSymptomOccurance": "Show details on headaches"
},
"plurals": {
"day": "{{count}} day",
+4
View File
@@ -39,4 +39,8 @@ export default {
url: 'https://www.flaticon.com',
text: 'Flaticon',
},
faq: {
url: 'https://dripapp.org/faq',
text: 'FAQ',
},
}
+70
View File
@@ -0,0 +1,70 @@
import * as joda from '@js-joda/core'
const LocalDate = joda.LocalDate
const DAYS = joda.ChronoUnit.DAYS
export default function config(opts) {
let cycleStartsSortedByDate
let painSortedByDate
if (!opts) {
// we only want to require (and run) the db module
// when not running the tests
cycleStartsSortedByDate = require('../db').getCycleStartsSortedByDate()
painSortedByDate = require('../db').getPainDaysSortedByDate()
// maxCycleLength = 45
} else {
cycleStartsSortedByDate = opts.cycleStartsSortedByDate || []
painSortedByDate = opts.painSortedByDate || []
// maxCycleLength = opts.maxCycleLength || 99
}
function getCycleStartsOfLastYear() {
const today = LocalDate.parse(new Date().toISOString().slice(0, 10))
const firstRelevantDay = today.minusYears(1)
const relevantCycles = cycleStartsSortedByDate.filter(({ date }) =>
LocalDate.parse(date).isAfter(firstRelevantDay)
)
return relevantCycles.map(({ date }) => date)
}
function getPainDaysOfLastYear() {
const today = LocalDate.parse(new Date().toISOString().slice(0, 10))
const firstRelevantDay = today.minusYears(1)
const relevantPainDays = painSortedByDate.filter(
({ date, pain }) =>
LocalDate.parse(date).isAfter(firstRelevantDay) && pain.headache
)
return relevantPainDays.map(({ date }) => date)
}
function getCycleDayForPainDays(cycleStarts, painDays) {
let i = 0
const cycleStartsAsc = cycleStarts.sort().reverse()
const painDaysAsc = painDays.sort().reverse()
const painCycleDays = painDaysAsc.map((pdate) => {
if (LocalDate.parse(pdate).isBefore(LocalDate.parse(cycleStartsAsc[i]))) {
// increase index i until cycleStart of this painDay is found
for (let j = i + 1; j < cycleStartsAsc.length; j++) {
i = j
if (
!LocalDate.parse(cycleStartsAsc[i]).isAfter(LocalDate.parse(pdate))
) {
// not(C > P) === C ≤ P
break
}
}
}
return LocalDate.parse(cycleStartsAsc[i]).until(
LocalDate.parse(pdate),
DAYS
)
})
return painCycleDays
}
return {
getCycleStartsOfLastYear,
getPainDaysOfLastYear,
getCycleDayForPainDays,
}
}
+2 -1
View File
@@ -7,7 +7,8 @@
"Tina Baumann",
"Sofiya Tepikin",
"Mariya Zadnepryanets",
"Lisa Hillebrand"
"Lisa Hillebrand",
"Martha Dörfler"
],
"scripts": {
"start": "react-native start",