summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/client.js9
-rw-r--r--client/components/App.jsx44
-rw-r--r--client/components/OrderList.jsx121
-rw-r--r--client/components/ProductList.jsx31
-rw-r--r--client/state_lookup.js74
5 files changed, 272 insertions, 7 deletions
diff --git a/client/client.js b/client/client.js
index 7bc5c51..b6c55ce 100644
--- a/client/client.js
+++ b/client/client.js
@@ -1,14 +1,15 @@
import request from 'superagent'
-function fetch (api) {
+function fetch (api, query) {
+ query = query || {}
return new Promise(function (resolve, reject){
request
- .api(api)
+ .get(api)
+ .query(query)
.set('Accept', 'application/json')
.end(function(err, res){
- console.log(res)
- resolve(res)
+ resolve(res.body)
})
})
}
diff --git a/client/components/App.jsx b/client/components/App.jsx
index 26af681..1b58e24 100644
--- a/client/components/App.jsx
+++ b/client/components/App.jsx
@@ -1,12 +1,50 @@
import React from 'react'
+import ProductList from './ProductList.jsx'
+import OrderList from './OrderList.jsx'
+import client from '../client'
export default class App extends React.Component {
constructor() {
super()
+ this.state = {
+ ready: false,
+ products: null,
+ product: null,
+ orders: null,
+ }
+ this.load = this.load.bind(this)
+ this.pick = this.pick.bind(this)
+ client.fetch('/api/products').then(this.load)
+ }
+ load(products) {
+ this.setState({
+ ready: true,
+ products: products,
+ })
+ }
+ pick(product) {
+ this.setState({
+ product: product,
+ orders: null
+ })
+ client.fetch('/api/orders', {id: product.product_merchant_product_id}).then((orders) => this.setState({ orders: orders }))
}
render() {
- return (
- <div>Loading...</div>
- )
+ if (! this.state.ready) {
+ return (
+ <div className='loading'>Loading...</div>
+ )
+ }
+ else {
+ const products = this.state.products
+ const product = this.state.product
+ const orders = this.state.orders
+ return (
+ <div>
+ <ProductList products={products} handleSelect={(product) => this.pick(product)} />
+ <OrderList product={product} orders={orders} />
+ </div>
+ )
+ }
}
} \ No newline at end of file
diff --git a/client/components/OrderList.jsx b/client/components/OrderList.jsx
new file mode 100644
index 0000000..5b0380b
--- /dev/null
+++ b/client/components/OrderList.jsx
@@ -0,0 +1,121 @@
+import React from 'react'
+import state_lookup from '../state_lookup'
+import saveAs from 'browser-saveas'
+import csvStringify from 'csv-stringify'
+
+export default class OrderList extends React.Component {
+ constructor(props) {
+ super()
+ this.downloadCsv = this.downloadCsv.bind(this)
+ }
+ downloadCsv() {
+ const orders = this.parseOrders().map((order) => {
+ return [
+ order.order_id,
+ order.order_date,
+ order.order_checkout_type,
+ order.order_ship_name,
+ order.order_company,
+ order.order_address1,
+ order.order_address2,
+ order.order_city,
+ state_lookup(order.order_state),
+ order.order_zip,
+ order.order_country !== 'United States' ? '' : order.order_country,
+ ]
+ })
+ csvStringify(orders, (err, csv) => {
+ const blob = new Blob([csv], {type : 'text/plain;charset=utf-8'})
+ saveAs(blob, this.props.product.product_name.replace(/\s+/g,"") +'.csv')
+ })
+ }
+ parseOrders() {
+ return this.props.orders.filter( (order) => {
+ // also filter where order.order_status == 3 (paid in full) ?
+ // filter weird blank orders if found
+ return !! order.order_ship_name
+ }).map( (order, i) => {
+ const name = order.order_ship_name
+ .toUpperCase()
+ .replace(/(Sr|Jr|I|II|III|IV)\.?$/i, "")
+ .split(" ")
+ .reverse()[0]
+ return [ name, order ]
+ }).sort((a,b) => {
+ return a[0] < b[0] ? -1 : a[0] === b[0] ? 0 : 1
+ }).map((pair, i) => {
+ return pair[1]
+ })
+ }
+ render() {
+ if (! this.props.product) {
+ return ( <div></div> )
+ }
+ if (! this.props.orders) {
+ return ( <div className='loading'>Loading...</div> )
+ }
+ if (! this.props.orders.length) {
+ return ( <div className='notfound'>No orders found</div> )
+ }
+
+ const items = this.parseOrders().map((order, i) => {
+ const order_link = (
+ <a href={'http://shopping.msana.com/cw4/admin/order-details.php?order_id=' + order.order_id}>
+ (order)
+ </a>
+ )
+ const customer_link = order.order_checkout_type === 'guest' ? '' : (
+ <a href={'http://shopping.msana.com/cw4/admin/customer-details.php?customer_id=' + order.order_customer_id}>
+ (customer)
+ </a>
+ )
+ let order_name, order_address
+ if (order.order_company && order.order_company !== order.order_ship_name) {
+ order_name = (
+ <span>
+ {order.order_ship_name}<br />
+ {order.order_company}
+ </span>
+ )
+ }
+ else {
+ order_name = order.order_ship_name
+ }
+ if (order.order_address2 && order.order_address2 !== order.order_address1) {
+ order_address = (
+ <span>
+ {order.order_address1}<br />
+ {order.order_address2}
+ </span>
+ )
+ }
+ else {
+ order_address = order.order_address1
+ }
+
+ const country = order.order_country !== 'United States' ? order.order_country : ""
+ return (
+ <div key={i}>
+ <div>
+ {order_link} {customer_link}
+ </div>
+ <div>
+ {order_name}<br />
+ {order_address}<br />
+ {order.order_city}, {state_lookup(order.order_state)} {order.order_zip} {country}
+ </div>
+ </div>
+ )
+ })
+
+ return (
+ <div className='orderList'>
+ <a href='#' onClick={() => this.downloadCsv()}>Download CSV</a>
+ {items}
+ <br />
+ <br />
+ <br />
+ </div>
+ )
+ }
+} \ No newline at end of file
diff --git a/client/components/ProductList.jsx b/client/components/ProductList.jsx
new file mode 100644
index 0000000..ab00e9f
--- /dev/null
+++ b/client/components/ProductList.jsx
@@ -0,0 +1,31 @@
+import React from 'react'
+
+export default class ProductList extends React.Component {
+ constructor(props) {
+ super()
+ this.state = { value: -1 }
+ this.pick = this.pick.bind(this)
+ }
+ pick(event) {
+ const value = Number(event.target.value)
+ this.setState({ value: value })
+ if (value === -1) return
+ const product = this.props.products[value]
+ this.props.handleSelect(product)
+ }
+ render() {
+ const items = this.props.products.map((product, i) => {
+ return (
+ <option key={i} value={i}>
+ {product.product_name} ({product.product_merchant_product_id})
+ </option>
+ )
+ })
+ items.unshift(<option key={-1} value={-1}>Select a product...</option>)
+ return (
+ <select value={this.state.value} onChange={this.pick}>
+ {items}
+ </select>
+ )
+ }
+} \ No newline at end of file
diff --git a/client/state_lookup.js b/client/state_lookup.js
new file mode 100644
index 0000000..145f344
--- /dev/null
+++ b/client/state_lookup.js
@@ -0,0 +1,74 @@
+
+const states = {
+ 'Alabama': 'AL',
+ 'Alaska': 'AK',
+ 'Arizona': 'AZ',
+ 'Arkansas': 'AR',
+ 'California': 'CA',
+ 'Colorado': 'CO',
+ 'Connecticut': 'CT',
+ 'Delaware': 'DE',
+ 'District Of Columbia': 'DC',
+ 'Florida': 'FL',
+ 'Georgia': 'GA',
+ 'Hawaii': 'HI',
+ 'Idaho': 'ID',
+ 'Illinois': 'IL',
+ 'Indiana': 'IN',
+ 'Iowa': 'IA',
+ 'Kansas': 'KS',
+ 'Kentucky': 'KY',
+ 'Louisiana': 'LA',
+ 'Maine': 'ME',
+ 'Maryland': 'MD',
+ 'Massachusetts': 'MA',
+ 'Michigan': 'MI',
+ 'Minnesota': 'MN',
+ 'Mississippi': 'MS',
+ 'Missouri': 'MO',
+ 'Montana': 'MT',
+ 'Nebraska': 'NE',
+ 'Nevada': 'NV',
+ 'New Hampshire': 'NH',
+ 'New Jersey': 'NJ',
+ 'New Mexico': 'NM',
+ 'New York': 'NY',
+ 'North Carolina': 'NC',
+ 'North Dakota': 'ND',
+ 'Ohio': 'OH',
+ 'Oklahoma': 'OK',
+ 'Oregon': 'OR',
+ 'Pennsylvania': 'PA',
+ 'Rhode Island': 'RI',
+ 'South Carolina': 'SC',
+ 'South Dakota': 'SD',
+ 'Tennessee': 'TN',
+ 'Texas': 'TX',
+ 'Utah': 'UT',
+ 'Vermont': 'VT',
+ 'Virginia': 'VA',
+ 'Washington': 'WA',
+ 'West Virginia': 'WV',
+ 'Wisconsin': 'WI',
+ 'Wyoming': 'WY',
+ 'Alberta': 'AB',
+ 'British Columbia': 'BC',
+ 'Manitoba': 'MB',
+ 'New Brunswick': 'NB',
+ 'Newfoundland and Labrador': 'NL',
+ 'Nova Scotia': 'NS',
+ 'Northwest Territories': 'NT',
+ 'Nunavut': 'NU',
+ 'Ontario': 'ON',
+ 'Prince Edward Island': 'PE',
+ 'Saskatchewan': 'SK',
+ 'Quebec': 'QC',
+ 'Yukon': 'YT',
+}
+
+export default function lookup (state) {
+ if (state in states) {
+ return states[state]
+ }
+ return state
+}