diff --git a/src/components/GradesView/PageButtons/PageButtons.test.jsx b/src/components/GradesView/PageButtons/PageButtons.test.jsx
deleted file mode 100644
index 4168022..0000000
--- a/src/components/GradesView/PageButtons/PageButtons.test.jsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-
-import selectors from 'data/selectors';
-import thunkActions from 'data/thunkActions';
-
-import { PageButtons, mapStateToProps, mapDispatchToProps } from '.';
-
-jest.mock('@edx/paragon', () => ({
- Button: () => 'Button',
-}));
-jest.mock('data/selectors', () => ({
- __esModule: true,
- default: {
- grades: {
- nextPage: jest.fn(state => ({ nextPage: state })),
- prevPage: jest.fn(state => ({ prevPage: state })),
- },
- },
-}));
-
-jest.mock('data/thunkActions', () => ({
- __esModule: true,
- default: {
- grades: {
- fetchPrevNextGrades: jest.fn(),
- },
- },
-}));
-
-let props;
-let el;
-describe('PageButtons component', () => {
- beforeEach(() => {
- props = {
- getPrevNextGrades: jest.fn(),
- nextPage: 'NEXT PAGE',
- prevPage: 'prev PAGE',
- };
- });
- describe('snapshots', () => {
- beforeEach(() => {
- el = shallow();
- el.instance.fetchNextGrades = jest.fn().mockName('fetchNextGrades');
- el.instance.fetchPrevGrades = jest.fn().mockName('fetchPrevGrades');
- });
- test('buttons enabled with both endpoints provided', () => {
- expect(el.instance().render()).toMatchSnapshot();
- });
- test('nextPage disabled if not provided', () => {
- el.setProps({ nextPage: undefined });
- expect(el.instance().render()).toMatchSnapshot();
- });
- test('prevPage disabled if not provided', () => {
- el.setProps({ prevPage: undefined });
- expect(el.instance().render()).toMatchSnapshot();
- });
- });
- describe('behavior', () => {
- beforeEach(() => {
- el = shallow();
- });
- describe('getPrevGrades', () => {
- it('calls props.getPrevNextGrades with props.prevPage', () => {
- el.instance().getPrevGrades();
- expect(props.getPrevNextGrades).toHaveBeenCalledWith(props.prevPage);
- });
- });
- describe('getNextGrades', () => {
- it('calls props.getPrevNextGrades with props.nextPage', () => {
- el.instance().getNextGrades();
- expect(props.getPrevNextGrades).toHaveBeenCalledWith(props.nextPage);
- });
- });
- });
- describe('mapStateToProps', () => {
- const testState = { l: 'eeeerroooooy', j: 'jjjjeeeeeeenkins' };
- let mapped;
- beforeEach(() => {
- mapped = mapStateToProps(testState);
- });
- test('nextPage from grades.nextPage', () => {
- expect(mapped.nextPage).toEqual(selectors.grades.nextPage(testState));
- });
- test('prevPage from grades.prevPage', () => {
- expect(mapped.prevPage).toEqual(selectors.grades.prevPage(testState));
- });
- });
- describe('mapDispatchToProps', () => {
- test('getPrevNextGrades from thunkActions.grades.fetchPrevNextGrades', () => {
- expect(
- mapDispatchToProps.getPrevNextGrades,
- ).toEqual(thunkActions.grades.fetchPrevNextGrades);
- });
- });
-});
diff --git a/src/components/GradesView/PageButtons/__snapshots__/PageButtons.test.jsx.snap b/src/components/GradesView/PageButtons/__snapshots__/PageButtons.test.jsx.snap
deleted file mode 100644
index 144c7c0..0000000
--- a/src/components/GradesView/PageButtons/__snapshots__/PageButtons.test.jsx.snap
+++ /dev/null
@@ -1,133 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`PageButtons component snapshots buttons enabled with both endpoints provided 1`] = `
-
-
-
-
-`;
-
-exports[`PageButtons component snapshots nextPage disabled if not provided 1`] = `
-
-
-
-
-`;
-
-exports[`PageButtons component snapshots prevPage disabled if not provided 1`] = `
-
-
-
-
-`;
diff --git a/src/components/GradesView/PageButtons/__snapshots__/index.test.jsx.snap b/src/components/GradesView/PageButtons/__snapshots__/index.test.jsx.snap
new file mode 100644
index 0000000..8fb8ffa
--- /dev/null
+++ b/src/components/GradesView/PageButtons/__snapshots__/index.test.jsx.snap
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PageButtons component render snapshot 1`] = `
+
+
+
+
+`;
diff --git a/src/components/GradesView/PageButtons/hooks.js b/src/components/GradesView/PageButtons/hooks.js
new file mode 100644
index 0000000..f102342
--- /dev/null
+++ b/src/components/GradesView/PageButtons/hooks.js
@@ -0,0 +1,34 @@
+import { useIntl } from '@edx/frontend-platform/i18n';
+
+import { selectors, thunkActions } from 'data/redux/hooks';
+import messages from './messages';
+
+export const usePageButtonsData = () => {
+ const { formatMessage } = useIntl();
+
+ const { nextPage, prevPage } = selectors.grades.useGradeData();
+ const getPrevNextGrades = thunkActions.grades.useFetchPrevNextGrades();
+
+ const getPrevGrades = () => {
+ getPrevNextGrades(prevPage);
+ };
+
+ const getNextGrades = () => {
+ getPrevNextGrades(nextPage);
+ };
+
+ return {
+ prev: {
+ disabled: !prevPage,
+ onClick: getPrevGrades,
+ text: formatMessage(messages.prevPage),
+ },
+ next: {
+ disabled: !nextPage,
+ onClick: getNextGrades,
+ text: formatMessage(messages.nextPage),
+ },
+ };
+};
+
+export default usePageButtonsData;
diff --git a/src/components/GradesView/PageButtons/hooks.test.js b/src/components/GradesView/PageButtons/hooks.test.js
new file mode 100644
index 0000000..8d96bec
--- /dev/null
+++ b/src/components/GradesView/PageButtons/hooks.test.js
@@ -0,0 +1,77 @@
+import { useIntl } from '@edx/frontend-platform/i18n';
+
+import { formatMessage } from 'testUtils';
+import { selectors, thunkActions } from 'data/redux/hooks';
+
+import usePageButtonsData from './hooks';
+import messages from './messages';
+
+jest.mock('data/redux/hooks', () => ({
+ selectors: {
+ grades: { useGradeData: jest.fn() },
+ },
+ thunkActions: {
+ grades: { useFetchPrevNextGrades: jest.fn() },
+ },
+}));
+
+const gradeData = { nextPage: 'test-next-page', prevPage: 'test-prev-page' };
+selectors.grades.useGradeData.mockReturnValue(gradeData);
+
+const fetchGrades = jest.fn();
+thunkActions.grades.useFetchPrevNextGrades.mockReturnValue(fetchGrades);
+
+let out;
+describe('usePageButtonsData', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ out = usePageButtonsData();
+ });
+ describe('behavior', () => {
+ it('initializes intl hook', () => {
+ expect(useIntl).toHaveBeenCalled();
+ });
+ it('initializes redux hooks', () => {
+ expect(selectors.grades.useGradeData).toHaveBeenCalled();
+ expect(thunkActions.grades.useFetchPrevNextGrades).toHaveBeenCalled();
+ });
+ });
+ describe('output', () => {
+ describe('prev button entry', () => {
+ it('is disabled iff prevPage is not provided', () => {
+ expect(out.prev.disabled).toEqual(false);
+ selectors.grades.useGradeData.mockReturnValueOnce({
+ ...gradeData,
+ prevPage: undefined,
+ });
+ out = usePageButtonsData();
+ expect(out.prev.disabled).toEqual(true);
+ });
+ it('calls fetch with prevPage on click', () => {
+ out.prev.onClick();
+ expect(fetchGrades).toHaveBeenCalledWith(gradeData.prevPage);
+ });
+ test('text display', () => {
+ expect(out.prev.text).toEqual(formatMessage(messages.prevPage));
+ });
+ });
+ describe('next button entry', () => {
+ it('is disabled iff nextPage is not provided', () => {
+ expect(out.next.disabled).toEqual(false);
+ selectors.grades.useGradeData.mockReturnValueOnce({
+ ...gradeData,
+ nextPage: undefined,
+ });
+ out = usePageButtonsData();
+ expect(out.next.disabled).toEqual(true);
+ });
+ it('calls fetch with prevPage on click', () => {
+ out.next.onClick();
+ expect(fetchGrades).toHaveBeenCalledWith(gradeData.nextPage);
+ });
+ test('text display', () => {
+ expect(out.next.text).toEqual(formatMessage(messages.nextPage));
+ });
+ });
+ });
+});
diff --git a/src/components/GradesView/PageButtons/index.jsx b/src/components/GradesView/PageButtons/index.jsx
index 0c2fb1b..bb377f4 100644
--- a/src/components/GradesView/PageButtons/index.jsx
+++ b/src/components/GradesView/PageButtons/index.jsx
@@ -1,75 +1,37 @@
import React from 'react';
-import PropTypes from 'prop-types';
-import { connect } from 'react-redux';
import { Button } from '@edx/paragon';
-import { FormattedMessage } from '@edx/frontend-platform/i18n';
-import selectors from 'data/selectors';
-import thunkActions from 'data/thunkActions';
-import messages from './messages';
+import usePageButtonsData from './hooks';
-export class PageButtons extends React.Component {
- constructor(props) {
- super(props);
- this.getPrevGrades = this.getPrevGrades.bind(this);
- this.getNextGrades = this.getNextGrades.bind(this);
- }
+export const PageButtons = () => {
+ const { prev, next } = usePageButtonsData();
- getPrevGrades() {
- this.props.getPrevNextGrades(this.props.prevPage);
- }
-
- getNextGrades() {
- this.props.getPrevNextGrades(this.props.nextPage);
- }
-
- render() {
- return (
-
+
- );
- }
-}
-
-PageButtons.defaultProps = {
- nextPage: '',
- prevPage: '',
+ {prev.text}
+
+
+ {next.text}
+
+
+ );
};
-PageButtons.propTypes = {
- // redux
- getPrevNextGrades: PropTypes.func.isRequired,
- nextPage: PropTypes.string,
- prevPage: PropTypes.string,
-};
+PageButtons.propTypes = {};
-export const mapStateToProps = (state) => ({
- nextPage: selectors.grades.nextPage(state),
- prevPage: selectors.grades.prevPage(state),
-});
-
-export const mapDispatchToProps = {
- getPrevNextGrades: thunkActions.grades.fetchPrevNextGrades,
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(PageButtons);
+export default PageButtons;
diff --git a/src/components/GradesView/PageButtons/index.test.jsx b/src/components/GradesView/PageButtons/index.test.jsx
new file mode 100644
index 0000000..3922408
--- /dev/null
+++ b/src/components/GradesView/PageButtons/index.test.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import { Button } from '@edx/paragon';
+
+import usePageButtonsData from './hooks';
+import PageButtons from '.';
+
+jest.mock('./hooks', () => jest.fn());
+
+const hookProps = {
+ prev: {
+ disabled: 'prev-disabled',
+ onClick: jest.fn().mockName('hooks.prev.onClick'),
+ text: 'prev-text',
+ },
+ next: {
+ disabled: 'next-disabled',
+ onClick: jest.fn().mockName('hooks.next.onClick'),
+ text: 'next-text',
+ },
+};
+usePageButtonsData.mockReturnValue(hookProps);
+
+let el;
+describe('PageButtons component', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ el = shallow();
+ });
+ describe('behavior', () => {
+ it('initializes component hooks', () => {
+ expect(usePageButtonsData).toHaveBeenCalled();
+ });
+ });
+ describe('render', () => {
+ test('snapshot', () => {
+ expect(el).toMatchSnapshot();
+ });
+ test('prev button', () => {
+ const button = el.find(Button).at(0);
+ expect(button.props().disabled).toEqual(hookProps.prev.disabled);
+ expect(button.props().onClick).toEqual(hookProps.prev.onClick);
+ expect(button.text()).toEqual(hookProps.prev.text);
+ });
+ test('next button', () => {
+ const button = el.find(Button).at(1);
+ expect(button.props().disabled).toEqual(hookProps.next.disabled);
+ expect(button.props().onClick).toEqual(hookProps.next.onClick);
+ expect(button.text()).toEqual(hookProps.next.text);
+ });
+ });
+});