Massive/ViewGraph.tsx
Brandon Presley 1603496424 Rework Best -> Graphs
I was considering adding weight tracking,
so then this graph page would include body
weight graphs. Meaning it's not really
recording the "best" of anything.
It currently only shows the best on the list
page anyway.
2023-07-04 11:35:52 +12:00

154 lines
4.9 KiB
TypeScript

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'
import Share from 'react-native-share'
import { captureScreen } from 'react-native-view-shot'
import { GraphsPageParams } from './GraphsPage'
import Chart from './Chart'
import { PADDING } from './constants'
import { setRepo } from './db'
import GymSet from './gym-set'
import { Metrics } from './metrics'
import { Periods } from './periods'
import Select from './Select'
import StackHeader from './StackHeader'
import useDark from './use-dark'
import Volume from './volume'
export default function ViewGraph() {
const { params } = useRoute<RouteProp<GraphsPageParams, 'ViewGraph'>>()
const [weights, setWeights] = useState<GymSet[]>()
const [volumes, setVolumes] = useState<Volume[]>()
const [metric, setMetric] = useState(Metrics.Weight)
const [period, setPeriod] = useState(Periods.Monthly)
const dark = useDark()
useEffect(() => {
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'
const builder = setRepo
.createQueryBuilder()
.select('STRFTIME(\'%Y-%m-%d\', created)', 'created')
.addSelect('unit')
.where('name = :name', { name: params.best.name })
.andWhere('NOT hidden')
.andWhere('DATE(created) >= DATE(\'now\', \'weekday 0\', :difference)', {
difference,
})
.groupBy('name')
.addGroupBy(`STRFTIME('${group}', created)`)
switch (metric) {
case Metrics.Weight:
builder
.addSelect('ROUND(MAX(weight), 2)', 'weight')
.getRawMany()
.then(setWeights)
break
case Metrics.Volume:
builder
.addSelect('ROUND(SUM(weight * reps), 2)', 'value')
.getRawMany()
.then(setVolumes)
break
default:
// Brzycki formula https://en.wikipedia.org/wiki/One-repetition_maximum#Brzycki
builder
.addSelect(
'ROUND(MAX(weight / (1.0278 - 0.0278 * reps)), 2)',
'weight',
)
.getRawMany()
.then((newWeights) => {
console.log({ weights: newWeights })
setWeights(newWeights)
})
}
}, [params.best.name, metric, period])
const charts = useMemo(() => {
if (
(metric === Metrics.Volume && volumes?.length === 0) ||
(metric === Metrics.Weight && weights?.length === 0) ||
(metric === Metrics.OneRepMax && weights?.length === 0)
) {
return <List.Item title='No data yet.' />
}
if (metric === Metrics.Volume && volumes?.length && weights?.length) {
return (
<Chart
yData={volumes.map((v) => v.value)}
yFormat={(value: number) =>
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${
volumes[0].unit || 'kg'
}`}
xData={weights}
xFormat={(_value, index) =>
format(new Date(weights[index].created), 'd/M')}
/>
)
}
return (
<Chart
yData={weights?.map((set) => set.weight) || []}
yFormat={(value) => `${value}${weights?.[0].unit}`}
xData={weights || []}
xFormat={(_value, index) =>
format(new Date(weights?.[index].created), 'd/M')}
/>
)
}, [volumes, weights, metric])
return (
<>
<StackHeader title={params.best.name}>
<IconButton
color={dark ? 'white' : 'white'}
onPress={() =>
captureScreen().then(async (uri) => {
const base64 = await FileSystem.readFile(uri, 'base64')
const url = `data:image/jpeg;base64,${base64}`
Share.open({
type: 'image/jpeg',
url,
})
})}
icon='share'
/>
</StackHeader>
<View style={{ padding: PADDING }}>
<Select
label='Metric'
items={[
{ value: Metrics.Volume, label: Metrics.Volume },
{ value: Metrics.OneRepMax, label: Metrics.OneRepMax },
{
label: Metrics.Weight,
value: Metrics.Weight,
},
]}
onChange={(value) => setMetric(value as Metrics)}
value={metric}
/>
<Select
label='Period'
items={[
{ value: Periods.Weekly, label: Periods.Weekly },
{ value: Periods.Monthly, label: Periods.Monthly },
{ value: Periods.Yearly, label: Periods.Yearly },
]}
onChange={(value) => setPeriod(value as Periods)}
value={period}
/>
{charts}
</View>
</>
)
}