Skip to content

Commit

Permalink
Porting real-world-example
Browse files Browse the repository at this point in the history
  • Loading branch information
tomkis committed Feb 18, 2016
1 parent 6f4ebb9 commit c64fc8a
Show file tree
Hide file tree
Showing 25 changed files with 978 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/real-world/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["es2015", "stage-2", "react"]
}
11 changes: 11 additions & 0 deletions examples/real-world/dev/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>redux-saga-rxjs</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="/app.bundle.js"></script>
</body>
</html>
39 changes: 39 additions & 0 deletions examples/real-world/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "redux-saga-rxjs-example-real-world",
"version": "0.1.0",
"scripts": {
"start": "./node_modules/.bin/webpack-dev-server --config webpack.config.js --port 3000 --hot --content-base ./dev"
},
"devDependencies": {
"babel-cli": "^6.5.1",
"babel-core": "^6.5.2",
"babel-eslint": "^4.1.8",
"babel-loader": "^6.2.2",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-2": "^6.5.0",
"redux-devtools": "^3.1.1",
"redux-devtools-dock-monitor": "^1.0.1",
"redux-devtools-log-monitor": "^1.0.4",
"webpack": "^1.12.4",
"webpack-dev-server": "^1.12.1"
},
"dependencies": {
"babel-runtime": "^6.5.0",
"humps": "^1.0.0",
"isomorphic-fetch": "^2.2.1",
"lodash": "^4.0.0",
"normalizr": "^2.0.0",
"react": "^0.14.2",
"react-dom": "^0.14.2",
"react-redux": "^4.0.0",
"react-router": "^2.0.0",
"react-router-redux": "^4.0.0-rc.1",
"redux": "^3.0.4",
"redux-logger": "^2.5.2",
"redux-saga-rxjs": "^0.2.0",
"rxjs": "^5.0.0-beta.2"
},
"author": "Tomas Weiss <tomas.weiss2@gmail.com>",
"license": "MIT"
}
56 changes: 56 additions & 0 deletions examples/real-world/src/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export const USER_REQUEST = 'USER_REQUEST';
export const USER_SUCCESS = 'USER_SUCCESS';
export const USER_FAILURE = 'USER_FAILURE';

export function loadUser(login, requiredFields = []) {
return {
type: USER_REQUEST,
login,
requiredFields
};
}

export const REPO_REQUEST = 'REPO_REQUEST';
export const REPO_SUCCESS = 'REPO_SUCCESS';
export const REPO_FAILURE = 'REPO_FAILURE';

export function loadRepo(fullName, requiredFields = []) {
return {
type: REPO_REQUEST,
fullName,
requiredFields
};
}

export const STARRED_REQUEST = 'STARRED_REQUEST';
export const STARRED_SUCCESS = 'STARRED_SUCCESS';
export const STARRED_FAILURE = 'STARRED_FAILURE';

export function loadStarred(login, nextPage) {
return {
type: STARRED_REQUEST,
login,
nextPage
};
}

export const STARGAZERS_REQUEST = 'STARGAZERS_REQUEST';
export const STARGAZERS_SUCCESS = 'STARGAZERS_SUCCESS';
export const STARGAZERS_FAILURE = 'STARGAZERS_FAILURE';

export function loadStargazers(fullName, nextPage) {
return {
type: STARGAZERS_REQUEST,
fullName,
nextPage
};
}

export const RESET_ERROR_MESSAGE = 'RESET_ERROR_MESSAGE';

// Resets the currently visible error message.
export function resetErrorMessage() {
return {
type: RESET_ERROR_MESSAGE
};
}
65 changes: 65 additions & 0 deletions examples/real-world/src/components/Explore.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { Component, PropTypes } from 'react';

const GITHUB_REPO = 'https://github.com/rackt/redux';

export default class Explore extends Component {

constructor(props) {
super(props);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.handleGoClick = this.handleGoClick.bind(this);
}

componentWillReceiveProps(nextProps) {
if (nextProps.value !== this.props.value) {
this.setInputValue(nextProps.value);
}
}

getInputValue() {
return this.refs.input.value;
}

setInputValue(val) {
// Generally mutating DOM is a bad idea in React components,
// but doing this for a single uncontrolled field is less fuss
// than making it controlled and maintaining a state for it.
this.refs.input.value = val;
}

handleKeyUp(e) {
if (e.keyCode === 13) {
this.handleGoClick();
}
}

handleGoClick() {
this.props.onChange(this.getInputValue());
}

render() {
return (
<div>
<p>Type a username or repo full name and hit 'Go':</p>
<input size="45"
ref="input"
defaultValue={this.props.value}
onKeyUp={this.handleKeyUp} />
<button onClick={this.handleGoClick}>
Go!
</button>
<p>
Code on <a href={GITHUB_REPO} target="_blank">Github</a>.
</p>
<p>
Move the DevTools with Ctrl+W or hide them with Ctrl+H.
</p>
</div>
);
}
}

Explore.propTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
};
28 changes: 28 additions & 0 deletions examples/real-world/src/components/List.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

const renderLoadMore = (isFetching, onLoadMoreClick) => (
<button style={{ fontSize: '150%' }}
onClick={onLoadMoreClick}
disabled={isFetching}>
{isFetching ? 'Loading...' : 'Load More'}
</button>
);

export default ({ isFetching, nextPageUrl, pageCount, items, renderItem, loadingLabel, onLoadMoreClick }) => {
const isEmpty = items.length === 0;
if (isEmpty && isFetching) {
return <h2><i>{loadingLabel}</i></h2>;
}

const isLastPage = !nextPageUrl;
if (isEmpty && isLastPage) {
return <h1><i>Nothing here!</i></h1>;
}

return (
<div>
{items.map(renderItem)}
{pageCount > 0 && !isLastPage && renderLoadMore(isFetching, onLoadMoreClick)}
</div>
);
};
24 changes: 24 additions & 0 deletions examples/real-world/src/components/Repo.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { Link } from 'react-router';

export default ({ owner, repo }) => {
const { login } = owner;
const { name, description } = repo;

return (
<div className="Repo">
<h3>
<Link to={`/${login}/${name}`}>
{name}
</Link>
{' by '}
<Link to={`/${login}`}>
{login}
</Link>
</h3>
{description &&
<p>{description}</p>
}
</div>
);
};
17 changes: 17 additions & 0 deletions examples/real-world/src/components/User.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Link } from 'react-router';

export default ({ user }) => {
const { login, avatarUrl, name } = user;

return (
<div className="User">
<Link to={`/${login}`}>
<img src={avatarUrl} width="72" height="72" />
<h3>
{login} {name && <span>({name})</span>}
</h3>
</Link>
</div>
);
};
73 changes: 73 additions & 0 deletions examples/real-world/src/containers/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { hashHistory } from 'react-router';
import Explore from '../components/Explore';
import { resetErrorMessage } from '../actions';

class App extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleDismissClick = this.handleDismissClick.bind(this);
}

handleDismissClick(e) {
this.props.resetErrorMessage();
e.preventDefault();
}

handleChange(nextValue) {
hashHistory.push(`/${nextValue}`);
}

renderErrorMessage() {
const { errorMessage } = this.props;
if (!errorMessage) {
return null;
}

return (
<p style={{ backgroundColor: '#e99', padding: 10 }}>
<b>{errorMessage}</b>
{' '}
(<a href="#"
onClick={this.handleDismissClick}>
Dismiss
</a>)
</p>
);
}

render() {
const { children, inputValue } = this.props;
return (
<div>
<Explore value={inputValue}
onChange={this.handleChange} />
<hr />
{this.renderErrorMessage()}
{children}
</div>
);
}
}

App.propTypes = {
// Injected by React Redux
errorMessage: PropTypes.string,
resetErrorMessage: PropTypes.func.isRequired,
inputValue: PropTypes.string.isRequired,
// Injected by React Router
children: PropTypes.node
};

function mapStateToProps(state, ownProps) {
return {
errorMessage: state.errorMessage,
inputValue: ownProps.location.pathname.substring(1)
};
}

export default connect(mapStateToProps, {
resetErrorMessage
})(App);
11 changes: 11 additions & 0 deletions examples/real-world/src/containers/DevTools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { createDevTools } from 'redux-devtools';
import LogMonitor from 'redux-devtools-log-monitor';
import DockMonitor from 'redux-devtools-dock-monitor';

export default createDevTools(
<DockMonitor toggleVisibilityKey="ctrl-h"
changePositionKey="ctrl-w">
<LogMonitor />
</DockMonitor>
);
Loading

0 comments on commit c64fc8a

Please sign in to comment.