mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 12:22:03 +00:00
fix(ui): defensive optional chains across summaries/medications/preferences/entries/measurements
Same anti-pattern as the v1.4.2 hotfix on /dashboard and /insights — the optional chain protected only the outer object, so any field on the inner object that didn't exist threw at access time. Marc's reports flagged dashboard, insights, medications, notification-preferences, admin login overview, mood list, and measurement list. Applied 'data?.X?.Y' to every spot the regex caught.
This commit is contained in:
1 parent
cfbd822862
commit
680b0019c1
6 files changed
+15
-15
No files matched your search
@@ -633,10 +633,10 @@ export default function InsightsPage() {
|
||||
staleTime: 60 * 1000,
|
||||
});
|
||||
const w = analytics?.summaries?.WEIGHT;
|
||||
const sys = analytics?.summaries.BLOOD_PRESSURE_SYS;
|
||||
const dia = analytics?.summaries.BLOOD_PRESSURE_DIA;
|
||||
const p = analytics?.summaries.PULSE;
|
||||
const bf = analytics?.summaries.BODY_FAT;
|
||||
const sys = analytics?.summaries?.BLOOD_PRESSURE_SYS;
|
||||
const dia = analytics?.summaries?.BLOOD_PRESSURE_DIA;
|
||||
const p = analytics?.summaries?.PULSE;
|
||||
const bf = analytics?.summaries?.BODY_FAT;
|
||||
const showBodyFatCard = (bf?.count ?? 0) > 0;
|
||||
const moodSummary = data?.moodSummary;
|
||||
const showMoodCard = (moodSummary?.count ?? 0) > 0;
|
||||
@@ -710,7 +710,7 @@ export default function InsightsPage() {
|
||||
classifyRangeValue(bmiAvg30, bmiRange),
|
||||
]);
|
||||
const bpMedications =
|
||||
data?.medications.filter(
|
||||
data?.medications?.filter(
|
||||
(medication) => medication.category === "BLOOD_PRESSURE",
|
||||
) ?? [];
|
||||
const bpMedicationCompliance30 =
|
||||
|
||||
@@ -112,7 +112,7 @@ export default function NotificationsPage() {
|
||||
});
|
||||
|
||||
function isEnabled(channelId: string, eventType: string): boolean {
|
||||
const pref = data?.preferences.find(
|
||||
const pref = data?.preferences?.find(
|
||||
(p) => p.channelId === channelId && p.eventType === eventType,
|
||||
);
|
||||
// Opt-out model: default is ON when no preference row exists
|
||||
|
||||
+6
-6
@@ -198,12 +198,12 @@ export default function DashboardPage() {
|
||||
});
|
||||
|
||||
const w = data?.summaries?.WEIGHT;
|
||||
const sys = data?.summaries.BLOOD_PRESSURE_SYS;
|
||||
const dia = data?.summaries.BLOOD_PRESSURE_DIA;
|
||||
const p = data?.summaries.PULSE;
|
||||
const bf = data?.summaries.BODY_FAT;
|
||||
const sleepSummary = data?.summaries.SLEEP_DURATION;
|
||||
const stepsSummary = data?.summaries.ACTIVITY_STEPS;
|
||||
const sys = data?.summaries?.BLOOD_PRESSURE_SYS;
|
||||
const dia = data?.summaries?.BLOOD_PRESSURE_DIA;
|
||||
const p = data?.summaries?.PULSE;
|
||||
const bf = data?.summaries?.BODY_FAT;
|
||||
const sleepSummary = data?.summaries?.SLEEP_DURATION;
|
||||
const stepsSummary = data?.summaries?.ACTIVITY_STEPS;
|
||||
const moodSummary = moodData?.summary;
|
||||
|
||||
// Resolve full dashboard layout — controls visibility + order of every widget
|
||||
|
||||
@@ -45,7 +45,7 @@ export function LoginOverviewSection({ id }: { id: string }) {
|
||||
|
||||
const entries =
|
||||
filter === "failed"
|
||||
? data?.entries.filter((e) => e.action === "auth.login.failed")
|
||||
? data?.entries?.filter((e) => e.action === "auth.login.failed")
|
||||
: data?.entries;
|
||||
|
||||
return (
|
||||
|
||||
@@ -300,7 +300,7 @@ export function MeasurementList({ onEdit }: MeasurementListProps) {
|
||||
<div className="flex h-32 items-center justify-center">
|
||||
<Loader2 className="text-primary h-6 w-6 animate-spin" />
|
||||
</div>
|
||||
) : !data?.measurements.length ? (
|
||||
) : !data?.measurements?.length ? (
|
||||
<div className="text-muted-foreground flex h-32 items-center justify-center rounded-lg border border-dashed">
|
||||
{t("measurements.noMeasurements")}
|
||||
</div>
|
||||
|
||||
@@ -296,7 +296,7 @@ export function MoodList() {
|
||||
<div className="flex h-32 items-center justify-center">
|
||||
<Loader2 className="text-primary h-6 w-6 animate-spin" />
|
||||
</div>
|
||||
) : !data?.entries.length ? (
|
||||
) : !data?.entries?.length ? (
|
||||
<div className="text-muted-foreground flex h-32 items-center justify-center rounded-lg border border-dashed">
|
||||
{t("mood.noEntries")}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user