You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.2 KiB
JavaScript

import {DateTime} from 'luxon'
import Head from 'next/head'
import Router from 'next/router'
import Link from 'next/link'
import Table from '~/components/table'
import useUser from '~/hooks/useUser'
import redirect from '~/utils/redirectGetInitialProps'
AccountPage.getInitialProps = async function({ctx, user}) {
const {axios} = ctx;
if(!user)
return redirect(ctx, 302, '/login')
if(!user.email_confirmed)
return redirect(ctx, 302, '/account/email/confirm')
const {data} = await axios.get(`/api/orders`)
return {orders: data.sort(sortOrders)}
}
export default function AccountPage({orders}) {
const user = useUser()
return (
<>
<Head>
<title>Account | Society of Socks</title>
</Head>
<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}
{/* <Link href="/account/change-email"><a>Change</a></Link> */}
</p>
{/* TODO: Store date password was set so we can show "Set on [date]"? */}
<p><strong>Password:</strong> {
!user.password_hash
? 'Unset'
: <>Last changed {DateTime.fromISO(user.time_password_changed).toFormat('LLLL dd yyyy, h:mm a')}. <Link href="/account/change-password"><a>Change</a></Link></>
}</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.number}`)}>Details</button>
}
]}
rows={orders}
/>
<p>
<strong>Note:</strong> Due to technical reasons, orders placed before June 7th 2021 are no longer visible
in your account details. If you have questions about orders you placed before then, please contact us.
</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)
}