|
|
|
import React from 'react'
|
|
|
|
import Router from 'next/router'
|
|
|
|
import Link from 'next/link'
|
|
|
|
import axios from 'axios'
|
|
|
|
import Head from 'next/head'
|
|
|
|
import {DateTime} from 'luxon'
|
|
|
|
|
|
|
|
import useCart, {useSetCart} from '~/hooks/useCart'
|
|
|
|
import {FormController, Button} from '~/components/form'
|
|
|
|
import Table from '~/components/table'
|
|
|
|
|
|
|
|
export default function Cart(){
|
|
|
|
const cart = useCart()
|
|
|
|
const setCart = useSetCart()
|
|
|
|
const numItems = (cart?.items) ? cart.items.length : 0
|
|
|
|
|
|
|
|
cart?.items?.forEach(({item, count}) => {
|
|
|
|
const stock = item.stock = {}
|
|
|
|
stock.is_preorder = item.preorder_availability_date && count > item.number_in_stock
|
|
|
|
stock.available = stock.is_preorder ? item.preorder_maximum - -Math.min(0, item.number_in_stock) : item.number_in_stock
|
|
|
|
stock.has_enough = count <= stock.available
|
|
|
|
})
|
|
|
|
|
|
|
|
const allInStock = !cart?.items?.some(item => !(item.item.number_in_stock > 0 || item.item.preorder_availability_date) )
|
|
|
|
const allHaveEnough = !cart?.items?.some(item => !item.item.stock.has_enough)
|
|
|
|
|
|
|
|
const preorderItems = cart?.items?.filter(({item, count}) => count > item.number_in_stock && item.preorder_availability_date).map(({item}) => DateTime.fromISO(item.preorder_availability_date)) || []
|
|
|
|
preorderItems.sort((b, a) => a < b ? -1 : a > b ? 1 : 0)
|
|
|
|
const latestPreorder = preorderItems[0]?.toLocaleString(DateTime.DATE_FULL)
|
|
|
|
|
|
|
|
const handleRemove = id => async ev => {
|
|
|
|
if(ev) ev.preventDefault()
|
|
|
|
|
|
|
|
const {data} = await axios.post(`/api/cart/remove/${id}`)
|
|
|
|
setCart(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can't let the form controller do this as it shouldn't actually pass a body
|
|
|
|
const handleCreateTransaction = async () => {
|
|
|
|
await axios.put(`/api/orders`)
|
|
|
|
Router.push('/store/checkout')
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Head>
|
|
|
|
<title>Cart | Society of Socks</title>
|
|
|
|
</Head>
|
|
|
|
<h2>Cart</h2>
|
|
|
|
|
|
|
|
{
|
|
|
|
numItems > 0
|
|
|
|
?<Table
|
|
|
|
columns={[
|
|
|
|
{name: 'Item', extractor: row => (
|
|
|
|
<>
|
|
|
|
<Link href={`/store/item/${row.item.urlslug}`}><a>{row.item.name}</a></Link>
|
|
|
|
{(() => {
|
|
|
|
const {stock} = row.item;
|
|
|
|
|
|
|
|
if(stock.is_preorder && !stock.has_enough)
|
|
|
|
return <strong style={{marginLeft: '6px'}}>Not enough expected stock</strong>
|
|
|
|
|
|
|
|
if(stock.is_preorder && stock.has_enough)
|
|
|
|
return <strong style={{marginLeft: '6px'}}>(Pre-order: available {DateTime.fromISO(row.item.preorder_availability_date).toLocaleString(DateTime.DATE_SHORT)})</strong>
|
|
|
|
|
|
|
|
if(!row.item.number_in_stock || row.item.number_in_stock < 1)
|
|
|
|
return <strong style={{marginLeft: '6px'}}>Out of stock</strong>
|
|
|
|
|
|
|
|
if (!stock.has_enough)
|
|
|
|
return <strong style={{marginLeft: '6px'}}>Not enough in stock</strong>
|
|
|
|
|
|
|
|
return null
|
|
|
|
})()}
|
|
|
|
</>
|
|
|
|
)},
|
|
|
|
{name: 'Quantity in Cart', extractor: row => row.count},
|
|
|
|
{name: 'Price Each', extractor: row => '$' + (row.item.price_cents / 100).toFixed(2)},
|
|
|
|
{name: 'Total Price', extractor: row => '$' + (row.count * row.item.price_cents / 100).toFixed(2)},
|
|
|
|
{name: '', extractor: row =>
|
|
|
|
<button className="buttonLink" onClick={handleRemove(row.item.uuid)}>Remove</button>
|
|
|
|
}
|
|
|
|
]}
|
|
|
|
rows={cart?.items?.map(row=>({
|
|
|
|
...row,
|
|
|
|
id: row.item.uuid
|
|
|
|
}))}
|
|
|
|
foot={[
|
|
|
|
'Total:',
|
|
|
|
cart?.items.map(r=>r.count).reduce((a,b) => (a+b), 0) || 0,
|
|
|
|
'',
|
|
|
|
'$' + ((cart?.items.map(r=>r.count * r.item.price_cents).reduce((a,b) => (a+b), 0) || 0) / 100).toFixed(2),
|
|
|
|
''
|
|
|
|
]}
|
|
|
|
/>
|
|
|
|
// Empty cart table
|
|
|
|
:<Table
|
|
|
|
columns={[
|
|
|
|
{name: 'No items in cart'}
|
|
|
|
]}
|
|
|
|
foot={[
|
|
|
|
'Total:',
|
|
|
|
'',
|
|
|
|
'',
|
|
|
|
'$0.00'
|
|
|
|
]}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
|
|
|
|
<FormController afterSubmit={handleCreateTransaction}>
|
|
|
|
{(()=>{
|
|
|
|
if(!(cart?.items?.length))
|
|
|
|
return <Button enabled={false} type="submit">No items in cart</Button>
|
|
|
|
|
|
|
|
if(!allInStock)
|
|
|
|
return <Button enabled={false} type="submit">Items out of stock</Button>
|
|
|
|
|
|
|
|
if(!allHaveEnough)
|
|
|
|
return <Button enabled={false} type="submit">Not enough stock</Button>
|
|
|
|
|
|
|
|
return <Button type="submit">Proceed to Checkout</Button>
|
|
|
|
})()}
|
|
|
|
{latestPreorder && allHaveEnough && (
|
|
|
|
<p className="warning">
|
|
|
|
<strong>Note: </strong>
|
|
|
|
Your cart contains one or more pre-order items. If you place an order with these items in your cart, it will not ship
|
|
|
|
until at least {latestPreorder}
|
|
|
|
</p>
|
|
|
|
)}
|
|
|
|
</FormController>
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|