Merge branch 'fix/v1436-oura' into release/v1.43.6

This commit is contained in:
Marc-André Bombeck committed 2026-10-19 20:20:29 +02:00
commit f05b2f71e7
17 files changed
+429 -54

No files matched your search

@@ -3,6 +3,7 @@ import { renderToStaticMarkup } from "react-dom/server";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { I18nProvider } from "@/lib/i18n/context";
import { queryKeys } from "@/lib/query-keys";
import type { DataSummary } from "@/lib/analytics/trends";
/**
@@ -45,6 +46,12 @@ function render(node: React.ReactNode) {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false, staleTime: Infinity } },
});
// The recovery page's empty note waits for the connection status; an
// account with no integrations is the settled answer here.
queryClient.setQueryData(queryKeys.integrationsStatus(), {
threshold: 3,
integrations: [],
});
return renderToStaticMarkup(
<QueryClientProvider client={queryClient}>
<I18nProvider initialLocale="en">{node}</I18nProvider>
@@ -9,10 +9,10 @@ import type { DataSummary } from "@/lib/analytics/trends";
/**
* The recovery page's empty note says what is missing for THIS account. An
* Oura ring fills the page through its resilience level alone, so a connected
* ring with an empty page is either a grant that leaves out the heart-health
* data the level sits behind, or Oura not having sent a level yet. The
* connection facts come from the server's integrations read; the page only
* picks the sentence.
* ring with an empty page asks for a reconnect only when the server recorded
* that the grant leaves resilience out, and otherwise says only that no
* level has arrived. The connection facts come from the server's
* integrations read; the page only picks the sentence, and waits for it.
*/
vi.mock("next/dynamic", () => ({
@@ -57,14 +57,19 @@ const OURA_SUMMARIES = {
HRV_RMSSD: summary(30),
};
function render(oura: Record<string, unknown> | null) {
function render(
oura: Record<string, unknown> | null,
opts: { statusLoaded?: boolean } = {},
) {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false, staleTime: Infinity } },
});
queryClient.setQueryData(queryKeys.integrationsStatus(), {
threshold: 3,
integrations: oura ? [{ integration: "oura", ...oura }] : [],
});
if (opts.statusLoaded !== false) {
queryClient.setQueryData(queryKeys.integrationsStatus(), {
threshold: 3,
integrations: oura ? [{ integration: "oura", ...oura }] : [],
});
}
return renderToStaticMarkup(
<QueryClientProvider client={queryClient}>
<I18nProvider initialLocale="en">
@@ -104,16 +109,34 @@ describe("<RecoverySection> empty note", () => {
expect(html).toContain('href="/settings/integrations"');
});
it("says Oura has sent no level yet when the grant covers it", () => {
it("says only that no level has arrived when no withheld permission is recorded", () => {
const html = render({
connected: true,
health: health([{ item: "spo2", cause: "permission" }]),
});
expect(html).toContain('data-empty-case="oura-no-resilience"');
expect(html).toContain("has not sent a resilience level");
expect(html).toContain("no resilience level has arrived");
// The server cannot prove the grant covers resilience, so the note
// never says it does.
expect(html).not.toContain("permission covers");
expect(html).not.toContain('href="/settings/integrations"');
});
it("stays neutral when the connection carries no health block", () => {
const html = render({ connected: true });
expect(html).toContain('data-empty-case="oura-no-resilience"');
expect(html).not.toContain("permission covers");
});
it("shows no note until the connection status has loaded", () => {
const html = render(
{ connected: true, health: health([]) },
{ statusLoaded: false },
);
expect(html).toContain('data-slot="recovery-loading"');
expect(html).not.toContain("data-empty-case");
});
it("keeps the general note for an account without Oura", () => {
const html = render(null);
expect(html).toContain('data-empty-case="general"');
@@ -49,11 +49,12 @@ interface BlockGroup {
/**
* Why this account's recovery page is empty, from the server's view of its
* Oura connection. An Oura ring feeds this page through its resilience level
* alone, so a connected ring with an empty page has exactly two causes: the
* grant does not cover the heart-health data the level sits behind (the
* server records that per collection and publishes it as an unavailable
* item), or Oura has not sent a level for this account. Everyone else gets
* the general note naming what fills the page.
* alone. When the server records that the grant leaves resilience out, the
* note asks for one reconnect. Otherwise it says only that no level has
* arrived: the server cannot tell "the grant covers it" from "not recorded
* yet" (the scope note is cleared on every reconnect and written only by a
* sync that reached Oura), so the note never claims coverage. Everyone else
* gets the general note naming what fills the page.
*/
type RecoveryEmptyCase = "general" | "oura-permission" | "oura-no-resilience";
@@ -222,7 +223,9 @@ export function RecoverySection() {
);
const emptyCase = recoveryEmptyCase(pickStatus(statuses.data, "oura"));
if (isLoading || summaries == null) {
// The empty note waits for the connection status, so it never reads as
// the general note first and then changes under the reader.
if (isLoading || summaries == null || (!hasAny && statuses.isPending)) {
return (
<div className="space-y-3" data-slot="recovery-loading">
<ChartSkeleton />