perf(dashboard): load the quick-entry forms when a sheet opens

The dashboard and the bottom bar's capture picker imported all five
quick-entry forms eagerly, so every authenticated paint carried them for
sheets most visits never open. One module now wraps them in next/dynamic
(client-only, a skeleton holding the sheet body while the chunk loads)
and both callers use it. The discard guard stays static. The picker tests
mock the one module instead of five.
This commit is contained in:
Marc-André Bombeck committed 2026-10-03 21:30:38 +02:00
1 parent bcbfd87ae9
commit 65b2f75421
5 files changed
+88 -22

No files matched your search

@@ -0,0 +1,68 @@
"use client";
/**
* The quick-entry forms, loaded when a sheet first opens rather than with the
* page. The dashboard and the bottom bar's capture picker are on nearly every
* authenticated paint, and both used to import all five forms eagerly (each
* with react-hook-form, zod, its pickers and its own queries) for sheets most
* visits never open.
*
* Client-only (`ssr: false`): every sheet is closed on the server render. The
* options are inline object literals because the bundler requires them so.
* The placeholder holds the sheet body's height while the chunk arrives so the
* sheet does not grow under the finger. Same `next/dynamic` arrangement as
* the Coach drawer mount.
*/
import dynamic from "next/dynamic";
import { Skeleton } from "@/components/ui/skeleton";
function SheetBodySkeleton() {
return (
<div className="space-y-4" data-slot="quick-entry-form-loading">
<Skeleton className="h-10 w-full" />
<Skeleton className="h-10 w-full" />
<Skeleton className="h-10 w-2/3" />
</div>
);
}
export const MeasurementForm = dynamic(
() =>
import("@/components/measurements/measurement-form").then((m) => ({
default: m.MeasurementForm,
})),
{ ssr: false, loading: SheetBodySkeleton },
);
export const MoodForm = dynamic(
() =>
import("@/components/mood/mood-form").then((m) => ({
default: m.MoodForm,
})),
{ ssr: false, loading: SheetBodySkeleton },
);
export const MedicationIntakeQuickAdd = dynamic(
() =>
import("@/components/dashboard/medication-intake-quick-add").then((m) => ({
default: m.MedicationIntakeQuickAdd,
})),
{ ssr: false, loading: SheetBodySkeleton },
);
export const ManualWorkoutForm = dynamic(
() =>
import("@/components/workouts/manual-workout-form").then((m) => ({
default: m.ManualWorkoutForm,
})),
{ ssr: false, loading: SheetBodySkeleton },
);
export const SymptomEntryForm = dynamic(
() =>
import("@/components/symptoms/symptom-entry-form").then((m) => ({
default: m.SymptomEntryForm,
})),
{ ssr: false, loading: SheetBodySkeleton },
);
@@ -11,6 +11,13 @@
*/
import { useState } from "react";
import { ResponsiveSheet } from "@/components/ui/responsive-sheet";
import {
ManualWorkoutForm,
MeasurementForm,
MedicationIntakeQuickAdd,
MoodForm,
SymptomEntryForm,
} from "@/components/dashboard/quick-entry-forms.lazy";
import {
AlertDialog,
AlertDialogAction,
@@ -21,11 +28,6 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { MeasurementForm } from "@/components/measurements/measurement-form";
import { MoodForm } from "@/components/mood/mood-form";
import { MedicationIntakeQuickAdd } from "@/components/dashboard/medication-intake-quick-add";
import { ManualWorkoutForm } from "@/components/workouts/manual-workout-form";
import { SymptomEntryForm } from "@/components/symptoms/symptom-entry-form";
import { useTranslations } from "@/lib/i18n/context";
import {
useRecordCapabilities,
@@ -82,14 +82,12 @@ vi.mock("@/components/ui/alert-dialog", () => ({
AlertDialogTitle: markedComponent("AlertDialogTitle"),
}));
vi.mock("@/components/measurements/measurement-form", () => ({
vi.mock("@/components/dashboard/quick-entry-forms.lazy", () => ({
MeasurementForm: markedComponent("MeasurementForm"),
}));
vi.mock("@/components/mood/mood-form", () => ({
MoodForm: markedComponent("MoodForm"),
}));
vi.mock("@/components/dashboard/medication-intake-quick-add", () => ({
MedicationIntakeQuickAdd: markedComponent("MedicationIntakeQuickAdd"),
ManualWorkoutForm: markedComponent("ManualWorkoutForm"),
SymptomEntryForm: markedComponent("SymptomEntryForm"),
}));
import { CapturePicker } from "../capture-picker";
@@ -35,16 +35,12 @@ vi.mock("@/components/ui/responsive-sheet", () => ({
}) => (open ? <section>{children}</section> : null),
}));
vi.mock("@/components/measurements/measurement-form", () => ({
vi.mock("@/components/dashboard/quick-entry-forms.lazy", () => ({
MeasurementForm: () => <div data-testid="measurement-form" />,
}));
vi.mock("@/components/mood/mood-form", () => ({
MoodForm: () => <div data-testid="mood-form" />,
}));
vi.mock("@/components/dashboard/medication-intake-quick-add", () => ({
MedicationIntakeQuickAdd: () => <div data-testid="medication-form" />,
ManualWorkoutForm: () => <div data-testid="workout-form" />,
SymptomEntryForm: () => <div data-testid="symptom-form" />,
}));
import { CapturePicker } from "../capture-picker";
+7 -5
View File
@@ -3,12 +3,14 @@
import { useState } from "react";
import { Activity, Footprints, Pill, Stethoscope, Waves } from "lucide-react";
import { MeasurementForm } from "@/components/measurements/measurement-form";
import { MoodForm } from "@/components/mood/mood-form";
import { MedicationIntakeQuickAdd } from "@/components/dashboard/medication-intake-quick-add";
import { ManualWorkoutForm } from "@/components/workouts/manual-workout-form";
import { SymptomEntryForm } from "@/components/symptoms/symptom-entry-form";
import { ResponsiveSheet } from "@/components/ui/responsive-sheet";
import {
ManualWorkoutForm,
MeasurementForm,
MedicationIntakeQuickAdd,
MoodForm,
SymptomEntryForm,
} from "@/components/dashboard/quick-entry-forms.lazy";
import {
AlertDialog,
AlertDialogAction,