Skip to content

Commit

Permalink
[FC-0036] Refined tag drawer UI style (openedx#947)
Browse files Browse the repository at this point in the history
* feat: Remove 'x' close btn from tags drawer

* feat: Change style for taxonomy tags count

* feat: Update heading styles in tags drawer

* feat: Move dropdown arrows to left of taxonomy

---------

Co-authored-by: Yusuf Musleh <[email protected]>
  • Loading branch information
ChrisChV and yusuf-musleh authored Apr 17, 2024
1 parent 612d1d8 commit 0814022
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 97 deletions.
140 changes: 77 additions & 63 deletions src/content-tags-drawer/ContentTagsCollapsible.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
import React from 'react';
import Select, { components } from 'react-select';
import {
Badge,
Collapsible,
Button,
Spinner,
Chip,
Icon,
} from '@openedx/paragon';
import classNames from 'classnames';
import { Tag, KeyboardArrowDown, KeyboardArrowUp } from '@openedx/paragon/icons';
import { SelectableBox } from '@edx/frontend-lib-content-components';
import { useIntl } from '@edx/frontend-platform/i18n';
import { debounce } from 'lodash';
Expand Down Expand Up @@ -363,71 +364,84 @@ const ContentTagsCollapsible = ({

return (
<div className="d-flex">
<Collapsible title={name} styling="card-lg" className="taxonomy-tags-collapsible">
<div key={taxonomyId}>
<ContentTagsTree tagsTree={appliedContentTagsTree} removeTagHandler={removeAppliedTagHandler} />
</div>
<Collapsible.Advanced
className="collapsible-card-lg taxonomy-tags-collapsible"
>
<Collapsible.Trigger className="collapsible-trigger pl-2.5">
<Collapsible.Visible whenClosed>
<Icon src={KeyboardArrowDown} />
</Collapsible.Visible>

<div className="d-flex taxonomy-tags-selector-menu">
<Collapsible.Visible whenOpen>
<Icon src={KeyboardArrowUp} />
</Collapsible.Visible>
<h4 className="flex-grow-1 pl-2">{name}</h4>
</Collapsible.Trigger>

{canTagObject && (
<Select
onBlur={handleOnBlur}
styles={{
// Overriding 'x' button styles for staged tags when navigating by keyboard
multiValueRemove: (base, state) => ({
...base,
background: state.isFocused ? 'black' : base.background,
color: state.isFocused ? 'white' : base.color,
}),
}}
menuIsOpen={selectMenuIsOpen}
onFocus={onSelectMenuFocus}
onKeyDown={handleSelectOnKeyDown}
ref={/** @type {React.RefObject} */(selectRef)}
isMulti
isLoading={updateTags.isLoading}
isDisabled={updateTags.isLoading}
name="tags-select"
placeholder={intl.formatMessage(messages.collapsibleAddTagsPlaceholderText)}
isSearchable
className="d-flex flex-column flex-fill"
classNamePrefix="react-select-add-tags"
onInputChange={handleSearchChange}
onChange={handleStagedTagsMenuChange}
components={{
Menu: CustomMenu,
LoadingIndicator: CustomLoadingIndicator,
IndicatorsContainer: CustomIndicatorsContainer,
}}
closeMenuOnSelect={false}
blurInputOnSelect={false}
handleSelectableBoxChange={handleSelectableBoxChange}
checkedTags={checkedTags}
taxonomyId={taxonomyId}
appliedContentTagsTree={appliedContentTagsTree}
stagedContentTagsTree={stagedContentTagsTree}
handleCommitStagedTags={handleCommitStagedTags}
handleCancelStagedTags={handleCancelStagedTags}
searchTerm={searchTerm}
selectCancelRef={selectCancelRef}
selectAddRef={selectAddRef}
selectInlineAddRef={selectInlineAddRef}
value={stagedContentTags}
/>
)}
</div>
</Collapsible>
<div className="d-flex">
<Badge
variant="light"
pill
className={classNames('align-self-start', 'mt-3', {
invisible: contentTagsCount === 0,
})}
<Collapsible.Body className="collapsible-body">
<div key={taxonomyId}>
<ContentTagsTree tagsTree={appliedContentTagsTree} removeTagHandler={removeAppliedTagHandler} />
</div>

<div className="d-flex taxonomy-tags-selector-menu">

{canTagObject && (
<Select
onBlur={handleOnBlur}
styles={{
// Overriding 'x' button styles for staged tags when navigating by keyboard
multiValueRemove: (base, state) => ({
...base,
background: state.isFocused ? 'black' : base.background,
color: state.isFocused ? 'white' : base.color,
}),
}}
menuIsOpen={selectMenuIsOpen}
onFocus={onSelectMenuFocus}
onKeyDown={handleSelectOnKeyDown}
ref={/** @type {React.RefObject} */(selectRef)}
isMulti
isLoading={updateTags.isLoading}
isDisabled={updateTags.isLoading}
name="tags-select"
placeholder={intl.formatMessage(messages.collapsibleAddTagsPlaceholderText)}
isSearchable
className="d-flex flex-column flex-fill"
classNamePrefix="react-select-add-tags"
onInputChange={handleSearchChange}
onChange={handleStagedTagsMenuChange}
components={{
Menu: CustomMenu,
LoadingIndicator: CustomLoadingIndicator,
IndicatorsContainer: CustomIndicatorsContainer,
}}
closeMenuOnSelect={false}
blurInputOnSelect={false}
handleSelectableBoxChange={handleSelectableBoxChange}
checkedTags={checkedTags}
taxonomyId={taxonomyId}
appliedContentTagsTree={appliedContentTagsTree}
stagedContentTagsTree={stagedContentTagsTree}
handleCommitStagedTags={handleCommitStagedTags}
handleCancelStagedTags={handleCancelStagedTags}
searchTerm={searchTerm}
selectCancelRef={selectCancelRef}
selectAddRef={selectAddRef}
selectInlineAddRef={selectInlineAddRef}
value={stagedContentTags}
/>
)}
</div>
</Collapsible.Body>
</Collapsible.Advanced>
<div className="d-flex align-items-start pt-2.5 taxonomy-tags-count-chip">
<Chip
iconBefore={Tag}
iconBeforeAlt="icon-before"
disabled={contentTagsCount === 0}
>
{contentTagsCount}
</Badge>
</Chip>
</div>
</div>
);
Expand Down
8 changes: 8 additions & 0 deletions src/content-tags-drawer/ContentTagsCollapsible.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

.collapsible-trigger {
border: none !important;

.pgn__icon {
margin-left: -3px;
}
}
}

Expand Down Expand Up @@ -57,3 +61,7 @@
color: white !important;
}
}

