Skip to content

Commit

Permalink
feat: added prequery event handler to search (#373)
Browse files Browse the repository at this point in the history
* feat: added prequery event handler to search
  • Loading branch information
katrinan029 authored Feb 20, 2024
1 parent b549a6f commit 5705327
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 51 deletions.
49 changes: 49 additions & 0 deletions packages/catalog-search/src/PrequerySearchSuggestionItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { Image } from '@openedx/paragon';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';

const PrequerySearchSuggestionItem = ({
url, hit, optimizelyPrequerySuggestionClickHandler,
}) => (
<Link
to={url}
key={hit.title}
className="prequery-item pr-4 d-flex flex-column"
onClick={() => optimizelyPrequerySuggestionClickHandler(hit.key)}
>
<div className="d-flex align-items-center justify-content-start">
<Image className="prequery-image mr-2" src={hit.card_image_url} />
<div className="d-flex flex-column">
{/* eslint-disable-next-line react/no-danger, no-underscore-dangle */}
<div dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }} />
<div className="x-small d-flex">
<span>
{hit.partners[0]?.name}
</span>
<span> | </span>
<span className="text-capitalize">{hit.learning_type}</span>
</div>
</div>
</div>
</Link>
);

PrequerySearchSuggestionItem.propTypes = {
url: PropTypes.string.isRequired,
hit: PropTypes.shape({
key: PropTypes.string,
title: PropTypes.string,
_highlightResult: PropTypes.shape({ title: PropTypes.shape({ value: PropTypes.string }) }),
card_image_url: PropTypes.string,
partners: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string,
}),
),
learning_type: PropTypes.string,
}).isRequired,
optimizelyPrequerySuggestionClickHandler: PropTypes.func.isRequired,
};

export default PrequerySearchSuggestionItem;
4 changes: 4 additions & 0 deletions packages/catalog-search/src/SearchBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const SearchBoxBase = ({
suggestionSubmitOverride,
disableSuggestionRedirect,
isPreQueryEnabled,
optimizelyPrequerySuggestionClickHandler,
}) => {
const { dispatch, trackingName } = useContext(SearchContext);

Expand Down Expand Up @@ -189,6 +190,7 @@ export const SearchBoxBase = ({
handleSubmit={() => handleSubmit(searchQuery)}
handleSuggestionClickSubmit={hit => handleSuggestionSubmit(hit)}
disableSuggestionRedirect={disableSuggestionRedirect}
optimizelyPrequerySuggestionClickHandler={optimizelyPrequerySuggestionClickHandler}
/>
)}
</div>
Expand All @@ -207,6 +209,7 @@ SearchBoxBase.propTypes = {
suggestionSubmitOverride: PropTypes.func,
disableSuggestionRedirect: PropTypes.bool,
isPreQueryEnabled: PropTypes.bool,
optimizelyPrequerySuggestionClickHandler: PropTypes.func,
};

SearchBoxBase.defaultProps = {
Expand All @@ -221,6 +224,7 @@ SearchBoxBase.defaultProps = {
suggestionSubmitOverride: undefined,
disableSuggestionRedirect: false,
isPreQueryEnabled: false,
optimizelyPrequerySuggestionClickHandler: undefined,
};

export default connectSearchBox(SearchBoxBase);
4 changes: 4 additions & 0 deletions packages/catalog-search/src/SearchHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const SearchHeader = ({
suggestionSubmitOverride,
enterpriseConfig: { slug, enablePathways, enterpriseFeatures },
disableSuggestionRedirect,
optimizelyPrequerySuggestionClickHandler,
}) => {
const { refinements } = useContext(SearchContext);
let searchQueryFromRefinements;
Expand Down Expand Up @@ -58,6 +59,7 @@ const SearchHeader = ({
suggestionSubmitOverride={suggestionSubmitOverride}
disableSuggestionRedirect={disableSuggestionRedirect}
isPreQueryEnabled={enterpriseFeatures.featurePrequerySearchSuggestions}
optimizelyPrequerySuggestionClickHandler={optimizelyPrequerySuggestionClickHandler}
/>
</Col>
<Col
Expand All @@ -83,6 +85,7 @@ SearchHeader.defaultProps = {
suggestionSubmitOverride: undefined,
disableSuggestionRedirect: false,
index: undefined,
optimizelyPrequerySuggestionClickHandler: undefined,
};

SearchHeader.propTypes = {
Expand All @@ -103,6 +106,7 @@ SearchHeader.propTypes = {
),
suggestionSubmitOverride: PropTypes.func,
disableSuggestionRedirect: PropTypes.bool,
optimizelyPrequerySuggestionClickHandler: PropTypes.func,
};

export default SearchHeader;
64 changes: 20 additions & 44 deletions packages/catalog-search/src/SearchSuggestionItem.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import { Image } from '@openedx/paragon';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';

const SearchSuggestionItem = ({
url, suggestionItemHandler, hit, disableSuggestionRedirect, isPreQuery,
url, suggestionItemHandler, hit, disableSuggestionRedirect,
}) => {
const authoringOrganization = hit.key && hit.key.split('+')[0];
// If the disable redirect bool is provided, prevent the redirect from happening and instead call the provided submit
Expand All @@ -16,47 +15,26 @@ const SearchSuggestionItem = ({
}
};
return (
<div>
{isPreQuery ? (
<Link to={url} key={hit.title} className="prequery-item pr-4 d-flex flex-column" onClick={handleLinkDisable}>
<div className="d-flex align-items-center justify-content-start">
<Image className="prequery-image mr-2" src={hit.card_image_url} />
<div className="d-flex flex-column">
{/* eslint-disable-next-line react/no-danger, no-underscore-dangle */}
<div dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }} />
<div className="x-small d-flex">
<span>
{hit.partners[0]?.name}
</span>
<span> | </span>
<span className="text-capitalize">{hit.learning_type}</span>
</div>
<Link to={url} key={hit.title} className="suggestion-item" onClick={handleLinkDisable}>
<div>
{ /* eslint-disable-next-line react/no-danger, no-underscore-dangle */}
<div dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }} />
{
authoringOrganization && (
<div className="badge badge-light ml-3 font-weight-light authoring-org-badge">
{authoringOrganization}
</div>
</div>
</Link>
) : (
<Link to={url} key={hit.title} className="suggestion-item" onClick={handleLinkDisable}>
<div>
{ /* eslint-disable-next-line react/no-danger, no-underscore-dangle */}
<div dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }} />
{
authoringOrganization && (
<div className="badge badge-light ml-3 font-weight-light authoring-org-badge">
{authoringOrganization}
</div>
)
}
</div>
{
hit.program_type && (
<p className="font-weight-light text-gray-400 program-type">
{hit.program_type}
</p>
)
}
</Link>
)}
</div>
)
}
</div>
{
hit.program_type && (
<p className="font-weight-light text-gray-400 program-type">
{hit.program_type}
</p>
)
}
</Link>
);
};

