Files
HealthLog/src/hooks/use-mood-day.ts
T
Marc-André Bombeck 3cf67d05f9 fix(ui): let the read-failure primitives decide by the error
About forty compact rows and seventy cards still offered a retry on a
spent read budget and drew an error card on a refusal, while a third
primitive (ReadFailureRow) did the right thing at eight places.

QueryErrorRow and QueryErrorCard now take the query's `error` and read
it through readFailureKind, which moves to src/lib/api next to
ApiError: a refusal (403) draws the surface's refused state or nothing,
a spent budget (429) says so without a retry, an ended session (401)
says so and offers sign-in instead of going blank, and only a real
failure offers the retry. ReadFailureRow is gone and every site passes
its error; a guard test fails on a site that does not.

The coach read strip keeps its card in the error state and holds one
body height across loading, failure and a one-line read.
2026-10-20 03:38:57 +02:00

75 lines
1.9 KiB
TypeScript

"use client";
import { useQuery } from "@tanstack/react-query";
import { apiGet } from "@/lib/api/api-fetch";
import { queryKeys } from "@/lib/query-keys";
/**
* Every mood entry a person logged on ONE local day, from
* `GET /api/mood-entries?from=<day>&to=<day>`.
*
* The route filters on the mood `date` column, which already IS the local
* day key, so no timezone maths happens here. Entries come back newest
* first (`sortBy=moodLoggedAt`, `sortDir=desc`, the route's defaults).
*/
export interface MoodDayEntry {
id: string;
date: string;
/** The mood enum, e.g. `GUT`. Rendered through `MOOD_LABEL_KEYS`. */
mood: string;
score: number;
note: string | null;
source: string;
moodLoggedAt: string;
}
interface MoodDayResponse {
entries: MoodDayEntry[];
meta: { total: number };
}
export interface UseMoodDayResult {
/** `undefined` until the route has answered; `[]` means the day really
* carried no entry. */
entries: MoodDayEntry[] | undefined;
isError: boolean;
/** The failed read's error, for the error row to read. */
error: unknown;
refetch: () => void;
}
/**
* Reads one day's mood entries.
*
* `enabled` is the caller's gate — pass `false` when the user is signed
* out, and nothing is fetched. Mood has no module gate, so there is
* nothing else to check.
*/
export function useMoodDay(
date: string | undefined,
enabled: boolean,
): UseMoodDayResult {
const { data, isError, error, refetch } = useQuery({
queryKey: queryKeys.moodEntriesDay(date ?? ""),
queryFn: () => {
const params = new URLSearchParams({
from: date as string,
to: date as string,
limit: "50",
});
return apiGet<MoodDayResponse>(`/api/mood-entries?${params}`);
},
enabled: enabled && Boolean(date),
staleTime: 5 * 60_000,
refetchOnWindowFocus: false,
});
return {
entries: data?.entries,
isError,
error,
refetch: () => void refetch(),
};
}