Orders now tagged to logged in user - user can see orders in account page

main
Ashelyn Dawn 4 years ago
parent 4c5ac35111
commit 59bca0bfc1

@ -10,8 +10,7 @@ const validate = require('./middleware/validators')
router.get('/', async (req, res) => {
if(req.user)
// TODO: Write this function
return res.json(await db.order.findAllforUser(req.user.uuid))
return res.json(await db.order.findAllForUser(req.user.uuid))
else
return res.json(await db.order.findAllForSession(req.session.uuid))
})
@ -159,6 +158,8 @@ router.post('/current/checkout/verify', ensureCart, parseJSON, async (req, res)
throw new Error("Unable to complete order")
}
if(req.user)
await db.order.setUser(order.uuid, req.user.uuid);
res.json({status: payment.status, order})
})

@ -35,6 +35,24 @@ order.findForCart = async function(cart_uuid) {
return joinjs.map(rows, mappings, 'orderMap', 'order_')[0];
}
order.findAllForUser = async (user_uuid) => dbUtil.executeFunction({
name: 'find_orders_for_user',
params: [
user_uuid
],
returnType: 'order',
single: false
})
order.setUser = (order_uuid, user_uuid) => dbUtil.executeFunction({
name: 'set_user_on_order',
params: [
order_uuid, user_uuid
],
returnType: 'order',
single: true
})
order.findAllForSession = async function(session_uuid) {
const query = {
text: 'select * from sos.find_orders_for_session($1)',

@ -544,6 +544,36 @@ begin
);
end; $function$;
create or replace function sos.find_orders_for_user(_user_uuid uuid)
returns setof sos.v_order
language plpgsql
as $function$
begin
return query
select * from sos.v_order
where order_user_uuid = _user_uuid
and (
transaction_payment_state = 'started'
or
transaction_payment_state = 'completed'
);
end; $function$;
create or replace function sos.set_user_on_order(_order_uuid uuid, _user_uuid uuid)
returns setof sos.v_order
language plpgsql
as $function$
begin
-- Update order
update sos."order" set
order_user_uuid = _user_uuid
where order_uuid = _order_uuid;
return query
select * from sos.v_order
where order_uuid = _order_uuid;
end; $function$;
create or replace function sos.create_address(_name text, _company text, _street1 text, _street2 text, _city text, _state text, _zip text, _country text, _phone text, _easypost_id text)
returns setof sos."address"
language plpgsql

@ -0,0 +1,112 @@
import {DateTime} from 'luxon'
import Router from 'next/router'
import Table from '~/components/table'
import useUser from '~/hooks/useUser'
AccountPage.getInitialProps = async function({ctx: {axios}}) {
const {data} = await axios.get(`/api/orders`)
return {orders: data.sort(sortOrders)}
}
export default function AccountPage({orders}) {
const user = useUser()
return (
<>
<h2>Account</h2>
{/* TODO: Red is kind of intimidating. Should we change this to a yellow or blue info style? */}
{!user.email_confirmed && (
<p className="warning">
<strong style={{display:'inline-block', marginBottom: 8}}>Confirm your email address</strong>
<br/>Confirming your email address allows it to be used for password recovery. <button className="buttonLink">Confirm email address</button>
</p>
)}
<h3>Email and Password</h3>
<div style={{maxWidth: 700, margin: '0 auto'}}>
<p><strong>Email:</strong> {user.email} <button className="buttonLink">Change</button></p>
{/* TODO: Store date password was set so we can show "Set on [date]"? */}
<p><strong>Password:</strong> {!user.password_hash ? 'Unset' : <>Set. <button className="buttonLink">Change</button></>}</p>
</div>
<h3>Your Orders</h3>
<Table
columns={[
{name: 'Purchased', extractor: getPurchaseTime},
{name: 'Items', extractor: getNumberItems},
{name: 'Item Price', extractor: getItemPrice},
{name: 'Shipping', extractor: getShippingEstimate},
{name: 'Total', extractor: getAmountPaid},
{name: '', extractor: order =>
<button className="buttonLink" onClick={() => Router.push(`/account/orders/${order.uuid}`)}>Details</button>
}
]}
rows={orders}
/>
<p/>
</>
)
}
function getPurchaseTime(order){
const mostRecentTransaction = order.transactions.sort(sortTransactions)[0]
const time = parsePaymentTime(mostRecentTransaction)
return time.setZone('local').toFormat('LLLL dd, h:mm a')
}
function getNumberItems(order){
return order.transactions.map(transaction =>
transaction.cart.items.map(item => item.count)
).reduce((a,b)=>(a+b))
}
function getItemPrice(order){
return formatMoney(order.transactions.map(transaction => transaction.item_total_price)
.reduce((a,b)=>(a+b)))
}
function getShippingEstimate(order){
return formatMoney(order.transactions.map(transaction => transaction.shipping_price)
.reduce((a,b)=>(a+b)))
}
function getAmountPaid(order){
return formatMoney(order.transactions.map(({payments}) => payments.map(payment => payment.value_cents))
.flat()
.reduce((a,b)=>(a+b)))
}
function parsePaymentTime({payments}){
for(const payment of payments) {
if(typeof payment.time === 'string')
payment.time = DateTime.fromISO(payment.time)
}
payments.sort((a,b) => b.time.diff(a.time))
return payments[0].time
}
function sortTransactions(a,b){
const timeA = parsePaymentTime(a)
const timeB = parsePaymentTime(b)
return timeB.diff(timeA).as('seconds')
}
function sortOrders(a,b){
const timePaidA = parsePaymentTime(a.transactions.sort(sortTransactions)[0])
const timePaidB = parsePaymentTime(b.transactions.sort(sortTransactions)[0])
return timePaidB.diff(timePaidA).as('seconds')
}
const formatMoney = money => {
if (money === undefined || money === null) return null;
return '$' + (money / 100).toFixed(2)
}

@ -77,10 +77,18 @@ export default function CheckoutComplete({order}){
)
}
function parsePaymentTime({payment}){
if(typeof payment.time === 'string')
payment.time = DateTime.fromISO(payment.time)
return payment.time
function parsePaymentTime({payments}){
if(payments.length < 1) return null;
let lastPaymentTime = DateTime.fromISO(payments[0].time)
for(const payment of payments) {
const current = DateTime.fromISO(payment.time)
if(current.diff(lastPaymentTime).as('seconds') > 0)
lastPaymentTime = current;
}
return lastPaymentTime
}
function sortTransactions(a,b){

@ -84,28 +84,27 @@ export default function CheckoutSummary({order: _order}){
</div>
)
: (
user
?(
<>
{user ? (
<div style={{textAlign: 'center'}}>
<p>
TODO: Load previous addresses
</p>
</div>
):(
<>
<div style={{textAlign: 'center'}}>
<p>
<Link href="/login"><a>Log in</a></Link> to use your<br/>saved addresses
</p>
</div>
<span className={styles.horizDivider}>
OR
</span>
<div>
<Button style={{width: '100px'}} onClick={()=>Router.push('/store/checkout/address')}>Input Address</Button>
</div>
</>
)
<div style={{textAlign: 'center'}}>
<p>
<Link href="/login"><a>Log in</a></Link> to use your<br/>saved addresses
</p>
</div>
)}
<span className={styles.horizDivider}>
OR
</span>
<div>
<Button style={{width: '100px'}} onClick={()=>Router.push('/store/checkout/address')}>Input Address</Button>
</div>
</>
)
}
</div>

@ -45,13 +45,23 @@ main {
padding-bottom: 15px;
}
main > p {
main > p, main > h3, main > h4, main > h5, main > h6 {
width: calc(100% - 100px);
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
main > p.warning {
padding: 8px;
border: solid 1px var(--error-color);
background: #ff74743d;
}
main > p.warning button.buttonLink {
color: red;
}
.cardContainer{
margin-left: auto;
margin-right: auto;

Loading…
Cancel
Save