Skip to content

feat(sleep-reports): align sleep calculations, fix charts, and improve data accuracy#854

Merged
CodeWithCJ merged 10 commits intomainfrom
dev
Mar 7, 2026
Merged

feat(sleep-reports): align sleep calculations, fix charts, and improve data accuracy#854
CodeWithCJ merged 10 commits intomainfrom
dev

Conversation

@CodeWithCJ
Copy link
Owner

feat(sleep-reports): align sleep calculations, fix charts, and improve data accuracy

Key Changes:

  • Logic Alignment: Updated SleepScience service to use the verified time_asleep_in_seconds from devices instead of manually summing sleep stages. This fixes the discrepancy between "Daily
    Breakdown" and "History Table."
  • Metric Accuracy: Fixed the MCTQ "Sleep Need" calculation to prevent it from spiking to 10 hours based on a single catch-up weekend. Implemented a confidence-weighted baseline with a 9-hour "sanity
    cap" for limited data.
  • Data Aggregation: Implemented "Session Merging" in the Sleep Report. Naps and multiple sleep sessions on the same day are now aggregated into a single "Biological Sleep Day," correcting Sleep
    Debt, Efficiency, and Score calculations.
  • Chart Improvements:
    • Sleep Debt: Added Red (Debt) and Green (Surplus) background zones and set the Y-Axis to ['auto', 'auto'] to properly visualize negative debt (surplus).
    • Efficiency: Set Y-Axis to ['auto', 100] to reveal trends in high-efficiency ranges.
    • Consistency: Fixed the "Cross-Midnight" bedtime bug (23:00 to 01:00) by normalizing post-midnight times to 24h+ (e.g., 25:00), creating a continuous trend line.
    • Tooltips: Added custom tooltips to "Sleep Stages" to show human-readable durations (e.g., "1h 30m") instead of raw decimals.
  • UI/UX Polish:
    • Merged the "Daily Breakdown" data into the main History Table (added Impact/Weight column and color-coded Debt).
    • Updated "Insight" logic to flag "High Debt" (>1.5h) even if the daily Sleep Score is good.
    • Fixed NaN display issues in Health Metric charts (SpO2, HRV) by adding null checks for averages.

Fixes:

  • Resolved TypeScript errors (undefined index access) in report aggregators.
  • Fixed chart rendering issues where ReferenceArea was missing or invisible.
    2* Corrected "Awake Periods" property naming in SleepEntry type.

Description

Provide a brief summary of your changes.

Related Issue

PR type [x] Issue [x] New Feature [ ] Documentation
Linked Issue: #

Checklist

Please check all that apply:

  • [MANDATORY for new feature] Alignment: I have raised a GitHub issue and it was reviewed/approved by maintainers
  • Tests: I have included automated tests for my changes.
  • [MANDATORY for UI changes] Screenshots: I have attached "Before" vs "After" screenshots below.
  • [MANDATORY for Frontend changes] Quality: I have run pnpm run validate (especially for Frontend).
  • Translations: I have only updated the English (en) translation file (if applicable).
  • Architecture: My code follows the existing architecture standards.
  • Database Security: I have updated rls_policies.sql for any new user-specific tables.
  • [MANDATORY - ALL] Integrity & License: I certify this is my own work, free of malicious code(phishing, malware, etc.) and I agree to the License terms.

Screenshots (if applicable)

Before

[Insert screenshot/GIF here]

After

[Insert screenshot/GIF here]

codewithcj001 added 2 commits March 6, 2026 17:43
…e data accuracy

**Key Changes:**

