Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

superConnect like connect, but takes a runSideEffects function #11

Open
wants to merge 1 commit into
base: routed-email-app
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions components/EmailPreview.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'

class EmailPreview extends Component {

render() {
console.log("Rendering email preview");
const { email } = this.props;
Expand All @@ -29,4 +28,8 @@ const mapStateToProps = function(state, existingProps) {
}
}

export default connect(mapStateToProps)(EmailPreview);
const runSideEffects = function() {
dispatch(emailApp.actions.email.ensureFreshEmails());
}

export default superConnect(runSideEffects, mapStateToProps)(EmailPreview);
28 changes: 19 additions & 9 deletions components/Emails.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'

import MoveEmail from './MoveEmail'

class Emails extends Component {

render() {
const { emails, fetchedAt } = this.props;
return (
Expand All @@ -27,9 +26,9 @@ class Emails extends Component {
<tr key={email.id}>
<td>{email.subject}</td>
<td>{email.sender}</td>
<td>{email.folderName}</td>
<td>{email.folder ? email.folder.name : 'Missing...'}</td>
<td><button onClick={() => this.props.removeEmail(email.id)}>Delete</button></td>
<td><MoveEmail emailId={email.id}/></td>
<td><MoveEmail email={email}/></td>
</tr>
)
})
Expand All @@ -42,11 +41,17 @@ class Emails extends Component {
}

const mapStateToProps = function(state) {
const emailState = state.emailApp.emails;
let folders = state.emailApp.folders.folders;
let emails = emailState.emails;
if(emails && folders) {
emails = emails.map((email) => {
return Object.assign({}, email, { folder: folders.find((folder) => folder.id === email.folderId) });
});
}
return {
emails: state.emailApp.emails.emails.map((email) => {
return Object.assign({}, email, { folderName: state.emailApp.folders.folders.find((folder) => folder.id === email.folderId).name });
}),
fetchedAt: state.emailApp.emails.fetchedAt
emails: emails,
fetchedAt: emailState.fetchedAt
}
}

Expand All @@ -57,4 +62,9 @@ const mapDispatchToProps = function(dispatch) {
}
}

export default connect(mapStateToProps, mapDispatchToProps)(Emails);
const runSideEffects = function(state, dispatch) {
dispatch(emailApp.actions.folder.ensureFreshFolders());
dispatch(emailApp.actions.email.ensureFreshEmails());
}

export default superConnect(runSideEffects, mapStateToProps, mapDispatchToProps)(Emails);
83 changes: 46 additions & 37 deletions components/Folder.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,59 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'
import { Link } from 'react-router'
import emailApp from '../emailApp'
import * as actions from '../actions'
import MoveEmail from './MoveEmail'


class Folder extends Component {

render() {
const { emails, folder, fetchedAt } = this.props;
return (
<div>
<h1>{folder.name} (fetched at {fetchedAt}</h1><button onClick={this.props.fetchEmails}>Fetch</button>
<table>
<thead>
<tr>
<th>Subject</th>
<th>Sender</th>
<th>Delete</th>
<th>Move</th>
<th>Open</th>
</tr>
</thead>
<tbody>
{
emails.map((email) => {
return (
<tr key={email.id}>
<td><Link to={'/folder/' + folder.id + '/email/' + email.id}>{email.subject}</Link></td>
<td>{email.sender}</td>
<td><button onClick={() => this.props.removeEmail(email.id)}>Delete</button></td>
<td><MoveEmail emailId={email.id}/></td>
<td><button onClick={() => this.props.openEmail(email.id)}>Open</button></td>
</tr>
)
})
}
</tbody>
</table>
{this.props.children}
</div>
folder !== undefined && emails !== undefined ? (
<div>
<h1>{folder.name} (fetched at {fetchedAt})</h1><button onClick={this.props.fetchEmails}>Fetch</button>
<table>
<thead>
<tr>
<th>Subject</th>
<th>Sender</th>
<th>Delete</th>
<th>Move</th>
<th>Open</th>
</tr>
</thead>
<tbody>
{
emails.map((email) => {
return (
<tr key={email.id}>
<td><Link to={'/folder/' + folder.id + '/email/' + email.id}>{email.subject}</Link></td>
<td>{email.sender}</td>
<td><button onClick={() => this.props.removeEmail(email.id)}>Delete</button></td>
<td><MoveEmail email={email}/></td>
<td><button onClick={() => this.props.openEmail(email.id)}>Open</button></td>
</tr>
)
})
}
</tbody>
</table>
{this.props.children}
</div>
) : <p>Loading...</p>
)
}
}

const mapStateToProps = function(state, existingProps) {
const foldersState = state.emailApp.folders;
const emailsState = state.emailApp.emails;
const folder = foldersState.folders ? foldersState.folders.find((folder) => folder.id === existingProps.params.folderId) : undefined;
const emails = emailsState.emails ? emailsState.emails.filter((email) => email.folderId === existingProps.params.folderId) : undefined;
return {
folder: state.emailApp.folders.folders.find((folder) => folder.id === existingProps.params.folderId),
emails: state.emailApp.emails.emails.filter((email) => email.folderId === existingProps.params.folderId),
fetchedAt: state.emailApp.emails.fetchedAt
folder: folder,
emails: emails,
fetchedAt: emailsState.fetchedAt
}
}

Expand All @@ -61,4 +65,9 @@ const mapDispatchToProps = function(dispatch) {
}
}

export default connect(mapStateToProps, mapDispatchToProps)(Folder);
const runSideEffects = function(state, dispatch) {
dispatch(emailApp.actions.folder.ensureFreshFolders());
dispatch(emailApp.actions.email.ensureFreshEmails());
}

export default superConnect(runSideEffects, mapStateToProps, mapDispatchToProps)(Folder);
30 changes: 18 additions & 12 deletions components/Folders.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'

import AddFolder from './AddFolder'
import emailApp from '../emailApp'

class Folders extends Component {

render() {
const { folders } = this.props;
return (
<div>
<h1>Folders</h1>
<ul>
{ folders.map((folder) => <li key={folder.id}>{folder.name} - <button onClick={() => this.props.removeFolder(folder.id)}>Delete</button></li>) }
</ul>
<AddFolder/>
</div>
folders ? (
<div>
<h1>Folders</h1>
<ul>
{ folders.map((folder) => <li key={folder.id}>{folder.name} - <button onClick={() => this.props.removeFolder(folder.id)}>Delete</button></li>) }
</ul>
<AddFolder/>
</div>
) : <p>Loading...</p>
)
}
}

const mapStateToProps = function(state) {
const foldersState = state.emailApp.folders;
return {
folders: state.emailApp.folders.folders,
fetchedAt: state.emailApp.folders.fetchedAt
folders: foldersState.folders,
fetchedAt: foldersState.fetchedAt
}
}

Expand All @@ -33,4 +35,8 @@ const mapDispatchToProps = function(dispatch) {
}
}

