-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #406 from openedx/knguyen2/ent-9166
feat: add users table
- Loading branch information
Showing
12 changed files
with
452 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
src/Configuration/Customers/CustomerDetailView/EnterpriseCustomerUserDetail.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { | ||
Icon, IconButton, Stack, Chip, | ||
} from '@openedx/paragon'; | ||
import { Person, Check, Timelapse } from '@openedx/paragon/icons'; | ||
|
||
export const EnterpriseCustomerUserDetail = ({ | ||
row, | ||
}) => { | ||
let memberDetails; | ||
const memberDetailIcon = ( | ||
<IconButton | ||
isActive | ||
invertColors | ||
src={Person} | ||
iconAs={Icon} | ||
className="border rounded-circle mr-3" | ||
alt="members detail column icon" | ||
style={{ opacity: 1, flexShrink: 0 }} | ||
/> | ||
); | ||
|
||
if (row.original.enterpriseCustomerUser?.username) { | ||
memberDetails = ( | ||
<div className="mb-n3"> | ||
<p className="font-weight-bold mb-0"> | ||
{row.original.enterpriseCustomerUser?.username} | ||
</p> | ||
<p>{row.original.enterpriseCustomerUser?.email}</p> | ||
</div> | ||
); | ||
} else { | ||
memberDetails = ( | ||
<p className="align-middle mb-0"> | ||
{row.original.pendingEnterpriseCustomerUser?.userEmail} | ||
</p> | ||
); | ||
} | ||
return ( | ||
<Stack gap={0} direction="horizontal"> | ||
{memberDetailIcon} | ||
{memberDetails} | ||
</Stack> | ||
); | ||
}; | ||
|
||
export const AdministratorCell = ({ row }) => { | ||
if (row.original?.pendingEnterpriseCustomerUser?.isPendingAdmin) { | ||
return ( | ||
<Chip | ||
iconBefore={Timelapse} | ||
> | ||
Pending | ||
</Chip> | ||
); | ||
} | ||
return ( | ||
<div> | ||
{row.original?.roleAssignments?.includes('enterprise_admin') ? <Check data-testid="admin check" aria-label="admin check" /> : null} | ||
</div> | ||
); | ||
}; | ||
|
||
export const LearnerCell = ({ row }) => { | ||
if (!row.original?.pendingEnterpriseCustomerUser?.isPendingLearner) { | ||
return ( | ||
<div> | ||
{row.original?.roleAssignments?.includes('enterprise_learner') ? <Check data-testid="learner check" aria-label="learner check" /> : null} | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<Chip | ||
iconBefore={Timelapse} | ||
> | ||
Pending | ||
</Chip> | ||
); | ||
}; | ||
|
||
EnterpriseCustomerUserDetail.propTypes = { | ||
row: PropTypes.shape({ | ||
original: PropTypes.shape({ | ||
enterpriseCustomerUser: PropTypes.shape({ | ||
email: PropTypes.string.isRequired, | ||
username: PropTypes.string, | ||
}), | ||
pendingEnterpriseCustomerUser: PropTypes.shape({ | ||
isPendingAdmin: PropTypes.bool, | ||
userEmail: PropTypes.string, | ||
}), | ||
roleAssignments: PropTypes.arrayOf(PropTypes.string), | ||
}).isRequired, | ||
}).isRequired, | ||
}; | ||
|
||
AdministratorCell.propTypes = { | ||
row: PropTypes.shape({ | ||
original: PropTypes.shape({ | ||
pendingEnterpriseCustomerUser: PropTypes.shape({ | ||
isPendingAdmin: PropTypes.bool, | ||
}), | ||
roleAssignments: PropTypes.arrayOf(PropTypes.string), | ||
}).isRequired, | ||
}).isRequired, | ||
}; | ||
|
||
LearnerCell.propTypes = { | ||
row: PropTypes.shape({ | ||
original: PropTypes.shape({ | ||
pendingEnterpriseCustomerUser: PropTypes.shape({ | ||
isPendingLearner: PropTypes.bool, | ||
}), | ||
roleAssignments: PropTypes.arrayOf(PropTypes.string), | ||
}).isRequired, | ||
}).isRequired, | ||
}; |
62 changes: 62 additions & 0 deletions
62
src/Configuration/Customers/CustomerDetailView/EnterpriseCustomerUsersTable.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { useParams } from 'react-router-dom'; | ||
import { DataTable, TextFilter } from '@openedx/paragon'; | ||
import { EnterpriseCustomerUserDetail, LearnerCell, AdministratorCell } from './EnterpriseCustomerUserDetail'; | ||
import useCustomerUsersTableData from '../data/hooks/useCustomerUsersTableData'; | ||
|
||
const EnterpriseCustomerUsersTable = () => { | ||
const { id } = useParams(); | ||
const { | ||
isLoading, | ||
enterpriseUsersTableData, | ||
fetchEnterpriseUsersData, | ||
} = useCustomerUsersTableData(id); | ||
return ( | ||
<div> | ||
<h2>Associated users ({enterpriseUsersTableData.itemCount})</h2> | ||
<hr /> | ||
<DataTable | ||
isLoading={isLoading} | ||
isExpandable | ||
isPaginated | ||
manualPagination | ||
isFilterable | ||
manualFilters | ||
initialState={{ | ||
pageSize: 8, | ||
pageIndex: 0, | ||
sortBy: [], | ||
filters: [], | ||
}} | ||
defaultColumnValues={{ Filter: TextFilter }} | ||
fetchData={fetchEnterpriseUsersData} | ||
data={enterpriseUsersTableData.results} | ||
itemCount={enterpriseUsersTableData.itemCount} | ||
pageCount={enterpriseUsersTableData.pageCount} | ||
columns={[ | ||
{ | ||
id: 'details', | ||
Header: 'User details', | ||
accessor: 'details', | ||
Cell: EnterpriseCustomerUserDetail, | ||
}, | ||
{ | ||
id: 'administrator', | ||
Header: 'Administrator', | ||
accessor: 'administrator', | ||
disableFilters: true, | ||
Cell: AdministratorCell, | ||
}, | ||
{ | ||
id: 'learner', | ||
Header: 'Learner', | ||
accessor: 'learner', | ||
disableFilters: true, | ||
Cell: LearnerCell, | ||
}, | ||
]} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
export default EnterpriseCustomerUsersTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
src/Configuration/Customers/CustomerDetailView/tests/EnterpriseCustomerUserDetail.test.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* eslint-disable react/prop-types */ | ||
import { | ||
screen, | ||
render, | ||
} from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
import { | ||
EnterpriseCustomerUserDetail, | ||
AdministratorCell, | ||
LearnerCell, | ||
} from '../EnterpriseCustomerUserDetail'; | ||
|
||
describe('EnterpriseCustomerUserDetail', () => { | ||
it('renders enterprise customer detail', () => { | ||
const enterpriseCustomerUser = { | ||
original: { | ||
enterpriseCustomerUser: { | ||
username: 'ash ketchum', | ||
email: 'ash@ketchum.org', | ||
}, | ||
}, | ||
}; | ||
render(<EnterpriseCustomerUserDetail row={enterpriseCustomerUser} />); | ||
expect(screen.getByText('ash ketchum')).toBeInTheDocument(); | ||
expect(screen.getByText('ash@ketchum.org')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders pending enterprise customer detail', () => { | ||
const pendingEnterpriseCustomerUser = { | ||
original: { | ||
pendingEnterpriseCustomerUser: { | ||
userEmail: 'pending@customer.org', | ||
}, | ||
}, | ||
}; | ||
render(<EnterpriseCustomerUserDetail row={pendingEnterpriseCustomerUser} />); | ||
expect(screen.getByText('pending@customer.org')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders AdministratorCell there is a pending admin', () => { | ||
const pendingAdmin = { | ||
original: { | ||
pendingEnterpriseCustomerUser: { | ||
isPendingAdmin: true, | ||
}, | ||
roleAssignments: ['enterprise_learner'], | ||
}, | ||
}; | ||
render(<AdministratorCell row={pendingAdmin} />); | ||
expect(screen.getByText('Pending')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders AdministratorCell there is a registered admin', () => { | ||
const adminRow = { | ||
original: { | ||
pendingEnterpriseCustomerUser: { | ||
isPendingAdmin: false, | ||
}, | ||
roleAssignments: ['enterprise_admin'], | ||
}, | ||
}; | ||
render(<AdministratorCell row={adminRow} />); | ||
expect(screen.queryByText('Pending')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('renders LearnerCell when there is a registered learner and not pending', () => { | ||
const learnerRow = { | ||
original: { | ||
pendingEnterpriseCustomerUser: null, | ||
enterpriseCustomerUser: { | ||
username: 'ash ketchum', | ||
email: 'ash@ketchum.org', | ||
}, | ||
roleAssignments: ['enterprise_learner'], | ||
}, | ||
}; | ||
render(<LearnerCell row={learnerRow} />); | ||
expect(screen.queryByText('Pending')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('renders LearnerCell for pending user', () => { | ||
const pendingLearnerRow = { | ||
original: { | ||
pendingEnterpriseCustomerUser: { | ||
isPendingLearner: true, | ||
userEmail: 'pending@customer.org', | ||
}, | ||
enterpriseCustomerUser: null, | ||
}, | ||
}; | ||
render(<LearnerCell row={pendingLearnerRow} />); | ||
expect(screen.queryByText('Pending')).toBeInTheDocument(); | ||
}); | ||
}); |
Oops, something went wrong.