Expand All @@ -77,12 +55,10 @@ SearchSuggestionItem.propTypes = {
learning_type: PropTypes.string,
}).isRequired,
disableSuggestionRedirect: PropTypes.bool.isRequired,
isPreQuery: PropTypes.bool,
};

SearchSuggestionItem.defaultProps = {
suggestionItemHandler: undefined,
isPreQuery: false,
};

export default SearchSuggestionItem;
14 changes: 7 additions & 7 deletions packages/catalog-search/src/SearchSuggestions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
LEARNING_TYPE_EXECUTIVE_EDUCATION, COURSE_TYPE_EXECUTIVE_EDUCATION,
MAX_NUM_PRE_QUERY_SUGGESTIONS,
} from './data/constants';
import PrequerySearchSuggestionItem from './PrequerySearchSuggestionItem';
import SearchSuggestionItem from './SearchSuggestionItem';

const SearchSuggestions = ({
Expand All @@ -15,6 +16,7 @@ const SearchSuggestions = ({
handleSubmit,
handleSuggestionClickSubmit,
disableSuggestionRedirect,
optimizelyPrequerySuggestionClickHandler,
}) => {
const getLinkToCourse = (course) => {
const { learning_type: learningType } = course;
Expand Down Expand Up @@ -59,15 +61,12 @@ const SearchSuggestions = ({
}
return getLinkToProgram(course);
};

return (
<SearchSuggestionItem
key={hit.title}
<PrequerySearchSuggestionItem
key={hit.key}
url={getUrl(hit)}
hit={hit}
isPreQuery={preQuerySuggestions.length > 0}
disableSuggestionRedirect={disableSuggestionRedirect}
suggestionItemHandler={handleSuggestionClickSubmit}
optimizelyPrequerySuggestionClickHandler={optimizelyPrequerySuggestionClickHandler}
/>
);
})
Expand All @@ -86,7 +85,6 @@ const SearchSuggestions = ({
key={hit.title}
url={getLinkToCourse(hit)}
hit={hit}
isPreQuery={preQuerySuggestions.length > 0}
disableSuggestionRedirect={disableSuggestionRedirect}
suggestionItemHandler={handleSuggestionClickSubmit}
/>
Expand Down Expand Up @@ -150,6 +148,7 @@ SearchSuggestions.propTypes = {
handleSuggestionClickSubmit: PropTypes.func,
disableSuggestionRedirect: PropTypes.bool,
preQueryHits: PropTypes.arrayOf(PropTypes.shape()),
optimizelyPrequerySuggestionClickHandler: PropTypes.func,
};

SearchSuggestions.defaultProps = {
Expand All @@ -158,6 +157,7 @@ SearchSuggestions.defaultProps = {
handleSuggestionClickSubmit: undefined,
disableSuggestionRedirect: false,
preQueryHits: undefined,
optimizelyPrequerySuggestionClickHandler: undefined,
};

export default SearchSuggestions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { renderWithRouter } from '@edx/frontend-enterprise-utils';
import React from 'react';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect';
import PrequerySearchSuggestionItem from '../PrequerySearchSuggestionItem';

describe('<PrequerySearchSuggestionItem />', () => {
test('sends optimizely event on prequery click', () => {
const mockData = {
url: '/test-enterprise/course/edX+courseX',
optimizelyPrequerySuggestionClickHandler: jest.fn(),
hit: {
partners: [{
name: 'edX',
}],
learning_type: 'course',
content_type: 'course',
card_image_url: 'url.com',
key: 'edX+courseX',
title: 'basket weaving',
_highlightResult: { title: { value: 'basket weaving' } },
},
};

renderWithRouter(<PrequerySearchSuggestionItem
url={mockData.url}
optimizelyPrequerySuggestionClickHandler={mockData.optimizelyPrequerySuggestionClickHandler}
hit={mockData.hit}
/>);
expect(screen.getByRole('link', { name: 'basket weaving edX | course' }))
.toHaveAttribute('href', '/test-enterprise/course/edX+courseX');
userEvent.click(screen.getByText('basket weaving'));
expect(mockData.optimizelyPrequerySuggestionClickHandler.mock.calls.length).toBe(1);
});
});

0 comments on commit 5705327

Please sign in to comment.