2023-06-27 03:16:59 +00:00
|
|
|
import { RouteProp, useRoute } from '@react-navigation/native'
|
|
|
|
import { format } from 'date-fns'
|
|
|
|
import { useEffect, useMemo, useState } from 'react'
|
|
|
|
import { View } from 'react-native'
|
|
|
|
import { FileSystem } from 'react-native-file-access'
|
|
|
|
import { IconButton, List } from 'react-native-paper'
|
2023-03-27 23:04:54 +00:00
|
|
|
import Share from 'react-native-share'
|
2023-06-27 03:16:59 +00:00
|
|
|
import { captureScreen } from 'react-native-view-shot'
|
2023-07-03 23:35:52 +00:00
|
|
|
import { GraphsPageParams } from './GraphsPage'
|
2022-10-31 04:22:08 +00:00
|
|
|
import Chart from './Chart'
|
2023-06-27 03:16:59 +00:00
|
|
|
import { PADDING } from './constants'
|
|
|
|
import { setRepo } from './db'
|
2022-10-31 04:22:08 +00:00
|
|
|
import GymSet from './gym-set'
|
2023-06-27 03:16:59 +00:00
|
|
|
import { Metrics } from './metrics'
|
|
|
|
import { Periods } from './periods'
|
2022-11-16 05:48:47 +00:00
|
|
|
import Select from './Select'
|
2022-10-31 04:22:08 +00:00
|
|
|
import StackHeader from './StackHeader'
|
2023-03-27 23:04:54 +00:00
|
|
|
import useDark from './use-dark'
|
2022-10-31 04:22:08 +00:00
|
|
|
import Volume from './volume'
|
2022-09-02 00:24:28 +00:00
|
|
|
|
2023-07-03 23:35:52 +00:00
|
|
|
export default function ViewGraph() {
|
|
|
|
const { params } = useRoute<RouteProp<GraphsPageParams, 'ViewGraph'>>()
|
2023-02-04 22:07:56 +00:00
|
|
|
const [weights, setWeights] = useState<GymSet[]>()
|
|
|
|
const [volumes, setVolumes] = useState<Volume[]>()
|
2022-10-31 04:22:08 +00:00
|
|
|
const [metric, setMetric] = useState(Metrics.Weight)
|
|
|
|
const [period, setPeriod] = useState(Periods.Monthly)
|
2023-03-27 23:04:54 +00:00
|
|
|
const dark = useDark()
|
2022-07-08 12:11:10 +00:00
|
|
|
|
2022-09-02 00:24:28 +00:00
|
|
|
useEffect(() => {
|
2022-10-31 04:22:08 +00:00
|
|
|
let difference = '-7 days'
|
|
|
|
if (period === Periods.Monthly) difference = '-1 months'
|
|
|
|
else if (period === Periods.Yearly) difference = '-1 years'
|
|
|
|
let group = '%Y-%m-%d'
|
|
|
|
if (period === Periods.Yearly) group = '%Y-%m'
|
2022-10-31 00:20:36 +00:00
|
|
|
const builder = setRepo
|
|
|
|
.createQueryBuilder()
|
2023-06-27 03:16:59 +00:00
|
|
|
.select('STRFTIME(\'%Y-%m-%d\', created)', 'created')
|
2022-10-31 00:20:36 +00:00
|
|
|
.addSelect('unit')
|
2023-06-27 03:16:59 +00:00
|
|
|
.where('name = :name', { name: params.best.name })
|
2022-10-31 00:20:36 +00:00
|
|
|
.andWhere('NOT hidden')
|
2023-06-27 03:16:59 +00:00
|
|
|
.andWhere('DATE(created) >= DATE(\'now\', \'weekday 0\', :difference)', {
|
2022-10-31 00:20:36 +00:00
|
|
|
difference,
|
|
|
|
})
|
|
|
|
.groupBy('name')
|
2022-10-31 04:22:08 +00:00
|
|
|
.addGroupBy(`STRFTIME('${group}', created)`)
|
2022-10-16 00:39:59 +00:00
|
|
|
switch (metric) {
|
|
|
|
case Metrics.Weight:
|
2023-02-22 06:42:00 +00:00
|
|
|
builder
|
|
|
|
.addSelect('ROUND(MAX(weight), 2)', 'weight')
|
|
|
|
.getRawMany()
|
|
|
|
.then(setWeights)
|
2022-10-31 04:22:08 +00:00
|
|
|
break
|
2022-10-16 00:39:59 +00:00
|
|
|
case Metrics.Volume:
|
2022-10-31 00:20:36 +00:00
|
|
|
builder
|
2023-02-22 06:42:00 +00:00
|
|
|
.addSelect('ROUND(SUM(weight * reps), 2)', 'value')
|
2022-10-31 00:20:36 +00:00
|
|
|
.getRawMany()
|
2022-10-31 04:22:08 +00:00
|
|
|
.then(setVolumes)
|
|
|
|
break
|
2022-10-16 00:39:59 +00:00
|
|
|
default:
|
2022-10-31 04:05:31 +00:00
|
|
|
// Brzycki formula https://en.wikipedia.org/wiki/One-repetition_maximum#Brzycki
|
|
|
|
builder
|
2023-02-22 06:42:00 +00:00
|
|
|
.addSelect(
|
|
|
|
'ROUND(MAX(weight / (1.0278 - 0.0278 * reps)), 2)',
|
|
|
|
'weight',
|
|
|
|
)
|
2022-10-31 04:05:31 +00:00
|
|
|
.getRawMany()
|
2023-06-27 03:16:59 +00:00
|
|
|
.then((newWeights) => {
|
|
|
|
console.log({ weights: newWeights })
|
2022-10-31 08:00:10 +00:00
|
|
|
setWeights(newWeights)
|
2022-10-31 04:22:08 +00:00
|
|
|
})
|
2022-10-16 00:39:59 +00:00
|
|
|
}
|
2022-10-31 04:22:08 +00:00
|
|
|
}, [params.best.name, metric, period])
|
2022-07-12 03:54:04 +00:00
|
|
|
|
2022-11-23 08:50:11 +00:00
|
|
|
const charts = useMemo(() => {
|
|
|
|
if (
|
2023-02-04 22:07:56 +00:00
|
|
|
(metric === Metrics.Volume && volumes?.length === 0) ||
|
|
|
|
(metric === Metrics.Weight && weights?.length === 0) ||
|
|
|
|
(metric === Metrics.OneRepMax && weights?.length === 0)
|
2023-06-27 03:16:59 +00:00
|
|
|
) {
|
|
|
|
return <List.Item title='No data yet.' />
|
|
|
|
}
|
|
|
|
if (metric === Metrics.Volume && volumes?.length && weights?.length) {
|
2022-11-23 08:50:11 +00:00
|
|
|
return (
|
|
|
|
<Chart
|
2023-06-27 03:16:59 +00:00
|
|
|
yData={volumes.map((v) => v.value)}
|
2022-11-23 08:50:11 +00:00
|
|
|
yFormat={(value: number) =>
|
|
|
|
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${
|
|
|
|
volumes[0].unit || 'kg'
|
2023-06-27 03:16:59 +00:00
|
|
|
}`}
|
2022-11-23 08:50:11 +00:00
|
|
|
xData={weights}
|
|
|
|
xFormat={(_value, index) =>
|
2023-06-27 03:16:59 +00:00
|
|
|
format(new Date(weights[index].created), 'd/M')}
|
2022-11-23 08:50:11 +00:00
|
|
|
/>
|
|
|
|
)
|
2023-06-27 03:16:59 +00:00
|
|
|
}
|
2022-11-23 08:50:11 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<Chart
|
2023-06-27 03:16:59 +00:00
|
|
|
yData={weights?.map((set) => set.weight) || []}
|
|
|
|
yFormat={(value) => `${value}${weights?.[0].unit}`}
|
2023-02-04 22:07:56 +00:00
|
|
|
xData={weights || []}
|
2022-11-23 08:50:11 +00:00
|
|
|
xFormat={(_value, index) =>
|
2023-06-27 03:16:59 +00:00
|
|
|
format(new Date(weights?.[index].created), 'd/M')}
|
2022-11-23 08:50:11 +00:00
|
|
|
/>
|
|
|
|
)
|
|
|
|
}, [volumes, weights, metric])
|
|
|
|
|
2022-07-08 12:11:10 +00:00
|
|
|
return (
|
2022-10-23 06:13:58 +00:00
|
|
|
<>
|
2023-03-27 23:04:54 +00:00
|
|
|
<StackHeader title={params.best.name}>
|
|
|
|
<IconButton
|
|
|
|
color={dark ? 'white' : 'white'}
|
|
|
|
onPress={() =>
|
2023-06-27 03:16:59 +00:00
|
|
|
captureScreen().then(async (uri) => {
|
2023-03-27 23:04:54 +00:00
|
|
|
const base64 = await FileSystem.readFile(uri, 'base64')
|
|
|
|
const url = `data:image/jpeg;base64,${base64}`
|
|
|
|
Share.open({
|
|
|
|
type: 'image/jpeg',
|
|
|
|
url,
|
|
|
|
})
|
2023-06-27 03:16:59 +00:00
|
|
|
})}
|
|
|
|
icon='share'
|
2023-03-27 23:04:54 +00:00
|
|
|
/>
|
|
|
|
</StackHeader>
|
2023-06-27 03:16:59 +00:00
|
|
|
<View style={{ padding: PADDING }}>
|
2022-11-16 05:48:47 +00:00
|
|
|
<Select
|
2023-06-27 03:16:59 +00:00
|
|
|
label='Metric'
|
2022-11-16 05:48:47 +00:00
|
|
|
items={[
|
2023-06-27 03:16:59 +00:00
|
|
|
{ value: Metrics.Volume, label: Metrics.Volume },
|
|
|
|
{ value: Metrics.OneRepMax, label: Metrics.OneRepMax },
|
2022-11-16 05:48:47 +00:00
|
|
|
{
|
|
|
|
label: Metrics.Weight,
|
|
|
|
value: Metrics.Weight,
|
|
|
|
},
|
|
|
|
]}
|
2023-06-27 03:16:59 +00:00
|
|
|
onChange={(value) => setMetric(value as Metrics)}
|
2022-11-16 05:48:47 +00:00
|
|
|
value={metric}
|
|
|
|
/>
|
|
|
|
<Select
|
2023-06-27 03:16:59 +00:00
|
|
|
label='Period'
|
2022-11-16 05:48:47 +00:00
|
|
|
items={[
|
2023-06-27 03:16:59 +00:00
|
|
|
{ value: Periods.Weekly, label: Periods.Weekly },
|
|
|
|
{ value: Periods.Monthly, label: Periods.Monthly },
|
|
|
|
{ value: Periods.Yearly, label: Periods.Yearly },
|
2022-11-16 05:48:47 +00:00
|
|
|
]}
|
2023-06-27 03:16:59 +00:00
|
|
|
onChange={(value) => setPeriod(value as Periods)}
|
2022-11-16 05:48:47 +00:00
|
|
|
value={period}
|
|
|
|
/>
|
2022-11-23 08:50:11 +00:00
|
|
|
{charts}
|
2022-10-23 06:13:58 +00:00
|
|
|
</View>
|
|
|
|
</>
|
2022-10-31 04:22:08 +00:00
|
|
|
)
|
2022-07-08 12:11:10 +00:00
|
|
|
}
|