*   **Logic Alignment:** Updated `SleepScience` service to use the verified `time_asleep_in_seconds` from devices instead of manually summing sleep stages. This fixes the discrepancy between "Daily
Breakdown" and "History Table."
*   **Metric Accuracy:** Fixed the MCTQ "Sleep Need" calculation to prevent it from spiking to 10 hours based on a single catch-up weekend. Implemented a confidence-weighted baseline with a 9-hour "sanity
cap" for limited data.
*   **Data Aggregation:** Implemented "Session Merging" in the Sleep Report. Naps and multiple sleep sessions on the same day are now aggregated into a single "Biological Sleep Day," correcting Sleep
Debt, Efficiency, and Score calculations.
*   **Chart Improvements:**
    *   **Sleep Debt:** Added Red (Debt) and Green (Surplus) background zones and set the Y-Axis to `['auto', 'auto']` to properly visualize negative debt (surplus).
    *   **Efficiency:** Set Y-Axis to `['auto', 100]` to reveal trends in high-efficiency ranges.
    *   **Consistency:** Fixed the "Cross-Midnight" bedtime bug (23:00 to 01:00) by normalizing post-midnight times to 24h+ (e.g., 25:00), creating a continuous trend line.
    *   **Tooltips:** Added custom tooltips to "Sleep Stages" to show human-readable durations (e.g., "1h 30m") instead of raw decimals.
*   **UI/UX Polish:**
    *   Merged the "Daily Breakdown" data into the main History Table (added Impact/Weight column and color-coded Debt).
    *   Updated "Insight" logic to flag "High Debt" (>1.5h) even if the daily Sleep Score is good.
    *   Fixed `NaN` display issues in Health Metric charts (SpO2, HRV) by adding null checks for averages.

**Fixes:**
*   Resolved TypeScript errors (`undefined` index access) in report aggregators.
*   Fixed chart rendering issues where `ReferenceArea` was missing or invisible.
   2*   Corrected "Awake Periods" property naming in `SleepEntry` type.
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the accuracy and presentation of sleep data within the application. It refines sleep calculations by leveraging device-provided data, improves the robustness of the personalized sleep need metric, and aggregates multiple sleep sessions into a single biological sleep day for more coherent reporting. Furthermore, it introduces several chart and UI/UX improvements, such as better visualization of sleep debt and efficiency, a fix for cross-midnight bedtimes, and clearer data presentation in tables and tooltips.

Highlights

  • Logic Alignment: Updated the SleepScience service to use the verified time_asleep_in_seconds from devices, resolving discrepancies between daily breakdowns and history tables.
  • Metric Accuracy: Fixed the MCTQ "Sleep Need" calculation to prevent spikes and implemented a confidence-weighted baseline with a 9-hour "sanity cap" for limited data.
  • Data Aggregation: Implemented "Session Merging" in the Sleep Report, aggregating naps and multiple sleep sessions into a single "Biological Sleep Day" for accurate debt, efficiency, and score calculations.
  • Chart Improvements: Enhanced Sleep Debt charts with red/green background zones and ['auto', 'auto'] Y-axis, set Sleep Efficiency Y-axis to ['auto', 100], fixed cross-midnight bedtime bugs for continuous trend lines, and added custom tooltips to Sleep Stages for human-readable durations.
  • UI/UX Polish: Merged the "Daily Breakdown" data into the main History Table, adding an Impact/Weight column and color-coding Debt. Updated "Insight" logic to flag "High Debt" and fixed NaN display issues in Health Metric charts with null checks.
  • Fixes: Resolved TypeScript errors related to undefined index access, corrected chart rendering issues with ReferenceArea, and fixed Awake Periods property naming in SleepEntry type.
