Skip to content

Commit

Permalink
feat: add allowances tab
Browse files Browse the repository at this point in the history
  • Loading branch information
alangsto committed Jul 16, 2024
1 parent 25eb21c commit 2b90f9f
Show file tree
Hide file tree
Showing 15 changed files with 379 additions and 9 deletions.
8 changes: 4 additions & 4 deletions src/index.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "@edx/brand/paragon/fonts.scss";
@import "@edx/brand/paragon/variables.scss";
@import "@openedx/paragon/scss/core/core.scss";
@import "@edx/brand/paragon/overrides.scss";
@import "~@edx/brand/paragon/fonts";
@import "~@edx/brand/paragon/variables";
@import "~@openedx/paragon/scss/core/core";
@import "~@edx/brand/paragon/overrides";
18 changes: 18 additions & 0 deletions src/pages/ExamsPage/__snapshots__/index.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ exports[`ExamsPage snapshots exams and attempts loaded 1`] = `
>
Review Dashboard
</a>
<a
aria-selected="false"
class="nav-item nav-link"
data-rb-event-key="allowances"
href="#"
role="tab"
>
Allowances
</a>
<a
class="pgn__tab_invisible pgn__tab_more nav-item nav-link"
href="#"
Expand Down Expand Up @@ -738,6 +747,15 @@ exports[`ExamsPage snapshots exams and attempts loaded 1`] = `
>
Review Dashboard
</a>
<a
aria-selected="false"
class="nav-item nav-link"
data-rb-event-key="allowances"
href="#"
role="tab"
>
Allowances
</a>
<a
class="pgn__tab_invisible pgn__tab_more nav-item nav-link"
href="#"
Expand Down
44 changes: 44 additions & 0 deletions src/pages/ExamsPage/components/AllowanceList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import PropTypes from 'prop-types';

import {
Button,
} from '@openedx/paragon';
import { Add } from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';

import messages from '../messages';
import './AllowanceList.scss';

const AllowanceList = ({ allowances }) => {
const { formatMessage } = useIntl();

return (
<>
<div className="allowances-header">
<h3 data-testid="allowances"> {formatMessage(messages.allowanceDashboardTabTitle)} </h3>
<Button variant="outline-primary" iconBefore={Add} size="sm" className="header-allowance-button">
{formatMessage(messages.allowanceButton)}
</Button>
</div>
<div className="allowances-body">
{ allowances.length === 0
? (
<>
<h4> {formatMessage(messages.noAllowancesHeader)} </h4>
<p> {formatMessage(messages.noAllowancesBody)} </p>
<Button variant="primary" iconBefore={Add}>
{formatMessage(messages.allowanceButton)}
</Button>
</>
)
: null }
</div>
</>
);
};

AllowanceList.propTypes = {
allowances: PropTypes.arrayOf(PropTypes.object).isRequired, // eslint-disable-line react/forbid-prop-types
};

export default AllowanceList;
18 changes: 18 additions & 0 deletions src/pages/ExamsPage/components/AllowanceList.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.allowances-body {
display: inline-block;
text-align: center;
width: 100%;
padding-bottom: 50px;
}

.allowances-header {
width: 100%;
padding: 10px;
position: relative;

.header-allowance-button {
position: absolute;
top: 10px;
right: 10px;
}
}
12 changes: 12 additions & 0 deletions src/pages/ExamsPage/components/AllowanceList.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { render } from '@testing-library/react';

import AllowanceList from './AllowanceList';

// normally mocked for unit tests but required for rendering/snapshots
// jest.unmock('react');

describe('AllowanceList', () => {
it('Test that the AllowanceList matches snapshot', () => {
expect(render(<AllowanceList allowances={[]} />)).toMatchSnapshot();
});
});
8 changes: 7 additions & 1 deletion src/pages/ExamsPage/components/ExamSelection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import PropTypes from 'prop-types';

import messages from '../messages';

