2023-10-24 08:32:31 +00:00
|
|
|
import { useFocusEffect } from "@react-navigation/native";
|
2023-10-26 23:36:56 +00:00
|
|
|
import { useCallback, useState } from "react";
|
2023-10-26 08:34:50 +00:00
|
|
|
import { ScrollView, View } from "react-native";
|
2023-10-26 08:02:25 +00:00
|
|
|
import { IconButton, Text } from "react-native-paper";
|
2023-10-28 02:10:58 +00:00
|
|
|
import AppPieChart from "./AppPieChart";
|
2023-10-26 23:36:56 +00:00
|
|
|
import Chart from "./Chart";
|
|
|
|
import ConfirmDialog from "./ConfirmDialog";
|
2023-10-24 08:32:31 +00:00
|
|
|
import DrawerHeader from "./DrawerHeader";
|
2023-10-24 21:21:21 +00:00
|
|
|
import Select from "./Select";
|
2023-10-26 23:36:56 +00:00
|
|
|
import { MARGIN, PADDING } from "./constants";
|
|
|
|
import { AppDataSource } from "./data-source";
|
2023-10-24 21:21:21 +00:00
|
|
|
import { Periods } from "./periods";
|
2023-11-06 01:27:27 +00:00
|
|
|
import { DAYS } from "./days";
|
2023-10-24 08:32:31 +00:00
|
|
|
|
2023-10-26 08:34:50 +00:00
|
|
|
interface WeekCount {
|
|
|
|
week: string;
|
|
|
|
count: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface HourCount {
|
|
|
|
hour: string;
|
2023-10-24 08:32:31 +00:00
|
|
|
count: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default function InsightsPage() {
|
2023-10-26 23:36:56 +00:00
|
|
|
const [weekCounts, setWeekCounts] = useState<WeekCount[]>();
|
|
|
|
const [hourCounts, setHourCounts] = useState<HourCount[]>();
|
2023-10-24 21:21:21 +00:00
|
|
|
const [period, setPeriod] = useState(Periods.Monthly);
|
2023-10-26 08:34:50 +00:00
|
|
|
const [showWeek, setShowWeek] = useState(false);
|
|
|
|
const [showHour, setShowHour] = useState(false);
|
2023-10-24 08:32:31 +00:00
|
|
|
|
|
|
|
useFocusEffect(
|
|
|
|
useCallback(() => {
|
2023-10-24 21:21:21 +00:00
|
|
|
let difference = "-1 months";
|
|
|
|
if (period === Periods.TwoMonths) difference = "-2 months";
|
|
|
|
if (period === Periods.ThreeMonths) difference = "-3 months";
|
|
|
|
if (period === Periods.SixMonths) difference = "-6 months";
|
2023-10-26 08:34:50 +00:00
|
|
|
const selectWeeks = `
|
|
|
|
SELECT strftime('%w', created) as week, COUNT(*) as count
|
|
|
|
FROM sets
|
|
|
|
WHERE DATE(created) >= DATE('now', 'weekday 0', '${difference}')
|
|
|
|
GROUP BY week
|
|
|
|
HAVING week IS NOT NULL
|
|
|
|
ORDER BY count DESC;
|
|
|
|
`;
|
|
|
|
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
|
|
|
|
`;
|
2023-11-08 02:34:48 +00:00
|
|
|
|
|
|
|
setTimeout(
|
|
|
|
() =>
|
|
|
|
AppDataSource.manager
|
|
|
|
.query(selectWeeks)
|
|
|
|
.then(setWeekCounts)
|
|
|
|
.then(() =>
|
|
|
|
AppDataSource.manager.query(selectHours).then(setHourCounts)
|
|
|
|
),
|
|
|
|
400
|
|
|
|
);
|
2023-10-24 21:21:21 +00:00
|
|
|
}, [period])
|
2023-10-24 08:32:31 +00:00
|
|
|
);
|
|
|
|
|
2023-10-26 08:34:50 +00:00
|
|
|
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}`;
|
|
|
|
};
|
|
|
|
|
2023-10-24 08:32:31 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<DrawerHeader name="Insights" />
|
2023-10-26 23:36:56 +00:00
|
|
|
<View
|
2023-10-24 08:32:31 +00:00
|
|
|
style={{
|
2023-10-26 23:36:56 +00:00
|
|
|
paddingLeft: PADDING,
|
|
|
|
paddingTop: PADDING,
|
|
|
|
paddingRight: PADDING,
|
2023-10-24 08:32:31 +00:00
|
|
|
}}
|
|
|
|
>
|
2023-10-26 08:34:50 +00:00
|
|
|
<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)}
|
|
|
|
/>
|
2023-10-26 23:36:56 +00:00
|
|
|
</View>
|
|
|
|
<ScrollView
|
|
|
|
style={{
|
|
|
|
padding: PADDING,
|
|
|
|
flexGrow: 1,
|
|
|
|
}}
|
|
|
|
>
|
2023-10-26 08:02:25 +00:00
|
|
|
<View
|
|
|
|
style={{
|
|
|
|
flexDirection: "row",
|
|
|
|
alignItems: "center",
|
|
|
|
alignContent: "center",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Text
|
|
|
|
variant="titleLarge"
|
|
|
|
style={{
|
|
|
|
marginBottom: MARGIN,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
Most active days of the week
|
|
|
|
</Text>
|
|
|
|
<IconButton
|
|
|
|
icon="help-circle-outline"
|
|
|
|
size={25}
|
|
|
|
style={{ padding: 0, margin: 0, paddingBottom: 10 }}
|
2023-10-26 08:34:50 +00:00
|
|
|
onPress={() => setShowWeek(true)}
|
2023-10-26 08:02:25 +00:00
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
|
2023-10-26 23:36:56 +00:00
|
|
|
{weekCounts?.length > 0 && (
|
2023-10-28 02:10:58 +00:00
|
|
|
<AppPieChart
|
2023-10-26 08:34:50 +00:00
|
|
|
options={weekCounts.map((weekCount) => ({
|
|
|
|
label: DAYS[weekCount.week],
|
|
|
|
value: weekCount.count,
|
|
|
|
}))}
|
|
|
|
/>
|
2023-10-26 23:36:56 +00:00
|
|
|
)}
|
|
|
|
{weekCounts?.length === 0 && (
|
2023-10-26 08:34:50 +00:00
|
|
|
<Text style={{ marginBottom: MARGIN }}>
|
|
|
|
No entries yet! Start recording sets to see your most active days of
|
|
|
|
the week.
|
|
|
|
</Text>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<View
|
|
|
|
style={{
|
|
|
|
flexDirection: "row",
|
|
|
|
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>
|
|
|
|
|
2023-10-26 23:36:56 +00:00
|
|
|
{hourCounts?.length > 0 && (
|
2023-10-26 08:34:50 +00:00
|
|
|
<Chart
|
|
|
|
data={hourCounts.map((hc) => hc.count)}
|
|
|
|
labels={hourCounts.map((hc) => hourLabel(hc.hour))}
|
|
|
|
/>
|
2023-10-26 23:36:56 +00:00
|
|
|
)}
|
|
|
|
{hourCounts?.length === 0 && (
|
2023-10-26 08:34:50 +00:00
|
|
|
<Text>
|
|
|
|
No entries yet! Start recording sets to see your most active hours
|
|
|
|
of the day.
|
|
|
|
</Text>
|
|
|
|
)}
|
2023-10-26 23:36:56 +00:00
|
|
|
<View style={{ marginBottom: MARGIN }} />
|
2023-10-26 08:34:50 +00:00
|
|
|
</ScrollView>
|
|
|
|
|
2023-10-26 08:02:25 +00:00
|
|
|
<ConfirmDialog
|
|
|
|
title="Most active days of the week"
|
2023-10-26 08:34:50 +00:00
|
|
|
show={showWeek}
|
|
|
|
setShow={setShowWeek}
|
|
|
|
onOk={() => setShowWeek(false)}
|
2023-10-26 08:02:25 +00:00
|
|
|
>
|
|
|
|
If your plan expects an equal # of sets each day of the week, then this
|
|
|
|
pie graph should be evenly sliced.
|
|
|
|
</ConfirmDialog>
|
2023-10-26 08:34:50 +00:00
|
|
|
|
|
|
|
<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>
|
2023-10-24 08:32:31 +00:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|