Skip to content

Commit

Permalink
Extend Component class instead of using x-interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-searle committed Jan 24, 2019
1 parent 1b94528 commit 538ee25
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 81 deletions.
1 change: 0 additions & 1 deletion components/x-topic-search/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"dependencies": {
"@financial-times/x-engine": "file:../../packages/x-engine",
"@financial-times/x-follow-button": "0.0.11",
"@financial-times/x-interaction": "^1.0.0-beta.6",
"classnames": "^2.2.6",
"debounce-promise": "^3.1.0"
},
Expand Down
10 changes: 5 additions & 5 deletions components/x-topic-search/src/ResultContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,24 @@ const arrayToSentence = followedSuggestions => {
};


export default ({ result, searchTerm, csrfToken, followedTopicIds }) => {
export default ({ followedSuggestions, searchTerm, csrfToken, followedTopicIds, unfollowedSuggestions }) => {

const hasFollowedSuggestions = result.followedSuggestions.length > 0;
const hasUnfollowedSuggestions = result.unfollowedSuggestions.length > 0;
const hasFollowedSuggestions = followedSuggestions.length > 0;
const hasUnfollowedSuggestions = unfollowedSuggestions.length > 0;

return (
<div className={ classNames(styles['result-container']) } data-component="topic-search">

{ hasUnfollowedSuggestions &&
<SuggestionList
suggestions={ result.unfollowedSuggestions }
suggestions={ unfollowedSuggestions }
searchTerm={ searchTerm }
csrfToken={ csrfToken }
followedTopicIds={ followedTopicIds }/> }

{ !hasUnfollowedSuggestions && hasFollowedSuggestions &&
<div className={ classNames(styles["all-followed"]) } aria-live="polite">
You already follow { arrayToSentence(result.followedSuggestions) }
You already follow { arrayToSentence(followedSuggestions) }
</div> }

{ !hasUnfollowedSuggestions && !hasFollowedSuggestions &&
Expand Down
154 changes: 79 additions & 75 deletions components/x-topic-search/src/TopicSearch.jsx
Original file line number Diff line number Diff line change
@@ -1,95 +1,99 @@
import { h } from '@financial-times/x-engine';
import { withActions } from '@financial-times/x-interaction';
import { h, Component } from '@financial-times/x-engine';
import styles from './TopicSearch.scss';
import classNames from 'classnames';
import getSuggestions from './lib/get-suggestions.js';
import debounce from 'debounce-promise';

import ResultContainer from './ResultContainer';

const debounceGetSuggestions = debounce(getSuggestions, 150);
class TopicSearch extends Component {
constructor(props) {
super(props);

this.minSearchLength = props.minSearchLength || 2;
this.maxSuggestions = props.maxSuggestions || 5;
this.apiUrl = props.apiUrl;
this.getSuggestions = debounce(getSuggestions, 150);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleInputClickOrFocus = this.handleInputClickOrFocus.bind(this);

this.state = {
followedTopicIds: [],
searchTerm: '',
showResult: false,
followedSuggestions: [],
unFollowedSuggestions: []
};
}

let resultExists = false;
handleInputChange(event) {
const searchTerm = event.target.value.trim();

const topicSearchActions = withActions(({ minSearchLength = 2, maxSuggestions = 5, apiUrl, followedTopicIds = [] }) => ({
async checkInput(event) {
const searchTerm = event.target.value && event.target.value.trim();
this.setState({ searchTerm });

if (searchTerm.length >= minSearchLength) {
return debounceGetSuggestions(searchTerm, maxSuggestions, apiUrl, followedTopicIds)
.then(result => {
resultExists = true;
return { showResult: true, result, searchTerm };
if (searchTerm.length >= this.minSearchLength) {
this.getSuggestions(searchTerm, this.maxSuggestions, this.apiUrl, this.state.followedTopicIds)
.then(({ followedSuggestions, unfollowedSuggestions }) => {
this.setState({
followedSuggestions,
unfollowedSuggestions,
showResult: true
});
})
.catch(() => {
resultExists = false;
return { showResult: false };
this.setState({
showResult: false
});
});
} else {
resultExists = false;
return Promise.resolve({ showResult: false });
}
},

topicFollowed (subjectId) {
if (!followedTopicIds.includes(subjectId)) {
followedTopicIds.push(subjectId);
}

return { followedTopicIds };
},

topicUnfollowed (subjectId) {
const targetIdIndex = followedTopicIds.indexOf(subjectId);

if (targetIdIndex > -1) {
followedTopicIds.splice(targetIdIndex, 1);
this.setState({
showResult: false
});
}

return { followedTopicIds };
},

selectInput (event) {
event.target.select();
return { showResult: resultExists };
},

hideResult() {
return { showResult: false };
}
}));

const TopicSearch = topicSearchActions(({ searchTerm, showResult, result, actions, isLoading, csrfToken, followedTopicIds }) => (
<div className={ classNames(styles['container']) }>
<h2 className="o-normalise-visually-hidden">
Search for topics, authors, companies, or other areas of interest
</h2>

<label className="o-normalise-visually-hidden" htmlFor="topic-search-input">
Search and add topics
</label>
<div className={ classNames(styles["input-wrapper"]) }>
<i className={ classNames(styles["search-icon"]) }/>
<input
type="search"
id="topic-search-input"
placeholder="Search and add topics"
className={ classNames(styles["input"]) }
data-trackable="topic-search"
autoComplete="off"
onInput={ actions.checkInput }
onClick={ actions.selectInput }
onFocus={ actions.selectInput }/>
</div>

{ showResult && !isLoading &&
<ResultContainer
result={ result }
searchTerm={ searchTerm }
csrfToken={ csrfToken }
followedTopicIds={ followedTopicIds }/> }
handleInputClickOrFocus() {
console.log('handleInputClickOrFocus');
// this.setState({
// showResult: true
// });
}

</div>
));
render() {
const { csrfToken, followedSuggestions, followedTopicIds, isLoading, searchTerm, showResult, unfollowedSuggestions } = this.state;

return (
<div className={ classNames(styles['container']) }>
<h2 className="o-normalise-visually-hidden">
Search for topics, authors, companies, or other areas of interest
</h2>

<label className="o-normalise-visually-hidden" htmlFor="topic-search-input">Search and add topics</label>
<div className={ classNames(styles["input-wrapper"]) }>
<i className={ classNames(styles["search-icon"]) }/>
<input
type="search"
id="topic-search-input"
placeholder="Search and add topics"
className={ classNames(styles["input"]) }
data-trackable="topic-search"
autoComplete="off"
onInput={this.handleInputChange}
onClick={this.handleInputClickOrFocus}
onFocus={this.handleInputClickOrFocus}
/>
</div>

{ showResult && !isLoading &&
<ResultContainer
followedSuggestions={ followedSuggestions }
unfollowedSuggestions={ unfollowedSuggestions }
searchTerm={ searchTerm }
csrfToken={ csrfToken }
followedTopicIds={ followedTopicIds }/> }
</div>
);
}
}

export { TopicSearch };

0 comments on commit 538ee25

Please sign in to comment.