summaryrefslogtreecommitdiff
path: root/client/components
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2017-04-21 16:03:11 -0400
committerJules Laplace <jules@okfoc.us>2017-04-21 16:03:11 -0400
commitef83dba4a83e23e38b67ee31b79e79c9e25a003d (patch)
treebe0e65ee556d215796f6c64e3df7d8adb5c51554 /client/components
parent5028ad81845308f3b1954dcc1fde664077fa0fa9 (diff)
display orders per product, download as csv
Diffstat (limited to 'client/components')
-rw-r--r--client/components/App.jsx44
-rw-r--r--client/components/OrderList.jsx121
-rw-r--r--client/components/ProductList.jsx31
3 files changed, 193 insertions, 3 deletions
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