Skip to content
4 changes: 3 additions & 1 deletion src/course-outline/OutlineAddChildButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import messages from './messages';
interface NewChildButtonsProps {
handleNewButtonClick: () => void;
handleUseFromLibraryClick: () => void;
onClickCard?: (e: React.MouseEvent) => void;
childType: ContainerType;
btnVariant?: string;
btnClasses?: string;
Expand All @@ -18,6 +19,7 @@ interface NewChildButtonsProps {
const OutlineAddChildButtons = ({
handleNewButtonClick,
handleUseFromLibraryClick,
onClickCard,
childType,
btnVariant = 'outline-primary',
btnClasses = 'mt-4 border-gray-500 rounded-0',
Expand Down Expand Up @@ -59,7 +61,7 @@ const OutlineAddChildButtons = ({
}

return (
<Stack direction="horizontal" gap={3}>
<Stack direction="horizontal" gap={3} onClick={onClickCard}>
<Button
className={btnClasses}
variant={btnVariant}
Expand Down
15 changes: 12 additions & 3 deletions src/course-outline/card-header/CardHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Icon,
IconButton,
IconButtonWithTooltip,
Stack,
useToggle,
} from '@openedx/paragon';
import {
Expand Down Expand Up @@ -48,6 +49,7 @@ interface CardHeaderProps {
onClickMoveUp: () => void;
onClickMoveDown: () => void;
onClickCopy?: () => void;
onClickCard?: (e: React.MouseEvent) => void;
titleComponent: ReactNode;
namePrefix: string;
proctoringExamConfigurationLink?: string,
Expand Down Expand Up @@ -90,6 +92,7 @@ const CardHeader = ({
onClickMoveUp,
onClickMoveDown,
onClickCopy,
onClickCard,
titleComponent,
namePrefix,
actions,
Expand Down Expand Up @@ -154,10 +157,16 @@ const CardHeader = ({

return (
<>
<div
{
/* This is a special case; we can skip accessibility here since the
{Container}Card handles that. This onClick allows the user to select the card
Comment thread
bradenmacdonald marked this conversation as resolved.
Outdated
by clicking on white areas of this component. */
}
<div // eslint-disable-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
className="item-card-header"
data-testid={`${namePrefix}-card-header`}
ref={cardHeaderRef}
onClick={onClickCard}
>
{isFormOpen ? (
<Form.Group className="m-0 w-75">
Expand All @@ -178,7 +187,7 @@ const CardHeader = ({
/>
</Form.Group>
) : (
<>
<Stack direction="horizontal" gap={2}>
{titleComponent}
<IconButtonWithTooltip
className="item-card-button-icon"
Expand All @@ -190,7 +199,7 @@ const CardHeader = ({
// @ts-ignore
disabled={isSaving}
/>
</>
</Stack>
)}
<div className="ml-auto d-flex">
{(isVertical || isSequential) && (
Expand Down
42 changes: 16 additions & 26 deletions src/course-outline/card-header/TitleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Button,
OverlayTrigger,
Tooltip,
IconButtonWithTooltip,
Stack,
} from '@openedx/paragon';
import {
ArrowDropDown as ArrowDownIcon,
Expand All @@ -29,32 +28,23 @@ const TitleButton = ({
const titleTooltipMessage = intl.formatMessage(messages.expandTooltip);

return (
<OverlayTrigger
placement="bottom"
overlay={(
<Tooltip
id={`${title}-${titleTooltipMessage}`}
>
{titleTooltipMessage}
</Tooltip>
)}
>
<Button
iconBefore={isExpanded ? ArrowDownIcon : ArrowRightIcon}
variant="tertiary"
<Stack direction="horizontal">
<IconButtonWithTooltip
src={isExpanded ? ArrowDownIcon : ArrowRightIcon}
data-testid={`${namePrefix}-card-header__expanded-btn`}
alt={title}
tooltipContent={<div>{titleTooltipMessage}</div>}
className="item-card-header__title-btn"
onClick={onTitleClick}
title={title}
>
<div className="mr-2">
{prefixIcon}
</div>
<span className={`${namePrefix}-card-title mb-0 truncate-1-line`}>
{title}
</span>
</Button>
</OverlayTrigger>
size="inline"
/>
<div className="mr-2">
{prefixIcon}
</div>
<span className={`${namePrefix}-card-title mb-0 truncate-1-line`}>
{title}
</span>
</Stack>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/course-outline/card-header/TitleLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const TitleLink = ({
to={titleLink}
title={title}
>
<span className={`${namePrefix}-card-title mb-0 truncate-1-line text-left`}>
Comment thread
ChrisChV marked this conversation as resolved.
<span className={`${namePrefix}-card-title truncate-1-line mb-0 text-left`}>
{title}
</span>
</Button>
Expand Down
12 changes: 12 additions & 0 deletions src/course-outline/drag-helper/SortableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface SortableItemProps {
isDraggable?: boolean;
children: React.ReactNode;
componentStyle?: object;
onClick?: (e: React.MouseEvent) => void;
}

const SortableItem = ({
Expand All @@ -30,6 +31,7 @@ const SortableItem = ({
componentStyle,
data,
children,
onClick,
}: SortableItemProps) => {
const intl = useIntl();
const {
Expand Down Expand Up @@ -66,8 +68,18 @@ const SortableItem = ({
return (
<Row
ref={setNodeRef}
tabIndex={onClick ? 0 : -1}
style={style}
className="mx-0"
onClick={onClick}
onKeyDown={(e) => {
if (!onClick) { return; }

if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onClick(e);
}
}}
>
<Col className="extend-margin px-0">
{children}
Expand Down
15 changes: 15 additions & 0 deletions src/course-outline/outline-sidebar/OutlineSidebarContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useState,
} from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import { useToggle } from '@openedx/paragon';
import { HelpOutline, Info } from '@openedx/paragon/icons';

Expand All @@ -25,6 +26,8 @@ interface OutlineSidebarContextData {
open: () => void;
toggle: () => void;
sidebarPages: OutlineSidebarPages;
selectedContainerId?: string;
openContainerInfoSidebar: (containerId: string) => void;
}

const OutlineSidebarContext = createContext<OutlineSidebarContextData | undefined>(undefined);
Expand All @@ -35,6 +38,14 @@ export const OutlineSidebarProvider = ({ children }: { children?: React.ReactNod
const [currentPageKey, setCurrentPageKeyState] = useState<OutlineSidebarPageKeys>('info');
const [isOpen, open, , toggle] = useToggle(true);

const [selectedContainerId, setSelectedContainerId] = useState<string | undefined>();

const openContainerInfoSidebar = useCallback((containerId: string) => {
if (getConfig().ENABLE_COURSE_OUTLINE_NEW_DESIGN?.toString().toLowerCase() === 'true') {
Comment thread
bradenmacdonald marked this conversation as resolved.
Outdated
setSelectedContainerId(containerId);
}
}, [setSelectedContainerId]);

const setCurrentPageKey = useCallback((pageKey: OutlineSidebarPageKeys) => {
setCurrentPageKeyState(pageKey);
open();
Expand All @@ -61,6 +72,8 @@ export const OutlineSidebarProvider = ({ children }: { children?: React.ReactNod
isOpen,
open,
toggle,
selectedContainerId,
openContainerInfoSidebar,
}),
[
currentPageKey,
Expand All @@ -69,6 +82,8 @@ export const OutlineSidebarProvider = ({ children }: { children?: React.ReactNod
isOpen,
open,
toggle,
selectedContainerId,
openContainerInfoSidebar,
],
);

Expand Down
74 changes: 52 additions & 22 deletions src/course-outline/section-card/SectionCard.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { getConfig, setConfig } from '@edx/frontend-platform';
import {
act, fireEvent, initializeMocks, render, screen, waitFor, within,
} from '@src/testUtils';
import { XBlock } from '@src/data/types';
import SectionCard from './SectionCard';
import { OutlineSidebarProvider } from '../outline-sidebar/OutlineSidebarContext';

const mockUseAcceptLibraryBlockChanges = jest.fn();
const mockUseIgnoreLibraryBlockChanges = jest.fn();
Expand Down Expand Up @@ -82,28 +84,30 @@ const section = {
const onEditSectionSubmit = jest.fn();

const renderComponent = (props?: object, entry = '/course/:courseId') => render(
<SectionCard
section={section}
index={1}
canMoveItem={jest.fn()}
onOrderChange={jest.fn()}
onOpenPublishModal={jest.fn()}
onOpenHighlightsModal={jest.fn()}
onOpenDeleteModal={jest.fn()}
onOpenUnlinkModal={jest.fn()}
onOpenConfigureModal={jest.fn()}
onEditSectionSubmit={onEditSectionSubmit}
onDuplicateSubmit={jest.fn()}
isSectionsExpanded
onNewSubsectionSubmit={jest.fn()}
isSelfPaced={false}
isCustomRelativeDatesActive={false}
onAddSubsectionFromLibrary={jest.fn()}
resetScrollState={jest.fn()}
{...props}
>
<span>children</span>
</SectionCard>,
<OutlineSidebarProvider>
<SectionCard
section={section}
index={1}
canMoveItem={jest.fn()}
onOrderChange={jest.fn()}
onOpenPublishModal={jest.fn()}
onOpenHighlightsModal={jest.fn()}
onOpenDeleteModal={jest.fn()}
onOpenUnlinkModal={jest.fn()}
onOpenConfigureModal={jest.fn()}
onEditSectionSubmit={onEditSectionSubmit}
onDuplicateSubmit={jest.fn()}
isSectionsExpanded
onNewSubsectionSubmit={jest.fn()}
isSelfPaced={false}
isCustomRelativeDatesActive={false}
onAddSubsectionFromLibrary={jest.fn()}
resetScrollState={jest.fn()}
{...props}
>
<span>children</span>
</SectionCard>
</OutlineSidebarProvider>,
{
path: '/course/:courseId',
params: { courseId: '5' },
Expand All @@ -123,6 +127,32 @@ describe('<SectionCard />', () => {

expect(screen.getByTestId('section-card-header')).toBeInTheDocument();
expect(screen.getByTestId('section-card__content')).toBeInTheDocument();

// The card is not selected
const card = screen.getByTestId('section-card');
expect(card).not.toHaveClass('outline-card-selected');
});

it('render SectionCard component in selected state', () => {
setConfig({
...getConfig(),
ENABLE_COURSE_OUTLINE_NEW_DESIGN: 'true',
});
const { container } = renderComponent();

expect(screen.getByTestId('section-card-header')).toBeInTheDocument();

// The card is not selected
const card = screen.getByTestId('section-card');
expect(card).not.toHaveClass('outline-card-selected');

// Get the <Row> that contains the card and click it to select the card
const el = container.querySelector('div.row.mx-0') as HTMLInputElement;
expect(el).not.toBeNull();
fireEvent.click(el!);

// The card is selected
expect(card).toHaveClass('outline-card-selected');
});

it('expands/collapses the card when the expand button is clicked', () => {
Expand Down
Loading