-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
373 lines (348 loc) · 11.3 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
const express = require("express");
const csrf = require("csurf");
const stripe = require("stripe")(process.env.STRIPE_PRIVATE_KEY);
const Product = require("../models/product");
const Category = require("../models/category");
const Cart = require("../models/cart");
const Order = require("../models/order");
const middleware = require("../middleware");
const router = express.Router();
const csrfProtection = csrf();
router.use(csrfProtection);
// GET: home page
router.get("/", async (req, res) => {
try {
const products = await Product.find({})
.sort("-createdAt")
.populate("category");
res.render("shop/home", { pageName: "Home", products });
} catch (error) {
console.log(error);
res.redirect("/");
}
});
// GET: add a product to the shopping cart when "Add to cart" button is pressed
router.get("/add-to-cart/:id", async (req, res) => {
const productId = req.params.id;
try {
// get the correct cart, either from the db, session, or an empty cart.
let user_cart;
if (req.user) {
user_cart = await Cart.findOne({ user: req.user._id });
}
let cart;
if (
(req.user && !user_cart && req.session.cart) ||
(!req.user && req.session.cart)
) {
cart = await new Cart(req.session.cart);
} else if (!req.user || !user_cart) {
cart = new Cart({});
} else {
cart = user_cart;
}
// add the product to the cart
const product = await Product.findById(productId);
const itemIndex = cart.items.findIndex((p) => p.productId == productId);
if (itemIndex > -1) {
// if product exists in the cart, update the quantity
cart.items[itemIndex].qty++;
cart.items[itemIndex].price = cart.items[itemIndex].qty * product.price;
cart.totalQty++;
cart.totalCost += product.price;
} else {
// if product does not exists in cart, find it in the db to retrieve its price and add new item
cart.items.push({
productId: productId,
qty: 1,
price: product.price,
title: product.title,
productCode: product.productCode,
});
cart.totalQty++;
cart.totalCost += product.price;
}
// if the user is logged in, store the user's id and save cart to the db
if (req.user) {
cart.user = req.user._id;
await cart.save();
}
req.session.cart = cart;
req.flash("success", "Thêm vào giỏ hàng thành công!");
res.redirect(req.headers.referer);
} catch (err) {
console.log(err.message);
res.redirect("/");
}
});
// GET: view shopping cart contents
router.get("/shopping-cart", async (req, res) => {
try {
// find the cart, whether in session or in db based on the user state
let cart_user;
if (req.user) {
cart_user = await Cart.findOne({ user: req.user._id });
}
// if user is signed in and has cart, load user's cart from the db
if (req.user && cart_user) {
req.session.cart = cart_user;
return res.render("shop/shopping-cart", {
cart: cart_user,
pageName: "Shopping Cart",
products: await productsFromCart(cart_user),
});
}
// if there is no cart in session and user is not logged in, cart is empty
if (!req.session.cart) {
return res.render("shop/shopping-cart", {
cart: null,
pageName: "Shopping Cart",
products: null,
});
}
// otherwise, load the session's cart
return res.render("shop/shopping-cart", {
cart: req.session.cart,
pageName: "Shopping Cart",
products: await productsFromCart(req.session.cart),
});
} catch (err) {
console.log(err.message);
res.redirect("/");
}
});
// GET: reduce one from an item in the shopping cart
router.get("/reduce/:id", async function (req, res, next) {
// if a user is logged in, reduce from the user's cart and save
// else reduce from the session's cart
const productId = req.params.id;
let cart;
try {
if (req.user) {
cart = await Cart.findOne({ user: req.user._id });
} else if (req.session.cart) {
cart = await new Cart(req.session.cart);
}
// find the item with productId
let itemIndex = cart.items.findIndex((p) => p.productId == productId);
if (itemIndex > -1) {
// find the product to find its price
const product = await Product.findById(productId);
// if product is found, reduce its qty
cart.items[itemIndex].qty--;
cart.items[itemIndex].price -= product.price;
cart.totalQty--;
cart.totalCost -= product.price;
// if the item's qty reaches 0, remove it from the cart
if (cart.items[itemIndex].qty <= 0) {
await cart.items.remove({ _id: cart.items[itemIndex]._id });
}
req.session.cart = cart;
//save the cart it only if user is logged in
if (req.user) {
await cart.save();
}
//delete cart if qty is 0
if (cart.totalQty <= 0) {
req.session.cart = null;
await Cart.findByIdAndRemove(cart._id);
}
}
res.redirect(req.headers.referer);
} catch (err) {
console.log(err.message);
res.redirect("/");
}
});
// GET: remove all instances of a single product from the cart
router.get("/removeAll/:id", async function (req, res, next) {
const productId = req.params.id;
let cart;
try {
if (req.user) {
cart = await Cart.findOne({ user: req.user._id });
} else if (req.session.cart) {
cart = await new Cart(req.session.cart);
}
//fnd the item with productId
let itemIndex = cart.items.findIndex((p) => p.productId == productId);
if (itemIndex > -1) {
//find the product to find its price
cart.totalQty -= cart.items[itemIndex].qty;
cart.totalCost -= cart.items[itemIndex].price;
await cart.items.remove({ _id: cart.items[itemIndex]._id });
}
req.session.cart = cart;
//save the cart it only if user is logged in
if (req.user) {
await cart.save();
}
//delete cart if qty is 0
if (cart.totalQty <= 0) {
req.session.cart = null;
await Cart.findByIdAndRemove(cart._id);
}
res.redirect(req.headers.referer);
} catch (err) {
console.log(err.message);
res.redirect("/");
}
});
// GET: checkout form with csrf token
router.get("/checkout", middleware.isLoggedIn, async (req, res) => {
const errorMsg = req.flash("error")[0];
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
//load the cart with the session's cart's id from the db
cart = await Cart.findById(req.session.cart._id);
const errMsg = req.flash("error")[0];
res.render("shop/checkout", {
total: cart.totalCost,
csrfToken: req.csrfToken(),
errorMsg,
pageName: "Checkout",
});
});
// // POST: handle checkout logic and payment using Stripe
// router.post("/checkout", middleware.isLoggedIn, async (req, res) => {
// if (!req.session.cart) {
// return res.redirect("/shopping-cart");
// }
// const cart = await Cart.findById(req.session.cart._id);
// stripe.charges.create(
// {
// amount: cart.totalCost * 100,
// currency: "usd",
// source: req.body.stripeToken,
// description: "Test charge",
// },
// function (err, charge) {
// if (err) {
// req.flash("error", err.message);
// console.log(err);
// return res.redirect("/checkout");
// }
// const order = new Order({
// user: req.user,
// cart: {
// totalQty: cart.totalQty,
// totalCost: cart.totalCost,
// items: cart.items,
// },
// address: req.body.address,
// paymentId: charge.id,
// });
// order.save(async (err, newOrder) => {
// if (err) {
// console.log(err);
// return res.redirect("/checkout");
// }
// await cart.save();
// await Cart.findByIdAndDelete(cart._id);
// req.flash("success", "Successfully purchased");
// req.session.cart = null;
// res.redirect("/user/profile");
// });
// }
// );
// });
router.post("/checkout", middleware.isLoggedIn, async (req, res) => {
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
const cart = await Cart.findById(req.session.cart._id);
// Convert total cost to VND (assuming prices are stored in USD)
// Conversion rate (replace with a mechanism to fetch live rates if needed)
const conversionRateToUSD = 0.000039;
// Convert total cost to VND
const totalCostInUSD = cart.totalCost * conversionRateToUSD;
// Enforce maximum Stripe charge amount
const maxChargeAmount = 99999.99;
if (totalCostInUSD > maxChargeAmount) {
req.flash("error", "Total cart cost exceeds the maximum allowed charge amount.");
console.log("Error: Cart total exceeds Stripe charge limit.");
return res.redirect("/checkout");
}
stripe.charges.create(
{
amount: Math.round(totalCostInUSD*100), // Round to nearest integer for VND (no decimals)
currency: "usd",
source: req.body.stripeToken,
description: "Test charge",
},
function (err, charge) {
if (err) {
req.flash("error", err.message);
console.log(err);
return res.redirect("/checkout");
}
const order = new Order({
user: req.user,
cart: {
totalQty: cart.totalQty,
totalCost: cart.totalCost, // Keep original USD cost for reference
items: cart.items,
},
address: req.body.address,
paymentId: charge.id,
});
order.save(async (err, newOrder) => {
if (err) {
console.log(err);
return res.redirect("/checkout");
}
await cart.save();
await Cart.findByIdAndDelete(cart._id);
req.flash("success", "Đặt hàng thành công! Cảm ơn bạn đã mua hàng tại Artisian Leather Craft, sản phẩm sẽ được giao tới bạn trong thời gian sớm nhất.");
req.session.cart = null;
res.redirect("/user/profile");
});
}
);
});
// create products array to store the info of each product in the cart
async function productsFromCart(cart) {
let products = []; // array of objects
for (const item of cart.items) {
let foundProduct = (
await Product.findById(item.productId).populate("category")
).toObject();
foundProduct["qty"] = item.qty;
foundProduct["totalPrice"] = item.price;
products.push(foundProduct);
}
return products;
}
router.get("/products", async (req, res) => {
console.log("all page")
try {
// Construct the query object
const query = {};
if (req.query.category) {
query.category = req.query.category;
}
if (req.query.price) {
// Implement price filtering logic if needed
}
let products;
// Check if sorting parameter exists
if (req.query.sort === 'price-low-to-high') {
products = await Product.find(query)
.sort({ price: 1 })
.populate("category");
} else if (req.query.sort === 'price-high-to-low') {
products = await Product.find(query)
.sort({ price: -1 })
.populate("category");
} else {
// If no sorting parameter provided, return unsorted products
products = await Product.find(query).populate("category");
}
res.render("shop/home", { pageName: "All Products", products });
} catch (error) {
console.log(error);
res.redirect("/");
}
});
module.exports = router;