Skip to content

perf: add loading fallbacks to dynamic imports and auto-dismiss settings alerts #66

@macwilling

Description

@macwilling

Problem

1. Dynamic imports have no loading fallback

Two dynamic(..., { ssr: false }) calls have no loading prop. While the JS bundle loads, the component area renders as nothing — a blank space with no indication content is coming.

File Component
components/portal/PortalTaskContent.tsx MilkdownEditor (portal read-only view)
Any admin task page that loads MilkdownEditor Rich text editor

The Milkdown bundle is ~180KB gzipped. On a slow mobile connection (common for portal clients), this blank area lasts 1–3 seconds.

2. Settings "Saved." alert never auto-dismisses

All five settings forms (BusinessInfoForm, BrandingForm, InvoiceSettingsForm, EmailTemplatesForm, TenantSlugForm) show a static <Alert>Saved.</Alert> on success. It persists indefinitely — stale after the user makes a second save.

Fix

Dynamic import loading prop

const MilkdownEditor = dynamic(
  () => import("@/components/editor/MilkdownEditor"),
  {
    ssr: false,
    loading: () => (
      <div className="space-y-2 min-h-[80px] py-1">
        {[100, 80, 60].map((w) => (
          <div key={w} className="h-3 rounded bg-muted animate-pulse" style={{ width: `${w}%` }} />
        ))}
      </div>
    ),
  }
);

Auto-dismiss success alert

const [showSuccess, setShowSuccess] = useState(false);

useEffect(() => {
  if (state && !state.error) {
    setShowSuccess(true);
    const t = setTimeout(() => setShowSuccess(false), 3000);
    return () => clearTimeout(t);
  }
}, [state]);

{showSuccess && <Alert><AlertDescription>Saved.</AlertDescription></Alert>}

Acceptance criteria

  • PortalReadOnlyEditor dynamic import has a skeleton loading state
  • Admin MilkdownEditor dynamic import has a skeleton loading state
  • All 5 settings forms auto-dismiss the "Saved." alert after 3 seconds
  • npm run build passes

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsize:SSmall effort

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions