Last active
March 28, 2018 13:59
-
-
Save jesterswilde/0fe1e8ef5ea7ce8852327d1edf011f08 to your computer and use it in GitHub Desktop.
A code sample from a mobile app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Item | |
import { h } from 'preact'; | |
import { appMethodsToProps } from '../appData'; | |
import { classNames } from '../../util'; | |
export default appMethodsToProps(({ clickOnItem, index, itemName, cost, selected, alreadyPaid })=> ( | |
<button | |
onClick={ ()=>clickOnItem(index) } | |
disabled={alreadyPaid} | |
className={classNames({ | |
'list-group-item': true, | |
'list-group-item-action': true, | |
active: !alreadyPaid && selected | |
})} | |
> | |
<span> { itemName } </span> | |
<span className='float-right'> ${ cost } </span> | |
</button> | |
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Item Component | |
import { h } from 'preact'; | |
import Item from './item'; | |
import { appStateToProps } from '../appData'; | |
export default appStateToProps(({ items = []})=> ( | |
<section className='card'> | |
<h3 className='card-header'>Items</h3> | |
<ul class="list-group"> | |
{items.map((item, index)=><li><Item {...item} index={ index } /></li>)} | |
</ul> | |
</section> | |
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This is code from a pay at your table app I worked on. This is the code to support display of items on the bill. | |
import { addAppMethodsWithState } from './bindings'; | |
import { pushAtPath, clearAtPath } from '../../firebase'; | |
export const clickOnItem = ({ items = [] }, index)=>{ | |
const modItemsArray = selectItem(items, index); | |
return itemsArrayToState(modItemsArray); | |
}; | |
export const selectItem = (items = [], index)=>{ | |
if(index !== undefined && index < items.length && typeof items[index] === 'object'){ | |
const moddedItems = [...items]; | |
const clickedItem = {...moddedItems[index]}; | |
clickedItem.selected = !clickedItem.selected; | |
moddedItems[index] = clickedItem; | |
return moddedItems; | |
} | |
return null; | |
}; | |
export const addItem = ({ url }, item)=>{ | |
const path = `${url.firebase}/items`; | |
pushAtPath(path, item); | |
}; | |
export const clearTable = ({ url })=>{ | |
const path = `${url.firebase}`; | |
clearAtPath(path); | |
}; | |
export const calcTotalBill = (itemsArray)=>{ | |
return itemsArray.reduce((total, { cost })=> Number(cost) + total, 0); | |
}; | |
export const calcPayingFor = (itemsArray)=>{ | |
const unpaidArray = itemsArray.filter(({ alreadyPaid })=> !alreadyPaid); | |
const anySelected = unpaidArray.some(({ selected })=> selected); | |
if(anySelected){ | |
return unpaidArray.reduce((total, { selected, cost })=>{ | |
if(selected){ | |
return total + Number(cost); | |
} | |
return total; | |
}, 0); | |
} | |
return unpaidArray.reduce((total, { cost })=> Number(cost) + total, 0); | |
}; | |
export const calcAlreadyPaid = (itemsArray)=>{ | |
return itemsArray | |
.filter(({ alreadyPaid })=> alreadyPaid) | |
.reduce((total, { cost })=> total + Number(cost), 0); | |
}; | |
export const collectPayingForItems = (itemsArray)=>{ | |
const unpaidArray = itemsArray.filter(({ alreadyPaid })=> !alreadyPaid); | |
const anySelected = unpaidArray.some(({ selected })=> selected); | |
if (anySelected){ | |
return unpaidArray.filter(({ selected })=> selected ); | |
} | |
return unpaidArray; | |
}; | |
export const itemsArrayToState = (itemsArray)=>{ | |
if(itemsArray === null){ | |
return { | |
items: null, | |
alreadyPaid: null, | |
totalBill: null, | |
payingFor: null, | |
}; | |
} | |
return { | |
items: itemsArray, | |
alreadyPaid: calcAlreadyPaid(itemsArray), | |
totalBill: calcTotalBill(itemsArray), | |
payingFor: calcPayingFor(itemsArray) | |
}; | |
}; | |
addAppMethodsWithState({ clickOnItem, addItem, clearTable }); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This was test driven, so these were written first. | |
jest.mock('../../firebase'); | |
import { pushAtPath, clearAtPath } from '../../firebase'; | |
import { selectItem, addItem, clearTable, calcTotalBill, calcPayingFor, calcAlreadyPaid } from './items'; | |
let bill1, bill2, bill3; | |
let stringBill; | |
beforeAll(()=>{ | |
stringBill = [ | |
{cost: '1'}, | |
{cost: '2'}, | |
{cost: '4', alreadyPaid: true}, | |
]; | |
bill1 = [ | |
{cost: 1}, | |
{cost: 2}, | |
{cost: 4, alreadyPaid: true}, | |
]; | |
bill2 = [ | |
{cost: 1, selected: true}, | |
{cost: 2, alreadyPaid: true, selected: true}, | |
{cost: 4} | |
]; | |
bill3 = [ | |
{cost: 1, selected: false, alreadyPaid: true}, | |
{cost: 2, selected: true, alreadyPaid: true}, | |
{cost: 4} | |
]; | |
}); | |
test('selectItem should add selected to an item if it doesn\'t exist', ()=>{ | |
const items = [{name: 'pad-see-ew', cost: 10}, {name: 'thai tea', cost: 3.5}] | |
const modItems = selectItem(items, 0); | |
expect(modItems).toEqual([ | |
{name: 'pad-see-ew', cost: 10, selected: true}, | |
{name: 'thai tea', cost: 3.5} | |
]); | |
}); | |
test('selectItem should flip the selected state', ()=>{ | |
const items = [ | |
{name: 'pad-see-ew', cost: 10, selected: false}, | |
{name: 'thai tea', cost: 3.5, selected: true} | |
]; | |
const firstClick = selectItem(items, 0); | |
const secondClick = selectItem(firstClick, 1); | |
expect(secondClick).toEqual([ | |
{name: 'pad-see-ew', cost: 10, selected: true}, | |
{name: 'thai tea', cost: 3.5, selected: false} | |
]); | |
}); | |
test('selectItem should return null if you give it bad info', ()=>{ | |
const items = [ | |
{name: 'pad-see-ew', cost: 10, selected: false}, | |
{name: 'thai tea', cost: 3.5, selected: true} | |
]; | |
const clicked = selectItem(items, 4); | |
expect(clicked).toBeNull(); | |
}); | |
test('addItem should push the item to db based on location', ()=>{ | |
const location = '/restaurant/thainakorn/1/chain/1/table/3'; | |
const state = { | |
url:{ | |
firebase: location | |
} | |
}; | |
const item = { | |
name: 'thaiTea', | |
cost: 3.5 | |
}; | |
addItem(state, item); | |
expect(pushAtPath).toHaveBeenCalledWith(`${location}/items`, item); | |
}); | |
test('clearTable should clear items from db based on location', ()=>{ | |
const location = '/restaurant/thainakorn/1/chain/1/table/3'; | |
const state = { | |
url:{ | |
firebase: location | |
} | |
}; | |
clearTable(state); | |
expect(clearAtPath).toHaveBeenCalledWith(location); | |
}); | |
test('totalBill should calculate the full cost of all items',()=>{ | |
const total1 = calcTotalBill(bill1); | |
const total2 = calcTotalBill(bill2); | |
const total3 = calcTotalBill(bill3); | |
expect(total1).toEqual(7); | |
expect(total2).toEqual(7); | |
expect(total3).toEqual(7); | |
}); | |
test('totalBill should handle string numbers', ()=>{ | |
const total4 = calcTotalBill(stringBill); | |
expect(total4).toEqual(7); | |
}); | |
test('payingFor should default to everything unpaid', ()=>{ | |
const payingFor1 = calcPayingFor(bill1); | |
expect(payingFor1).toEqual(3); | |
}); | |
test('payingFor should not take into account things already paid',()=>{ | |
const payingFor2 = calcPayingFor(bill2); | |
const payingFor3 = calcPayingFor(bill3); | |
expect(payingFor2).toEqual(1); | |
expect(payingFor3).toEqual(4); | |
}); | |
test('payingFor should handle string numbers', ()=>{ | |
const payingFor4 = calcPayingFor(stringBill); | |
expect(payingFor4).toEqual(3); | |
}); | |
test('alreadyPaid should calculate the total of what has already been paid', ()=>{ | |
const alreadyPaid3 = calcAlreadyPaid(bill3); | |
expect(alreadyPaid3).toEqual(3); | |
}); | |
test('alreadyPaid should handle string numbers', ()=>{ | |
const alreadyPaid4 = calcAlreadyPaid(stringBill); | |
expect(alreadyPaid4).toEqual(4); | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment