ETHReport/components/browseArchives/index.js

308 lines
8.6 KiB
JavaScript
Raw Normal View History

import React from 'react';
2018-07-09 14:29:57 +00:00
import _ from 'lodash';
2018-07-06 12:36:22 +00:00
import RelatedInterviewsList from '../interviews/relatedInterviewsList';
import InterviewsList from '../interviews/interviewsList';
import SingleInterview from '../interviews/singleInterview';
import TopicsList from '../topicsList';
import ProjectsList from '../projectsList';
import SearchBar from '../searchBar';
import SearchResults from '../searchResults';
2018-07-16 15:13:29 +00:00
import { InterviewsData, Questions } from '../../data/archives/interviews';
import './style.scss';
class BrowseArchives extends React.Component {
constructor(props) {
super(props);
this.state = {
term: '',
2018-07-13 10:43:51 +00:00
debounceTerm: '',
2018-07-18 10:34:35 +00:00
searchResults: [],
isSingleInterviewModalOpen: false,
isInterviewsListModalOpen: false,
activeSingleInterviewId: 1,
isSearchActive: false,
2018-07-13 09:11:32 +00:00
interviewData: this.transformInterviews(InterviewsData),
2018-07-18 10:34:35 +00:00
matchedCount: 0,
};
2018-07-06 13:49:24 +00:00
2018-07-09 14:29:57 +00:00
this.onSearchInputChange = this.onSearchInputChange.bind(this);
this.toggleSingleInterview = this.toggleSingleInterview.bind(this);
this.toggleInterviewsListModal = this.toggleInterviewsListModal.bind(this);
2018-07-09 14:29:57 +00:00
this.setSearchTerm = this.setSearchTerm.bind(this);
this.clearSearchInput = this.clearSearchInput.bind(this);
2018-07-13 09:11:32 +00:00
this.transformInterviews = this.transformInterviews.bind(this);
this.termIsInInterview = this.termIsInInterview.bind(this);
this.getSearchResultsDebounce = this.getSearchResultsDebounce.bind(this);
}
2018-07-09 14:29:57 +00:00
onSearchInputChange = (event) => {
this.setState({
term: event.target.value,
isSearchActive: true,
2018-07-18 10:34:35 +00:00
searchResults: [],
});
if (event.target.value.length === 0) {
2018-07-06 12:36:22 +00:00
this.setState({ isSearchActive: false });
}
2018-07-09 14:29:57 +00:00
// Throttle search result frequency with debounce while typing
2018-07-13 09:11:32 +00:00
this.getSearchResultsDebounce();
}
2018-07-09 14:29:57 +00:00
getSearchResults = (term) => {
2018-07-13 09:11:32 +00:00
const { interviewData } = this.state;
const searchResults = interviewData.reduce((filtered, interview) => {
const findTerm = this.termIsInInterview(term, interview);
const matchedIndex = findTerm.foundIndex;
2018-07-17 15:34:40 +00:00
const { matchingQuestionAnswerPositions } = findTerm;
2018-07-18 10:13:04 +00:00
const { matchCount } = findTerm;
2018-07-13 09:11:32 +00:00
if (findTerm.found) {
2018-07-18 10:13:04 +00:00
filtered.push({
...interview,
matchedIndex,
matchingQuestionAnswerPositions,
matchCount,
});
2018-07-13 09:11:32 +00:00
}
return filtered;
}, []);
2018-07-18 10:34:35 +00:00
const matchedCount = searchResults
.reduce((accumulator, match) => accumulator + match.matchCount, 0);
2018-07-09 14:29:57 +00:00
this.setState({
2018-07-13 09:11:32 +00:00
searchResults,
2018-07-13 11:25:13 +00:00
debounceTerm: term,
2018-07-18 10:34:35 +00:00
matchedCount,
2018-07-09 14:29:57 +00:00
});
}
getSelectedInterview = () => {
2018-07-13 10:43:51 +00:00
const { activeSingleInterviewId, interviewData } = this.state;
const selectedInterview = interviewData
2018-07-13 09:11:32 +00:00
.find(item => item.id === activeSingleInterviewId);
2018-07-06 12:36:22 +00:00
return selectedInterview;
}
2018-07-09 14:29:57 +00:00
setSearchTerm = (event) => {
this.setState({
term: event.target.innerText,
isSearchActive: true,
});
2018-07-13 09:11:32 +00:00
this.getSearchResults(event.target.innerText);
2018-07-09 14:29:57 +00:00
}
2018-07-13 09:11:32 +00:00
getSearchResultsDebounce = _.debounce(() => {
const { term } = this.state;
this.getSearchResults(term);
}, 700);
2018-07-09 14:29:57 +00:00
clearSearchInput = () => {
this.setState({
isSearchActive: false,
term: '',
2018-07-18 10:34:35 +00:00
matchedCount: 0,
searchResults: [],
2018-07-09 14:29:57 +00:00
});
}
2018-07-13 09:11:32 +00:00
transformInterviews = (interviews) => {
2018-07-18 10:16:40 +00:00
const { length } = Object.keys(interviews);
2018-07-13 09:11:32 +00:00
const betterInterviews = [];
for (let i = 0; i < length; i++) {
const interview = interviews[i];
const qKeys = Object.keys(interview);
const interviewFormatted = [];
qKeys.forEach((key, index) => {
2018-07-16 07:39:44 +00:00
if (key !== 'Name' && interview[key] !== null) {
2018-07-13 09:11:32 +00:00
interviewFormatted.push({
question: index,
answer: interview[key],
});
}
});
betterInterviews.push({
2018-07-16 07:39:44 +00:00
id: i + 1,
2018-07-13 09:11:32 +00:00
tags: 'tag1, tag2, tag3',
name: interview.Name,
matchedIndex: -1,
interview: interviewFormatted,
});
}
return betterInterviews;
}
2018-07-09 14:29:57 +00:00
toggleInterviewsListModal = () => {
const { isInterviewsListModalOpen } = this.state;
2018-07-06 13:49:24 +00:00
this.setState({
isInterviewsListModalOpen: !isInterviewsListModalOpen,
isSingleInterviewModalOpen: false,
});
}
2018-07-09 14:29:57 +00:00
toggleSingleInterview = (event) => {
const { isSingleInterviewModalOpen, isInterviewsListModalOpen } = this.state;
2018-07-06 13:49:24 +00:00
2018-07-09 14:29:57 +00:00
let clickedInterview = event.target;
while (clickedInterview.id === '') {
clickedInterview = clickedInterview.parentNode;
}
const clickedSingleInterviewId = clickedInterview.id;
this.setState({
isInterviewsListModalOpen: !isInterviewsListModalOpen,
isSingleInterviewModalOpen: !isSingleInterviewModalOpen,
2018-07-09 14:29:57 +00:00
activeSingleInterviewId: Number(clickedSingleInterviewId),
});
}
2018-07-13 09:11:32 +00:00
termIsInInterview = (term, interview) => {
const lcTerm = term.toLowerCase();
const matchesName = interview.name.toLowerCase().includes(lcTerm);
let foundIndex = 0;
2018-07-17 15:34:40 +00:00
let positionInAnswer = -1;
2018-07-13 09:11:32 +00:00
if (matchesName) {
return {
found: true,
foundIndex: 0,
2018-07-18 10:13:04 +00:00
matchCount: 0,
2018-07-13 09:11:32 +00:00
};
}
const matchesTag = interview.tags.toLowerCase().indexOf(lcTerm) !== -1;
if (matchesTag) {
return {
found: true,
foundIndex: 0,
2018-07-18 10:13:04 +00:00
matchCount: 0,
2018-07-13 09:11:32 +00:00
};
}
2018-07-17 15:34:40 +00:00
const matchingQuestionAnswerPositions = [];
2018-07-13 09:11:32 +00:00
const matchingQuestions = interview.interview
.filter((question, questionIndex) => {
if (question.answer === null) {
return false;
}
const index = question.answer.toLowerCase().indexOf(lcTerm);
if (index !== -1 && interview.activeIndex !== -1) {
2018-07-18 10:13:04 +00:00
const cleanTerm = term.replace(/[^a-zA-Z 0-9]+/g, '');
const regex = new RegExp(cleanTerm, 'ig');
const count = question.answer.match(regex).length;
2018-07-13 09:11:32 +00:00
foundIndex = questionIndex;
2018-07-17 15:34:40 +00:00
positionInAnswer = index;
2018-07-17 15:35:04 +00:00
matchingQuestionAnswerPositions.push({
2018-07-17 15:34:40 +00:00
id: question.question,
strpos: index,
answer: question.answer,
index: questionIndex,
2018-07-18 10:13:04 +00:00
count,
2018-07-17 15:34:40 +00:00
});
2018-07-13 09:11:32 +00:00
}
return index !== -1;
});
2018-07-18 10:13:04 +00:00
const matchCount = matchingQuestionAnswerPositions
.reduce((accumulator, match) => accumulator + match.count, 0);
2018-07-13 09:11:32 +00:00
if (matchingQuestions.length > 0) {
return {
found: true,
foundIndex,
2018-07-17 15:34:40 +00:00
positionInAnswer,
matchingQuestionAnswerPositions,
2018-07-18 10:13:04 +00:00
matchCount,
2018-07-13 09:11:32 +00:00
};
}
return false;
}
render() {
2018-07-06 12:36:22 +00:00
const {
isSingleInterviewModalOpen,
isInterviewsListModalOpen,
isSearchActive,
activeSingleInterviewId,
term,
2018-07-09 14:29:57 +00:00
searchResults,
2018-07-13 10:43:51 +00:00
interviewData,
debounceTerm,
2018-07-18 10:34:35 +00:00
matchedCount,
2018-07-06 12:36:22 +00:00
} = this.state;
return (
2018-07-10 12:32:06 +00:00
<div className="browse-wrap" id="browse">
2018-07-09 14:29:57 +00:00
<SearchBar
onSearchInputChange={this.onSearchInputChange}
clearSearchInput={this.clearSearchInput}
isSearchActive={isSearchActive}
term={term}
2018-07-18 10:34:35 +00:00
numResults={searchResults.length}
numMatchedTerms={matchedCount}
2018-07-09 14:29:57 +00:00
/>
<div className="browse-content-wrap container">
<div className="browse-content-left">
2018-07-06 12:36:22 +00:00
{isSearchActive &&
(<RelatedInterviewsList
2018-07-13 12:02:09 +00:00
data={searchResults}
2018-07-06 12:36:22 +00:00
toggleSingleInterview={this.toggleSingleInterview}
/>)
}
</div>
<div className="browse-content-right">
2018-07-09 14:29:57 +00:00
{isSearchActive ? (
<SearchResults
data={searchResults}
2018-07-13 09:11:32 +00:00
questions={Questions}
2018-07-13 10:43:51 +00:00
term={debounceTerm}
2018-07-09 14:29:57 +00:00
toggleSingleInterview={this.toggleSingleInterview}
/>) :
2018-07-06 12:36:22 +00:00
(
<React.Fragment>
<InterviewsList
2018-07-13 10:43:51 +00:00
data={interviewData}
isInterviewsListModalOpen={isInterviewsListModalOpen}
toggleSingleInterview={this.toggleSingleInterview}
toggleInterviewsListModal={this.toggleInterviewsListModal}
/>
2018-07-09 14:29:57 +00:00
<TopicsList setSearchTerm={this.setSearchTerm} />
<ProjectsList setSearchTerm={this.setSearchTerm} />
</React.Fragment>
)
}
</div>
{isSingleInterviewModalOpen &&
(<SingleInterview
activeSingleInterviewId={activeSingleInterviewId}
selectedInterview={this.getSelectedInterview()}
toggleSingleInterview={this.toggleSingleInterview}
2018-07-13 09:11:32 +00:00
questions={Questions}
/>)
}
</div>
</div>
);
}
}
export default BrowseArchives;