export default connect(mapStateToProps, mapDispatchToProps)(Folders);
const runSideEffects = function(state, dispatch) {
dispatch(emailApp.actions.folder.ensureFreshFolders());
}

export default superConnect(runSideEffects, mapStateToProps, mapDispatchToProps)(Folders);
21 changes: 14 additions & 7 deletions components/MoveEmail.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'

import emailApp from '../emailApp'

Expand All @@ -25,7 +25,11 @@ class MoveEmail extends Component {
return (
<form onSubmit={(e) => this.submit(e)}>
<select onChange={(e) => this.updateSelectedFolder(e.target.value)} value={this.state.selectedFolderId}>
{ folders.map((folder) => <option key={folder.id} value={folder.id}>{folder.name}</option> )}
{
folders ? (
folders.map((folder) => <option key={folder.id} value={folder.id}>{folder.name}</option> )
) : null
}
</select>
<button type="submit">Move</button>
</form>
Expand All @@ -34,17 +38,20 @@ class MoveEmail extends Component {
}

const mapStateToProps = function(state, existingProps) {
const email = state.emailApp.emails.emails.find((email) => email.id === existingProps.emailId);
const foldersState = state.emailApp.folders;
return {
email: email,
folders: state.emailApp.folders.folders
folders: foldersState.folders
}
}

const mapDispatchToProps = function(dispatch, existingProps) {
return {
moveToFolder: (folderId) => dispatch(emailApp.actions.email.moveEmailToFolder(existingProps.emailId, folderId))
moveToFolder: (folderId) => dispatch(emailApp.actions.email.moveEmailToFolder(existingProps.email.id, folderId))
}
}

export default connect(mapStateToProps, mapDispatchToProps)(MoveEmail);
const runSideEffects = function(state, dispatch) {
dispatch(emailApp.actions.folder.ensureFreshFolders());
}

export default superConnect(runSideEffects, mapStateToProps, mapDispatchToProps)(MoveEmail);
10 changes: 8 additions & 2 deletions components/OpenEmail.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'

import emailApp from '../emailApp'

class OpenEmail extends Component {

Expand All @@ -20,4 +22,8 @@ const mapStateToProps = function(state, existingProps) {
}
}

export default connect(mapStateToProps)(OpenEmail);
const runSideEffects = function(state, dispatch) {
dispatch(emailApp.actions.email.ensureFreshEmails());
}

export default superConnect(runSideEffects, mapStateToProps)(OpenEmail);
23 changes: 16 additions & 7 deletions containers/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import superConnect from '../utils/superConnect'
import Folders from '../components/Folders'
import OpenEmails from '../components/OpenEmails.js';
import { Link } from 'react-router'

import emailApp from '../emailApp';


class App extends Component {
render() {
Expand All @@ -17,11 +19,13 @@ class App extends Component {
<Link to="/folders">Folders</Link>
<ul>
{
folders.map((folder) => {
return (
<li key={folder.id}><Link to={'/folder/' + folder.id}>{folder.name}</Link></li>
)
})
folders ? (
folders.map((folder) => {
return (
<li key={folder.id}><Link to={'/folder/' + folder.id}>{folder.name}</Link></li>
)
})
) : <li>Loading Folders...</li>
}
</ul>
</li>
Expand All @@ -37,10 +41,15 @@ class App extends Component {
{this.props.children}
</div>
<OpenEmails/>

</div>
)
}
}

const runSideEffects = function(state, dispatch) {
dispatch(emailApp.actions.folder.ensureFreshFolders());
}

// Wrap the component to inject dispatch and state into it
export default connect((state) => { return { folders: state.emailApp.folders.folders } })(App)
export default superConnect(runSideEffects, (state) => { return { folders: state.emailApp.folders.folders } })(App)
24 changes: 21 additions & 3 deletions emailApp/actions/emailActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@ import { api } from '../api'
window.api = api;

export const FETCHED_EMAILS = 'FETCHED_EMAILS'
export const REMOVED_EMAIL = 'REMOVED_EMAIL'
export const MOVED_EMAIL_TO_FOLDER = 'MOVED_EMAIL_TO_FOLDER'

// State actions
const removedEmail = function(emailId) {
return { type: REMOVED_EMAIL, emailId: emailId };
}

const movedEmailToFolder = function(emailId, folderId) {
return { type: MOVED_EMAIL_TO_FOLDER, emailId: emailId, folderId: folderId };
}

// State action
const fetchedEmails = function(emails, fetchedAt) {
return { type: FETCHED_EMAILS, emails: emails, fetchedAt: fetchedAt };
}
Expand All @@ -17,16 +27,24 @@ export function fetchEmails() {
}
}

export function ensureFreshEmails() {
return (dispatch, getState) => {
if(getState().emailApp.emails.dirty) {
dispatch(fetchEmails());
}
}
}

export function removeEmail(emailId) {
return (dispatch) => {
api.removeEmail(emailId);
dispatch(fetchEmails());
dispatch(removedEmail(emailId));
}
}

export function moveEmailToFolder(emailId, folderId) {
return (dispatch) => {
api.moveEmailToFolder(emailId, folderId);
dispatch(fetchEmails());
dispatch(movedEmailToFolder(emailId, folderId));
}
}
Loading