Changelog
  • SparkyFitnessFrontend/public/locales/en/translation.json
    • Added new translation keys for "Impact" and "High Debt".
    • Updated CSV header for "Debt" and added "Weight (%)."
  • SparkyFitnessFrontend/src/pages/Reports/SleepAnalyticsCharts.tsx
    • Imported ReferenceArea and ReferenceLine for chart enhancements.
    • Implemented cross-midnight bedtime normalization for continuous trend lines.
    • Introduced a CustomTooltip for sleep stages to display human-readable durations and percentages.
    • Adjusted Y-axis domain for Sleep Debt chart to ['auto', 'auto'] and added ReferenceArea for visual debt/surplus zones.
    • Adjusted Y-axis domain for Sleep Efficiency chart to ['auto', 100].
    • Updated Sleep Debt disclaimer to use formatSecondsToHHMM for personalized sleep need.
  • SparkyFitnessFrontend/src/pages/Reports/SleepAnalyticsTable.tsx
    • Added an optional renderHeaderActions prop to allow external control over table header actions.
    • Included a new "Impact" column in the sleep analytics table.
    • Modified insight logic to prioritize "High Debt" over "Good Sleep" and color-coded sleep debt values.
    • Expanded TableCell colspan to accommodate the new "Impact" column.
  • SparkyFitnessFrontend/src/pages/Reports/SleepReport.tsx
    • Implemented sleep session merging logic to aggregate multiple sleep entries into a single "Biological Sleep Day".
    • Updated CSV export logic to reflect the new "High Debt" insight and "Weight" column.
    • Refactored data processing functions (processSpO2Data, processHRVData, processRespirationData, processHeartRateData) to aggregate data by date, handling multiple entries per day and null values.
    • Removed the SleepDebtBreakdown component and integrated its functionality into the main Sleep History & Analytics table.
    • Moved the CSV export button to the SleepReport component, above the SleepAnalyticsTable.
  • SparkyFitnessFrontend/src/pages/Reports/SleepScience/SleepDebtBreakdown.tsx
    • Removed the component as its functionality was integrated elsewhere.
  • SparkyFitnessFrontend/src/pages/Reports/SleepScience/SleepScienceSection.tsx
    • Removed the import and usage of the SleepDebtBreakdown component.
  • SparkyFitnessFrontend/src/types.ts
    • Extended the SleepAnalyticsData interface with an optional weight property.
  • SparkyFitnessServer/models/sleepScienceRepository.js
    • Modified the sleep history query to include timeAsleepHours, directly fetching time_asleep_in_seconds.
  • SparkyFitnessServer/services/sleepScienceService.js
    • Refined sleep calculation logic by prioritizing device-provided sleep time in getTST.
    • Updated calculateSleepDebt to allow negative deviation (sleep surplus) to reduce weighted debt and adjusted average debt calculation.
    • Enhanced calculateBaseline with confidence levels (low, medium, high) based on data points.
    • Implemented a weighted pull towards a default sleep need (8.25 hours) for sparse data in calculateBaseline.
    • Applied a sanity cap of 9 hours for sleep need in low confidence scenarios.
    • Refined mid-sleep point calculation to use actual TST for better accuracy.
Activity
  • The pull request was created by CodeWithCJ.
  • No specific review comments or progress updates are available in the provided context.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant enhancements to sleep analytics and reporting. Key changes include adding new translation keys for 'impact' and 'high debt', and refining existing ones. The SleepAnalyticsCharts component now features improved bedtime/wake time formatting to handle cross-midnight scenarios, a custom tooltip for sleep stage charts, and visual enhancements to the sleep debt chart with ReferenceArea and ReferenceLine components to indicate debt/surplus zones. The SleepAnalyticsTable has been updated to include an 'Impact' column, conditional styling for sleep debt, and a revised insight logic that prioritizes 'High Debt'. The SleepReport component underwent a major refactor to aggregate multiple sleep entries per day into a single data point for more accurate daily analytics, and its CSV export now includes 'Weight (%)'. Additionally, the SleepDebtBreakdown component was removed. On the backend, the sleepScienceService was updated to allow negative sleep debt (surplus) in calculations and to introduce a confidence metric for personalized sleep need, with a weighted pull towards a default sleep need for lower confidence data. Review comments highlighted the need to remove redundant ReferenceArea components in SleepAnalyticsCharts, optimize the renderHeaderActions call in SleepAnalyticsTable to avoid inefficient re-renders, and improve type safety by using SleepStageEvent[] instead of any[] for allStageEvents and defining a specific type for combinedEntry.

