From ef83dba4a83e23e38b67ee31b79e79c9e25a003d Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 21 Apr 2017 16:03:11 -0400 Subject: display orders per product, download as csv --- client/client.js | 9 +-- client/components/App.jsx | 44 +++++++++++++- client/components/OrderList.jsx | 121 ++++++++++++++++++++++++++++++++++++++ client/components/ProductList.jsx | 31 ++++++++++ client/state_lookup.js | 74 +++++++++++++++++++++++ 5 files changed, 272 insertions(+), 7 deletions(-) create mode 100644 client/components/OrderList.jsx create mode 100644 client/components/ProductList.jsx create mode 100644 client/state_lookup.js (limited to 'client') 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 ( -
Loading...
- ) + if (! this.state.ready) { + return ( +
Loading...
+ ) + } + else { + const products = this.state.products + const product = this.state.product + const orders = this.state.orders + return ( +
+ this.pick(product)} /> + +
+ ) + } } } \ 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 (
) + } + if (! this.props.orders) { + return (
Loading...
) + } + if (! this.props.orders.length) { + return (
No orders found
) + } + + const items = this.parseOrders().map((order, i) => { + const order_link = ( + + (order) + + ) + const customer_link = order.order_checkout_type === 'guest' ? '' : ( + + (customer) + + ) + let order_name, order_address + if (order.order_company && order.order_company !== order.order_ship_name) { + order_name = ( + + {order.order_ship_name}
+ {order.order_company} +
+ ) + } + else { + order_name = order.order_ship_name + } + if (order.order_address2 && order.order_address2 !== order.order_address1) { + order_address = ( + + {order.order_address1}
+ {order.order_address2} +
+ ) + } + else { + order_address = order.order_address1 + } + + const country = order.order_country !== 'United States' ? order.order_country : "" + return ( +
+
+ {order_link} {customer_link} +
+
+ {order_name}
+ {order_address}
+ {order.order_city}, {state_lookup(order.order_state)} {order.order_zip} {country} +
+
+ ) + }) + + return ( +
+ this.downloadCsv()}>Download CSV + {items} +
+
+
+
+ ) + } +} \ 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 ( + + ) + }) + items.unshift() + return ( + + ) + } +} \ 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 +} -- cgit v1.2.3-70-g09d2