.taxonomy-tags-count-chip > .pgn__chip {
background: none;
}
7 changes: 4 additions & 3 deletions src/content-tags-drawer/ContentTagsCollapsible.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ describe('<ContentTagsCollapsible />', () => {
it('should render taxonomy tags data along content tags number badge', async () => {
const { container, getByText } = await getComponent();
expect(getByText('Taxonomy 1')).toBeInTheDocument();
expect(container.getElementsByClassName('badge').length).toBe(1);
expect(container.getElementsByClassName('taxonomy-tags-count-chip').length).toBe(1);
expect(getByText('3')).toBeInTheDocument();
});

Expand Down Expand Up @@ -546,13 +546,14 @@ describe('<ContentTagsCollapsible />', () => {
expect(appliedTag).not.toBeInTheDocument();
});

it('should render taxonomy tags data without tags number badge', async () => {
it('should render taxonomy tags data with tags number badge as cero', async () => {
const updatedData = { ...data };
updatedData.taxonomyAndTagsData = { ...updatedData.taxonomyAndTagsData };
updatedData.taxonomyAndTagsData.contentTags = [];
const { container, getByText } = await getComponent(updatedData);

expect(getByText('Taxonomy 1')).toBeInTheDocument();
expect(container.getElementsByClassName('invisible').length).toBe(1);
expect(container.getElementsByClassName('taxonomy-tags-count-chip').length).toBe(1);
expect(getByText('0')).toBeInTheDocument();
});
});
6 changes: 2 additions & 4 deletions src/content-tags-drawer/ContentTagsDrawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import React, {
import PropTypes from 'prop-types';
import {
Container,
CloseButton,
Spinner,
} from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
Expand Down Expand Up @@ -135,10 +134,8 @@ const ContentTagsDrawer = ({ id, onClose }) => {

<div id="content-tags-drawer" className="mt-1">
<Container size="xl">
<CloseButton onClick={() => onCloseDrawer()} data-testid="drawer-close-button" />
<span>{intl.formatMessage(messages.headerSubtitle)}</span>
{ isContentDataLoaded
? <h3>{ contentName }</h3>
? <h2>{ contentName }</h2>
: (
<div className="d-flex justify-content-center align-items-center flex-column">
<Spinner
Expand All @@ -150,6 +147,7 @@ const ContentTagsDrawer = ({ id, onClose }) => {
)}

<hr />
<p className="lead text-gray-500 font-weight-bold">{intl.formatMessage(messages.headerSubtitle)}</p>

{ isTaxonomyListLoaded && isContentTaxonomyTagsLoaded
? taxonomies.map((data) => (
Expand Down
27 changes: 1 addition & 26 deletions src/content-tags-drawer/ContentTagsDrawer.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { getTaxonomyListData } from '../taxonomy/data/api';
import messages from './messages';

const contentId = 'block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@7f47fe2dbcaf47c5a071671c741fe1ab';
const mockOnClose = jest.fn();

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
Expand Down Expand Up @@ -250,7 +249,7 @@ describe('<ContentTagsDrawer />', () => {
await waitFor(() => { expect(getByText('Taxonomy 1')).toBeInTheDocument(); });
expect(getByText('Taxonomy 1')).toBeInTheDocument();
expect(getByText('Taxonomy 2')).toBeInTheDocument();
const tagCountBadges = container.getElementsByClassName('badge');
const tagCountBadges = container.getElementsByClassName('taxonomy-tags-count-chip');
expect(tagCountBadges[0].textContent).toBe('2');
expect(tagCountBadges[1].textContent).toBe('1');
});
Expand Down Expand Up @@ -354,30 +353,6 @@ describe('<ContentTagsDrawer />', () => {
expect(queryByText('Tag 3')).not.toBeInTheDocument();
});

it('should call closeManageTagsDrawer when CloseButton is clicked', async () => {
const postMessageSpy = jest.spyOn(window.parent, 'postMessage');

const { getByTestId } = render(<RootWrapper />);

// Find the CloseButton element by its test ID and trigger a click event
const closeButton = getByTestId('drawer-close-button');
fireEvent.click(closeButton);

expect(postMessageSpy).toHaveBeenCalledWith('closeManageTagsDrawer', '*');

postMessageSpy.mockRestore();
});

it('should call onClose param when CloseButton is clicked', async () => {
render(<RootWrapper onClose={mockOnClose} />);

// Find the CloseButton element by its test ID and trigger a click event
const closeButton = screen.getByTestId('drawer-close-button');
fireEvent.click(closeButton);

expect(mockOnClose).toHaveBeenCalled();
});

it('should call closeManageTagsDrawer when Escape key is pressed and no selectable box is active', () => {
const postMessageSpy = jest.spyOn(window.parent, 'postMessage');

Expand Down
2 changes: 1 addition & 1 deletion src/course-outline/card-header/CardHeader.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ describe('<CardHeader />', () => {
fireEvent.click(manageTagsMenuItem);

// Check if the drawer is open
expect(screen.getByTestId('drawer-close-button')).toBeInTheDocument();
expect(screen.getAllByText('Manage tags').length).toBe(2);
});

it('calls onClickEdit when the button is clicked', async () => {
Expand Down

0 comments on commit 0814022

Please sign in to comment.