Skip to content

Commit

Permalink
[CPCN-47] SearchTips Panel (#416)
Browse files Browse the repository at this point in the history
* ui: New SearchTips Panel

* api: render search tips html onto window object

* api: Move search into a module

* Fix tests

* Update messages.pot

* fix explicit rendering of null
  • Loading branch information
MarkLark86 authored Jun 27, 2023
1 parent e091668 commit 74609c8
Show file tree
Hide file tree
Showing 29 changed files with 639 additions and 259 deletions.
13 changes: 13 additions & 0 deletions assets/components/HTMLContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react';
import Proptypes from 'prop-types';
import * as DOMPurify from 'dompurify';

export function HTMLContent({text}) {
return (
<div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(text)}} />
);
}

HTMLContent.propTypes = {
text: Proptypes.string.isRequired,
};
11 changes: 11 additions & 0 deletions assets/search/components/AdvancedSearchPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function AdvancedSearchPanelComponent({
params,
fetchItems,
toggleAdvancedSearchPanel,
toggleSearchTipsPanel,
toggleField,
setKeywords,
clearParams
Expand All @@ -24,6 +25,15 @@ function AdvancedSearchPanelComponent({
<nav className="content-bar navbar">
<h3>{gettext('Advanced Search')}</h3>
<div className="btn-group">
<div className="mx-2">
<button
className="icon-button"
aria-label={gettext('Show Search Tips')}
onClick={toggleSearchTipsPanel}
>
<i className="icon--info" />
</button>
</div>
<div className="mx-2">
<button
className="icon-button icon-button icon-button--bordered"
Expand Down Expand Up @@ -156,6 +166,7 @@ AdvancedSearchPanelComponent.propTypes = {
}),
fetchItems: PropTypes.func,
toggleAdvancedSearchPanel: PropTypes.func,
toggleSearchTipsPanel: PropTypes.func,
toggleField: PropTypes.func,
setKeywords: PropTypes.func,
clearParams: PropTypes.func,
Expand Down
17 changes: 13 additions & 4 deletions assets/search/components/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,25 @@ class SearchBar extends React.Component {
</div>
</form>
</div>
{this.props.toggleAdvancedSearchPanel == null ? this.props.toggleAdvancedSearchPanel : (
<div className="mx-2 d-flex gap-2">
<div className="mx-2 d-flex gap-2">
{this.props.toggleAdvancedSearchPanel == null ? null : (
<button
data-test-id="show-advanced-search-panel-btn"
className="nh-button nh-button--secondary"
onClick={this.props.toggleAdvancedSearchPanel}
>
{gettext('Advanced Search')}
</button>
</div>
)}
)}
<button
data-test-id="show-search-tips-panel-btn"
className="icon-button icon-button--tertiary icon-button--bordered"
aria-label={gettext('Show Search tips')}
onClick={this.props.toggleSearchTipsPanel}
>
<i className="icon--info" />
</button>
</div>
</React.Fragment>
);
}
Expand All @@ -106,6 +114,7 @@ SearchBar.propTypes = {
fetchItems: PropTypes.func,
enableQueryAction: PropTypes.bool,
toggleAdvancedSearchPanel: PropTypes.func,
toggleSearchTipsPanel: PropTypes.func,
};

const mapStateToProps = (state) => ({
Expand Down
100 changes: 100 additions & 0 deletions assets/search/components/SearchTipsPanel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import {gettext} from 'utils';
import {HTMLContent} from 'components/HTMLContent';

export class SearchTipsPanel extends React.Component {
constructor(props) {
super(props);

this.state = {activeTab: this.props.defaultTab};
this.handleTabClick = this.handleTabClick.bind(this);
}

handleTabClick(tabName) {
this.setState({activeTab: tabName});
}

render() {
const {toggleSearchTipsPanel} = this.props;
const activeTabHtml = window.searchTipsHtml[this.state.activeTab] || '';

if (activeTabHtml.length) {
console.warn('Search tip HTML not found on window.');
}

return (
<div className="advanced-search__wrapper">
<div className="advanced-search__header">
<h3 className="a11y-only">{gettext('Advanced Search Tips dialog')}</h3>
<nav className="content-bar navbar">
<h3>{gettext('Tips')}</h3>
<div className="btn-group">
<div className="mx-2">
<button
onClick={toggleSearchTipsPanel}
className="icon-button icon-button icon-button--bordered"
aria-label={gettext('Close Search Tips')}
>
<i className="icon--close-thin" />
</button>
</div>
</div>
</nav>
<div className="advanced-search__subnav-wrapper">
<div className="advanced-search__subnav-content">
<ul className="nav nav-tabs nav-tabs--light">
<li className="nav-item">
<a
data-test-id="tab-regular"
name="regular"
className={classNames(
'nav-link',
{'active': this.state.activeTab === 'regular'}
)}
href="#"
onClick={() => {
this.handleTabClick('regular');
}}
>
{gettext('Regular search')}
</a>
</li>
<li className="nav-item">
<a
data-test-id="tab-advanced"
name="advanced"
className={classNames(
'nav-link',
{'active': this.state.activeTab === 'advanced'}
)}
href="#"
onClick={() => {
this.handleTabClick('advanced');
}}
>
{gettext('Advanced search')}
</a>
</li>
</ul>
</div>
</div>
</div>
<div className="advanced-search__content-wrapper">
<HTMLContent text={activeTabHtml} />
</div>
</div>
);
}
}

SearchTipsPanel.propTypes = {
defaultTab: PropTypes.oneOf(['regular', 'advanced']),
toggleSearchTipsPanel: PropTypes.func,
};

SearchTipsPanel.defaultProps = {
defaultTab: 'regular',
};
13 changes: 10 additions & 3 deletions assets/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2389,16 +2389,23 @@ article.list {
padding: 0;
margin: 10px 0;
}

.blue {
color: #00658A;
}
.green {
color: #51831C;
}
.red {
color: #BC3434;
}
}
.advanced-search__content-block-text {
font-weight: 400;
margin-block-end: 0;
&--bold {
font-weight: 700;
}
span {
text-decoration: underline;
}
.blue {
color: #00658A;
}
Expand Down
16 changes: 16 additions & 0 deletions assets/wire/components/WireApp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import getItemActions from '../item-actions';
import BookmarkTabs from 'components/BookmarkTabs';
import ItemStatisticsModal from './ItemStatisticsModal';
import {AdvancedSearchPanel} from 'search/components/AdvancedSearchPanel';
import {SearchTipsPanel} from 'search/components/SearchTipsPanel';

import {SearchResultsBar} from 'search/components/SearchResultsBar';

Expand Down Expand Up @@ -83,12 +84,19 @@ class WireApp extends BaseApp {

this.toggleAdvancedSearchPanel = this.toggleAdvancedSearchPanel.bind(this);
this.state.isAdvancedSearchShown = false;

this.toggleSearchTipsPanel = this.toggleSearchTipsPanel.bind(this);
this.state.isSearchTipsShown = false;
}

toggleAdvancedSearchPanel() {
this.setState((prevState) => ({isAdvancedSearchShown: !prevState.isAdvancedSearchShown}));
}

toggleSearchTipsPanel() {
this.setState((prevState) => ({isSearchTipsShown: !prevState.isSearchTipsShown}));
}

render() {
if (this.state.initialLoad){
return this.renderLoader();
Expand All @@ -103,6 +111,13 @@ class WireApp extends BaseApp {
<AdvancedSearchPanel
fetchItems={this.props.fetchItems}
toggleAdvancedSearchPanel={this.toggleAdvancedSearchPanel}
toggleSearchTipsPanel={this.toggleSearchTipsPanel}
/>
)}
{!this.state.isSearchTipsShown ? null : (
<SearchTipsPanel
toggleSearchTipsPanel={this.toggleSearchTipsPanel}
defaultTab={this.state.isAdvancedSearchShown ? 'advanced' : 'regular'}
/>
)}
</React.Fragment>
Expand Down Expand Up @@ -219,6 +234,7 @@ class WireApp extends BaseApp {
fetchItems={this.props.fetchItems}
setQuery={this.props.setQuery}
toggleAdvancedSearchPanel={this.toggleAdvancedSearchPanel}
toggleSearchTipsPanel={this.toggleSearchTipsPanel}
/>
</nav>
</section>,
Expand Down
Loading

0 comments on commit 74609c8

Please sign in to comment.