Merge pull request #14 from RandellDawson/feat/create-search-component

[feature] created Search component
This commit is contained in:
Honman Yau
2018-11-30 13:56:43 +11:00
committed by mrugesh mohapatra
parent c1c1154bc3
commit db0fd603a5
7 changed files with 103 additions and 72 deletions

View File

@ -2,8 +2,7 @@ import React, { Component } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import Tabs from './components/Tabs'; import Tabs from './components/Tabs';
import Input from './components/Input'; import Search from './components/Search';
import Results from './components/Results';
import Pareto from './components/Pareto'; import Pareto from './components/Pareto';
const Container = styled.div` const Container = styled.div`
@ -11,79 +10,34 @@ const Container = styled.div`
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
max-width: 960px;
width: 90vw;
padding: 15px; padding: 15px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0 0 4px 0 #777; box-shadow: 0 0 4px 0 #777;
`; `;
class App extends Component { class App extends Component {
state = { state = {
number: '',
foundPRs: [],
pareto: [],
view: 'search' view: 'search'
}; };
clearObj = { number: '', foundPRs: [] };
inputRef = React.createRef();
handleInputEvent = (event) => {
const { type, key, target: { value } } = event;
if (type === 'change') {
if (Number(value) || value === '') {
this.setState((prevState) => ({ number: value, foundPRs: [] }));
}
}
else if (type === 'keypress' && key === 'Enter') {
this.searchPRs(value);
}
}
handleButtonClick = () => {
const { number } = this.state;
this.searchPRs(number);
}
searchPRs = (number) => {
fetch(`https://pr-relations.glitch.me/pr/${number}`)
.then((response) => response.json())
.then(({ ok, foundPRs }) => {
if (ok) {
if (!foundPRs.length) {
foundPRs.push({ number: 'No PRs with matching files', filenames: [] });
}
this.setState((prevState) => ({ foundPRs }));
}
else {
this.inputRef.current.focus();
}
})
.catch(() => {
this.setState((prevState) => (this.clearObj));
});
}
handleViewChange = ( { target: { id } }) => { handleViewChange = ( { target: { id } }) => {
const view = id.replace('tabs-', ''); const view = id.replace('tabs-', '');
this.setState((prevState) => ({ ...this.clearObj, view })); this.setState((prevState) => ({ ...this.clearObj, view }));
} }
render() { render() {
const { handleButtonClick, handleViewChange, handleInputEvent, inputRef, state } = this; const { handleViewChange, state: { view } } = this;
const { number, foundPRs, view } = state;
return ( return (
<Container> <>
<Tabs view={view} onViewChange={handleViewChange}/> <Tabs view={view} onViewChange={handleViewChange}/>
<Input ref={inputRef} value={number} onInputEvent={handleInputEvent} /> <Container>
<button onClick={handleButtonClick}>Search</button> { view === 'search' && <Search /> }
{ view === 'search' && <Results foundPRs={foundPRs} /> } { view === 'reports' && <Pareto /> }
{ view === 'reports' && <Pareto /> } </Container>
</Container> </>
); );
} }
} }
export default App; export default App;

View File

@ -1,7 +1,12 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components';
const Container = styled.input`
margin-bottom: 10px;
`;
const Input = React.forwardRef((props, ref) => ( const Input = React.forwardRef((props, ref) => (
<input <Container
type="text" type="text"
placeholder="PR #" placeholder="PR #"
onChange={props.onInputEvent} onChange={props.onInputEvent}

View File

@ -54,7 +54,7 @@ class Pareto extends React.Component {
return ( return (
<div> <div>
{elements} {data.length ? elements : 'Report Loading...'}
</div> </div>
); );
} }

View File

@ -1,4 +1,9 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components';
const List = styled.ul`
margin: 5px;
`;
const Results = ({ foundPRs }) => { const Results = ({ foundPRs }) => {
const elements = foundPRs.map((foundPR) => { const elements = foundPRs.map((foundPR) => {
@ -10,18 +15,16 @@ const Results = ({ foundPRs }) => {
return ( return (
<div key={number}> <div key={number}>
<h5> {!Number(number)
{!Number(number) ? number
? number : <>
: <> <a href={prUrl} rel="noopener noreferrer" target="_blank">{number}</a>
<a href={prUrl} rel="noopener noreferrer" target="_blank">{number}</a> <span>&nbsp;{username}</span>
<span>&nbsp;{username}</span> </>
</> }
} <List>
</h5>
<ul>
{files} {files}
</ul> </List>
</div> </div>
); );
}); });

View File

@ -0,0 +1,66 @@
import React, { Component } from 'react';
import Input from './Input';
import Results from './Results';
class Search extends Component {
state = {
number: '',
foundPRs: [],
};
clearObj = { number: '', foundPRs: [] };
inputRef = React.createRef();
handleInputEvent = (event) => {
const { type, key, target: { value } } = event;
if (type === 'change') {
if (Number(value) || value === '') {
this.setState((prevState) => ({ number: value, foundPRs: [] }));
}
}
else if (type === 'keypress' && key === 'Enter') {
this.searchPRs(value);
}
}
handleButtonClick = () => {
const { number } = this.state;
this.searchPRs(number);
}
searchPRs = (number) => {
fetch(`https://pr-relations.glitch.me/pr/${number}`)
.then((response) => response.json())
.then(({ ok, foundPRs }) => {
if (ok) {
if (!foundPRs.length) {
foundPRs.push({ number: 'No PRs with matching files', filenames: [] });
}
this.setState((prevState) => ({ foundPRs }));
}
else {
this.inputRef.current.focus();
}
})
.catch(() => {
this.setState((prevState) => (this.clearObj));
});
}
render() {
const { handleButtonClick, handleInputEvent, inputRef, state } = this;
const { number, foundPRs } = state;
return (
<>
<Input ref={inputRef} value={number} onInputEvent={handleInputEvent} />
<button onClick={handleButtonClick}>Search</button>
<Results foundPRs={foundPRs} />
</>
);
}
}
export default Search;

View File

@ -5,6 +5,7 @@ const Container = styled.div`
display: flex; display: flex;
justify-content: center; justify-content: center;
height: 40px; height: 40px;
margin: 10px;
`; `;
const Tab = styled.div` const Tab = styled.div`
@ -14,10 +15,12 @@ const Tab = styled.div`
padding: 5px; padding: 5px;
border: 2px solid ${({ theme }) => theme.primary}; border: 2px solid ${({ theme }) => theme.primary};
border-left: none; border-left: none;
flex-basis: 200px;
text-align: center;
&:hover { &:hover {
cursor: pointer; cursor: pointer;
background: ${({ theme }) => theme.primary}; background: rgba(0, 0, 255, 0.8);
color: white; color: white;
} }
@ -30,7 +33,7 @@ const Tabs = ({ view, onViewChange }) => {
return ( return (
<Container> <Container>
<Tab id="tabs-search" onClick={onViewChange} active={view === 'search'}>Search</Tab> <Tab id="tabs-search" onClick={onViewChange} active={view === 'search'}>Search</Tab>
<Tab id="tabs-reports" onClick={onViewChange} active={view === 'reports'}>Reports</Tab> <Tab id="tabs-reports" onClick={onViewChange} active={view === 'reports'}>Pareto</Tab>
</Container> </Container>
); );
}; };

View File

@ -6,7 +6,7 @@ body {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
/* height: 100vh; */ min-height: 100vh;
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",