Skip to content

Commit

Permalink
✨ Ability to create a contract.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlee-dev committed Aug 27, 2019
1 parent 46c6285 commit e29f8f1
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 27 deletions.
38 changes: 26 additions & 12 deletions src/components/ContractsDisplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,32 @@ import { Box, Heading, Text, Button } from 'grommet'
import { Checkmark, Close } from 'grommet-icons'
import { connect } from 'react-redux'
import { resetContract, setContract } from '../redux/actions/user'
import CreateContract from './CreateContract'
import { setIsCreatingContract } from '../redux/actions/ui'

/**
* Displays a set of item contracts.
*/
const ContractsDisplay = ({
contracts,
currentContract,
handleCreateInit,
handleResetContract,
handleSetContract
handleSetContract,
isCreatingContract
}) => {
return (
<Box gap="small" margin={{ vertical: 'medium' }}>
<Heading level="3">Contracts</Heading>
<Box align="center" direction="row" gap="medium">
<Heading level="3">Contracts</Heading>
<Button
hoverIndicator
label="Create"
onClick={() => handleCreateInit()}
plain
/>
</Box>
{isCreatingContract && <CreateContract />}
{currentContract && (
<Box direction="row" gap="small">
<Text>Current Contract: {currentContract.id}</Text>
Expand All @@ -42,13 +55,7 @@ const ContractsDisplay = ({
disabled={currentContract !== null}
hoverIndicator
icon={<Checkmark />}
onClick={e =>
handleSetContract(
contracts.find(
contract => contract.id === e.target.parentElement.value
)
)
}
onClick={() => handleSetContract(contract)}
plain
value={contract.id}
/>
Expand All @@ -61,20 +68,27 @@ const ContractsDisplay = ({
ContractsDisplay.propTypes = {
contracts: PropTypes.array.isRequired,
currentContract: PropTypes.object,
handleCreateInit: PropTypes.func.isRequired,
handleResetContract: PropTypes.func.isRequired,
handleSetContract: PropTypes.func.isRequired
handleSetContract: PropTypes.func.isRequired,
isCreatingContract: PropTypes.bool.isRequired
}

const mapStateToProps = ({ user, world }) => ({
const mapStateToProps = ({ ui, user, world }) => ({
contracts: world.contracts,
currentContract: user.contract
currentContract: user.contract,
isCreatingContract: ui.isCreatingContract
})

const mapDispatchToProps = dispatch => ({
handleCreateInit: () => {
dispatch(setIsCreatingContract(true))
},
handleResetContract: () => {
dispatch(resetContract())
},
handleSetContract: contract => {
console.log({ contract })
dispatch(setContract(contract))
}
})
Expand Down
87 changes: 87 additions & 0 deletions src/components/CreateContract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { Box } from 'grommet'
import { itemList } from '../constants'
import { connect } from 'react-redux'
import { createContract } from '../redux/actions/world'
import { generateContract } from '../util'

/**
* Inputs for creating a contract.
*/
const CreateContract = ({ handleCreateContract, planets }) => {
const [itemType, setItemType] = useState(itemList[0])
const [destination, setDestination] = useState({
location: planets[0].location,
name: planets[0].name
})

return (
<Box width="medium">
<label htmlFor="item-type">Item Type</label>
<select
id="item-type"
onChange={e => setItemType(JSON.parse(e.target.value))}
>
{itemList.map(item => (
<option key={item.name} value={JSON.stringify(item)}>
{item.name}
</option>
))}
</select>
<label htmlFor="item-volume">Item Volume</label>
<input
disabled
id="item-volume"
type="number"
value={itemType ? itemType.volume : 0}
/>
<label htmlFor="item-value">Item Value</label>
<input
disabled
id="item-value"
type="number"
value={itemType ? itemType.value : 0}
/>
<label htmlFor="item-destination">Destination</label>
<select
id="item-destination"
onChange={e => {
const planet = planets.find(planet => planet.id === e.target.value)
setDestination({ location: planet.location, name: planet.name })
}}
>
{planets.map(planet => (
<option key={planet.id} value={planet.id}>
{planet.name}
</option>
))}
</select>
<button
onClick={() => {
handleCreateContract(
generateContract(planets, itemType.name, destination)
)
}}
>
Create Contract
</button>
</Box>
)
}

CreateContract.propTypes = {
handleCreateContract: PropTypes.func.isRequired,
planets: PropTypes.array.isRequired
}

const mapStateToProps = ({ world }) => ({ planets: world.planets })

const mapDispatchToProps = dispatch => ({
handleCreateContract: contract => dispatch(createContract(contract))
})

export default connect(
mapStateToProps,
mapDispatchToProps
)(CreateContract)
14 changes: 14 additions & 0 deletions src/redux/actions/ship.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ export const storeCargo = (item, quantity) => ({
// * PROMISES

// * THUNKS
/**
* Sets the ship to be traveling, sets the destination, and sets the ETA.
* @param {object} destination Destination object.
* @param {object} ship Ship object.
*/
export const departShip = (destination, ship) => dispatch => {
// * set isShipTraveling to true
dispatch(setShipTraveling(true))
Expand All @@ -85,6 +90,10 @@ export const departShip = (destination, ship) => dispatch => {
dispatch(setETA(eta.format('x')))
}

/**
* If the ship is carrying items to sell, will sell those items if necessary. Removes items from cargo if needed. Sets the ship location, destination, and isShipTraveling.
* @param {object} ship Ship object.
*/
export const landShip = ship => dispatch => {
const { cargo, destination } = ship
const sellableItems = cargo.items.filter(
Expand All @@ -107,6 +116,11 @@ export const landShip = ship => dispatch => {
dispatch(setShipTraveling(false))
}

/**
* Removes cash from the user, stores the cargo in the ship cargo, and removes the item from the planet.
* @param {object} item Item object.
* @param {number} quantity Quantity of the item.
*/
export const purchaseCargo = (item, quantity) => dispatch => {
// * dispatch an action to buy the items with the user's cash
dispatch(removeCash(item.price * quantity))
Expand Down
6 changes: 6 additions & 0 deletions src/redux/actions/ui.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
// * ACTION TYPES
const SET_IS_CREATING_CONTRACT = 'SET_IS_CREATING_CONTRACT'
const SET_VIEW = 'SET_VIEW'

// * ACTION GENERATORS
export const setIsCreatingContract = isCreatingContract => ({
type: SET_IS_CREATING_CONTRACT,
payload: { isCreatingContract }
})

/**
* Sets the view displayed to the user.
* @param {string} view View to display.
Expand Down
26 changes: 26 additions & 0 deletions src/redux/actions/world.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { setShipLocation } from './ship'
import { generatePlanets, generateContracts } from '../../util'
import { setIsCreatingContract } from './ui'

// * ACTION TYPES
const ADD_CONTRACT = 'ADD_CONTRACT'
const CLEAR_ITEMS = 'CLEAR_ITEMS'
const REFRESH_ITEMS = 'REFRESH_ITEMS'
const REMOVE_ITEM = 'REMOVE_ITEM'
Expand All @@ -10,6 +12,15 @@ const SET_PLANETS = 'SET_PLANETS'
const SET_TIMER_RUNNING = 'SET_TIMER_RUNNING'

// * ACTION GENERATORS
/**
* Adds a contract to the contract array.
* @param {object} contract Contract object.
*/
export const addContract = contract => ({
type: ADD_CONTRACT,
payload: { contract }
})

/**
* Removes all items from planets.
*/
Expand Down Expand Up @@ -63,6 +74,18 @@ export const setTimerRunning = isTimerRunning => ({
// * PROMISES

// * THUNKS
/**
* Sets the isCreatingContract value in UI to false, and adds the contract to the contract array in World.
* @param {object} contract Contract object.
*/
export const createContract = contract => dispatch => {
dispatch(setIsCreatingContract(false))
dispatch(addContract(contract))
}

/**
* Sets the planets, ship location, and contracts initially.
*/
export const initializeApplication = () => dispatch => {
const planets = generatePlanets()
const homePlanet = planets.find(planet => planet.isHomePlanet === true)
Expand All @@ -74,6 +97,9 @@ export const initializeApplication = () => dispatch => {
dispatch(setContracts(contracts))
}

/**
* Clears and refreshes items, and sets the timer to be no longer running.
*/
export const itemTimerFinish = () => dispatch => {
// * Clear all items from planets
dispatch(clearItems())
Expand Down
3 changes: 3 additions & 0 deletions src/redux/reducers/ui.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const uiDefaultState = {
isCreatingContract: false,
view: 'Ship'
}

export default (state = uiDefaultState, action) => {
switch (action.type) {
case 'SET_IS_CREATING_CONTRACT':
return { ...state, isCreatingContract: action.payload.isCreatingContract }
case 'SET_VIEW':
return { ...state, view: action.payload.view }
default:
Expand Down
3 changes: 3 additions & 0 deletions src/redux/reducers/world.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const worldDefaultState = {

export default (state = worldDefaultState, action) => {
switch (action.type) {
case 'ADD_CONTRACT':
state.contracts.push(action.payload.contract)
return { ...state, contracts: state.contracts }
case 'CLEAR_ITEMS':
return {
...state,
Expand Down
44 changes: 29 additions & 15 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,34 @@ export const createDiffDuration = eta => {
return moment.duration({ milliseconds: differenceMill })
}

/**
* Generates a single contract.
* @param {array} planets Planet array.
* @param {string || undefined} itemType Item type name.
* @param {object || undefined} destination Destination object.
*/
export const generateContract = (planets, itemType, destination) => {
let finalItemType = itemType
if (!itemType) {
finalItemType = itemList[Math.floor(Math.random() * itemList.length)].name
}
let finalDestination = destination
if (!destination) {
finalDestination = planets[Math.floor(Math.random() * planets.length)]
}

return {
destination: {
name: finalDestination.name,
value: finalDestination.location
},
id: uuidv4(),
itemType: finalItemType,
value: itemList.find(item => item.name === finalItemType).value + 1,
volume: itemList.find(item => item.name === finalItemType).volume
}
}

/**
* Generates an array of item contracts randomly.
* @param {array} planets Array of planet objects.
Expand All @@ -152,21 +180,7 @@ export const generateContracts = planets => {
const contracts = []

for (let i = 0; i < 5; i++) {
const itemType = itemList[Math.floor(Math.random() * itemList.length)].name
const destinationPlanet =
planets[Math.floor(Math.random() * planets.length)]

const contract = {
destination: {
name: destinationPlanet.name,
value: destinationPlanet.location
},
id: uuidv4(),
itemType,
value: itemList.find(item => item.name === itemType).value + 1,
volume: itemList.find(item => item.name === itemType).volume
}
contracts.push(contract)
contracts.push(generateContract(planets))
}

return contracts
Expand Down

0 comments on commit e29f8f1

Please sign in to comment.