const ExamSelection = ({ exams, onSelect }) => {
const ExamSelection = ({ exams, onSelect, isDisabled }) => {
const { formatMessage } = useIntl();
const [searchText, setSearchText] = useState('');
const getMenuItems = () => {
Expand Down Expand Up @@ -38,6 +38,7 @@ const ExamSelection = ({ exams, onSelect }) => {
<div data-testid="exam_selection">
<SelectMenu
defaultMessage={formatMessage(messages.examSelectDropdownLabel)}
disabled={isDisabled}
>
{ getMenuItems() }
</SelectMenu>
Expand All @@ -51,6 +52,11 @@ ExamSelection.propTypes = {
name: PropTypes.string,
})).isRequired,
onSelect: PropTypes.func.isRequired,
isDisabled: PropTypes.bool,
};

ExamSelection.defaultProps = {
isDisabled: false,
};

export default ExamSelection;
4 changes: 4 additions & 0 deletions src/pages/ExamsPage/components/ExamSelection.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ describe('ExamSelection', () => {
expect(mockHandleSelectExam).toHaveBeenCalledTimes(1);
expect(mockHandleSelectExam).toHaveBeenCalledWith(27);
});
it('button disabled when isDisabled is true', () => {
renderWithoutError(<ExamSelection exams={defaultExams} onSelect={mockHandleSelectExam} isDisabled />);
expect(screen.getByText('Select an exam')).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AllowanceList Test that the AllowanceList matches snapshot 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<div
class="allowances-header"
>
<h3
data-testid="allowances"
>
Allowances
</h3>
<button
class="header-allowance-button btn btn-outline-primary btn-sm"
type="button"
>
<span
class="pgn__icon pgn__icon__sm btn-icon-before"
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="24"
role="img"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2Z"
fill="currentColor"
/>
</svg>
</span>
Add allowance
</button>
</div>
<div
class="allowances-body"
>
<h4>
No Allowances
</h4>
<p>
Need to grant an allowance? Get started here.
</p>
<button
class="btn btn-primary"
type="button"
>
<span
class="pgn__icon btn-icon-before"
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="24"
role="img"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2Z"
fill="currentColor"
/>
</svg>
</span>
Add allowance
</button>
</div>
</div>
</body>,
"container": <div>
<div
class="allowances-header"
>
<h3
data-testid="allowances"
>
Allowances
</h3>
<button
class="header-allowance-button btn btn-outline-primary btn-sm"
type="button"
>
<span
class="pgn__icon pgn__icon__sm btn-icon-before"
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="24"
role="img"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2Z"
fill="currentColor"
/>
</svg>
</span>
Add allowance
</button>
</div>
<div
class="allowances-body"
>
<h4>
No Allowances
</h4>
<p>
Need to grant an allowance? Get started here.
</p>
<button
class="btn btn-primary"
type="button"
>
<span
class="pgn__icon btn-icon-before"
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="24"
role="img"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2Z"
fill="currentColor"
/>
</svg>
</span>
Add allowance
</button>
</div>
</div>,
"debug": [Function],
"findAllByAltText": [Function],
"findAllByDisplayValue": [Function],
"findAllByLabelText": [Function],
"findAllByPlaceholderText": [Function],
"findAllByRole": [Function],
"findAllByTestId": [Function],
"findAllByText": [Function],
"findAllByTitle": [Function],
"findByAltText": [Function],
"findByDisplayValue": [Function],
"findByLabelText": [Function],
"findByPlaceholderText": [Function],
"findByRole": [Function],
"findByTestId": [Function],
"findByText": [Function],
"findByTitle": [Function],
"getAllByAltText": [Function],
"getAllByDisplayValue": [Function],
"getAllByLabelText": [Function],
"getAllByPlaceholderText": [Function],
"getAllByRole": [Function],
"getAllByTestId": [Function],
"getAllByText": [Function],
"getAllByTitle": [Function],
"getByAltText": [Function],
"getByDisplayValue": [Function],
"getByLabelText": [Function],
"getByPlaceholderText": [Function],
"getByRole": [Function],
"getByTestId": [Function],
"getByText": [Function],
"getByTitle": [Function],
"queryAllByAltText": [Function],
"queryAllByDisplayValue": [Function],
"queryAllByLabelText": [Function],
"queryAllByPlaceholderText": [Function],
"queryAllByRole": [Function],
"queryAllByTestId": [Function],
"queryAllByText": [Function],
"queryAllByTitle": [Function],
"queryByAltText": [Function],
"queryByDisplayValue": [Function],
"queryByLabelText": [Function],
"queryByPlaceholderText": [Function],
"queryByRole": [Function],
"queryByTestId": [Function],
"queryByText": [Function],
"queryByTitle": [Function],
"rerender": [Function],
"unmount": [Function],
}
`;
1 change: 1 addition & 0 deletions src/pages/ExamsPage/data/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const initialState = {
currentExamIndex: null,
examsList: [],
attemptsList: [],
allowancesList: [],
};

const getStatusFromAction = (action, status) => {
Expand Down
Loading

0 comments on commit 2b90f9f

Please sign in to comment.