1- import React , { useState , useEffect } from 'react' ;
1+ import { useState , useEffect } from 'react' ;
22import {
33 Box ,
44 Button ,
@@ -101,7 +101,7 @@ const DummyComponent = ({ data, isProjectLead, setUserToEdit }) => {
101101} ;
102102
103103const UserPermissionSearch = ( { admins, projectLeads, setUserToEdit } ) => {
104- const [ userType , setUserType ] = useState ( 'admin' ) ; // Which results will display
104+ const [ userType ] = useState ( 'admin' ) ; // Which results will display
105105 const [ searchText , setSearchText ] = useState ( '' ) ; // Search term for the admin/PM search
106106 const [ isProjectLead , setIsProjectLead ] = useState ( false ) ;
107107
@@ -136,15 +136,15 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
136136 . filter ( ( user ) =>
137137 isProjectLead
138138 ? user . isProjectLead === true
139- : user . isProjectLead === undefined
139+ : user . isProjectLead === undefined ,
140140 )
141141 . flatMap ( ( user ) =>
142142 isProjectLead && user . managedProjectNames . length > 0
143143 ? user . managedProjectNames . map ( ( managedProjectName ) => ( {
144144 ...user ,
145145 managedProjectName,
146146 } ) )
147- : [ { ...user } ]
147+ : [ { ...user } ] ,
148148 )
149149 . filter ( ( user ) => {
150150 const fullName =
@@ -175,13 +175,13 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
175175 filteredData = resultData . filter ( ( user ) =>
176176 isProjectLead
177177 ? user . isProjectLead === true
178- : user . isProjectLead === undefined
178+ : user . isProjectLead === undefined ,
179179 ) ;
180180
181181 if ( ! isProjectLead ) {
182182 // Default display for admins, sorted ASC based on first name
183183 filteredData . sort ( ( u1 , u2 ) =>
184- u1 . name ?. firstName . localeCompare ( u2 . name ?. firstName )
184+ u1 . name ?. firstName . localeCompare ( u2 . name ?. firstName ) ,
185185 ) ;
186186 } else {
187187 // Default display of all PMs, sorted ASC based on project name, then first name
@@ -194,7 +194,7 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
194194 tempFilter . sort (
195195 ( u1 , u2 ) =>
196196 u1 . managedProjectName . localeCompare ( u2 . managedProjectName ) ||
197- u1 . name ?. firstName . localeCompare ( u2 . name ?. firstName )
197+ u1 . name ?. firstName . localeCompare ( u2 . name ?. firstName ) ,
198198 ) ;
199199 filteredData = [ ...tempFilter ] ;
200200 }
@@ -203,6 +203,42 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
203203 filteredData = getFilteredData ( resultData , searchText , isProjectLead ) ;
204204 }
205205
206+ // No need to limit export to the search results
207+ const exportAllData = getFilteredData ( resultData , '' , isProjectLead ) ;
208+
209+ // Export CSV file
210+ const exportCSV = ( data , fileName ) => {
211+ // Header row
212+ const headers = [ 'User Name' , 'Project Name' ] ;
213+
214+ // Map each user into CSV row values
215+ const dataItems = data . map ( ( user ) => [
216+ `${ user . name ?. firstName ?? '' } ${ user . name ?. lastName ?? '' } ` ,
217+ user . managedProjectName ?? '' ,
218+ ] ) ;
219+
220+ // Combine header + data rows
221+ const rows = [ headers , ...dataItems ] ;
222+
223+ // Convert rows to CSV formatted string
224+ const csvData = rows . map ( ( row ) => row . join ( ',' ) ) . join ( '\r\n' ) ;
225+
226+ // Create CSV Blob from string
227+ const blob = new Blob ( [ csvData ] , { type : 'text/csv' } ) ;
228+ const url = URL . createObjectURL ( blob ) ;
229+
230+ // Create a temporary download link
231+ const link = document . createElement ( 'a' ) ;
232+ link . href = url ;
233+ link . download = fileName ;
234+
235+ // Trigger download
236+ link . click ( ) ;
237+
238+ // Clean up object URL
239+ URL . revokeObjectURL ( url ) ;
240+ } ;
241+
206242 return (
207243 < Box className = "container--usermanagement" sx = { { px : '1.8rem' , mb : 0 } } >
208244 < Box
@@ -250,6 +286,21 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
250286 </ Button >
251287 </ ButtonGroup >
252288 </ Box >
289+ { isProjectLead && (
290+ < Box
291+ sx = { {
292+ mb : 2 ,
293+ } }
294+ >
295+ < Button
296+ sx = { Buttonsx }
297+ variant = "secondary"
298+ onClick = { ( ) => exportCSV ( exportAllData , 'project_members.csv' ) }
299+ >
300+ Export CSV
301+ </ Button >
302+ </ Box >
303+ ) }
253304 < TextField
254305 type = "text"
255306 placeholder = { isProjectLead ? 'Search name or project' : 'Search name' }
0 commit comments