diff --git a/controllers/orderController.js b/controllers/orderController.js index 954e7f0..615e9f1 100644 --- a/controllers/orderController.js +++ b/controllers/orderController.js @@ -1,145 +1,122 @@ const Order = require('../models/order'); const Cart = require('../models/cart'); const User = require('../models/user'); -const mongoose = require('mongoose'); const Book = require('../models/book'); +require('dotenv').config(); +const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); // Display list of all Orders. exports.order_list = async (req, res) => { try { - const cart = await Cart.findOne({ user: req.user._id }).populate('books'); + const cart = await Cart.findOne({ user: req.user._id }).populate( + 'books', + ); const user = await User.findById(req.user._id); let wallet_amount = user.wallet_amount; let total_price = 0; - cart.books.forEach(book => { + cart.books.forEach((book) => { total_price += book.price; }); // render checkout view res.render('checkout', { cart, total_price, wallet_amount }); - } - catch(err) { + } catch (err) { console.log(err); res.status(500).json(err); } }; - -// ... - // Handle Order create on POST. exports.order_create_post = async (req, res) => { - // Start a new session for the transaction - const session = await mongoose.startSession(); - session.startTransaction(); - try { - console.log('Creating order') - const cart = await Cart.findOne({ user: req.user._id }).populate('books'); - let total_price = 0; - for (let book of cart.books) { - total_price += book.price; - } + console.log('Creating order'); + const cart = await Cart.findOne({ user: req.user._id }).populate( + 'books', + ); - const user = await User.findById(req.user._id); - if (user.wallet_amount < total_price) { - req.flash('error', 'Insufficient funds in wallet'); - res.redirect('back'); + if (!cart || !Array.isArray(cart.books)) { + res.status(400).send('Cart is not properly defined'); return; } - // decrement the quantity of each book in the cart - for (let book of cart.books) { - book.quantity -= 1; - await book.save({ session }); - } + const stripe_session = await stripe.checkout.sessions.create({ + payment_method_types: ['card'], + mode: 'payment', + line_items: cart.books.map((book) => { + return { + price_data: { + currency: 'usd', + product_data: { + name: book.title, + }, + unit_amount: Math.round(book.price * 100), + }, + quantity: 1, + }; + }), + success_url: `${process.env.DOMAIN}/orders/mybooks`, + cancel_url: `${process.env.DOMAIN}/orders/`, + }); - // for each seller in the cart, give them 97% of the total price of their books - let sellers = []; + let total_price = 0; for (let book of cart.books) { - if (!sellers.includes(book.seller)) { - sellers.push(book.seller); - } - } - - for (let seller of sellers) { - let seller_total = 0; - for (let book of cart.books) { - if (book.seller.equals(seller)) { - seller_total += book.price; - } - } - const seller_user = await User.findById(seller); - seller_user.wallet_amount += seller_total * 0.97; - seller_user.wallet_amount = Math.round(seller_user.wallet_amount * 100) / 100; - - // the 3% profit goes to the admin - // not yet implemented - - await seller_user.save({session}); + total_price += book.price; } - // Create a new order const order = new Order({ user: req.user._id, - bought_books: cart.books, - total_price: total_price, + bought_books: cart.books.map((book) => book._id), + total_price: total_price, // Ensure total_price is defined order_date: Date.now(), }); - // Clear the user's cart - cart.books = []; - await cart.save({ session }); - - // Save the order - await order.save({ session }); + await order.save(); - // Deduct the total price of the order from the user's wallet - user.wallet_amount -= total_price; - await user.save({ session }); + // Update book quantities + for (let book of cart.books) { + book.quantity -= 1; + await book.save(); + } - // Commit the transaction - await session.commitTransaction(); - session.endSession(); + // Clear the user's cart + cart.books = []; + await cart.save(); - // redirect to 'books' and display success message + + res.json({ url: stripe_session.url }); req.flash('success', 'Order placed successfully'); - res.redirect('/orders/mybooks'); - } catch (err) { - // If an error occurred, abort the transaction - await session.abortTransaction(); - session.endSession(); - - console.log(err); + console.error(err.message); res.status(500).json(err); } }; - // Display list of all books bought by the user. exports.order_mybooks = async (req, res) => { try { let books; if (req.user.type === 'buyer') { - const orders = await Order.find({ user: req.user._id }).populate('bought_books'); - books = orders.flatMap(order => order.bought_books); + const orders = await Order.find({ user: req.user._id }).populate( + 'bought_books', + ); + books = orders.flatMap((order) => order.bought_books); } else if (req.user.type === 'seller') { books = await Book.find({ seller: req.user._id }); } // Loop over each book and populate - books = await Promise.all(books.map(async (book) => { - return await Book.populate(book, [ - {path: 'authors'}, - {path: 'publisher', select: 'name'}, - {path: 'categories', select: 'name'} - ]); - })); - - res.render('mybooks', {books: books}); - } - catch(err) { + books = await Promise.all( + books.map(async (book) => { + return await Book.populate(book, [ + { path: 'authors' }, + { path: 'publisher', select: 'name' }, + { path: 'categories', select: 'name' }, + ]); + }), + ); + + res.render('mybooks', { books: books }); + } catch (err) { console.log(err); res.status(500).json(err); } diff --git a/package-lock.json b/package-lock.json index af71122..9bf57b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,8 @@ "multer": "^1.4.5-lts.1", "passport": "^0.7.0", "passport-local": "^1.0.0", - "pdfjs-dist": "^4.0.269" + "pdfjs-dist": "^4.0.269", + "stripe": "^14.10.0" }, "devDependencies": { "prettier": "^3.1.0" @@ -259,6 +260,19 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/canvas": { "version": "2.11.2", "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", @@ -442,6 +456,19 @@ "node": ">=8" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -693,6 +720,14 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -712,6 +747,20 @@ "node": ">=10" } }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -731,11 +780,66 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -1345,6 +1449,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1635,11 +1747,38 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sift": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", @@ -1756,6 +1895,32 @@ "node": ">=8" } }, + "node_modules/stripe": { + "version": "14.10.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.10.0.tgz", + "integrity": "sha512-zI6yxYVFJtjibgb06Xn08KsJy1Zq+KE3jLkhZ8bJOTrxNVi2CtCreQdUn+NjXN5lTEdiNhxIqL0NmuSza+rOGw==", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=12.*" + } + }, + "node_modules/stripe/node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tar": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", @@ -2080,6 +2245,16 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, "canvas": { "version": "2.11.2", "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", @@ -2224,6 +2399,16 @@ "mimic-response": "^2.0.0" } }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -2408,6 +2593,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, "gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -2424,6 +2614,17 @@ "wide-align": "^1.1.2" } }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2437,11 +2638,45 @@ "path-is-absolute": "^1.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -2856,6 +3091,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -3063,11 +3303,32 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "sift": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", @@ -3146,6 +3407,25 @@ "ansi-regex": "^5.0.1" } }, + "stripe": { + "version": "14.10.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.10.0.tgz", + "integrity": "sha512-zI6yxYVFJtjibgb06Xn08KsJy1Zq+KE3jLkhZ8bJOTrxNVi2CtCreQdUn+NjXN5lTEdiNhxIqL0NmuSza+rOGw==", + "requires": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "dependencies": { + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, "tar": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", diff --git a/package.json b/package.json index 40cb438..2e63157 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "multer": "^1.4.5-lts.1", "passport": "^0.7.0", "passport-local": "^1.0.0", - "pdfjs-dist": "^4.0.269" + "pdfjs-dist": "^4.0.269", + "stripe": "^14.10.0" }, "devDependencies": { "prettier": "^3.1.0" diff --git a/public/stylesheets/nav.css b/public/stylesheets/nav.css index 8a5e519..1b55f01 100644 --- a/public/stylesheets/nav.css +++ b/public/stylesheets/nav.css @@ -13,8 +13,13 @@ nav{ justify-content: space-between; position: relative; } +nav h1{ + color: #fff; + margin-bottom: 0; + font-wight: bold; +} .user-pic{ - width: 60px; + width: 50px; border-radius: 50%; cursor: pointer; margin-left: 30px; @@ -68,6 +73,7 @@ nav ul li a:hover{ .user-info h3{ font-weight: 500; color: white; + margin: 0; } .user-info img{ width: 50px; diff --git a/views/book_instance.ejs b/views/book_instance.ejs index 2cda90a..a3ce9b4 100644 --- a/views/book_instance.ejs +++ b/views/book_instance.ejs @@ -32,7 +32,7 @@
- + <% const stock = book.quantity %> <% if( stock > 0 ){ %> @@ -46,6 +46,11 @@ (cart_book) => cart_book._id.toString() === book._id.toString(), )) { %> + <% if( stock <= 0 ){ %> +

Out of stock

+ <% } else {%> +

In stock

+ <% } %>
diff --git a/views/checkout.ejs b/views/checkout.ejs index 9d63151..65cf747 100644 --- a/views/checkout.ejs +++ b/views/checkout.ejs @@ -57,9 +57,8 @@ <% }) %>
-
Wallet Amount$<%= wallet_amount %>
Total:$<%= total_price %>
- +
@@ -69,7 +68,37 @@ <% } %> + \ No newline at end of file diff --git a/views/partials/navbar.ejs b/views/partials/navbar.ejs index 4d4f0fa..3121373 100644 --- a/views/partials/navbar.ejs +++ b/views/partials/navbar.ejs @@ -13,7 +13,7 @@