- Timestamp:
- 05/05/26 18:06:26 (2 months ago)
- Branches:
- master
- Children:
- a8381b1
- Parents:
- e9a0543
- Location:
- frontend
- Files:
-
- 3 added
- 4 edited
-
package-lock.json (modified) (7 diffs)
-
package.json (modified) (1 diff)
-
src/components/graphs/PercentChangeAreaChart.jsx (added)
-
src/components/graphs/TimeRangeToggle.jsx (added)
-
src/pages/Dashboard/pages/Training/TrainingTracking.jsx (modified) (2 diffs)
-
src/pages/Dashboard/pages/Training/components/TrainingProgressCard.jsx (modified) (2 diffs)
-
src/utils/timeSeries.js (added)
Legend:
- Unmodified
- Added
- Removed
-
frontend/package-lock.json
re9a0543 rb3d5fed 15 15 "@relume_io/relume-ui": "^1.3.1", 16 16 "@tailwindcss/vite": "^4.1.18", 17 "apexcharts": "^5.10.6", 17 18 "axios": "^1.13.4", 18 19 "daisyui": "^5.5.18", 19 20 "react": "^19.2.0", 21 "react-apexcharts": "^2.1.0", 20 22 "react-dom": "^19.2.0", 21 23 "react-icons": "^5.5.0", … … 5724 5726 "url": "https://github.com/chalk/ansi-styles?sponsor=1" 5725 5727 } 5728 }, 5729 "node_modules/apexcharts": { 5730 "version": "5.10.6", 5731 "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.10.6.tgz", 5732 "integrity": "sha512-FJQGbso3iRuOwUYnj0yUhkWeKeJE6aboVol+ae09lsc+lbLMWZqSRbrAWVa/qishLiaeG2icxdvmVkm+9n6kOQ==", 5733 "license": "SEE LICENSE IN LICENSE" 5726 5734 }, 5727 5735 "node_modules/argparse": { … … 6911 6919 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 6912 6920 "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 6913 "dev": true,6914 6921 "license": "MIT" 6915 6922 }, … … 7280 7287 "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 7281 7288 "license": "MIT" 7289 }, 7290 "node_modules/loose-envify": { 7291 "version": "1.4.0", 7292 "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 7293 "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 7294 "license": "MIT", 7295 "dependencies": { 7296 "js-tokens": "^3.0.0 || ^4.0.0" 7297 }, 7298 "bin": { 7299 "loose-envify": "cli.js" 7300 } 7282 7301 }, 7283 7302 "node_modules/lru-cache": { … … 9353 9372 "license": "ISC" 9354 9373 }, 9374 "node_modules/object-assign": { 9375 "version": "4.1.1", 9376 "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 9377 "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 9378 "license": "MIT", 9379 "engines": { 9380 "node": ">=0.10.0" 9381 } 9382 }, 9355 9383 "node_modules/optionator": { 9356 9384 "version": "0.9.4", … … 9515 9543 } 9516 9544 }, 9545 "node_modules/prop-types": { 9546 "version": "15.8.1", 9547 "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", 9548 "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", 9549 "license": "MIT", 9550 "dependencies": { 9551 "loose-envify": "^1.4.0", 9552 "object-assign": "^4.1.1", 9553 "react-is": "^16.13.1" 9554 } 9555 }, 9556 "node_modules/prop-types/node_modules/react-is": { 9557 "version": "16.13.1", 9558 "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 9559 "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", 9560 "license": "MIT" 9561 }, 9517 9562 "node_modules/proxy-from-env": { 9518 9563 "version": "1.1.0", … … 9538 9583 "engines": { 9539 9584 "node": ">=0.10.0" 9585 } 9586 }, 9587 "node_modules/react-apexcharts": { 9588 "version": "2.1.0", 9589 "resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-2.1.0.tgz", 9590 "integrity": "sha512-xrmeTKRKHh3cvvLc8SasqFjlOgIqGpyHc81qjnRtcjUM0Fu7qEjgVRWGPokGFjqhwRZVgEym8zmuEyYr5LMYIg==", 9591 "license": "SEE LICENSE IN LICENSE", 9592 "dependencies": { 9593 "prop-types": "^15.8.1" 9594 }, 9595 "peerDependencies": { 9596 "apexcharts": ">=5.10.1", 9597 "react": ">=16.8.0" 9540 9598 } 9541 9599 }, -
frontend/package.json
re9a0543 rb3d5fed 17 17 "@relume_io/relume-ui": "^1.3.1", 18 18 "@tailwindcss/vite": "^4.1.18", 19 "apexcharts": "^5.10.6", 19 20 "axios": "^1.13.4", 20 21 "daisyui": "^5.5.18", 21 22 "react": "^19.2.0", 23 "react-apexcharts": "^2.1.0", 22 24 "react-dom": "^19.2.0", 23 25 "react-icons": "^5.5.0", -
frontend/src/pages/Dashboard/pages/Training/TrainingTracking.jsx
re9a0543 rb3d5fed 2 2 import { useNavigate } from "react-router-dom"; 3 3 import api from "../../../../api/axios"; 4 import graphPlaceholder from "../../../../assets/graph-placeholder.svg";5 4 6 5 import TrainingTrackingHeader from "./components/TrainingTrackingHeader.jsx"; … … 103 102 onAddSession={() => navigate("/dashboard/training/sessions/new")} 104 103 /> 105 <TrainingProgressCard graphSrc={graphPlaceholder} />104 <TrainingProgressCard sessions={sessions} /> 106 105 <TrainingSessionsTable 107 106 columns={columns} -
frontend/src/pages/Dashboard/pages/Training/components/TrainingProgressCard.jsx
re9a0543 rb3d5fed 1 import React from "react";1 import React, { useMemo, useState } from "react"; 2 2 3 const TrainingProgressCard = ({ graphSrc }) => { 3 import TimeRangeToggle from "../../../../../components/graphs/TimeRangeToggle.jsx"; 4 import PercentChangeAreaChart from "../../../../../components/graphs/PercentChangeAreaChart.jsx"; 5 import { percentChangeSeries, sumByTimeBucket } from "../../../../../utils/timeSeries.js"; 6 7 const TrainingProgressCard = ({ sessions }) => { 8 const [range, setRange] = useState("weekly"); 9 10 const points = useMemo(() => { 11 const buckets = sumByTimeBucket( 12 sessions, 13 range, 14 (s) => s.date, 15 (s) => s.calories 16 ); 17 return percentChangeSeries(buckets); 18 }, [range, sessions]); 19 20 const latest = points?.length ? points[points.length - 1] : null; 21 const latestPct = latest ? Number(latest.value ?? 0) : 0; 22 const latestBase = latest ? Number(latest.base ?? 0) : 0; 23 4 24 return ( 5 25 <div className="card bg-base-200 border border-base-300"> … … 7 27 <div className="flex items-center justify-between gap-4"> 8 28 <h2 className="card-title">Progress</h2> 9 <span className="badge badge-ghost">Graph placeholder</span> 29 <div className="flex items-center gap-3"> 30 <span className="badge badge-ghost"> 31 {latestPct >= 0 ? "+" : ""} 32 {latestPct.toFixed(1)}% (last) 33 </span> 34 <TimeRangeToggle value={range} onChange={setRange} /> 35 </div> 10 36 </div> 11 <div className="mt-4 w-full overflow-hidden rounded-xl border border-base-300 bg-base-100"> 12 <img 13 src={graphSrc} 14 alt="Training progress graph placeholder" 15 className="block h-65 w-full object-cover" 16 /> 37 38 <div className="mt-4 w-full overflow-hidden rounded-xl border border-base-300 bg-base-100 p-2"> 39 {points.length < 2 ? ( 40 <div className="flex h-65 items-center justify-center text-sm opacity-70"> 41 Add at least 2 sessions to see % change. 42 </div> 43 ) : ( 44 <PercentChangeAreaChart 45 points={points} 46 granularity={range} 47 height={260} 48 /> 49 )} 50 </div> 51 52 <div className="mt-2 text-xs opacity-70"> 53 Showing percentage change in calories burned per {range} bucket. Latest bucket total: {Math.round(latestBase)}. 17 54 </div> 18 55 </div>
Note:
See TracChangeset
for help on using the changeset viewer.