Comment on lines +523 to +534
<ReferenceArea
y1={0}
y2={100}
fill="#ff0000"
fillOpacity={0.05}
/>
<ReferenceArea
y1={-100}
y2={0}
fill="#00ff00"
fillOpacity={0.05}
/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block adds ReferenceArea components that are redundant with another set defined on lines 569-582. The y-axis range [-100, 100] here also seems incorrect for sleep debt measured in hours. To avoid redundancy and use the more appropriate range from the other block, I suggest removing these ReferenceArea components, while keeping the useful ReferenceLine that follows.

Comment on lines +73 to +83
{renderHeaderActions ? (
renderHeaderActions() !== null && (
<div className="flex justify-end mb-4">{renderHeaderActions()}</div>
)
) : (
<div className="flex justify-end mb-4">
<Button onClick={handleExportClick}>
{t('sleepAnalyticsTable.exportToCSV', 'Export to CSV')}
</Button>
</div>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The renderHeaderActions function is called twice here: once for the conditional check and again for rendering. This is inefficient as it can cause the component to render twice. It's better to call it once, store the result in a variable, and then use that variable for both the check and the render. You can achieve this with an IIFE (Immediately Invoked Function Expression) to keep the logic contained within the JSX.

      {(() => {
        if (renderHeaderActions) {
          const actions = renderHeaderActions();
          return actions !== null ? (
            <div className="flex justify-end mb-4">{actions}</div>
          ) : null;
        }
        return (
          <div className="flex justify-end mb-4">
            <Button onClick={handleExportClick}>
              {t('sleepAnalyticsTable.exportToCSV', 'Export to CSV')}
            </Button>
          </div>
        );
      })()}

let earliestBedtime = mainEntry.bedtime;
let latestWakeTime = mainEntry.wake_time;

const allStageEvents: any[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any[] bypasses TypeScript's type safety. Since SleepStageEvent is already defined and imported, please use SleepStageEvent[] here to ensure type correctness throughout the data processing pipeline.

Suggested change
const allStageEvents: any[] = [];
const allStageEvents: SleepStageEvent[] = [];

totalAwakeDuration: aggregatedStages.awake,
};

const combinedEntry: any = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any for combinedEntry weakens type safety. This object represents an aggregated sleep session and has a different structure from the base SleepEntry (e.g., it includes is_aggregated). To maintain type safety and improve code clarity, consider defining a new type, for example AggregatedSleepEntry, and use it here. This will also help ensure it's compatible with the CombinedSleepData type it's being assigned to.

@CodeWithCJ
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request delivers a substantial set of features and fixes for the sleep reports, greatly improving data accuracy and visualization. The introduction of session merging for a single 'Biological Sleep Day' is a major enhancement. The backend changes to sleep need and sleep debt calculations make the metrics more robust and accurate. The frontend sees numerous chart improvements, such as background zones for sleep debt and better handling of cross-midnight times, which significantly enhance usability. My review focuses on a few areas to improve code quality: removing duplicate translation keys, cleaning up redundant chart components, improving performance by avoiding repeated function calls, and enhancing maintainability by using constants for colors.

@CodeWithCJ
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant improvements to the sleep reporting and analytics features. Key changes include aligning frontend and backend sleep calculations, implementing session merging to aggregate multiple sleep periods in a day, and substantially improving the accuracy of sleep need and sleep debt calculations. The UI has also been enhanced with better chart visualizations, more informative tooltips, and a consolidated history table.

My review focuses on improving code maintainability by addressing hardcoded values used for calculating user insights. By extracting these thresholds into named constants, the code becomes more readable and easier to update consistently across different components. The core logic for data aggregation and the updated scientific calculations on the backend appear solid and well-implemented.

CodeWithCJ and others added 6 commits March 6, 2026 19:09
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@CodeWithCJ CodeWithCJ merged commit 94f12a1 into main Mar 7, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant