Skip to content

Commit

Permalink
🔀 Merge pull request #76 from alexlee-dev/feature/thunks
Browse files Browse the repository at this point in the history
⚛️ Implement Redux-Thunk.
  • Loading branch information
Alex Lee authored Aug 27, 2019
2 parents c4a038c + a53d8ae commit 09e4209
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 75 deletions.
13 changes: 2 additions & 11 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { generatePlanets } from './util'
import { setShipLocation } from './redux/actions/ship'
import { setPlanets } from './redux/actions/world'
import { initializeApplication } from './redux/actions/world'
import View from './views/View'
import { Box } from 'grommet'
import CashDisplay from './components/CashDisplay'
Expand Down Expand Up @@ -45,14 +43,7 @@ const mapStateToProps = ({ world }) => ({
})

const mapDispatchToProps = dispatch => ({
handleInitializeApplication: () => {
const planets = generatePlanets()
const homePlanet = planets.find(planet => planet.isHomePlanet === true)
const location = { name: homePlanet.name, value: homePlanet.location }

dispatch(setPlanets(planets))
dispatch(setShipLocation(location))
}
handleInitializeApplication: () => dispatch(initializeApplication())
})

export default connect(
Expand Down
13 changes: 2 additions & 11 deletions src/components/ItemDisplayInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import PropTypes from 'prop-types'
import { Box, Button } from 'grommet'
import { Add } from 'grommet-icons'
import { connect } from 'react-redux'
import { storeCargo } from '../redux/actions/ship'
import { removeCash } from '../redux/actions/user'
import { removeItem } from '../redux/actions/world'
import { purchaseCargo } from '../redux/actions/ship'

/**
* Allows the user to select a specific number of this item.
Expand Down Expand Up @@ -64,14 +62,7 @@ const mapStateToProps = ({ ship, user }) => ({
})

const mapDispatchToProps = dispatch => ({
handleStoreCargo: (item, quantity) => {
// * dispatch an action to buy the items with the user's cash
dispatch(removeCash(item.price * quantity))
// * dispatch an action to store the item in ship cargo
dispatch(storeCargo(item, quantity))
// * dispatch an action to remove the item from the list of stored items on this planet
dispatch(removeItem(item, quantity))
}
handleStoreCargo: (item, quantity) => dispatch(purchaseCargo(item, quantity))
})

export default connect(
Expand Down
15 changes: 2 additions & 13 deletions src/components/ItemTimer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
setTimerRunning,
clearItems,
refreshItems
} from '../redux/actions/world'
import { setTimerRunning, itemTimerFinish } from '../redux/actions/world'
import { itemTimerLogic } from '../util'
import { Box, Heading } from 'grommet'

Expand Down Expand Up @@ -44,14 +40,7 @@ const mapStateToProps = ({ world }) => ({ world })

const mapDispatchToProps = dispatch => ({
handleTimerStarted: () => dispatch(setTimerRunning(true)),
handleTimerStopped: () => {
// * Clear all items from planets
dispatch(clearItems())
// * Put new items on planets
dispatch(refreshItems())
// * Tell Redux the timer is no longer running
dispatch(setTimerRunning(false))
}
handleTimerStopped: () => dispatch(itemTimerFinish())
})

export default connect(
Expand Down
13 changes: 3 additions & 10 deletions src/components/PlanetDisplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Box, Button, Heading, Text } from 'grommet'
import { Target } from 'grommet-icons'
import { setShipTraveling, setDestination, setETA } from '../redux/actions/ship'
import { departShip } from '../redux/actions/ship'
import ItemDisplay from './ItemDisplay'
import { createETA, createDiffDuration } from '../util'

Expand Down Expand Up @@ -56,15 +56,8 @@ PlanetDisplay.propTypes = {
const mapStateToProps = ({ ship }) => ({ ship })

const mapDispatchToProps = dispatch => ({
handleShipTravel: (destination, ship) => {
// * set isShipTraveling to true
dispatch(setShipTraveling(true))
// * set destination
dispatch(setDestination(destination))
// * set ETA
const eta = createETA(destination, ship)
dispatch(setETA(eta.format('x')))
}
handleShipTravel: (destination, ship) =>
dispatch(departShip(destination, ship))
})

export default connect(
Expand Down
30 changes: 2 additions & 28 deletions src/components/TravelTimer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Box, Heading } from 'grommet'
import { addCash } from '../redux/actions/user'
import {
removeCargo,
setShipLocation,
setDestination,
setShipTraveling
} from '../redux/actions/ship'
import { landShip } from '../redux/actions/ship'
import { travelTimerLogic } from '../util'

/**
Expand Down Expand Up @@ -42,27 +36,7 @@ TravelTimer.propTypes = {
const mapStateToProps = ({ ship }) => ({ ship })

const mapDispatchToProps = dispatch => ({
handleTimerStopped: ship => {
const { cargo, destination } = ship
const sellableItems = cargo.items.filter(
item => item.destination.value === destination.value
)
let profit = 0
sellableItems.forEach(item => {
const { quantity, value } = item
const itemProfit = quantity * value
profit += itemProfit
})
dispatch(addCash(profit))
sellableItems.forEach(item => {
dispatch(removeCargo(item))
})
dispatch(
setShipLocation({ name: destination.name, value: destination.value })
)
dispatch(setDestination(null))
dispatch(setShipTraveling(false))
}
handleTimerStopped: ship => dispatch(landShip(ship))
})

export default connect(
Expand Down
44 changes: 44 additions & 0 deletions src/redux/actions/ship.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { addCash, removeCash } from './user'
import { removeItem } from './world'
import { createETA } from '../../util'

// * ACTION TYPES
const REMOVE_CARGO = 'REMOVE_CARGO'
const SET_DESTINATION = 'SET_DESTINATION'
Expand Down Expand Up @@ -71,3 +75,43 @@ export const storeCargo = (item, quantity) => ({
// * PROMISES

// * THUNKS
export const departShip = (destination, ship) => dispatch => {
// * set isShipTraveling to true
dispatch(setShipTraveling(true))
// * set destination
dispatch(setDestination(destination))
// * set ETA
const eta = createETA(destination, ship)
dispatch(setETA(eta.format('x')))
}

export const landShip = ship => dispatch => {
const { cargo, destination } = ship
const sellableItems = cargo.items.filter(
item => item.destination.value === destination.value
)
let profit = 0
sellableItems.forEach(item => {
const { quantity, value } = item
const itemProfit = quantity * value
profit += itemProfit
})
dispatch(addCash(profit))
sellableItems.forEach(item => {
dispatch(removeCargo(item))
})
dispatch(
setShipLocation({ name: destination.name, value: destination.value })
)
dispatch(setDestination(null))
dispatch(setShipTraveling(false))
}

export const purchaseCargo = (item, quantity) => dispatch => {
// * dispatch an action to buy the items with the user's cash
dispatch(removeCash(item.price * quantity))
// * dispatch an action to store the item in ship cargo
dispatch(storeCargo(item, quantity))
// * dispatch an action to remove the item from the list of stored items on this planet
dispatch(removeItem(item, quantity))
}
20 changes: 20 additions & 0 deletions src/redux/actions/world.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { setShipLocation } from './ship'
import { generatePlanets } from '../../util'

// * ACTION TYPES
const CLEAR_ITEMS = 'CLEAR_ITEMS'
const REFRESH_ITEMS = 'REFRESH_ITEMS'
Expand Down Expand Up @@ -50,3 +53,20 @@ export const setTimerRunning = isTimerRunning => ({
// * PROMISES

// * THUNKS
export const initializeApplication = () => dispatch => {
const planets = generatePlanets()
const homePlanet = planets.find(planet => planet.isHomePlanet === true)
const location = { name: homePlanet.name, value: homePlanet.location }

dispatch(setPlanets(planets))
dispatch(setShipLocation(location))
}

export const itemTimerFinish = () => dispatch => {
// * Clear all items from planets
dispatch(clearItems())
// * Put new items on planets
dispatch(refreshItems())
// * Tell Redux the timer is no longer running
dispatch(setTimerRunning(false))
}
18 changes: 16 additions & 2 deletions src/test-utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import React from 'react';
import React from 'react'
import configureStore from 'redux-mock-store'
import { Provider } from 'react-redux'
import { defaultState } from './fixtures'
import { render } from '@testing-library/react'

const middlewares = []
const mockThunks = ({ dispatch, getState }) => next => action => {
const mockedAction = () => ({ type: 'MOCKED ACTION' })

let returnValue

if (typeof action === 'function' || action === undefined) {
returnValue = mockedAction
} else {
returnValue = next(action)
}

return returnValue
}

const middlewares = [mockThunks]

export const mockStore = configureStore(middlewares)

Expand Down

0 comments on commit 09e4209

Please sign in to comment.