Fix UI freeze by removing cyclical useEffect and stabilizing executive candidate memo

This commit is contained in:
2026-10-25 12:13:15 +02:00
parent 07018c3ce4
commit 78d147b002
@@ -292,69 +292,64 @@ export const GovernancePage: React.FC = () => {
}, [tenantUsersList]);
const modalExecutiveUsers = React.useMemo(() => {
let list: User[] = [];
const list: User[] = [];
const seenIds = new Set<string>();
if (isAdmin) {
list = usersDirectory.filter((u) => String(u.role || '').toLowerCase() === 'executive');
} else {
list = tenantUsersList
.map((tu) => tu.user || ({ id: tu.userId, email: getUserEmail(tu.userId), role: 'Executive' } as User))
.filter((u) => String(u.role || '').toLowerCase() === 'executive');
}
const addCandidate = (u?: User | null) => {
if (!u || !u.id) return;
const key = String(u.id).toLowerCase();
if (seenIds.has(key)) return;
seenIds.add(key);
list.push(u);
};
const currentLinkedUserId =
// 1. Always include the organisation's linked user so the select option exists and selects immediately
const linkedUserId =
editingOrg?.userId ||
editingOrg?.UserId ||
editingOrg?.organisationUser ||
editingOrg?.OrganisationUser ||
'';
if (currentLinkedUserId) {
const alreadyIncluded = list.some(
(u) => u.id && String(u.id).toLowerCase() === String(currentLinkedUserId).toLowerCase()
if (linkedUserId) {
const resolvedEmail = getUserEmail(linkedUserId);
const matched = usersDirectory.find(
(u) => u.id && String(u.id).toLowerCase() === String(linkedUserId).toLowerCase()
);
if (!alreadyIncluded) {
const resolvedEmail = getUserEmail(currentLinkedUserId);
const matchedInDir = usersDirectory.find(
(u) => u.id && String(u.id).toLowerCase() === String(currentLinkedUserId).toLowerCase()
);
list = [
{
id: currentLinkedUserId,
email: matchedInDir?.email || (resolvedEmail !== '—' && resolvedEmail ? resolvedEmail : currentLinkedUserId),
role: 'Executive',
status: ActivityStatus.Active,
lastLoginAt: null,
},
...list,
];
}
addCandidate({
id: linkedUserId,
email: matched?.email || (resolvedEmail !== '—' && resolvedEmail ? resolvedEmail : linkedUserId),
role: matched?.role || 'Executive',
status: ActivityStatus.Active,
lastLoginAt: null,
});
}
// 2. Load Executive role users: Admin sees all executives across tenants; normal tenant user focuses on tenantusers
if (isAdmin) {
usersDirectory
.filter((u) => String(u.role || '').toLowerCase() === 'executive')
.forEach(addCandidate);
} else {
tenantUsersList
.filter((tu) => String(tu.user?.role || '').toLowerCase() === 'executive')
.forEach((tu) => {
if (tu.user) {
addCandidate(tu.user);
} else if (tu.userId) {
addCandidate({
id: tu.userId,
email: getUserEmail(tu.userId),
role: 'Executive',
status: ActivityStatus.Active,
lastLoginAt: null,
});
}
});
}
return list;
}, [isAdmin, usersDirectory, tenantUsersList, editingOrg]);
useEffect(() => {
if (isOrgModalOpen && editingOrg) {
const targetUserId =
editingOrg.userId ||
editingOrg.UserId ||
editingOrg.organisationUser ||
editingOrg.OrganisationUser ||
'';
if (targetUserId) {
const targetEmail = getUserEmail(targetUserId);
const matched = modalExecutiveUsers.find(
(u) =>
(u.id && String(u.id).toLowerCase() === String(targetUserId).toLowerCase()) ||
(u.email && targetEmail && targetEmail !== '—' && u.email.toLowerCase() === targetEmail.toLowerCase())
);
const resolvedId = matched?.id || targetUserId;
orgForm.setValue('organisationUser', resolvedId, { shouldValidate: true, shouldDirty: false });
}
}
}, [isOrgModalOpen, editingOrg, modalExecutiveUsers]);
}, [isAdmin, usersDirectory, tenantUsersList, editingOrg?.id, editingOrg?.userId]);
// Quick Add Executive User Subform state
const [isQuickAddUserOpen, setIsQuickAddUserOpen] = useState(false);