From 1711cd194b3c9816fd9c0cee09e95a75f6694ea6 Mon Sep 17 00:00:00 2001 From: Ashelyn Dawn Date: Fri, 27 Nov 2020 20:58:14 -0700 Subject: [PATCH] Allow users to re-use previously entered addresses --- api/orders.js | 22 +++++++++ db/models/address.js | 29 ++++++++++++ pages/store/checkout/index.js | 66 +++++++++++++++++++-------- pages/store/checkout/style.module.css | 27 ++++++++++- 4 files changed, 124 insertions(+), 20 deletions(-) diff --git a/api/orders.js b/api/orders.js index 4fb7152..b579449 100644 --- a/api/orders.js +++ b/api/orders.js @@ -5,6 +5,7 @@ const stripe = require('stripe')(process.env.STRIPE_PRIVATE_KEY); const easypost = new (require('@easypost/api'))(process.env.EASYPOST_API_KEY); const ensureAdmin = require('./middleware/ensureAdmin') const ensureCart = require('./middleware/ensureCart') +const ensureUser = require('./middleware/ensureUser') const validate = require('./middleware/validators') @@ -15,6 +16,11 @@ router.get('/', async (req, res) => { return res.json(await db.order.findAllForSession(req.session.uuid)) }) +router.get('/addresses', async (req, res) => { + if(!req.user) return res.json(null) + return res.json(await db.address.findAllForUser(req.user.uuid)) +}) + router.get('/all', ensureAdmin, async (req, res) => { const orders = await db.order.findAllComplete() res.json(orders) @@ -39,6 +45,22 @@ router.get('/:uuid', ensureAdmin, async (req, res) => { res.json(order) }) +router.post('/current/address/:uuid', ensureUser, ensureCart, async (req, res) => { + const origOrder = await db.order.findForCart(req.cart.uuid); + if(!origOrder) throw new Error("Unable to find current order"); + + const currentTransaction = origOrder + .transactions.find(transaction => ( + transaction.payment_state === 'started' + )) + + const address = await db.address.findByUUID(req.params.uuid, req.user.uuid) + if(!address) throw new Error("Unable to find address"); + const order = await db.order.addAddress(currentTransaction, address) + + res.json(order) +}) + router.post('/current/address', ensureCart, parseJSON, validate.address, validate.handleApiError, async (req, res) => { const origOrder = await db.order.findForCart(req.cart.uuid); if(!origOrder) throw new Error("Unable to find current order"); diff --git a/db/models/address.js b/db/models/address.js index 108ad40..fe8ef2e 100644 --- a/db/models/address.js +++ b/db/models/address.js @@ -2,6 +2,7 @@ const pg = require('../pg') const joinjs = require('join-js').default; const debug = require('debug')('sos:db:address') const mappings = require('../mappings') +const dbUtil = require('../util') const easypost = new (require('@easypost/api'))(process.env.EASYPOST_API_KEY); @@ -41,3 +42,31 @@ address.create = async (name, street1, street2, city, state, zip, country) => { const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'addressMap', 'address_')[0] } + +address.findByUUID = async (address_uuid, user_uuid) => dbUtil.executeQuery({ + query: { + text: ` + select * from sos.v_order + where address_uuid = $1 + and order_user_uuid = $2;`, + values: [ + address_uuid, + user_uuid + ] + }, + returnType: 'address', + single: true +}) + +address.findAllForUser = async (user_uuid) => dbUtil.executeQuery({ + query: { + text: ` + select * from sos.v_order + where order_user_uuid = $1 + and transaction_payment_state = 'completed';`, + values: [ + user_uuid + ] + }, + returnType: 'address' +}) diff --git a/pages/store/checkout/index.js b/pages/store/checkout/index.js index f31700f..11338fe 100644 --- a/pages/store/checkout/index.js +++ b/pages/store/checkout/index.js @@ -12,13 +12,13 @@ const { publicRuntimeConfig: {STRIPE_PUBLIC_KEY} } = getConfig() const stripePromise = loadStripe(STRIPE_PUBLIC_KEY); import PaypalIcon from '../../../images/icons/paypal.svg' -// TODO: Load previous addresses CheckoutSummary.getInitialProps = async function({ctx: {axios}}){ + const {data: addresses} = await axios.get(`/api/orders/addresses`) const {data: order} = await axios.get(`/api/orders/current`) - return {order} + return {order, addresses} } -export default function CheckoutSummary({order: _order}){ +export default function CheckoutSummary({order: _order, addresses}){ const user = useUser(); const [order, updateOrder] = useState(_order) const [couponError, setCouponError] = useState(null) @@ -52,7 +52,6 @@ export default function CheckoutSummary({order: _order}){ try { const {data: updatedOrder} = await axios.post(`/api/orders/current/coupon`, {code}) - console.log(order, updatedOrder) updateOrder(updatedOrder) } catch (err) { console.log(err.response.data.errors) @@ -64,6 +63,14 @@ export default function CheckoutSummary({order: _order}){ } } + // For address selection + const onAddressSelect = uuid => async ev => { + if(ev) ev.preventDefault() + + const {data: updatedOrder} = await axios.post(`/api/orders/current/address/${uuid}`) + updateOrder(updatedOrder) + } + // For Stripe checkout const handleStripeButton = async ev => { if(ev) ev.preventDefault() @@ -90,6 +97,7 @@ export default function CheckoutSummary({order: _order}){ order.address ? (
+

Shipping To:

{order.address.name}

{order.address.street1}

{order.address.street2}

@@ -99,22 +107,42 @@ export default function CheckoutSummary({order: _order}){ ) : ( <> - {user ? ( -
-

- TODO: Load previous addresses -

-
- ):( -
-

- Log in to use your
saved addresses -

-
+ {!user && ( + <> +
+

+ Log in to use your
saved addresses +

+
+ + OR + + + )} + {user && addresses && addresses.length && ( + <> +
+ Select a previous address: + {addresses.map(address => ( +
+ + {address.name || address.company} / {address.street1}
+ {address.street2 && <> {address.street2}
} + {address.city} / {address.state} / {address.zip} +
+ + +
+ ))} +
+ + OR + + )} - - OR - +
diff --git a/pages/store/checkout/style.module.css b/pages/store/checkout/style.module.css index 4567a9d..cd71b64 100644 --- a/pages/store/checkout/style.module.css +++ b/pages/store/checkout/style.module.css @@ -54,4 +54,29 @@ .paymentButtons button { margin: 4px; -} \ No newline at end of file +} + +.addressCard { + font-size: 12px; + margin: 0 12px; + padding: 12px; + background: white; + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); + white-space: normal; + margin-bottom: 4px; + display: flex; + flex-direction: row; + align-items: center; +} + +.addressCard:last-child { + margin-bottom: 0; +} + +.addressCard > span { + flex: 1; +} + +.addressCard > button { + width: 80px; +}