Skip to content

Instantly share code, notes, and snippets.

@jesterswilde
Last active March 28, 2018 13:59
Show Gist options
  • Save jesterswilde/0fe1e8ef5ea7ce8852327d1edf011f08 to your computer and use it in GitHub Desktop.
Save jesterswilde/0fe1e8ef5ea7ce8852327d1edf011f08 to your computer and use it in GitHub Desktop.
A code sample from a mobile app
//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>
));
//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 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 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