Skip to content
65 changes: 58 additions & 7 deletions client/src/components/user-admin/UserPermissionSearch.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import { useState, useEffect } from 'react';
import {
Box,
Button,
Expand Down Expand Up @@ -101,7 +101,7 @@ const DummyComponent = ({ data, isProjectLead, setUserToEdit }) => {
};

const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
const [userType, setUserType] = useState('admin'); // Which results will display
const [userType] = useState('admin'); // Which results will display
const [searchText, setSearchText] = useState(''); // Search term for the admin/PM search
const [isProjectLead, setIsProjectLead] = useState(false);

Expand Down Expand Up @@ -136,15 +136,15 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
.filter((user) =>
isProjectLead
? user.isProjectLead === true
: user.isProjectLead === undefined
: user.isProjectLead === undefined,
)
.flatMap((user) =>
isProjectLead && user.managedProjectNames.length > 0
? user.managedProjectNames.map((managedProjectName) => ({
...user,
managedProjectName,
}))
: [{ ...user }]
: [{ ...user }],
)
.filter((user) => {
const fullName =
Expand Down Expand Up @@ -175,13 +175,13 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
filteredData = resultData.filter((user) =>
isProjectLead
? user.isProjectLead === true
: user.isProjectLead === undefined
: user.isProjectLead === undefined,
);

if (!isProjectLead) {
// Default display for admins, sorted ASC based on first name
filteredData.sort((u1, u2) =>
u1.name?.firstName.localeCompare(u2.name?.firstName)
u1.name?.firstName.localeCompare(u2.name?.firstName),
);
} else {
// Default display of all PMs, sorted ASC based on project name, then first name
Expand All @@ -194,7 +194,7 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
tempFilter.sort(
(u1, u2) =>
u1.managedProjectName.localeCompare(u2.managedProjectName) ||
u1.name?.firstName.localeCompare(u2.name?.firstName)
u1.name?.firstName.localeCompare(u2.name?.firstName),
);
filteredData = [...tempFilter];
}
Expand All @@ -203,6 +203,42 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
filteredData = getFilteredData(resultData, searchText, isProjectLead);
}

// No need to limit export to the search results
const exportAllData = getFilteredData(resultData, '', isProjectLead);

// Export CSV file
const exportCSV = (data, fileName) => {
// Header row
const headers = ['User Name', 'Project Name'];

// Map each user into CSV row values
const dataItems = data.map((user) => [
`${user.name?.firstName ?? ''} ${user.name?.lastName ?? ''}`,
user.managedProjectName ?? '',
]);

// Combine header + data rows
const rows = [headers, ...dataItems];

// Convert rows to CSV formatted string
const csvData = rows.map((row) => row.join(',')).join('\r\n');

// Create CSV Blob from string
const blob = new Blob([csvData], { type: 'text/csv' });
const url = URL.createObjectURL(blob);

// Create a temporary download link
const link = document.createElement('a');
link.href = url;
link.download = fileName;

// Trigger download
link.click();

// Clean up object URL
URL.revokeObjectURL(url);
};

return (
<Box className="container--usermanagement" sx={{ px: '1.8rem', mb: 0 }}>
<Box
Expand Down Expand Up @@ -250,6 +286,21 @@ const UserPermissionSearch = ({ admins, projectLeads, setUserToEdit }) => {
</Button>
</ButtonGroup>
</Box>
{isProjectLead && (
<Box
sx={{
mb: 2,
}}
>
<Button
sx={Buttonsx}
variant="secondary"
onClick={() => exportCSV(exportAllData, 'project_members.csv')}
>
Export CSV
</Button>
</Box>
)}
<TextField
type="text"
placeholder={isProjectLead ? 'Search name or project' : 'Search name'}
Expand Down
Loading