Skip to content

Commit c0ebee8

Browse files
committed
Initial commit. App working as expected.
0 parents  commit c0ebee8

19 files changed

+5740
-0
lines changed

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# See http://help.github.com/ignore-files/ for more about ignoring files.
2+
3+
# dependencies
4+
node_modules
5+
6+
# testing
7+
coverage
8+
9+
# production
10+
build
11+
12+
# misc
13+
.DS_Store
14+
.env
15+
npm-debug.log

package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "github-viewer",
3+
"version": "0.1.0",
4+
"private": true,
5+
"devDependencies": {
6+
"react-scripts": "0.8.5"
7+
},
8+
"dependencies": {
9+
"axios": "^0.15.3",
10+
"lodash": "^4.17.4",
11+
"react": "^15.4.2",
12+
"react-dom": "^15.4.2",
13+
"react-redux": "^5.0.2",
14+
"react-router": "^3.0.2",
15+
"react-router-redux": "^4.0.8",
16+
"redux": "^3.6.0",
17+
"redux-logger": "^2.8.2",
18+
"seamless-immutable": "^7.0.1"
19+
},
20+
"scripts": {
21+
"start": "react-scripts start",
22+
"build": "react-scripts build",
23+
"test": "react-scripts test --env=jsdom",
24+
"eject": "react-scripts eject"
25+
}
26+
}

public/favicon.ico

24.3 KB
Binary file not shown.

public/index.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
7+
<!--
8+
Notice the use of %PUBLIC_URL% in the tag above.
9+
It will be replaced with the URL of the `public` folder during the build.
10+
Only files inside the `public` folder can be referenced from the HTML.
11+
12+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
13+
work correctly both with client-side routing and a non-root public URL.
14+
Learn how to configure a non-root public URL by running `npm run build`.
15+
-->
16+
<title>React App</title>
17+
</head>
18+
<body>
19+
<div id="root"></div>
20+
<!--
21+
This HTML file is a template.
22+
If you open it directly in the browser, you will see an empty page.
23+
24+
You can add webfonts, meta tags, or analytics to this file.
25+
The build step will place the bundled scripts into the <body> tag.
26+
27+
To begin the development, run `npm start`.
28+
To create a production bundle, use `npm run build`.
29+
-->
30+
</body>
31+
</html>

src/AppContainer.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { connect } from 'react-redux';
2+
import { bindActionCreators } from 'redux';
3+
import { App } from './components';
4+
import { save, getProfiles } from './redux/reducer';
5+
6+
const mapStateToProps = state => ({
7+
profiles: getProfiles(state)
8+
});
9+
10+
const mapDispatchToProps = dispatch => bindActionCreators({
11+
save
12+
}, dispatch);
13+
14+
export default connect(
15+
mapStateToProps,
16+
mapDispatchToProps
17+
)(App);
18+

src/Root.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { Provider } from 'react-redux';
3+
import { Router, Route, hashHistory } from 'react-router';
4+
import AppContainer from './AppContainer';
5+
6+
export default function Root(props) {
7+
const { store } = props;
8+
console.log({ store });
9+
return (
10+
<Provider store={store}>
11+
<Router history={hashHistory}>
12+
<Route path="/" component={AppContainer} />
13+
</Router>
14+
</Provider>
15+
);
16+
}
17+
18+
/* eslint react/forbid-prop-types: 0 */
19+
Root.propTypes = {
20+
store: React.PropTypes.object.isRequired
21+
22+
};

src/components/App.css

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.App {
2+
text-align: center;
3+
}
4+
5+
.App-logo{
6+
height: 200px;
7+
}
8+
9+
.App-header {
10+
background-color: #222;
11+
height: 300px;
12+
padding: 20px;
13+
color: white;
14+
}
15+
16+
.App-intro {
17+
font-size: large;
18+
}
19+
20+
.col {
21+
width: 48%;
22+
display: inline-block;
23+
margin: 10px;
24+
vertical-align: top;
25+
}
26+
27+
a {
28+
cursor: pointer;
29+
}
30+
31+
a.info-holder:hover {
32+
background: #d6d6d6;
33+
}
34+
35+
.info-holder {
36+
width: 75%;
37+
margin: 25px auto;
38+
}
39+
40+
.info-box {
41+
text-align: left;
42+
background: #dddddd;
43+
border: 1px solid #cccccc;
44+
padding: 10px;
45+
font-size: 10px;
46+
font-weight: 300;
47+
}
48+

