Skip to content

Commit

Permalink
fix: adding in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kiram15 committed Dec 4, 2024
1 parent 65ea07d commit feebc26
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 138 deletions.
2 changes: 1 addition & 1 deletion src/components/Admin/tabs/ModuleActivityReport.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ const ModuleActivityReport = ({ enterpriseId }) => {
/>,
]}
>
<DataTable.TableControlBar />
<DataTable.TableControlBar />
<DataTable.EmptyTable
content={intl.formatMessage({
id: 'adminPortal.LPR.moduleActivityReport.table.empty',
Expand Down
119 changes: 40 additions & 79 deletions src/components/PeopleManagement/OrgMemberCard.jsx
Original file line number Diff line number Diff line change
@@ -1,92 +1,53 @@
import { Avatar, Card, Col, Row } from '@openedx/paragon';
import PropTypes from 'prop-types';

import {
Avatar, Card, Col, Row,
} from '@openedx/paragon';

const OrgMemberCard = ({ original }) => {
const { name, email, joinedOrg, enrollments } = original;
const { enterpriseCustomerUser, enrollments } = original;
const { name, joinedOrg, email } = enterpriseCustomerUser;

return (
<Card orientation="horizontal">
<Card.Body>
<Card.Section className="pb-1">
<Row className="d-flex flex-row">
<Col xs={2}>
<Avatar size="lg" />
</Col>
<Col>
<Row>
<h3 className="pt-2">{name}</h3>
</Row>
<Row>
<p>{email}</p>
</Row>
</Col>
<Col>
<h5 className="pt-2 text-uppercase">Joined org</h5>
{joinedOrg}
</Col>
<Col>
<h5 className="pt-2 text-uppercase">Enrollments </h5>
{enrollments}
</Col>
</Row>
<Row className="d-flex flex-row">
<Col xs={2}>
<Avatar size="lg" />
</Col>
<Col>
<Row>
<h3 className="pt-2">{name}</h3>
</Row>
<Row>
<p>{email}</p>
</Row>
</Col>
<Col>
<h5 className="pt-2 text-uppercase">Joined org</h5>
{joinedOrg}
</Col>
<Col>
<h5 className="pt-2 text-uppercase">Enrollments</h5>
{enrollments}
</Col>
</Row>
</Card.Section>
</Card.Body>
</Card>
// <Card
// className="mb-4 org-member-card"
// orientation="horizontal"
// >
// <Card.Body>
// <Card.Section>



// <Col>
// <h3>
// {name}
// {/* <FormattedMessage
// id="executive.education.external.course.enrollment.page.registration.summarycard.title"
// defaultMessage="Registration summary:"
// description="Title for the registration summary card on the executive education course enrollment page"
// /> */}
// </h3>
// <br />
// <p className="small font-weight-light text-gray-500 font-italic">
// {/* <FormattedMessage
// id="executive.education.external.course.enrollment.page.course"
// defaultMessage="This course is covered by the Learner Credit provided by your organization."
// description="Message about the course being covered by the Learner Credit"
// /> */}
// {email}
// </p>
// </Col>
// <Col xs={12} lg={{ span: 5, offset: 2 }}>
// <div className="registration-details rounded-lg border p-3">
// <Row>
// <Col xs={12} lg={{ span: 6, offset: 0 }} className="small font-weight-light text-gray-500 justify-content-start">
// {/* <FormattedMessage
// id="executive.education.external.course.enrollment.page.registration.total.message"
// defaultMessage="Registration total:"
// description="Total registration cost for the executive education course"
// /> */}
// {joinedOrg}
// </Col>
// <Col xs={12} lg={{ span: 6, offset: 0 }} className="justify-content-end">
// <div className="d-flex justify-content-end small font-weight-light text-gray-500 mr-2.5">
// {/* <FormattedMessage
// id="executive.education.external.course.enrollment.page.registration.tax.included"
// defaultMessage="Tax included"
// description="Message about tax being included in the registration cost"
// /> */}
// {enrollments}
// </div>
// </Col>
// </Row>
// </div>
// </Col>
// </Card.Section>
// </Card.Body>
// </Card>
);
};

export default OrgMemberCard;
OrgMemberCard.propTypes = {
original: PropTypes.shape({
enterpriseCustomerUser: PropTypes.shape({
email: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
joinedOrg: PropTypes.string.isRequired,
}),
enrollments: PropTypes.number.isRequired,
}),
};

export default OrgMemberCard;
103 changes: 46 additions & 57 deletions src/components/PeopleManagement/PeopleManagementTable.jsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,68 @@
import { CardView, Container, DataTable, TextFilter } from "@openedx/paragon";
import { useIntl } from "@edx/frontend-platform/i18n";
import React from 'react';
import { CardView, DataTable } from '@openedx/paragon';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import OrgMemberCard from "./OrgMemberCard";
import TableTextFilter from '../learner-credit-management/TableTextFilter';
import CustomDataTableEmptyState from '../learner-credit-management/CustomDataTableEmptyState';
import OrgMemberCard from './OrgMemberCard';
import useEnterpriseMembersTableData from './data/hooks/useEnterpriseMembersTableData';

const PeopleManagementTable = () => {
const pageSize = 10;
const intl = useIntl();
// const tableColumns = [
// {
// Header: "Name",
// accessor: "name",
// },
// {
// Header: "Email",
// accessor: "email",
// },
// {
// Header: "Joined org",
// accessor: "joinedOrg",
// },
// {
// Header: "Enrollments",
// accessor: "enrollments",
// },
// ];
const FilterStatus = (rest) => <DataTable.FilterStatus showFilteredFields={false} {...rest} />;

const PeopleManagementTable = ({ enterpriseId }) => {
const {
isLoading: isTableLoading,
enterpriseMembersTableData,
fetchEnterpriseMembersTableData,
} = useEnterpriseMembersTableData({ enterpriseId });

const tableColumns = [{ Header: 'Name', accessor: 'name' }];

return (
<DataTable
className="pt-4 mt-4"
isFilterable
isSortable
defaultColumnValues={{ Filter: TextFilter }}
// isLoading={isFetching}
manualSortBy
isPaginated
manualPagination
isFilterable
manualFilters
isLoading={isTableLoading}
defaultColumnValues={{ Filter: TableTextFilter }}
FilterStatusComponent={FilterStatus}
numBreakoutFilters={2}
columns={tableColumns}
initialState={{
pageSize,
pageSize: 10,
pageIndex: 0,
sortBy: [
{ id: 'enterpriseCustomerUser.name', desc: true },
],
filters: [],
}}
// itemCount={paginatedData.itemCount}
// pageCount={paginatedData.pageCount}
// fetchData={fetchData}
// data={paginatedData.data}
data={[
{
name: "April Ludgate",
email: "[email protected]",
joinedOrg: "Jan 21, 2021",
enrollments: 3,
},
{
name: "Ben Wyatt",
email: "[email protected]",
joinedOrg: "Oct 31, 2022",
enrollments: 1,
},
]}
columns={tableColumns}>
fetchData={fetchEnterpriseMembersTableData}
data={enterpriseMembersTableData.results}
itemCount={enterpriseMembersTableData.itemCount}
pageCount={enterpriseMembersTableData.pageCount}
EmptyTableComponent={CustomDataTableEmptyState}
>
<DataTable.TableControlBar />
<CardView
className="d-block"
CardComponent={OrgMemberCard}
columnSizes={{ xs: 12 }}
/>
{/* <DataTable.Table /> */}
{/* <DataTable.EmptyTable
content={intl.formatMessage({
id: 'peopleManagement.dataTable.empty',
defaultMessage: 'No results found.',
description: 'Message displayed when the table has no data.',
})}
/> */}
<DataTable.TableFooter />
</DataTable>
);
};

export default PeopleManagementTable;
PeopleManagementTable.propTypes = {
enterpriseId: PropTypes.string.isRequired,
};

const mapStateToProps = state => ({
enterpriseId: state.portalConfiguration.enterpriseId,
});

export default connect(mapStateToProps)(PeopleManagementTable);
7 changes: 7 additions & 0 deletions src/components/PeopleManagement/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ export const MAX_LENGTH_GROUP_NAME = 60;

export const GROUP_TYPE_BUDGET = 'budget';
export const GROUP_TYPE_FLEX = 'flex';

// Query Key factory for the people management module, intended to be used with `@tanstack/react-query`.
// Inspired by https://tkdodo.eu/blog/effective-react-query-keys#use-query-key-factories.
export const peopleManagementQueryKeys = {
all: ['people-management'],
members: (enterpriseUuid) => [...peopleManagementQueryKeys.all, 'members', enterpriseUuid],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
useCallback, useMemo, useState,
} from 'react';
import { camelCaseObject } from '@edx/frontend-platform/utils';
import { logError } from '@edx/frontend-platform/logging';
import debounce from 'lodash.debounce';

import LmsApiService from '../../../../data/services/LmsApiService';

const useEnterpriseMembersTableData = ({ enterpriseId }) => {
const [isLoading, setIsLoading] = useState(true);
const [enterpriseMembersTableData, setEnterpriseMembersTableData] = useState({
itemCount: 0,
pageCount: 0,
results: [],
});
const fetchEnterpriseMembersData = useCallback((args) => {
const fetch = async () => {
try {
setIsLoading(true);
const options = {};
args.filters.forEach((filter) => {
const { id, value } = filter;
if (id === 'name') {
options.user_query = value;
}
});

options.page = args.pageIndex + 1;
const response = await LmsApiService.fetchEnterpriseCustomerMembers(enterpriseId, options);
const data = camelCaseObject(response.data);
setEnterpriseMembersTableData({
itemCount: data.count,
pageCount: data.numPages ?? Math.floor(data.count / options.pageSize),
results: data.results,
});
} catch (error) {
logError(error);
} finally {
setIsLoading(false);
}
};
fetch();
}, [enterpriseId]);

const debouncedFetchEnterpriseMembersData = useMemo(
() => debounce(fetchEnterpriseMembersData, 300),
[fetchEnterpriseMembersData],
);

return {
isLoading,
enterpriseMembersTableData,
fetchEnterpriseMembersTableData: debouncedFetchEnterpriseMembersData,
};
};

export default useEnterpriseMembersTableData;
1 change: 0 additions & 1 deletion src/components/PeopleManagement/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const PeopleManagementPage = ({ enterpriseId }) => {
}
}, [data]);


return (
<>
<Helmet title={PAGE_TITLE} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { renderHook } from '@testing-library/react-hooks';
import { camelCaseObject } from '@edx/frontend-platform/utils';
import LmsApiService from '../../../data/services/LmsApiService';

import useEnterpriseMembersTableData from '../data/hooks/useEnterpriseMembersTableData';

describe('useEnterpriseMembersTableData', () => {
it('should fetch and return members of an enterprise', async () => {
const mockEnterpriseUUID = 'uuid-bb';
const mockData = {
count: 1,
current_page: 1,
next: null,
num_pages: 1,
previous: null,
results: [{
enterprise_customer_user: {
email: '[email protected]',
joinedOrg: 'Sep 15, 2021',
name: 'Jeez Louise',
},
enrollments: 11,
}],
};
const mockEnterpriseMembers = jest.spyOn(LmsApiService, 'fetchEnterpriseCustomerMembers');
mockEnterpriseMembers.mockResolvedValue({ data: mockData });

const { result, waitForNextUpdate } = renderHook(
() => useEnterpriseMembersTableData({ enterpriseId: mockEnterpriseUUID }),
);
result.current.fetchEnterpriseMembersTableData({
pageIndex: 0,
pageSize: 10,
filters: [],
sortBy: [],
});
await waitForNextUpdate();
expect(LmsApiService.fetchEnterpriseCustomerMembers).toHaveBeenCalledWith(mockEnterpriseUUID, { page: 1 });
expect(result.current.isLoading).toEqual(false);
expect(result.current.enterpriseMembersTableData.results).toEqual(camelCaseObject(mockData.results));
});
});
Loading

0 comments on commit feebc26

Please sign in to comment.