From 891096a18439c542d086dad9ebc21f6980eea890 Mon Sep 17 00:00:00 2001 From: laxmanhalaki Date: Wed, 12 Nov 2025 18:24:19 +0530 Subject: [PATCH] user tab enhanced and user search bug fixed --- .../admin/UserRoleManager/UserRoleManager.tsx | 331 ++++++++++++++---- .../AddApproverModal/AddApproverModal.tsx | 10 +- .../AddSpectatorModal/AddSpectatorModal.tsx | 10 +- src/pages/CreateRequest/CreateRequest.tsx | 18 +- src/services/userApi.ts | 12 +- 5 files changed, 290 insertions(+), 91 deletions(-) diff --git a/src/components/admin/UserRoleManager/UserRoleManager.tsx b/src/components/admin/UserRoleManager/UserRoleManager.tsx index 614ee49..e6561e7 100644 --- a/src/components/admin/UserRoleManager/UserRoleManager.tsx +++ b/src/components/admin/UserRoleManager/UserRoleManager.tsx @@ -67,13 +67,21 @@ export function UserRoleManager() { const [updating, setUpdating] = useState(false); const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); - // Users with elevated roles - const [elevatedUsers, setElevatedUsers] = useState([]); + // Users list with filtering and pagination + const [users, setUsers] = useState([]); const [loadingUsers, setLoadingUsers] = useState(false); const [roleStats, setRoleStats] = useState({ admins: 0, management: 0, users: 0 }); + + // Pagination and filtering + const [roleFilter, setRoleFilter] = useState<'ELEVATED' | 'ALL' | 'ADMIN' | 'MANAGEMENT' | 'USER'>('ELEVATED'); + const [currentPage, setCurrentPage] = useState(1); + const [totalPages, setTotalPages] = useState(1); + const [totalUsers, setTotalUsers] = useState(0); + const limit = 10; - // Ref for search container (click outside to close) + // Refs for search container and user list const searchContainerRef = useRef(null); + const userListRef = useRef(null); // Search users from Okta const searchUsers = useCallback( @@ -134,7 +142,7 @@ export function UserRoleManager() { try { // Call backend to assign role (will create user if doesn't exist) - const response = await userApi.assignRole(selectedUser.email, selectedRole); + await userApi.assignRole(selectedUser.email, selectedRole); setMessage({ type: 'success', @@ -146,8 +154,8 @@ export function UserRoleManager() { setSearchQuery(''); setSelectedRole('USER'); - // Refresh the elevated users list - await fetchElevatedUsers(); + // Refresh the users list + await fetchUsers(); await fetchRoleStatistics(); } catch (error: any) { console.error('Role assignment failed:', error); @@ -160,26 +168,39 @@ export function UserRoleManager() { } }; - // Fetch users with ADMIN and MANAGEMENT roles - const fetchElevatedUsers = async () => { + // Fetch users with filtering and pagination + const fetchUsers = async (page: number = currentPage) => { setLoadingUsers(true); try { - const [adminResponse, managementResponse] = await Promise.all([ - userApi.getUsersByRole('ADMIN'), - userApi.getUsersByRole('MANAGEMENT') - ]); - - console.log('Admin response:', adminResponse); - console.log('Management response:', managementResponse); - - // Backend returns { success: true, data: { users: [...], summary: {...} } } - const admins = adminResponse.data?.data?.users || []; - const managers = managementResponse.data?.data?.users || []; + const response = await userApi.getUsersByRole(roleFilter, page, limit); - console.log('Parsed admins:', admins); - console.log('Parsed managers:', managers); + console.log('Users response:', response); - setElevatedUsers([...admins, ...managers]); + // Backend returns { success: true, data: { users: [...], pagination: {...}, summary: {...} } } + const usersData = response.data?.data?.users || []; + const paginationData = response.data?.data?.pagination; + const summaryData = response.data?.data?.summary; + + console.log('Parsed users:', usersData); + console.log('Pagination:', paginationData); + console.log('Summary:', summaryData); + + setUsers(usersData); + + if (paginationData) { + setCurrentPage(paginationData.currentPage); + setTotalPages(paginationData.totalPages); + setTotalUsers(paginationData.totalUsers); + } + + // Update summary stats if available + if (summaryData) { + setRoleStats({ + admins: summaryData.ADMIN || 0, + management: summaryData.MANAGEMENT || 0, + users: summaryData.USER || 0 + }); + } } catch (error) { console.error('Failed to fetch users:', error); } finally { @@ -207,11 +228,39 @@ export function UserRoleManager() { } }; - // Load data on mount + // Load data on mount and when filter changes useEffect(() => { - fetchElevatedUsers(); + fetchUsers(1); // Reset to page 1 when filter changes fetchRoleStatistics(); - }, []); + }, [roleFilter]); + + // Handle filter change + const handleFilterChange = (value: string) => { + setRoleFilter(value as any); + setCurrentPage(1); + }; + + // Handle page change + const handlePageChange = (page: number) => { + fetchUsers(page); + }; + + // Handle statistics card click - filter and scroll to user list + const handleStatCardClick = (filter: 'ADMIN' | 'MANAGEMENT' | 'USER') => { + setRoleFilter(filter); + setCurrentPage(1); + + // Immediate scroll without waiting for data load + requestAnimationFrame(() => { + const element = userListRef.current; + if (element) { + element.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + }); + }; // Handle click outside to close search results useEffect(() => { @@ -256,13 +305,21 @@ export function UserRoleManager() {
{/* Statistics Cards */}
- + handleStatCardClick('ADMIN')} + >