src/components/App.jsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React, { Component } from 'react';
2+
import InfoBox from './InfoBox';
3+
import _ from 'lodash';
4+
import logo from './logo.svg';
5+
import { getProfileData } from '../request';
6+
import './App.css';
7+
8+
class App extends Component {
9+
constructor(props) {
10+
super(props);
11+
this.state = {
12+
currentUser: {},
13+
input: ''
14+
}
15+
}
16+
handleChange = (event) => {
17+
const val = event.target.value;
18+
this.setState({ input: val });
19+
}
20+
getUser = async (e) => {
21+
e.preventDefault();
22+
const input = this.state.input;
23+
console.log(`Getting Data.... for ${input}`);
24+
const data = await getProfileData(input);
25+
this.props.save(data);
26+
this.setState({ currentUser: data });
27+
}
28+
handleProfileClick = (profile) => {
29+
this.setState({ currentUser: profile, input: profile.login });
30+
}
31+
render() {
32+
const { currentUser } = this.state;
33+
const { profiles } = this.props;
34+
return (
35+
<div className="App">
36+
<div className="App-header">
37+
<img src={currentUser.avatar_url || logo} className="App-logo" alt="logo" />
38+
<h2>{currentUser.name || 'Welcome to React'}</h2>
39+
<h4>{currentUser.bio || 'Prepare to be dazzled'}</h4>
40+
</div>
41+
<p className="App-intro">
42+
To get started, edit <code>src/App.js</code> and save to reload.
43+
</p>
44+
<form onSubmit={this.getUser}>
45+
<input value={this.state.input} onChange={this.handleChange}/>
46+
<button type="submit">Get Data!</button>
47+
</form>
48+
<div className="info-holder">
49+
<div>
50+
<div className="col">
51+
<h2>Current Profile</h2>
52+
</div>
53+
<div className="col">
54+
<h2>Searched Profiles</h2>
55+
</div>
56+
</div>
57+
<div className="col">
58+
{Object.keys(currentUser).map((key, index) => {
59+
return (<InfoBox key={index} keyName={key} value={currentUser[key]} />)
60+
})}
61+
</div>
62+
<div className="col">
63+
{_.map(profiles, (profile, index) => (
64+
<a key={index} onClick={() => this.handleProfileClick(profile)}>
65+
<InfoBox keyName={'User'} value={profile.login} />
66+
</a>
67+
))}
68+
</div>
69+
</div>
70+
</div>
71+
);
72+
}
73+
}
74+
75+
export default App;

src/components/App.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import App from './App';
4+
5+
it('renders without crashing', () => {
6+
const div = document.createElement('div');
7+
ReactDOM.render(<App />, div);
8+
});

src/components/InfoBox.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React, { Component } from 'react';
2+
3+
class InfoBox extends Component {
4+
render() {
5+
const { keyName, value } = this.props;
6+
return (
7+
<div className="info-box">
8+
<h3>{keyName}: {value}</h3>
9+
</div>
10+
)
11+
}
12+
}
13+
14+
export default InfoBox;

src/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as App } from './App.jsx';

src/components/logo.svg

Lines changed: 7 additions & 0 deletions
Loading

src/index.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
body {
2+
margin: 0;
3+
padding: 0;
4+
font-family: sans-serif;
5+
}

src/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import { render } from 'react-dom';
3+
import makeStore from './redux/makeStore';
4+
import Root from './Root.jsx';
5+
import './index.css';
6+
7+
const initialState = {
8+
profiles: []
9+
}
10+
11+
const store = makeStore(initialState);
12+
13+
render(<Root store={store} />, document.getElementById('root'));

src/redux/makeStore.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* globals __PRODUCTION__ */
2+
import { createStore, applyMiddleware, compose } from 'redux';
3+
import { routerMiddleware } from 'react-router-redux';
4+
import { hashHistory } from 'react-router';
5+
import reducer from './reducer';
6+
7+
export default function makeStore(initialState) {
8+
const createLogger = require('redux-logger');
9+
const logger = createLogger({
10+
level: 'info',
11+
collapsed: true
12+
});
13+
14+
const middlewares = [
15+
routerMiddleware(hashHistory),
16+
logger
17+
];
18+
19+
const mw = compose(
20+
applyMiddleware(...middlewares)
21+
);
22+
23+
const store = createStore(reducer, initialState, mw);
24+
window.store = store;
25+
26+
return store;
27+
}

src/redux/reducer.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import immutable from 'seamless-immutable';
2+
3+
const defaultState = immutable({
4+
profiles: []
5+
});
6+
7+
const SAVE = 'github-viewer/profiles/SAVE';
8+
9+
export default function reducer(state = defaultState, { type, ...payload } = {}) {
10+
switch (type) {
11+
case SAVE:
12+
console.log('STATE', state);
13+
const profiles = state.profiles;
14+
profiles.push(payload.profile);
15+
return { ...state, isFetching: false, profiles };
16+
17+
default: return state;
18+
}
19+
}
20+
21+
export function save(profile) {
22+
console.log('Saving...', profile);
23+
return { type: SAVE, profile };
24+
}
25+
26+
export const getProfiles = state => state.profiles;
27+

src/request.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import axios from 'axios';
2+
const apiUrl = 'https://api.github.com/users';
3+
4+
export function getProfileData(username) {
5+
return new Promise(async (resolve, reject) => {
6+
const { data } = await axios.get(`${apiUrl}/${username}`)
7+
resolve(data);
8+
})
9+
}
10+
11+
export default {
12+
getProfileData
13+
}

src/test.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Hello World
2+
===========
3+
4+
Writing a bit of *markdown*
5+
6+
```elixir
7+
def hello do
8+
IO.inspect "hello"
9+
end
10+
```

0 commit comments

Comments
 (0)