diff --git a/AppBarChart.tsx b/AppBarChart.tsx new file mode 100644 index 0000000..ccdf630 --- /dev/null +++ b/AppBarChart.tsx @@ -0,0 +1,56 @@ +import { useWindowDimensions } from "react-native"; +import { PieChart } from "react-native-chart-kit"; + +export interface Option { + value: number; + label: string; +} + +export default function AppBarChart({ options }: { options: Option[] }) { + const { width } = useWindowDimensions(); + + const pieChartColors = [ + "#1f77b4", // Blue + "#ff7f0e", // Orange + "#2ca02c", // Green + "#d62728", // Red + "#9467bd", // Purple + "#8c564b", // Brown + "#e377c2", // Pink + "#7f7f7f", // Gray + ]; + + const data = options.map((option, index) => ({ + name: option.label, + value: option.value, + color: pieChartColors[index], + legendFontColor: "white", + legendFontSize: 15, + })); + + return ( + `rgba(255, 255, 255, ${opacity})`, + labelColor: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`, + style: { + borderRadius: 16, + }, + propsForDots: { + r: "6", + strokeWidth: "2", + stroke: "#ffa726", + }, + }} + accessor={"value"} + backgroundColor={"transparent"} + /> + ); +} diff --git a/InsightsPage.tsx b/InsightsPage.tsx new file mode 100644 index 0000000..f270f52 --- /dev/null +++ b/InsightsPage.tsx @@ -0,0 +1,52 @@ +import { useFocusEffect } from "@react-navigation/native"; +import { useCallback, useState } from "react"; +import { View } from "react-native"; +import { Text } from "react-native-paper"; +import AppBarChart from "./AppBarChart"; +import { PADDING } from "./constants"; +import { AppDataSource } from "./data-source"; +import DrawerHeader from "./DrawerHeader"; +import { DAYS } from "./time"; + +export interface WeekCounts { + week: number; + count: number; +} + +export default function InsightsPage() { + const [weekCounts, setWeekCounts] = useState([]); + + useFocusEffect( + useCallback(() => { + const select = ` + SELECT strftime('%w', created) as week, COUNT(*) as count + FROM sets + WHERE created IS NOT NULL + GROUP BY week + HAVING week IS NOT NULL + ORDER BY count DESC; + `; + AppDataSource.manager.query(select).then(setWeekCounts); + }, []) + ); + + return ( + <> + + + Most active days of the week + ({ + label: DAYS[weekCount.week], + value: weekCount.count, + }))} + /> + + + ); +} diff --git a/Routes.tsx b/Routes.tsx index bd79b83..2097643 100644 --- a/Routes.tsx +++ b/Routes.tsx @@ -9,6 +9,7 @@ import TimerPage from "./TimerPage"; import useDark from "./use-dark"; import WorkoutsPage from "./WorkoutsPage"; import WeightPage from "./WeightPage"; +import InsightsPage from "./InsightsPage"; const Drawer = createDrawerNavigator(); @@ -55,6 +56,13 @@ export default function Routes() { component={WeightPage} options={{ drawerIcon: () => }} /> + , + }} + /> =8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/csstype": { "version": "3.1.2", "license": "MIT" @@ -5401,9 +5445,60 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, "node_modules/dom-walk": { "version": "0.1.2" }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dotenv": { "version": "16.3.1", "license": "BSD-2-Clause", @@ -5444,6 +5539,17 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.10.0", "license": "MIT", @@ -8138,6 +8244,11 @@ "tmpl": "1.0.5" } }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, "node_modules/memoize-one": { "version": "5.2.1", "license": "MIT" @@ -8951,6 +9062,17 @@ "node": ">=8" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "license": "MIT" @@ -9329,6 +9451,14 @@ "node": ">=8" } }, + "node_modules/paths-js": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/paths-js/-/paths-js-0.4.11.tgz", + "integrity": "sha512-3mqcLomDBXOo7Fo+UlaenG6f71bk1ZezPQy2JCmYHy2W2k5VKpP+Jbin9H0bjXynelTbglCqdFhSEkeIkKTYUA==", + "engines": { + "node": ">=0.11.0" + } + }, "node_modules/pegjs": { "version": "0.10.0", "license": "MIT", @@ -9378,6 +9508,11 @@ "node": ">=8" } }, + "node_modules/point-in-polygon": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", + "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==" + }, "node_modules/prelude-ls": { "version": "1.2.1", "license": "MIT", @@ -9654,6 +9789,21 @@ "react": "18.2.0" } }, + "node_modules/react-native-chart-kit": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/react-native-chart-kit/-/react-native-chart-kit-6.12.0.tgz", + "integrity": "sha512-nZLGyCFzZ7zmX0KjYeeSV1HKuPhl1wOMlTAqa0JhlyW62qV/1ZPXHgT8o9s8mkFaGxdqbspOeuaa6I9jUQDgnA==", + "dependencies": { + "lodash": "^4.17.13", + "paths-js": "^0.4.10", + "point-in-polygon": "^1.0.1" + }, + "peerDependencies": { + "react": "> 16.7.0", + "react-native": ">= 0.50.0", + "react-native-svg": "> 6.4.1" + } + }, "node_modules/react-native-document-picker": { "version": "9.0.1", "license": "MIT", @@ -9791,18 +9941,16 @@ } }, "node_modules/react-native-svg": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-7.2.1.tgz", - "integrity": "sha512-9T0m/FSv8l7Vohcuc1odLHK/TCRCNWyhMGOvg6pblbhjPWTM+CSF+jgVxU4i92dKCvsYj0GYpEtuzYknyCAuqw==", + "version": "13.14.0", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.14.0.tgz", + "integrity": "sha512-27ZnxUkHgWICimhuj6MuqBkISN53lVvgWJB7pIypjXysAyM+nqgQBPh4vXg+7MbqLBoYvR4PiBgKfwwGAqVxHg==", "dependencies": { - "color": "^2.0.1", - "lodash": "^4.16.6", - "pegjs": "^0.10.0" + "css-select": "^5.1.0", + "css-tree": "^1.1.3" }, "peerDependencies": { - "prop-types": "^15.5.7", "react": "*", - "react-native": ">=0.50.0" + "react-native": "*" } }, "node_modules/react-native-svg-charts": { @@ -9821,15 +9969,6 @@ "react-native-svg": "^6.2.1||^7.0.3" } }, - "node_modules/react-native-svg/node_modules/color": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color/-/color-2.0.1.tgz", - "integrity": "sha512-ubUCVVKfT7r2w2D3qtHakj8mbmKms+tThR8gI8zEYCbUBl8/voqFGt3kgBqGwXAopgXybnkuOq+qMYCRrp4cXw==", - "dependencies": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, "node_modules/react-native-vector-icons": { "version": "9.2.0", "license": "MIT", diff --git a/package.json b/package.json index 87b8365..4ddbac2 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "react": "^18.2.0", "react-hook-form": "^7.45.1", "react-native": "^0.72.3", + "react-native-chart-kit": "^6.12.0", "react-native-document-picker": "^9.0.1", "react-native-file-access": "^3.0.4", "react-native-gesture-handler": "^2.12.0", @@ -44,7 +45,7 @@ "react-native-screens": "^3.22.1", "react-native-share": "^9.2.3", "react-native-sqlite-storage": "^6.0.1", - "react-native-svg": "^7.0.3", + "react-native-svg": "^13.10.10", "react-native-svg-charts": "^5.4.0", "react-native-vector-icons": "^9.2.0", "react-native-view-shot": "^3.7.0",