Massive/ViewBest.tsx

170 lines
5.1 KiB
TypeScript
Raw Normal View History

2022-07-11 01:00:17 +00:00
import {
RouteProp,
useFocusEffect,
useNavigation,
useRoute,
} from '@react-navigation/native';
2022-08-24 01:23:21 +00:00
import React, {
useCallback,
useContext,
useEffect,
useRef,
useState,
} from 'react';
2022-08-26 01:54:51 +00:00
import {FileSystem} from 'react-native-file-access';
2022-09-02 00:24:28 +00:00
import {IconButton} from 'react-native-paper';
import RNPickerSelect from 'react-native-picker-select';
2022-08-24 01:23:21 +00:00
import Share from 'react-native-share';
import ViewShot from 'react-native-view-shot';
2022-07-11 01:00:17 +00:00
import {BestPageParams} from './BestPage';
2022-09-02 00:24:28 +00:00
import Chart from './Chart';
import {DatabaseContext} from './Routes';
2022-07-11 01:00:17 +00:00
import Set from './set';
import {formatMonth} from './time';
2022-07-08 12:11:10 +00:00
2022-08-24 00:32:57 +00:00
interface Volume {
name: string;
created: string;
value: number;
unit: string;
}
2022-09-02 00:24:28 +00:00
enum Metrics {
Weight = 'Best weight per day',
Volume = 'Volume per day',
2022-09-02 00:24:28 +00:00
}
enum Periods {
Weekly = 'This week',
Monthly = 'This month',
Yearly = 'This year',
}
2022-07-11 01:00:17 +00:00
export default function ViewBest() {
const {params} = useRoute<RouteProp<BestPageParams, 'ViewBest'>>();
2022-08-24 00:32:57 +00:00
const [weights, setWeights] = useState<Set[]>([]);
const [volumes, setVolumes] = useState<Volume[]>([]);
2022-09-02 00:24:28 +00:00
const [metric, setMetric] = useState(Metrics.Weight);
const [period, setPeriod] = useState(Periods.Monthly);
2022-07-08 12:11:10 +00:00
const db = useContext(DatabaseContext);
2022-07-11 01:00:17 +00:00
const navigation = useNavigation();
2022-08-24 01:23:21 +00:00
const viewShot = useRef<ViewShot>(null);
2022-07-11 01:00:17 +00:00
useFocusEffect(
useCallback(() => {
2022-07-12 03:54:04 +00:00
console.log(`${ViewBest.name}.useFocusEffect`);
2022-07-11 01:00:17 +00:00
navigation.getParent()?.setOptions({
headerLeft: () => (
<IconButton icon="arrow-back" onPress={() => navigation.goBack()} />
),
2022-08-24 01:23:21 +00:00
headerRight: () => (
<IconButton
onPress={() =>
viewShot.current?.capture?.().then(async uri => {
const base64 = await FileSystem.readFile(uri, 'base64');
const url = `data:image/jpeg;base64,${base64}`;
Share.open({
message: params.best.name,
2022-08-24 01:23:21 +00:00
type: 'image/jpeg',
url,
failOnCancel: false,
});
})
}
icon="share-social-outline"
/>
),
2022-07-11 01:00:17 +00:00
title: params.best.name,
});
2022-08-24 01:23:21 +00:00
}, [navigation, params.best]),
2022-07-11 01:00:17 +00:00
);
2022-07-08 12:11:10 +00:00
2022-09-02 00:24:28 +00:00
const refreshWeight = useCallback(async () => {
const select = `
2022-08-24 00:32:57 +00:00
SELECT max(weight) AS weight,
STRFTIME('%Y-%m-%d', created) as created, unit
FROM sets
WHERE name = ? AND NOT hidden
2022-09-02 00:24:28 +00:00
AND DATE(created) >= DATE('now', 'weekday 0', ?)
2022-08-24 00:32:57 +00:00
GROUP BY name, STRFTIME('%Y-%m-%d', created)
`;
2022-09-02 00:24:28 +00:00
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
const [result] = await db.executeSql(select, [
params.best.name,
difference,
]);
if (result.rows.length === 0) return;
setWeights(result.rows.raw());
}, [params.best.name, db, period]);
const refreshVolume = useCallback(async () => {
const select = `
2022-08-24 00:32:57 +00:00
SELECT sum(weight * reps) AS value,
STRFTIME('%Y-%m-%d', created) as created, unit
FROM sets
WHERE name = ? AND NOT hidden
2022-09-02 00:24:28 +00:00
AND DATE(created) >= DATE('now', 'weekday 0', ?)
GROUP BY name, STRFTIME('%Y-%m-%d', created)
`;
2022-09-02 00:24:28 +00:00
let difference = '-7 days';
if (period === Periods.Monthly) difference = '-1 months';
else if (period === Periods.Yearly) difference = '-1 years';
const [result] = await db.executeSql(select, [
params.best.name,
difference,
]);
if (result.rows.length === 0) return;
setVolumes(result.rows.raw());
}, [db, params.best.name, period]);
2022-09-02 00:24:28 +00:00
useEffect(() => {
if (metric === Metrics.Weight) refreshWeight();
else if (metric === Metrics.Volume) refreshVolume();
console.log(`${ViewBest.name}.useEffect`, {metric, period});
}, [params.best.name, db, metric, period, refreshVolume, refreshWeight]);
2022-07-12 03:54:04 +00:00
2022-07-08 12:11:10 +00:00
return (
2022-08-24 01:23:21 +00:00
<ViewShot style={{padding: 10}} ref={viewShot}>
2022-09-02 00:24:28 +00:00
<RNPickerSelect
onValueChange={setMetric}
items={[
{label: Metrics.Weight, value: Metrics.Weight},
{label: Metrics.Volume, value: Metrics.Volume},
]}
value={metric}
/>
<RNPickerSelect
onValueChange={setPeriod}
items={[
{label: Periods.Weekly, value: Periods.Weekly},
{label: Periods.Monthly, value: Periods.Monthly},
{label: Periods.Yearly, value: Periods.Yearly},
]}
value={period}
/>
{metric === Metrics.Volume && (
<Chart
yData={volumes.map(v => v.value)}
yFormat={(value: number) =>
2022-08-24 00:32:57 +00:00
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}${
volumes[0].unit
}`
}
2022-09-02 00:24:28 +00:00
xData={weights}
xFormat={(_value, index) => formatMonth(weights[index].created!)}
2022-07-11 01:00:17 +00:00
/>
2022-09-02 00:24:28 +00:00
)}
{metric === Metrics.Weight && (
<Chart
yData={weights.map(set => set.weight)}
yFormat={value => `${value}${weights[0].unit}`}
xData={weights}
xFormat={(_value, index) => formatMonth(weights[index].created!)}
/>
)}
2022-08-24 01:23:21 +00:00
</ViewShot>
2022-07-08 12:11:10 +00:00
);
}