Add most active hours of the day to insights - 1.166 🚀

This commit is contained in:
Brandon Presley 2023-10-26 21:34:50 +13:00
parent 32da68e905
commit 7ea91eeca9
3 changed files with 121 additions and 41 deletions

View File

@ -1,6 +1,6 @@
import { useFocusEffect } from "@react-navigation/native"; import { useFocusEffect } from "@react-navigation/native";
import { useCallback, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { View } from "react-native"; import { ScrollView, View } from "react-native";
import { IconButton, Text } from "react-native-paper"; import { IconButton, Text } from "react-native-paper";
import AppBarChart from "./AppBarChart"; import AppBarChart from "./AppBarChart";
import { MARGIN, PADDING } from "./constants"; import { MARGIN, PADDING } from "./constants";
@ -10,16 +10,24 @@ import { DAYS } from "./time";
import Select from "./Select"; import Select from "./Select";
import { Periods } from "./periods"; import { Periods } from "./periods";
import ConfirmDialog from "./ConfirmDialog"; import ConfirmDialog from "./ConfirmDialog";
import Chart from "./Chart";
export interface WeekCounts { interface WeekCount {
week: number; week: string;
count: number;
}
interface HourCount {
hour: string;
count: number; count: number;
} }
export default function InsightsPage() { export default function InsightsPage() {
const [weekCounts, setWeekCounts] = useState<WeekCounts[]>([]); const [weekCounts, setWeekCounts] = useState<WeekCount[]>([]);
const [hourCounts, setHourCounts] = useState<HourCount[]>([]);
const [period, setPeriod] = useState(Periods.Monthly); const [period, setPeriod] = useState(Periods.Monthly);
const [showActive, setShowActive] = useState(false); const [showWeek, setShowWeek] = useState(false);
const [showHour, setShowHour] = useState(false);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
@ -27,27 +35,57 @@ export default function InsightsPage() {
if (period === Periods.TwoMonths) difference = "-2 months"; if (period === Periods.TwoMonths) difference = "-2 months";
if (period === Periods.ThreeMonths) difference = "-3 months"; if (period === Periods.ThreeMonths) difference = "-3 months";
if (period === Periods.SixMonths) difference = "-6 months"; if (period === Periods.SixMonths) difference = "-6 months";
const select = ` const selectWeeks = `
SELECT strftime('%w', created) as week, COUNT(*) as count SELECT strftime('%w', created) as week, COUNT(*) as count
FROM sets FROM sets
WHERE DATE(created) >= DATE('now', 'weekday 0', '${difference}') WHERE DATE(created) >= DATE('now', 'weekday 0', '${difference}')
GROUP BY week GROUP BY week
HAVING week IS NOT NULL HAVING week IS NOT NULL
ORDER BY count DESC; ORDER BY count DESC;
`; `;
AppDataSource.manager.query(select).then(setWeekCounts); const selectHours = `
SELECT strftime('%H', created) AS hour, COUNT(*) AS count
FROM sets
WHERE DATE(created) >= DATE('now', 'weekday 0', '${difference}')
GROUP BY hour
having hour is not null
ORDER BY hour
`;
AppDataSource.manager.query(selectWeeks).then(setWeekCounts);
AppDataSource.manager.query(selectHours).then(setHourCounts);
}, [period]) }, [period])
); );
const hourLabel = (hour: string) => {
let twelveHour = Number(hour);
if (twelveHour === 0) return "12AM";
let amPm = "AM";
if (twelveHour >= 12) amPm = "PM";
if (twelveHour > 12) twelveHour -= 12;
return `${twelveHour} ${amPm}`;
};
return ( return (
<> <>
<DrawerHeader name="Insights" /> <DrawerHeader name="Insights" />
<View <ScrollView
style={{ style={{
padding: PADDING, padding: PADDING,
flexGrow: 1, flexGrow: 1,
}} }}
> >
<Select
label="Period"
items={[
{ value: Periods.Monthly, label: Periods.Monthly },
{ value: Periods.TwoMonths, label: Periods.TwoMonths },
{ value: Periods.ThreeMonths, label: Periods.ThreeMonths },
{ value: Periods.SixMonths, label: Periods.SixMonths },
]}
value={period}
onChange={(value) => setPeriod(value as Periods)}
/>
<View <View
style={{ style={{
flexDirection: "row", flexDirection: "row",
@ -67,37 +105,79 @@ export default function InsightsPage() {
icon="help-circle-outline" icon="help-circle-outline"
size={25} size={25}
style={{ padding: 0, margin: 0, paddingBottom: 10 }} style={{ padding: 0, margin: 0, paddingBottom: 10 }}
onPress={() => setShowActive(true)} onPress={() => setShowWeek(true)}
/> />
</View> </View>
<Select {weekCounts.length > 0 ? (
label="Period" <AppBarChart
items={[ options={weekCounts.map((weekCount) => ({
{ value: Periods.Monthly, label: Periods.Monthly }, label: DAYS[weekCount.week],
{ value: Periods.TwoMonths, label: Periods.TwoMonths }, value: weekCount.count,
{ value: Periods.ThreeMonths, label: Periods.ThreeMonths }, }))}
{ value: Periods.SixMonths, label: Periods.SixMonths }, />
]} ) : (
value={period} <Text style={{ marginBottom: MARGIN }}>
onChange={(value) => setPeriod(value as Periods)} No entries yet! Start recording sets to see your most active days of
/> the week.
<AppBarChart </Text>
options={weekCounts.map((weekCount) => ({ )}
label: DAYS[weekCount.week],
value: weekCount.count, <View
}))} style={{
/> flexDirection: "row",
</View> alignItems: "center",
alignContent: "center",
}}
>
<Text
variant="titleLarge"
style={{
marginBottom: MARGIN,
}}
>
Most active hours of the day
</Text>
<IconButton
icon="help-circle-outline"
size={25}
style={{ padding: 0, margin: 0, paddingBottom: 10 }}
onPress={() => setShowHour(true)}
/>
</View>
{hourCounts.length > 0 ? (
<Chart
data={hourCounts.map((hc) => hc.count)}
labels={hourCounts.map((hc) => hourLabel(hc.hour))}
/>
) : (
<Text>
No entries yet! Start recording sets to see your most active hours
of the day.
</Text>
)}
</ScrollView>
<ConfirmDialog <ConfirmDialog
title="Most active days of the week" title="Most active days of the week"
show={showActive} show={showWeek}
setShow={setShowActive} setShow={setShowWeek}
onOk={() => setShowActive(false)} onOk={() => setShowWeek(false)}
> >
If your plan expects an equal # of sets each day of the week, then this If your plan expects an equal # of sets each day of the week, then this
pie graph should be evenly sliced. pie graph should be evenly sliced.
</ConfirmDialog> </ConfirmDialog>
<ConfirmDialog
title="Most active hours of the day"
show={showHour}
setShow={setShowHour}
onOk={() => setShowHour(false)}
>
If you find yourself giving up on the gym after 5pm, consider starting
earlier! Or vice-versa.
</ConfirmDialog>
</> </>
); );
} }

View File

@ -85,8 +85,8 @@ android {
applicationId "com.massive" applicationId "com.massive"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 36191 versionCode 36192
versionName "1.165" versionName "1.166"
} }
signingConfigs { signingConfigs {
release { release {

View File

@ -1,6 +1,6 @@
{ {
"name": "massive", "name": "massive",
"version": "1.165", "version": "1.166",
"private": true, "private": true,
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"scripts": { "scripts": {