Skip to content

Commit

Permalink
✨ Store cart to user db (#1965)
Browse files Browse the repository at this point in the history
* ✨ Store cart to user db

* 🐛 Dont clear cart on add cart items

* 🐛 Overwrite cart item on recover

* 🚸 Clear local cart on account restore

* ♻️ Combine cart API path
  • Loading branch information
williamchong authored Dec 3, 2024
1 parent 6866503 commit 4b4ef47
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 13 deletions.
4 changes: 4 additions & 0 deletions src/server/api/routes/users/v2/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ router.get('/self', authenticateV2Login, async (req, res, next) => {
eventLastSeenTs,
lastLoginMethod: loginMethod,
locale = DEFAULT_LOCALE,
cart,
} = userDoc.data();
if (email) {
try {
Expand All @@ -53,6 +54,7 @@ router.get('/self', authenticateV2Login, async (req, res, next) => {
eventLastSeenTs: eventLastSeenTs ? eventLastSeenTs.toMillis() : 1000,
locale,
crispToken: email ? getCrispUserHash(email) : undefined,
cart,
});
} catch (err) {
if (req.session) req.session = null;
Expand All @@ -71,6 +73,7 @@ router.post('/login', async (req, res, next) => {
loginMethod = '',
gaClientId,
userIdHash,
cart,
} = req.body;
try {
if (!inputWallet || !signature || !publicKey || !message) {
Expand Down Expand Up @@ -158,6 +161,7 @@ router.post('/login', async (req, res, next) => {
displayName,
isNew,
crispToken: email ? getCrispUserHash(email) : undefined,
cart,
};
res.json(payload);
return;
Expand Down
72 changes: 72 additions & 0 deletions src/server/api/routes/users/v2/cart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const { Router } = require('express');

const { authenticateV2Login } = require('../../../middleware/auth');
const {
FieldValue,
walletUserCollection,
} = require('../../../../modules/firebase');

const router = Router();

router.get('/cart', authenticateV2Login, async (req, res) => {
const { user } = req.session;
const cartDoc = await walletUserCollection.doc(user).get();
const { cart } = cartDoc.data();
res.json({ cart: cart || [] });
});

router.post('/cart', authenticateV2Login, async (req, res) => {
const { user } = req.session;
const { cart: inputCart } = req.body;
if (!Array.isArray(inputCart)) {
res.status(400).send('INVALID_CART');
return;
}
const cart = Object.values(
inputCart.reduce((acc, item) => {
acc[item.productId] = item;
return acc;
}, {})
).map(item => {
const {
productId,
collectionId,
classId,
coupon,
customPriceInDecimal,
from,
timestamp,
quantity,
priceIndex,
} = item;
return JSON.parse(
JSON.stringify({
productId,
collectionId,
classId,
coupon,
customPriceInDecimal,
from,
timestamp,
quantity,
priceIndex,
})
);
});
await walletUserCollection.doc(user).update({
cart: cart?.length ? cart : FieldValue.delete(),
cartUpdateTimestamp: FieldValue.serverTimestamp(),
});
res.sendStatus(200);
});

router.delete('/cart', authenticateV2Login, async (req, res) => {
const { user } = req.session;
await walletUserCollection.doc(user).update({
cart: FieldValue.delete(),
cartUpdateTimestamp: FieldValue.serverTimestamp(),
});
res.sendStatus(200);
});

module.exports = router;
2 changes: 2 additions & 0 deletions src/server/api/routes/users/v2/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { Router } = require('express');

const auth = require('./auth');
const cart = require('./cart');
const email = require('./email');
const event = require('./event');
const follow = require('./follow');
Expand All @@ -12,6 +13,7 @@ const wallet = require('./wallet');
const router = Router();

router.use(auth);
router.use(cart);
router.use(email);
router.use(event);
router.use(follow);
Expand Down
45 changes: 33 additions & 12 deletions src/store/modules/cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
saveShoppingCartToStorage,
} from '~/util/shopping-cart';
import { BATCH_COLLECT_MAX } from '~/constant';
import { postShoppingCart, deleteShoppingCart } from '~/util/api';
import * as TYPES from '../mutation-types';

const state = () => ({
Expand Down Expand Up @@ -34,7 +35,10 @@ const mutations = {
[TYPES.SHOPPING_CART_REPLACE_ALL_NFT_CLASS](state, map) {
state.shoppingCartNFTClassByIdMap = map;
},
[TYPES.SHOPPING_CART_ADD_BOOK_PRODUCT](state, newItem) {
[TYPES.SHOPPING_CART_ADD_BOOK_PRODUCT](
state,
{ item: newItem, overwrite = false }
) {
const {
collectionId,
classId,
Expand All @@ -57,7 +61,7 @@ const mutations = {
quantity: 1,
priceIndex: priceIndex ?? (classId ? 0 : undefined),
};
} else {
} else if (!overwrite) {
item = {
...item,
quantity: item.quantity + 1,
Expand Down Expand Up @@ -151,13 +155,12 @@ const actions = {
if (getters.shoppingCartBookProductList.length >= BATCH_COLLECT_MAX) {
return;
}
commit(TYPES.SHOPPING_CART_ADD_BOOK_PRODUCT, item);
commit(TYPES.SHOPPING_CART_ADD_BOOK_PRODUCT, { item });
dispatch('saveBookProductShoppingCart');
},
addBookProductsToShoppingCart({ commit, dispatch }, items) {
commit(TYPES.SHOPPING_CART_REPLACE_ALL_BOOK_PRODUCT, {});
items.slice(0, BATCH_COLLECT_MAX).forEach(item => {
commit(TYPES.SHOPPING_CART_ADD_BOOK_PRODUCT, item);
commit(TYPES.SHOPPING_CART_ADD_BOOK_PRODUCT, { item, overwrite: true });
});
dispatch('saveBookProductShoppingCart');
},
Expand All @@ -169,14 +172,32 @@ const actions = {
commit(TYPES.SHOPPING_CART_REPLACE_ALL_BOOK_PRODUCT, {});
dispatch('saveBookProductShoppingCart');
},
saveBookProductShoppingCart({ state }) {
saveShoppingCartToStorage(state.shoppingCartBookProductByIdMap, 'book');
async saveBookProductShoppingCart({ state, getters }) {
if (getters.loginAddress) {
const cart = Object.values(state.shoppingCartBookProductByIdMap);
try {
if (cart.length) {
await this.$api.$post(postShoppingCart(), { cart });
} else {
await this.$api.$delete(postShoppingCart());
}
saveShoppingCartToStorage({}, 'book');
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
saveShoppingCartToStorage(state.shoppingCartBookProductByIdMap, 'book');
}
} else {
saveShoppingCartToStorage(state.shoppingCartBookProductByIdMap, 'book');
}
},
loadBookProductShoppingCart({ commit }) {
commit(
TYPES.SHOPPING_CART_REPLACE_ALL_BOOK_PRODUCT,
loadShoppingCartFromStorage('book')
);
loadBookProductShoppingCart({ commit, getters }) {
if (!getters.shoppingCartBookItems.length) {
commit(
TYPES.SHOPPING_CART_REPLACE_ALL_BOOK_PRODUCT,
loadShoppingCartFromStorage('book')
);
}
},
};

Expand Down
5 changes: 4 additions & 1 deletion src/store/modules/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -840,13 +840,16 @@ const actions = {
if (!checkIsLikeCoinAppInAppBrowser(this.$router.app.$route)) {
await dispatch('setLocale', userInfo.locale);
}
const { displayName, email, crispToken } = userInfo;
const { displayName, email, crispToken, cart } = userInfo;
updateLoggerUserInfo(this, {
email,
displayName,
wallet: state.address,
crispToken,
});
if (cart?.length) {
dispatch('addBookProductsToShoppingCart', cart);
}
return userInfo;
},
async walletFetchSessionUserData(
Expand Down
4 changes: 4 additions & 0 deletions src/util/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ export const getUserV2Self = () => '/api/v2/users/self';
export const postUserV2Login = () => '/api/v2/users/login';
export const postUserV2Logout = () => '/api/v2/users/logout';

export const getShoppingCart = () => '/api/v2/users/cart';
export const postShoppingCart = getShoppingCart;
export const deleteShoppingCart = getShoppingCart;

export const postUserV2WalletEmail = ({
email,
followee,
Expand Down

0 comments on commit 4b4ef47

Please sign in to comment.