Skip to content

Commit b650c57

Browse files
committed
Taking first baby steps in React & Redux and rewriting foobar-kiosk
0 parents  commit b650c57

20 files changed

+1045
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
node_modules/

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 Uppsala Datavetare and individual contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# foobar-kiosk
2+
3+
This repository contains the frontend for the FooBar kiosk and inventory system.

actions/index.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import fetch from 'isomorphic-fetch';
2+
3+
export const ADD_PRODUCT = 'ADD_PRODUCT';
4+
export const INCREASE_PRODUCT_QTY = 'INCREASE_PRODUCT_QTY';
5+
export const SELECT_PRODUCT = 'SELECT_PRODUCT';
6+
export const REMOVE_PRODUCT = 'REMOVE_PRODUCT';
7+
export const REQUEST_PRODUCT = 'REQUEST_PRODUCT';
8+
9+
export function addProduct(ean) {
10+
return dispatch => {
11+
dispatch(requestProduct(ean));
12+
return fetch(`http://dev.foocash.me/api/products/?code=${ean}`, {
13+
headers: {
14+
'Authorization': 'Token ###'
15+
}
16+
})
17+
.then(response => response.json())
18+
.then(data => {
19+
if (data.length) {
20+
dispatch(receiveProduct(data[0]))
21+
}
22+
});
23+
}
24+
};
25+
26+
export function requestProduct(ean) {
27+
return {
28+
type: REQUEST_PRODUCT,
29+
ean
30+
};
31+
}
32+
33+
export function receiveProduct(data) {
34+
return {
35+
type: ADD_PRODUCT,
36+
...data
37+
}
38+
}
39+
40+
export function increaseProductQty(count) {
41+
return {
42+
type: INCREASE_PRODUCT_QTY,
43+
count
44+
};
45+
}
46+
47+
export function selectProduct(ean) {
48+
return {
49+
type: SELECT_PRODUCT,
50+
ean
51+
};
52+
}
53+
54+
export function removeProduct() {
55+
return {
56+
type: REMOVE_PRODUCT
57+
}
58+
};

components/AccountBar.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React, { PropTypes, Component } from 'react';
2+
3+
export default class AccountBar extends Component {
4+
render() {
5+
const {dispatch} = this.props;
6+
return (
7+
<div id="account">
8+
<div className="name">{this.props.name}</div>
9+
<div id="balance">Balance: <span>{this.props.balance}</span> kr</div>
10+
</div>
11+
);
12+
}
13+
}
14+
15+
AccountBar.propTypes = {
16+
name: PropTypes.string,
17+
balance: PropTypes.string
18+
};

components/Product.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, { PropTypes, Component } from 'react';
2+
import selectProduct from '../actions';
3+
4+
export default class Product extends Component {
5+
render() {
6+
const {dispatch} = this.props;
7+
return (
8+
<colu className={this.props.selected ? 'selected' : ''} onClick={(e) => this.props.onSelect(this.props.ean)}>
9+
<cell className="image"><img src={this.props.image} alt="" /></cell>
10+
<cell className="name">{this.props.name}</cell>
11+
<cell className="quantity">{this.props.qty} x</cell>
12+
<cell className="price"><span>{this.props.price} kr</span></cell>
13+
<div className="overlay"></div>
14+
</colu>
15+
);
16+
}
17+
}
18+
19+
Product.propTypes = {
20+
name: PropTypes.string
21+
};

components/ProductList.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React, { PropTypes, Component } from 'react';
2+
import Product from './Product';
3+
4+
export default class ProductList extends Component {
5+
render() {
6+
const {products} = this.props;
7+
return (
8+
<div id="purchase">
9+
{products.products.map((product, index) =>
10+
<Product {...product} key={index}
11+
onSelect={this.props.onSelect} />
12+
)}
13+
</div>
14+
);
15+
}
16+
}
17+
18+
// ProductList.propTypes = {
19+
// products: PropTypes.array
20+
// };

components/PurchaseButton.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { PropTypes, Component } from 'react';
2+
3+
export default class PurchaseButton extends Component {
4+
render() {
5+
const {products} = this.props.products;
6+
let total = products
7+
.filter((p) => !p.loading)
8+
.map((p) => p.price * p.qty).reduce((x, y) => x + y, 0)
9+
return (
10+
<span id="buy" className="button" href="#">
11+
<span>{total}</span>
12+
<span> kr</span>
13+
<div>
14+
<i className="fa fa-shopping-cart"></i>
15+
<span></span>
16+
</div>
17+
</span>
18+
);
19+
}
20+
}
21+
22+
// PurchaseButton.propTypes = {
23+
// products: PropTypes.array
24+
// };

containers/App.js

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import { connect } from 'react-redux';
3+
import {
4+
addProduct,
5+
removeProduct,
6+
selectProduct,
7+
increaseProductQty
8+
} from '../actions';
9+
import ProductList from '../components/ProductList';
10+
import PurchaseButton from '../components/PurchaseButton';
11+
import AccountBar from '../components/AccountBar';
12+
13+
14+
class App extends Component {
15+
componentDidMount() {
16+
}
17+
18+
componentWillReceiveProps(nextProps) {
19+
}
20+
21+
addRandomProduct() {
22+
var eans = [
23+
'7310500088853',
24+
'7340083438684',
25+
'7611612221351',
26+
'7310500114934',
27+
'7310070765840',
28+
'7315360010754',
29+
'7622300342753'
30+
];
31+
32+
var randomIndex = Math.floor(Math.random() * eans.length);
33+
this.props.dispatch(addProduct(eans[randomIndex]));
34+
}
35+
36+
render() {
37+
const { dispatch, products } = this.props;
38+
return (
39+
<div id="container">
40+
<ProductList products={products}
41+
onSelect={(ean) => dispatch(selectProduct(ean))} />
42+
<span id="trash" className="button"></span>
43+
<div id="sidebar">
44+
<AccountBar name="Krzysztof" balance="0" />
45+
<div id="menubox"></div>
46+
<PurchaseButton products={products} />
47+
</div>
48+
<div id="edit">
49+
<span className="button scroll up" onClick={(e) => this.addRandomProduct()}><i className="fa fa-chevron-up"></i></span>
50+
<div className="container">
51+
<span className="button plus"
52+
onClick={(e) => dispatch(increaseProductQty(1))}>
53+
<i className="fa fa-plus"></i>
54+
</span>
55+
<span className="button minus"
56+
onClick={(e) => dispatch(increaseProductQty(-1))}>
57+
<i className="fa fa-minus"></i>
58+
</span>
59+
<span className="button trash"
60+
onClick={(e) => dispatch(removeProduct())}>
61+
<i className="fa fa-trash"></i>
62+
</span>
63+
</div>
64+
<span className="button scroll down">
65+
<i className="fa fa-chevron-down"></i>
66+
</span>
67+
</div>
68+
</div>
69+
);
70+
}
71+
}
72+
73+
App.propTypes = {
74+
dispatch: PropTypes.func.isRequired
75+
};
76+
77+
function mapStateToProps(state) {
78+
const { products } = state;
79+
80+
return {
81+
products
82+
};
83+
}
84+
85+
export default connect(mapStateToProps)(App);

0 commit comments

Comments
 (0)