feat: add functionality to see unit draft preview (#1501)
* feat: add functionality to see unit draft preview * feat: add tests for course link redirects * fix: course redirect unit to sequnce unit redirect * fix: test coverage
This commit is contained in:
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { breakpoints, useWindowSize } from '@openedx/paragon';
|
||||
|
||||
import { AlertList } from '@src/generic/user-messages';
|
||||
@@ -38,6 +39,13 @@ const Course = ({
|
||||
const section = useModel('sections', sequence ? sequence.sectionId : null);
|
||||
const { enableNavigationSidebar } = useSelector(getCoursewareOutlineSidebarSettings);
|
||||
const navigationDisabled = enableNavigationSidebar || (sequence?.navigationDisabled ?? false);
|
||||
const navigate = useNavigate();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
if (!isStaff && pathname.startsWith('/preview')) {
|
||||
const courseUrl = pathname.replace('/preview', '');
|
||||
navigate(courseUrl, { replace: true });
|
||||
}
|
||||
|
||||
const pageTitleBreadCrumbs = [
|
||||
sequence,
|
||||
|
||||
@@ -204,6 +204,7 @@ const Sequence = ({
|
||||
sequenceId={sequenceId}
|
||||
unitId={unitId}
|
||||
unitLoadedHandler={handleUnitLoaded}
|
||||
isStaff={isStaff}
|
||||
/>
|
||||
{unitHasLoaded && renderUnitNavigation(false)}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Suspense, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import PageLoading from '../../../generic/PageLoading';
|
||||
import { useModel } from '../../../generic/model-store';
|
||||
|
||||
@@ -11,12 +11,13 @@ const ContentLock = React.lazy(() => import('./content-lock'));
|
||||
|
||||
const SequenceContent = ({
|
||||
gated,
|
||||
intl,
|
||||
courseId,
|
||||
sequenceId,
|
||||
unitId,
|
||||
unitLoadedHandler,
|
||||
isStaff,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const sequence = useModel('sequences', sequenceId);
|
||||
|
||||
// Go back to the top of the page whenever the unit or sequence changes.
|
||||
@@ -59,6 +60,7 @@ const SequenceContent = ({
|
||||
key={unitId}
|
||||
id={unitId}
|
||||
onLoaded={unitLoadedHandler}
|
||||
isStaff={isStaff}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -69,11 +71,11 @@ SequenceContent.propTypes = {
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string,
|
||||
unitLoadedHandler: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
isStaff: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
SequenceContent.defaultProps = {
|
||||
unitId: null,
|
||||
};
|
||||
|
||||
export default injectIntl(SequenceContent);
|
||||
export default SequenceContent;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useSearchParams, useLocation } from 'react-router-dom';
|
||||
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
@@ -22,15 +22,18 @@ const Unit = ({
|
||||
format,
|
||||
onLoaded,
|
||||
id,
|
||||
isStaff,
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { pathname } = useLocation();
|
||||
const { authenticatedUser } = React.useContext(AppContext);
|
||||
const examAccess = useExamAccess({ id });
|
||||
const shouldDisplayHonorCode = useShouldDisplayHonorCode({ courseId, id });
|
||||
const unit = useModel(modelKeys.units, id);
|
||||
const isProcessing = unit.bookmarkedUpdateState === 'loading';
|
||||
const view = authenticatedUser ? views.student : views.public;
|
||||
const shouldDisplayUnitPreview = pathname.startsWith('/preview') && isStaff;
|
||||
|
||||
const getUrl = usePluginsCallback('getIFrameUrl', () => getIFrameUrl({
|
||||
id,
|
||||
@@ -38,6 +41,7 @@ const Unit = ({
|
||||
format,
|
||||
examAccess,
|
||||
jumpToId: searchParams.get('jumpToId'),
|
||||
preview: shouldDisplayUnitPreview ? '1' : '0',
|
||||
}));
|
||||
|
||||
const iframeUrl = getUrl();
|
||||
@@ -74,6 +78,7 @@ Unit.propTypes = {
|
||||
format: PropTypes.string,
|
||||
id: PropTypes.string.isRequired,
|
||||
onLoaded: PropTypes.func,
|
||||
isStaff: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
Unit.defaultProps = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { when } from 'jest-when';
|
||||
import { formatMessage, shallow } from '@edx/react-unit-test-utils/dist';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useSearchParams, useLocation } from 'react-router-dom';
|
||||
|
||||
import { useModel } from '@src/generic/model-store';
|
||||
|
||||
@@ -55,6 +55,7 @@ const props = {
|
||||
format: 'test-format',
|
||||
onLoaded: jest.fn().mockName('props.onLoaded'),
|
||||
id: 'test-props-id',
|
||||
isStaff: false,
|
||||
};
|
||||
|
||||
const context = { authenticatedUser: { test: 'user' } };
|
||||
@@ -89,6 +90,7 @@ describe('Unit component', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
useSearchParams.mockImplementation(() => [searchParams, setSearchParams]);
|
||||
useLocation.mockImplementation(() => ({ pathname: `/course/${props.courseId}` }));
|
||||
jest.clearAllMocks();
|
||||
el = shallow(<Unit {...props} />);
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ export const getIFrameUrl = ({
|
||||
format,
|
||||
examAccess,
|
||||
jumpToId,
|
||||
preview,
|
||||
}) => {
|
||||
const xblockUrl = `${getConfig().LMS_BASE_URL}/xblock/${id}`;
|
||||
return stringifyUrl({
|
||||
@@ -20,6 +21,7 @@ export const getIFrameUrl = ({
|
||||
query: {
|
||||
...iframeParams,
|
||||
view,
|
||||
preview,
|
||||
...(format && { format }),
|
||||
...(!examAccess.blockAccess && { exam_access: examAccess.accessToken }),
|
||||
jumpToId, // Pass jumpToId as query param as fragmentIdentifier is not passed to server.
|
||||
|
||||
@@ -17,6 +17,7 @@ const props = {
|
||||
view: 'test-view',
|
||||
format: 'test-format',
|
||||
examAccess: { blockAccess: false, accessToken: 'test-access-token' },
|
||||
preview: false,
|
||||
};
|
||||
|
||||
describe('urls module getIFrameUrl', () => {
|
||||
@@ -28,6 +29,7 @@ describe('urls module getIFrameUrl', () => {
|
||||
view: props.view,
|
||||
format: props.format,
|
||||
exam_access: props.examAccess.accessToken,
|
||||
preview: props.preview,
|
||||
},
|
||||
});
|
||||
expect(getIFrameUrl(props)).toEqual(url);
|
||||
@@ -35,11 +37,12 @@ describe('urls module getIFrameUrl', () => {
|
||||
test('no format provided, exam access blocked', () => {
|
||||
const url = stringifyUrl({
|
||||
url: `${config.LMS_BASE_URL}/xblock/${props.id}`,
|
||||
query: { ...iframeParams, view: props.view },
|
||||
query: { ...iframeParams, view: props.view, preview: props.preview },
|
||||
});
|
||||
expect(getIFrameUrl({
|
||||
id: props.id,
|
||||
view: props.view,
|
||||
preview: props.preview,
|
||||
examAccess: { blockAccess: true },
|
||||
})).toEqual(url);
|
||||
});
|
||||
@@ -50,6 +53,7 @@ describe('urls module getIFrameUrl', () => {
|
||||
...iframeParams,
|
||||
view: props.view,
|
||||
format: props.format,
|
||||
preview: props.preview,
|
||||
exam_access: props.examAccess.accessToken,
|
||||
jumpToId: 'some-xblock-id',
|
||||
},
|
||||
@@ -60,4 +64,20 @@ describe('urls module getIFrameUrl', () => {
|
||||
jumpToId: 'some-xblock-id',
|
||||
})).toEqual(url);
|
||||
});
|
||||
test('preview is true and url param equals 1', () => {
|
||||
const url = stringifyUrl({
|
||||
url: `${config.LMS_BASE_URL}/xblock/${props.id}`,
|
||||
query: {
|
||||
...iframeParams,
|
||||
view: props.view,
|
||||
format: props.format,
|
||||
preview: true,
|
||||
exam_access: props.examAccess.accessToken,
|
||||
},
|
||||
});
|
||||
expect(getIFrameUrl({
|
||||
...props,
|
||||
preview: true,
|
||||
})).toEqual(url);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { breakpoints, Button, useWindowSize } from '@openedx/paragon';
|
||||
import { ChevronLeft, ChevronRight } from '@openedx/paragon/icons';
|
||||
import { breakpoints, useWindowSize } from '@openedx/paragon';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
injectIntl,
|
||||
intlShape,
|
||||
isRtl,
|
||||
getLocale,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { PluginSlot } from '@openedx/frontend-plugin-framework';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
@@ -21,9 +14,10 @@ import { useSequenceNavigationMetadata } from './hooks';
|
||||
import { useModel } from '../../../../generic/model-store';
|
||||
|
||||
import messages from './messages';
|
||||
import PreviousButton from './generic/PreviousButton';
|
||||
import NextButton from './generic/NextButton';
|
||||
|
||||
const SequenceNavigation = ({
|
||||
intl,
|
||||
unitId,
|
||||
sequenceId,
|
||||
className,
|
||||
@@ -36,6 +30,7 @@ const SequenceNavigation = ({
|
||||
open,
|
||||
close,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const sequence = useModel('sequences', sequenceId);
|
||||
const {
|
||||
isFirstUnit,
|
||||
@@ -76,29 +71,21 @@ const SequenceNavigation = ({
|
||||
);
|
||||
};
|
||||
|
||||
const renderPreviousButton = () => {
|
||||
const disabled = isFirstUnit;
|
||||
const prevArrow = isRtl(getLocale()) ? ChevronRight : ChevronLeft;
|
||||
return navigationDisabledPrevSequence || (
|
||||
<Button
|
||||
variant="link"
|
||||
className="previous-btn"
|
||||
onClick={previousHandler}
|
||||
disabled={disabled}
|
||||
iconBefore={prevArrow}
|
||||
as={disabled ? undefined : Link}
|
||||
to={disabled ? undefined : previousLink}
|
||||
>
|
||||
{shouldDisplayNotificationTriggerInSequence ? null : intl.formatMessage(messages.previousButton)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
const renderPreviousButton = () => navigationDisabledPrevSequence || (
|
||||
<PreviousButton
|
||||
variant="link"
|
||||
buttonStyle="previous-btn"
|
||||
onClick={previousHandler}
|
||||
previousLink={previousLink}
|
||||
isFirstUnit={isFirstUnit}
|
||||
buttonLabel={shouldDisplayNotificationTriggerInSequence ? null : intl.formatMessage(messages.previousButton)}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderNextButton = () => {
|
||||
const { exitActive, exitText } = GetCourseExitNavigation(courseId, intl);
|
||||
const buttonText = (isLastUnit && exitText) ? exitText : intl.formatMessage(messages.nextButton);
|
||||
const disabled = isLastUnit && !exitActive;
|
||||
const nextArrow = isRtl(getLocale()) ? ChevronLeft : ChevronRight;
|
||||
|
||||
return navigationDisabledNextSequence || (
|
||||
<PluginSlot
|
||||
@@ -106,10 +93,8 @@ const SequenceNavigation = ({
|
||||
pluginProps={{
|
||||
courseId,
|
||||
disabled,
|
||||
buttonText,
|
||||
nextArrow,
|
||||
buttonText: shouldDisplayNotificationTriggerInSequence ? null : buttonText,
|
||||
nextLink,
|
||||
shouldDisplayNotificationTriggerInSequence,
|
||||
sequenceId,
|
||||
unitId,
|
||||
nextSequenceHandler,
|
||||
@@ -117,20 +102,16 @@ const SequenceNavigation = ({
|
||||
isOpen,
|
||||
open,
|
||||
close,
|
||||
linkComponent: Link,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
<NextButton
|
||||
variant="link"
|
||||
className="next-btn"
|
||||
buttonStyle="next-btn"
|
||||
onClick={nextHandler}
|
||||
nextLink={nextLink}
|
||||
disabled={disabled}
|
||||
iconAfter={nextArrow}
|
||||
as={disabled ? undefined : Link}
|
||||
to={disabled ? undefined : nextLink}
|
||||
>
|
||||
{shouldDisplayNotificationTriggerInSequence ? null : buttonText}
|
||||
</Button>
|
||||
buttonLabel={shouldDisplayNotificationTriggerInSequence ? null : buttonText}
|
||||
/>
|
||||
</PluginSlot>
|
||||
);
|
||||
};
|
||||
@@ -145,7 +126,6 @@ const SequenceNavigation = ({
|
||||
};
|
||||
|
||||
SequenceNavigation.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
@@ -169,4 +149,4 @@ SequenceNavigation.defaultProps = {
|
||||
nextSequenceHandler: null,
|
||||
};
|
||||
|
||||
export default injectIntl(SequenceNavigation);
|
||||
export default SequenceNavigation;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
@@ -22,6 +22,9 @@ const UnitButton = ({
|
||||
showTitle,
|
||||
}) => {
|
||||
const { courseId, sequenceId } = useSelector(state => state.courseware);
|
||||
const { pathname } = useLocation();
|
||||
const basePath = `/course/${courseId}/${sequenceId}/${unitId}`;
|
||||
const unitPath = pathname.startsWith('/preview') ? `/preview${basePath}` : basePath;
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
onClick(unitId);
|
||||
@@ -37,7 +40,7 @@ const UnitButton = ({
|
||||
onClick={handleClick}
|
||||
title={title}
|
||||
as={Link}
|
||||
to={`/course/${courseId}/${sequenceId}/${unitId}`}
|
||||
to={unitPath}
|
||||
>
|
||||
<UnitIcon type={contentType} />
|
||||
{showTitle && <span className="unit-title">{title}</span>}
|
||||
|
||||
@@ -1,70 +1,53 @@
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from '@openedx/paragon';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
|
||||
import {
|
||||
injectIntl, intlShape, isRtl, getLocale,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { GetCourseExitNavigation } from '../../course-exit';
|
||||
|
||||
import UnitNavigationEffortEstimate from './UnitNavigationEffortEstimate';
|
||||
import { useSequenceNavigationMetadata } from './hooks';
|
||||
import messages from './messages';
|
||||
import PreviousButton from './generic/PreviousButton';
|
||||
import NextButton from './generic/NextButton';
|
||||
|
||||
const UnitNavigation = ({
|
||||
intl,
|
||||
sequenceId,
|
||||
unitId,
|
||||
onClickPrevious,
|
||||
onClickNext,
|
||||
isAtTop,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
isFirstUnit, isLastUnit, nextLink, previousLink,
|
||||
} = useSequenceNavigationMetadata(sequenceId, unitId);
|
||||
const { courseId } = useSelector(state => state.courseware);
|
||||
|
||||
const renderPreviousButton = () => {
|
||||
const disabled = isFirstUnit;
|
||||
const prevArrow = isRtl(getLocale()) ? faChevronRight : faChevronLeft;
|
||||
return (
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
className="previous-button mr-sm-2 d-flex align-items-center justify-content-center"
|
||||
disabled={disabled}
|
||||
onClick={onClickPrevious}
|
||||
as={disabled ? undefined : Link}
|
||||
to={disabled ? undefined : previousLink}
|
||||
>
|
||||
<FontAwesomeIcon icon={prevArrow} className="mr-2" size="sm" />
|
||||
{intl.formatMessage(messages.previousButton)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
const renderPreviousButton = () => (
|
||||
<PreviousButton
|
||||
isFirstUnit={isFirstUnit}
|
||||
variant="outline-secondary"
|
||||
buttonLabel={intl.formatMessage(messages.previousButton)}
|
||||
buttonStyle="previous-button justify-content-center"
|
||||
onClick={onClickPrevious}
|
||||
previousLink={previousLink}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderNextButton = () => {
|
||||
const { exitActive, exitText } = GetCourseExitNavigation(courseId, intl);
|
||||
const buttonText = (isLastUnit && exitText) ? exitText : intl.formatMessage(messages.nextButton);
|
||||
const disabled = isLastUnit && !exitActive;
|
||||
const nextArrow = isRtl(getLocale()) ? faChevronLeft : faChevronRight;
|
||||
return (
|
||||
<Button
|
||||
<NextButton
|
||||
variant="outline-primary"
|
||||
className="next-button d-flex align-items-center justify-content-center"
|
||||
buttonStyle="next-button justify-content-center"
|
||||
onClick={onClickNext}
|
||||
disabled={disabled}
|
||||
as={disabled ? undefined : Link}
|
||||
to={disabled ? undefined : nextLink}
|
||||
>
|
||||
<UnitNavigationEffortEstimate sequenceId={sequenceId} unitId={unitId}>
|
||||
{buttonText}
|
||||
</UnitNavigationEffortEstimate>
|
||||
<FontAwesomeIcon icon={nextArrow} className="ml-2" size="sm" />
|
||||
</Button>
|
||||
buttonLabel={buttonText}
|
||||
nextLink={nextLink}
|
||||
hasEffortEstimate
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -77,7 +60,6 @@ const UnitNavigation = ({
|
||||
};
|
||||
|
||||
UnitNavigation.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string,
|
||||
onClickPrevious: PropTypes.func.isRequired,
|
||||
@@ -90,4 +72,4 @@ UnitNavigation.defaultProps = {
|
||||
isAtTop: false,
|
||||
};
|
||||
|
||||
export default injectIntl(UnitNavigation);
|
||||
export default UnitNavigation;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Button } from '@openedx/paragon';
|
||||
import { ChevronLeft, ChevronRight } from '@openedx/paragon/icons';
|
||||
import { isRtl, getLocale } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import UnitNavigationEffortEstimate from '../UnitNavigationEffortEstimate';
|
||||
|
||||
const NextButton = ({
|
||||
onClick,
|
||||
buttonLabel,
|
||||
nextLink,
|
||||
variant,
|
||||
buttonStyle,
|
||||
disabled,
|
||||
hasEffortEstimate,
|
||||
}) => {
|
||||
const nextArrow = isRtl(getLocale()) ? ChevronLeft : ChevronRight;
|
||||
const { pathname } = useLocation();
|
||||
const navLink = pathname.startsWith('/preview') ? `/preview${nextLink}` : nextLink;
|
||||
const buttonContent = hasEffortEstimate ? (
|
||||
<UnitNavigationEffortEstimate>
|
||||
{buttonLabel}
|
||||
</UnitNavigationEffortEstimate>
|
||||
) : buttonLabel;
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant={variant}
|
||||
className={buttonStyle}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
as={disabled ? undefined : Link}
|
||||
to={disabled ? undefined : navLink}
|
||||
iconAfter={nextArrow}
|
||||
>
|
||||
{buttonContent}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
NextButton.defaultProps = {
|
||||
hasEffortEstimate: false,
|
||||
};
|
||||
|
||||
NextButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
buttonLabel: PropTypes.string.isRequired,
|
||||
nextLink: PropTypes.string.isRequired,
|
||||
variant: PropTypes.string.isRequired,
|
||||
buttonStyle: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
hasEffortEstimate: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default NextButton;
|
||||
@@ -0,0 +1,44 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Button } from '@openedx/paragon';
|
||||
import { ChevronLeft, ChevronRight } from '@openedx/paragon/icons';
|
||||
import { isRtl, getLocale } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const PreviousButton = ({
|
||||
onClick,
|
||||
buttonLabel,
|
||||
previousLink,
|
||||
variant,
|
||||
buttonStyle,
|
||||
isFirstUnit,
|
||||
}) => {
|
||||
const disabled = isFirstUnit;
|
||||
const prevArrow = isRtl(getLocale()) ? ChevronRight : ChevronLeft;
|
||||
const { pathname } = useLocation();
|
||||
const navLink = pathname.startsWith('/preview') ? `/preview${previousLink}` : previousLink;
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant={variant}
|
||||
className={buttonStyle}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
as={disabled ? undefined : Link}
|
||||
to={disabled ? undefined : navLink}
|
||||
iconBefore={prevArrow}
|
||||
>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
PreviousButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
buttonLabel: PropTypes.string.isRequired,
|
||||
previousLink: PropTypes.string.isRequired,
|
||||
variant: PropTypes.string.isRequired,
|
||||
buttonStyle: PropTypes.string.isRequired,
|
||||
isFirstUnit: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default PreviousButton;
|
||||
Reference in New Issue
Block a user