From 9a4f2599a684a29a6f3c7fc95b500d81b1138ee8 Mon Sep 17 00:00:00 2001 From: Brandon Presley Date: Fri, 9 Feb 2024 15:20:17 +1300 Subject: [PATCH] Add date range selectors to graphs --- ViewGraph.tsx | 82 ++++++++++++++++++++++++++++++++++++----- ViewWeightGraph.tsx | 90 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 153 insertions(+), 19 deletions(-) diff --git a/ViewGraph.tsx b/ViewGraph.tsx index a419c15..21eb330 100644 --- a/ViewGraph.tsx +++ b/ViewGraph.tsx @@ -1,7 +1,7 @@ -import { RouteProp, useRoute } from "@react-navigation/native"; +import { RouteProp, useFocusEffect, useRoute } from "@react-navigation/native"; import { format } from "date-fns"; -import { useEffect, useMemo, useState } from "react"; -import { ScrollView, View } from "react-native"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { Keyboard, ScrollView, View } from "react-native"; import { FileSystem } from "react-native-file-access"; import { IconButton, List } from "react-native-paper"; import Share from "react-native-share"; @@ -10,12 +10,15 @@ import { StackParams } from "./AppStack"; import AppLineChart from "./AppLineChart"; import Select from "./Select"; import StackHeader from "./StackHeader"; -import { PADDING } from "./constants"; -import { setRepo } from "./db"; +import { MARGIN, PADDING } from "./constants"; +import { setRepo, settingsRepo } from "./db"; import GymSet from "./gym-set"; import { Metrics } from "./metrics"; import { Periods } from "./periods"; import Volume from "./volume"; +import AppInput from "./AppInput"; +import { DateTimePickerAndroid } from "@react-native-community/datetimepicker"; +import Settings from "./settings"; export default function ViewGraph() { const { params } = useRoute>(); @@ -24,6 +27,13 @@ export default function ViewGraph() { const [metric, setMetric] = useState(Metrics.OneRepMax); const [period, setPeriod] = useState(Periods.Monthly); const [unit, setUnit] = useState('kg'); + const [start, setStart] = useState(null) + const [end, setEnd] = useState(null) + const [settings, setSettings] = useState({} as Settings); + + useFocusEffect(useCallback(() => { + settingsRepo.findOne({ where: {} }).then(setSettings) + }, [])) const convertWeight = (weight: number, unitFrom: string, unitTo: string) => { let result = weight; @@ -50,13 +60,17 @@ export default function ViewGraph() { .select("STRFTIME('%Y-%m-%d', created)", "created") .addSelect("unit") .where("name = :name", { name: params.name }) - .andWhere("NOT hidden"); + .andWhere("NOT hidden") - if (difference) { + if (start) + builder.andWhere("DATE(created) >= :start", { start }); + if (end) + builder.andWhere("DATE(created) <= :end", { end }); + if (difference) builder.andWhere("DATE(created) >= DATE('now', 'weekday 0', :difference)", { difference, }); - } + builder .groupBy("name") @@ -90,7 +104,7 @@ export default function ViewGraph() { setWeights(newWeights); }); } - }, [params.name, metric, period, unit]); + }, [params.name, metric, period, unit, start, end]); const weightChart = useMemo(() => { if (weights === undefined) return null; @@ -121,6 +135,34 @@ export default function ViewGraph() { ); }, [volumes]); + const pickStart = useCallback(() => { + DateTimePickerAndroid.open({ + value: start || new Date(), + onChange: (event, date) => { + if (event.type === 'dismissed') return; + if (date === start) return; + setStart(date); + setPeriod(Periods.AllTime); + Keyboard.dismiss(); + }, + mode: "date", + }); + }, [start]); + + const pickEnd = useCallback(() => { + DateTimePickerAndroid.open({ + value: end || new Date(), + onChange: (event, date) => { + if (event.type === 'dismissed') return; + if (date === end) return; + setEnd(date); + setPeriod(Periods.AllTime); + Keyboard.dismiss(); + }, + mode: "date", + }); + }, [end]); + return ( <> @@ -149,6 +191,7 @@ export default function ViewGraph() { onChange={(value) => setMetric(value as Metrics)} value={metric} /> + (); const [period, setPeriod] = useState(Periods.TwoMonths); + const [start, setStart] = useState(null) + const [end, setEnd] = useState(null) + const [settings, setSettings] = useState({} as Settings); + + useFocusEffect(useCallback(() => { + settingsRepo.findOne({ where: {} }).then(setSettings) + }, [])) useEffect(() => { let difference = "-7 days"; @@ -24,22 +35,61 @@ export default function ViewWeightGraph() { else if (period === Periods.ThreeMonths) difference = "-3 months"; else if (period === Periods.SixMonths) difference = "-6 months"; else if (period === Periods.Yearly) difference = "-1 years"; + else if (period === Periods.AllTime) difference = null; let group = "%Y-%m-%d"; if (period === Periods.Yearly) group = "%Y-%m"; - weightRepo + const builder = weightRepo .createQueryBuilder() .select("STRFTIME('%Y-%m-%d', created)", "created") .addSelect("AVG(value) as value") .addSelect("unit") - .where("DATE(created) >= DATE('now', 'weekday 0', :difference)", { + .groupBy(`STRFTIME('${group}', created)`) + + if (difference) + builder.where("DATE(created) >= DATE('now', 'weekday 0', :difference)", { difference, }) - .groupBy(`STRFTIME('${group}', created)`) + + if (start) + builder.andWhere("DATE(created) >= :start", { start }); + if (end) + builder.andWhere("DATE(created) <= :end", { end }); + + builder .getRawMany() .then(setWeights); - }, [period]); + }, [period, start, end]); + + const pickStart = useCallback(() => { + DateTimePickerAndroid.open({ + value: start || new Date(), + onChange: (event, date) => { + if (event.type === 'dismissed') return; + if (date === start) return; + setStart(date); + setPeriod(Periods.AllTime); + Keyboard.dismiss(); + }, + mode: "date", + }); + }, [start]); + + const pickEnd = useCallback(() => { + DateTimePickerAndroid.open({ + value: end || new Date(), + onChange: (event, date) => { + if (event.type === 'dismissed') return; + if (date === end) return; + setEnd(date); + setPeriod(Periods.AllTime); + Keyboard.dismiss(); + }, + mode: "date", + }); + }, [end]); + const charts = useMemo(() => { if (!weights) return; @@ -84,10 +134,32 @@ export default function ViewWeightGraph() { { value: Periods.ThreeMonths, label: Periods.ThreeMonths }, { value: Periods.SixMonths, label: Periods.SixMonths }, { value: Periods.Yearly, label: Periods.Yearly }, + { value: Periods.AllTime, label: Periods.AllTime }, ]} - onChange={(value) => setPeriod(value as Periods)} + onChange={(value) => { + setPeriod(value as Periods); + if (value === Periods.AllTime) return; + setStart(null); + setEnd(null); + }} value={period} /> + + + + + + {charts}