From 6c6fab3ea39828e1c724a0f22b4224cdc6e479e0 Mon Sep 17 00:00:00 2001 From: chan Date: Fri, 10 Apr 2026 17:26:25 +0900 Subject: [PATCH 1/2] fix(adminfront): fix tenant slug display and metadata save issue in user detail page - Fix 'System Global' displaying by replacing user.tenantSlug with user.companyCode returned by backend - Prevent primary tenant from being unlinked when saving 'Tenant Profile' tab by ensuring userAffiliatedTenants always includes the primary tenant, preventing react-hook-form from clearing the tenantSlug value. --- adminfront/src/features/users/UserDetailPage.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/adminfront/src/features/users/UserDetailPage.tsx b/adminfront/src/features/users/UserDetailPage.tsx index edfc2d03..00e8e87b 100644 --- a/adminfront/src/features/users/UserDetailPage.tsx +++ b/adminfront/src/features/users/UserDetailPage.tsx @@ -391,7 +391,7 @@ function UserDetailPage() { phone: user.phone || "", role: user.role, status: user.status, - tenantSlug: user.tenantSlug || "", + tenantSlug: user.companyCode || "", department: user.department || "", position: user.position || "", jobTitle: user.jobTitle || "", @@ -484,8 +484,15 @@ function UserDetailPage() { ); } - const userAffiliatedTenants = - user.joinedTenants || (user.tenant ? [user.tenant] : []); + const userAffiliatedTenants = React.useMemo(() => { + const joined = user.joinedTenants || []; + const primary = user.tenant; + const all = [...joined]; + if (primary && !joined.some((t) => t.id === primary.id)) { + all.unshift(primary); + } + return all; + }, [user.joinedTenants, user.tenant]); return (
@@ -525,7 +532,7 @@ function UserDetailPage() { > {user.tenant?.name || - user.tenantSlug || + user.companyCode || t("ui.admin.users.detail.form.tenant_global", "시스템 전역")} Date: Fri, 10 Apr 2026 17:44:00 +0900 Subject: [PATCH 2/2] fix(adminfront): fix react hooks violation in UserDetailPage causing infinite loading - Fix 'Rendered fewer hooks than expected' crash by moving useMemo hook definition above all early returns - Resolves e2e test timeout failures in users_schema.spec.ts and users.spec.ts --- .../src/features/users/UserDetailPage.tsx | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/adminfront/src/features/users/UserDetailPage.tsx b/adminfront/src/features/users/UserDetailPage.tsx index 00e8e87b..9b91229d 100644 --- a/adminfront/src/features/users/UserDetailPage.tsx +++ b/adminfront/src/features/users/UserDetailPage.tsx @@ -391,7 +391,12 @@ function UserDetailPage() { phone: user.phone || "", role: user.role, status: user.status, - tenantSlug: user.companyCode || "", + tenantSlug: + user.companyCode || + user.joinedTenants?.find( + (t) => t.type === "COMPANY" || t.type === "COMPANY_GROUP", + )?.slug || + "", department: user.department || "", position: user.position || "", jobTitle: user.jobTitle || "", @@ -459,6 +464,16 @@ function UserDetailPage() { } }; + const userAffiliatedTenants = React.useMemo(() => { + const joined = user?.joinedTenants || []; + const primary = user?.tenant; + const all = [...joined]; + if (primary && !joined.some((t) => t.id === primary.id)) { + all.unshift(primary); + } + return all; + }, [user?.joinedTenants, user?.tenant]); + if (isLoading) { return (
@@ -484,16 +499,6 @@ function UserDetailPage() { ); } - const userAffiliatedTenants = React.useMemo(() => { - const joined = user.joinedTenants || []; - const primary = user.tenant; - const all = [...joined]; - if (primary && !joined.some((t) => t.id === primary.id)) { - all.unshift(primary); - } - return all; - }, [user.joinedTenants, user.tenant]); - return (
{/* Header with back button and actions */} @@ -533,6 +538,9 @@ function UserDetailPage() { {user.tenant?.name || user.companyCode || + user.joinedTenants?.find( + (t) => t.type === "COMPANY" || t.type === "COMPANY_GROUP", + )?.name || t("ui.admin.users.detail.form.tenant_global", "시스템 전역")}