From c3d24445e8d37fc51c7ad23f3033cab45d6cd234 Mon Sep 17 00:00:00 2001 From: Ariel Vernaza Date: Sun, 14 Jun 2026 10:51:28 -0700 Subject: [PATCH] fix(shared-ui): use named React hook imports in Account panels BillingPanel used React.useMemo and ProfilePanel used React.useState/ React.useEffect via the default React namespace. Under the web Module Federation build (React as a shared singleton) the minifier rewrites the property access into a bare, unbound useMemo reference, crashing the Account screen with 'ReferenceError: useMemo is not defined'. The VS Code build (React bundled directly) is unaffected, which is why it was web-only. Switch both panels to named hook imports, matching every other panel in the account module (AccountView, MembersPanel, EnvironmentPanel). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/modules/account/components/BillingPanel.tsx | 4 ++-- .../src/modules/account/components/ProfilePanel.tsx | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/shared-ui/src/modules/account/components/BillingPanel.tsx b/packages/shared-ui/src/modules/account/components/BillingPanel.tsx index 343c44e8e..50e1db497 100644 --- a/packages/shared-ui/src/modules/account/components/BillingPanel.tsx +++ b/packages/shared-ui/src/modules/account/components/BillingPanel.tsx @@ -15,7 +15,7 @@ * for visual consistency across account tabs. */ -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useMemo } from 'react'; import type { CSSProperties } from 'react'; import { commonStyles } from '../../../themes/styles'; import type { BillingDetail, CreditBalance, TransactionsResult, UsageRollup } from '../../billing/types'; @@ -198,7 +198,7 @@ export const BillingPanel: React.FC = ({ isConnected, subscri const isSubscribed = subscriptions.length > 0; const handleAddCapacity = useCallback(() => setShowTopUpModal(true), []); // Build appId → app lookup for display name resolution - const appMap = React.useMemo(() => { + const appMap = useMemo(() => { const map: Record = {}; for (const a of apps ?? []) map[a.id] = a; return map; diff --git a/packages/shared-ui/src/modules/account/components/ProfilePanel.tsx b/packages/shared-ui/src/modules/account/components/ProfilePanel.tsx index 8a84a0f8a..3c8cb46ef 100644 --- a/packages/shared-ui/src/modules/account/components/ProfilePanel.tsx +++ b/packages/shared-ui/src/modules/account/components/ProfilePanel.tsx @@ -12,7 +12,7 @@ * the host via callback props. */ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import type { CSSProperties } from 'react'; import { commonStyles } from '../../../themes/styles'; import type { ConnectResult, ProfileUpdate } from '../types'; @@ -90,13 +90,13 @@ export const ProfilePanel: React.FC = ({ profile, authUser, o locale: profile?.locale || authUser?.locale || '', }); - const [editOpen, setEditOpen] = React.useState(false); - const [fields, setFields] = React.useState(fromProfile); - const [saving, setSaving] = React.useState(false); - const [error, setError] = React.useState(null); + const [editOpen, setEditOpen] = useState(false); + const [fields, setFields] = useState(fromProfile); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(null); // Re-sync form fields when the server profile or auth user data is refreshed. - React.useEffect(() => { + useEffect(() => { setFields(fromProfile()); // eslint-disable-next-line react-hooks/exhaustive-deps }, [profile?.displayName, profile?.email, authUser?.email]);