Administrators

{roleStats.admins}

-

Full system access

+

+ {roleFilter === 'ADMIN' ? '✓ Viewing' : 'Click to view'} +

@@ -271,13 +328,21 @@ export function UserRoleManager() { - + handleStatCardClick('MANAGEMENT')} + >

Management

{roleStats.management}

-

Read all data access

+

+ {roleFilter === 'MANAGEMENT' ? '✓ Viewing' : 'Click to view'} +

@@ -286,13 +351,21 @@ export function UserRoleManager() { - + handleStatCardClick('USER')} + >

Regular Users

{roleStats.users}

-

Standard access

+

+ {roleFilter === 'USER' ? '✓ Viewing' : 'Click to view'} +

@@ -328,7 +401,7 @@ export function UserRoleManager() { placeholder="Type name or email address..." value={searchQuery} onChange={handleSearchChange} - className="pl-10 pr-10 h-12 border-2 rounded-lg focus:border-purple-500 focus:ring-2 focus:ring-purple-200 transition-all" + className="pl-10 pr-10 h-12 border rounded-lg border-gray-300 focus:border-purple-500 focus:ring-2 focus:ring-purple-200 transition-all" data-testid="user-search-input" /> {searching && ( @@ -339,13 +412,13 @@ export function UserRoleManager() { {/* Search Results Dropdown */} {searchResults.length > 0 && ( -
+

{searchResults.length} user{searchResults.length > 1 ? 's' : ''} found

-
+
{searchResults.map((user) => (
@@ -503,47 +613,114 @@ export function UserRoleManager() {

Loading users...

- ) : elevatedUsers.length === 0 ? ( + ) : users.length === 0 ? (
-

No elevated users found

-

Assign ADMIN or MANAGEMENT roles to see users here

+

No users found

+

+ {roleFilter === 'ELEVATED' + ? 'Assign ADMIN or MANAGEMENT roles to see users here' + : 'No users match the selected filter' + } +

) : ( -
- {elevatedUsers.map((user) => ( -
-
-
-
- {getRoleIcon(user.role)} -
-
-

{user.displayName}

-

{user.email}

- {user.department && ( -

- {user.department}{user.designation ? ` • ${user.designation}` : ''} -

- )} + <> +
+ {users.map((user) => ( +
+
+
+
+ {getRoleIcon(user.role)} +
+
+

{user.displayName}

+

{user.email}

+ {user.department && ( +

+ {user.department}{user.designation ? ` • ${user.designation}` : ''} +

+ )} +
+ + {user.role} +
- - {user.role} - +
+ ))} +
+ + {/* Pagination Controls */} + {totalPages > 1 && ( +
+
+ Showing {((currentPage - 1) * limit) + 1} to {Math.min(currentPage * limit, totalUsers)} of {totalUsers} users +
+
+ +
+ {Array.from({ length: Math.min(5, totalPages) }, (_, i) => { + let pageNum; + if (totalPages <= 5) { + pageNum = i + 1; + } else if (currentPage <= 3) { + pageNum = i + 1; + } else if (currentPage >= totalPages - 2) { + pageNum = totalPages - 4 + i; + } else { + pageNum = currentPage - 2 + i; + } + return ( + + ); + })} +
+
- ))} -
+ )} + )} - + +
); } diff --git a/src/components/participant/AddApproverModal/AddApproverModal.tsx b/src/components/participant/AddApproverModal/AddApproverModal.tsx index a7b27a0..e05a7b2 100644 --- a/src/components/participant/AddApproverModal/AddApproverModal.tsx +++ b/src/components/participant/AddApproverModal/AddApproverModal.tsx @@ -189,7 +189,9 @@ export function AddApproverModal({ // If user was NOT selected via @ search, validate against Okta if (!selectedUser || selectedUser.email.toLowerCase() !== emailToAdd) { try { - const searchOktaResults = await searchUsers(emailToAdd, 1); + const response = await searchUsers(emailToAdd, 1); + // Backend returns { success: true, data: [...users] } + const searchOktaResults = response.data?.data || []; if (searchOktaResults.length === 0) { // User not found in Okta @@ -310,7 +312,9 @@ export function AddApproverModal({ searchTimer.current = setTimeout(async () => { try { const term = value.slice(1); // Remove @ prefix - const results = await searchUsers(term, 10); + const response = await searchUsers(term, 10); + // Backend returns { success: true, data: [...users] } + const results = response.data?.data || []; setSearchResults(results); } catch (error) { console.error('Search failed:', error); @@ -352,7 +356,7 @@ export function AddApproverModal({ return ( - +