├── src
├── components
│ ├── Blog
│ │ ├── Blog.css
│ │ └── Blog.js
│ ├── AdminPanel
│ │ ├── Order
│ │ │ ├── Order.css
│ │ │ ├── AdminPlaceOrder.js
│ │ │ └── Orders.js
│ │ ├── Billing
│ │ │ ├── Billing.js
│ │ │ ├── Requests.js
│ │ │ ├── Transactions.js
│ │ │ └── PreviousTransactions.js
│ │ ├── Analytics
│ │ │ └── Analytics.js
│ │ ├── Support
│ │ │ ├── Support.js
│ │ │ ├── Support.css
│ │ │ ├── SupportSideBar.js
│ │ │ └── SupportContent.js
│ │ ├── AdminPanel.js
│ │ ├── Navigation
│ │ │ ├── AdminAppBar.js
│ │ │ ├── AdminPanelNavbar.js
│ │ │ └── AdminContentPanel.js
│ │ ├── Book
│ │ │ ├── Book.css
│ │ │ ├── AdminFindBook.js
│ │ │ ├── BookVerification
│ │ │ │ ├── AdminBookDelete.js
│ │ │ │ └── AdminBookApprove.js
│ │ │ └── Book.js
│ │ ├── AdminPanel.css
│ │ └── UserProfile.js
│ ├── auth
│ │ ├── signup
│ │ │ ├── signup.css
│ │ │ └── verify.js
│ │ ├── auth.css
│ │ └── recovery
│ │ │ └── recovery.css
│ ├── MicroComponents
│ │ ├── MicroComponents.css
│ │ ├── BookshlfLoader.js
│ │ ├── customCopyText.js
│ │ └── Mail.js
│ ├── search
│ │ ├── searchresults.js
│ │ ├── pagination.js
│ │ ├── search.js
│ │ ├── searchbook.js
│ │ ├── search.css
│ │ └── searchfilter.js
│ ├── home
│ │ ├── NotFoundPage.js
│ │ ├── Categories.css
│ │ ├── home.js
│ │ ├── Categories.js
│ │ ├── home.css
│ │ └── Benefits.js
│ ├── navbar
│ │ ├── navbarlinks.js
│ │ ├── navbarsearch.js
│ │ └── navbarmenu.js
│ ├── BookDetails
│ │ ├── BookDetails.css
│ │ ├── BookPurchaseAdmin.js
│ │ └── Booksnaps.js
│ ├── userpanel
│ │ ├── usernav.js
│ │ ├── userpanel.css
│ │ ├── profile.js
│ │ └── userpanel.js
│ ├── Footer
│ │ └── Footer.css
│ ├── Checkout
│ │ ├── CheckoutLoading.js
│ │ ├── CheckoutOrderReview.js
│ │ ├── CheckoutPayment.js
│ │ ├── CheckoutAddress.js
│ │ ├── CheckoutOrderPlace.js
│ │ └── CheckoutStepper.js
│ ├── Order
│ │ └── tracking
│ │ │ ├── tracking.js
│ │ │ ├── tracking.css
│ │ │ ├── trackprogress.js
│ │ │ └── trackingstepper.js
│ ├── Wallet
│ │ └── Wallet.css
│ ├── About
│ │ ├── AboutSocial.js
│ │ └── About.js
│ ├── SellerPanel
│ │ └── SellerPanel.css
│ ├── Book
│ │ └── AddBook.css
│ └── AddressBook
│ │ ├── AddressDetails.js
│ │ └── AddressList.js
├── service
│ ├── auth
│ │ ├── verification.js
│ │ ├── recovery.js
│ │ ├── logout.js
│ │ ├── login.js
│ │ └── signup.js
│ ├── AdminPanel
│ │ └── Analytics
│ │ │ ├── Analytics.js
│ │ │ └── OrdersAnalytics.js
│ ├── search
│ │ └── booksearch.js
│ └── Book
│ │ └── AdminBookPurchase
│ │ └── purchaseOrder.js
├── assets
│ ├── Theme
│ │ ├── fonts.js
│ │ └── colors.js
│ ├── components
│ │ ├── input
│ │ │ ├── textfield.js
│ │ │ ├── passwordfield.js
│ │ │ └── otpfield.js
│ │ ├── buttons
│ │ │ ├── button.js
│ │ │ ├── bookbutton.js
│ │ │ ├── loadingbutton.js
│ │ │ ├── ordercancelbutton.js
│ │ │ ├── cartbutton.js
│ │ │ └── wishlistbutton.js
│ │ ├── links
│ │ │ ├── navlink.js
│ │ │ ├── link.js
│ │ │ └── links.css
│ │ ├── container.js
│ │ ├── pageloader.js
│ │ └── base.css
│ ├── counter.js
│ └── utils
│ │ ├── date.js
│ │ └── commons.js
├── api
│ ├── debounce.js
│ ├── axios.js
│ ├── requests
│ │ ├── deleteAPI.js
│ │ ├── postAPI.js
│ │ └── getAPI.js
│ └── endpoints.js
├── index.css
├── reportWebVitals.js
├── app
│ ├── app.css
│ └── app.js
├── context
│ ├── adminContext.js
│ └── userContext.js
├── index.js
└── route
│ └── router.js
├── .prettierignore
├── Demo.env.txt
├── public
├── images
│ ├── ghost.png
│ ├── india.png
│ ├── logo.png
│ ├── user.png
│ ├── favicon.ico
│ ├── logoView.png
│ ├── smallLogo.png
│ ├── userprofile.png
│ ├── Benefits
│ │ ├── book.png
│ │ ├── easy.png
│ │ ├── package.png
│ │ ├── support.png
│ │ ├── doorstep.png
│ │ └── free-delivery.png
│ ├── favicon-32x32.ico
│ ├── smallLogoView.png
│ ├── Categories
│ │ ├── school.png
│ │ ├── cbse-logo.png
│ │ ├── novel-logo.jpg
│ │ ├── neet-ug-logo.png
│ │ ├── jeemains-logo.png
│ │ └── JEE-Advance-Logo.png
│ ├── Carousel
│ │ ├── CarouselMobile
│ │ │ ├── Carousel_bg1.png
│ │ │ ├── Carousel_bg2.png
│ │ │ ├── Carousel_bg3.png
│ │ │ ├── Carousel_bg4.png
│ │ │ ├── Carousel_bg5.png
│ │ │ └── Carousel_bg6.png
│ │ └── CarouselDesktop
│ │ │ ├── Carousel_bg1.png
│ │ │ ├── Carousel_bg2.png
│ │ │ ├── Carousel_bg3.png
│ │ │ ├── Carousel_bg4.png
│ │ │ ├── Carousel_bg5.png
│ │ │ └── Carousel_bg6.png
│ ├── smallLogo.svg
│ └── enviaLogo.svg
├── robots.txt
├── manifest.json
├── sitemap.xml
└── index.html
├── .prettierrc
├── .github
├── dependabot.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
└── package.json
/src/components/Blog/Blog.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/service/auth/verification.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Order/Order.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Billing/Billing.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Billing/Requests.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/service/AdminPanel/Analytics/Analytics.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Billing/Transactions.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Billing/PreviousTransactions.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/.prettierignore
--------------------------------------------------------------------------------
/src/assets/Theme/fonts.js:
--------------------------------------------------------------------------------
1 | // Main Font
2 | export const DMsans = "'DM Sans', sans-serif";
3 |
--------------------------------------------------------------------------------
/Demo.env.txt:
--------------------------------------------------------------------------------
1 | REACT_APP_BOOKSHLF=https://bookshlf.herokuapp.com/
2 | REACT_APP_NODE_ENV=development
--------------------------------------------------------------------------------
/public/images/ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/ghost.png
--------------------------------------------------------------------------------
/public/images/india.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/india.png
--------------------------------------------------------------------------------
/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/logo.png
--------------------------------------------------------------------------------
/public/images/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/user.png
--------------------------------------------------------------------------------
/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/favicon.ico
--------------------------------------------------------------------------------
/public/images/logoView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/logoView.png
--------------------------------------------------------------------------------
/public/images/smallLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/smallLogo.png
--------------------------------------------------------------------------------
/public/images/userprofile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/userprofile.png
--------------------------------------------------------------------------------
/public/images/Benefits/book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Benefits/book.png
--------------------------------------------------------------------------------
/public/images/Benefits/easy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Benefits/easy.png
--------------------------------------------------------------------------------
/public/images/favicon-32x32.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/favicon-32x32.ico
--------------------------------------------------------------------------------
/public/images/smallLogoView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/smallLogoView.png
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": false
6 | }
7 |
--------------------------------------------------------------------------------
/public/images/Benefits/package.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Benefits/package.png
--------------------------------------------------------------------------------
/public/images/Benefits/support.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Benefits/support.png
--------------------------------------------------------------------------------
/public/images/Benefits/doorstep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Benefits/doorstep.png
--------------------------------------------------------------------------------
/public/images/Categories/school.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Categories/school.png
--------------------------------------------------------------------------------
/public/images/Categories/cbse-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Categories/cbse-logo.png
--------------------------------------------------------------------------------
/public/images/Categories/novel-logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Categories/novel-logo.jpg
--------------------------------------------------------------------------------
/public/images/Benefits/free-delivery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Benefits/free-delivery.png
--------------------------------------------------------------------------------
/public/images/Categories/neet-ug-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Categories/neet-ug-logo.png
--------------------------------------------------------------------------------
/public/images/Categories/jeemains-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Categories/jeemains-logo.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Allow: /
4 |
5 | Sitemap: https://rohit-kumar.me/sitemap.xml
--------------------------------------------------------------------------------
/public/images/Categories/JEE-Advance-Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Categories/JEE-Advance-Logo.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselMobile/Carousel_bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselMobile/Carousel_bg1.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselMobile/Carousel_bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselMobile/Carousel_bg2.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselMobile/Carousel_bg3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselMobile/Carousel_bg3.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselMobile/Carousel_bg4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselMobile/Carousel_bg4.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselMobile/Carousel_bg5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselMobile/Carousel_bg5.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselMobile/Carousel_bg6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselMobile/Carousel_bg6.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselDesktop/Carousel_bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselDesktop/Carousel_bg1.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselDesktop/Carousel_bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselDesktop/Carousel_bg2.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselDesktop/Carousel_bg3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselDesktop/Carousel_bg3.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselDesktop/Carousel_bg4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselDesktop/Carousel_bg4.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselDesktop/Carousel_bg5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselDesktop/Carousel_bg5.png
--------------------------------------------------------------------------------
/public/images/Carousel/CarouselDesktop/Carousel_bg6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bookshlf-in/Website/HEAD/public/images/Carousel/CarouselDesktop/Carousel_bg6.png
--------------------------------------------------------------------------------
/src/components/AdminPanel/Order/AdminPlaceOrder.js:
--------------------------------------------------------------------------------
1 | const AdminPlaceOrder = () => {
2 | return
Place Order Coming Soon
;
3 | };
4 |
5 | export default AdminPlaceOrder;
6 |
--------------------------------------------------------------------------------
/src/components/Blog/Blog.js:
--------------------------------------------------------------------------------
1 | import { React } from "react";
2 | const Blog = () => {
3 | return (
4 |
5 |
Blogs Coming Soon...
6 |
7 | );
8 | };
9 |
10 | export default Blog;
11 |
--------------------------------------------------------------------------------
/src/components/auth/signup/signup.css:
--------------------------------------------------------------------------------
1 | .signUp-bg .Mui-disabled,
2 | .signUp-bg input.Mui-disabled {
3 | color: rgba(255, 255, 255, 0.6) !important;
4 | -webkit-text-fill-color: rgba(255, 255, 255, 0.6) !important;
5 | }
6 |
--------------------------------------------------------------------------------
/src/assets/components/input/textfield.js:
--------------------------------------------------------------------------------
1 | import { TextField } from "@mui/material";
2 |
3 | const InputTextField = (props) => {
4 | return ;
5 | };
6 |
7 | export default InputTextField;
8 |
--------------------------------------------------------------------------------
/src/api/debounce.js:
--------------------------------------------------------------------------------
1 | export const debounce = (func, timeout = 500) => {
2 | let timer;
3 | return (...args) => {
4 | clearTimeout(timer);
5 | timer = setTimeout(() => {
6 | func.apply(this, args);
7 | }, timeout);
8 | };
9 | };
10 |
--------------------------------------------------------------------------------
/src/assets/components/buttons/button.js:
--------------------------------------------------------------------------------
1 | import { Button } from "@mui/material";
2 |
3 | const SimpleButton = (props) => {
4 | return (
5 |
8 | );
9 | };
10 |
11 | export default SimpleButton;
12 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 | commit-message:
8 | prefix: "Dependency Update: "
9 | assignees:
10 | - "mrhb787"
11 | labels:
12 | - "dependency"
13 | target-branch: "dev"
14 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=DM+Sans&display=swap');
2 |
3 | * {
4 | margin: 0;
5 | padding: 0;
6 | box-sizing: border-box;
7 | scroll-behavior: smooth;
8 | font-family: 'DM Sans', sans-serif;
9 | }
10 |
11 | body {
12 | overflow-y: auto;
13 | scrollbar-gutter: stable;
14 | }
--------------------------------------------------------------------------------
/src/service/auth/recovery.js:
--------------------------------------------------------------------------------
1 | import { PostRequest } from "../../api/requests/postAPI";
2 | import { passwordReset } from "../../api/endpoints";
3 |
4 | export const handleResetPassword = async (requestBody) => {
5 | // console.log(requestBody);
6 | const response = await PostRequest(passwordReset, requestBody);
7 | return response;
8 | };
9 |
--------------------------------------------------------------------------------
/src/assets/Theme/colors.js:
--------------------------------------------------------------------------------
1 | // primary
2 | export const primary = "#F4A946";
3 |
4 | // secondary
5 | export const secondary = "#1E1E1E";
6 |
7 | // disabled
8 | export const disabled = "#99A2A5";
9 |
10 | // error
11 | export const error = "#FF564F";
12 |
13 | // customs
14 |
15 | // bookshlf-white
16 | export const bookshlfWhite = "#FDFDFD";
17 |
--------------------------------------------------------------------------------
/src/assets/components/links/navlink.js:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 | import "./links.css";
3 |
4 | const NavLink = ({ path, name, active = false }) => {
5 | return (
6 |
7 |
8 | {name}
9 |
10 |
11 | );
12 | };
13 |
14 | export default NavLink;
15 |
--------------------------------------------------------------------------------
/src/components/auth/auth.css:
--------------------------------------------------------------------------------
1 | /* Login */
2 | .auth-container {
3 | padding: 10px 15px;
4 | width: 100%;
5 | max-width: 600px;
6 |
7 | }
8 |
9 | .auth-title {
10 | text-align: center;
11 | }
12 |
13 | .login-links {
14 | padding: 0px 15px;
15 | }
16 |
17 | @media screen and (max-width: 600px) {
18 | .auth-title {
19 | font-size: 2em !important;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/components/MicroComponents/MicroComponents.css:
--------------------------------------------------------------------------------
1 | /* ========== Bookshlf Loader ========== */
2 | .bookshlf-loader {
3 | animation: fadeinout 1s infinite;
4 | height: auto;
5 | width: 70px;
6 | margin: 10px;
7 | }
8 |
9 | @keyframes fadeinout {
10 | 0% {
11 | opacity: 0;
12 | transform: rotateY(0deg);
13 | }
14 |
15 | 100% {
16 | opacity: 1;
17 | transform: rotateY(360deg);
18 | }
19 | }
--------------------------------------------------------------------------------
/src/api/axios.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const instance = axios.create({
4 | baseURL: process.env.REACT_APP_BOOKSHLF,
5 | withCredentials: true,
6 | });
7 |
8 | const bookshlf_user = JSON.parse(localStorage.getItem("bookshlf_user"));
9 |
10 | if (bookshlf_user?.authHeader) {
11 | instance.defaults.headers.common["Authorization"] = bookshlf_user.authHeader;
12 | }
13 |
14 | export default instance;
15 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = (onPerfEntry) => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/assets/components/links/link.js:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 | import { Typography } from "@mui/material";
3 | const BaseLink = ({ path, isExternal = false, name }) => {
4 | return (
5 |
9 | {name}
10 |
11 | );
12 | };
13 |
14 | export default BaseLink;
15 |
--------------------------------------------------------------------------------
/src/assets/components/buttons/bookbutton.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from "react-router-dom";
2 | import { Button } from "@mui/material";
3 |
4 | const BookButton = ({ book, ...props }) => {
5 | const navigate = useNavigate();
6 | return (
7 |
14 | );
15 | };
16 |
17 | export default BookButton;
18 |
--------------------------------------------------------------------------------
/src/assets/counter.js:
--------------------------------------------------------------------------------
1 | import { Typography } from "@mui/material";
2 | import { useEffect } from "react";
3 |
4 | const Counter = ({ counter, setCounter, typographyProps }) => {
5 | // OTP Countdown
6 | useEffect(() => {
7 | const timer =
8 | counter > 0 && setInterval(() => setCounter(counter - 1), 1000);
9 | return () => clearInterval(timer);
10 | }, [counter]);
11 |
12 | return 00:{counter};
13 | };
14 |
15 | export default Counter;
16 |
--------------------------------------------------------------------------------
/src/service/auth/logout.js:
--------------------------------------------------------------------------------
1 | import { GetRequest } from "../../api/requests/getAPI";
2 | import { logout } from "../../api/endpoints";
3 | import axios from "../../api/axios";
4 |
5 | export const Logout = async () => {
6 | const response = await GetRequest(logout);
7 | if (response.success) {
8 | localStorage.removeItem("bookshlf_user");
9 | localStorage.removeItem("bookshlf_user_AddBook");
10 | delete axios.defaults.headers.common["Authorization"];
11 | }
12 | return response;
13 | };
14 |
--------------------------------------------------------------------------------
/src/components/MicroComponents/BookshlfLoader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./MicroComponents.css";
3 |
4 | // Mui Components
5 | import { Stack } from "@mui/material";
6 |
7 | const BookshlfLoader = (props) => {
8 | return (
9 |
10 |
16 |
17 | );
18 | };
19 | export default BookshlfLoader;
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # ide
4 | .vscode
5 |
6 | # dependencies
7 | /node_modules
8 | /.pnp
9 | .pnp.js
10 |
11 | # testing
12 | /coverage
13 |
14 | # production
15 | /build
16 | .firebaserc
17 | firebase.json
18 | /.firebase
19 |
20 | #api keys
21 | .env
22 |
23 | # misc
24 | .DS_Store
25 | .env.local
26 | .env.development.local
27 | .env.test.local
28 | .env.production.local
29 |
30 | #logs
31 | npm-debug.log*
32 | yarn-debug.log*
33 | yarn-error.log*
34 |
--------------------------------------------------------------------------------
/src/app/app.css:
--------------------------------------------------------------------------------
1 | /* width */
2 | ::-webkit-scrollbar {
3 | width: 5px;
4 | height: 5px;
5 | }
6 |
7 | /* Track */
8 | ::-webkit-scrollbar-track {
9 | background: transparent;
10 | overflow: overlay;
11 | }
12 |
13 | /* Handle */
14 | ::-webkit-scrollbar-thumb {
15 | background: rgb(255, 182, 73);
16 | border-radius: 5px;
17 | transition: height 0.2s ease-in-out;
18 | }
19 |
20 | /* Handle on hover */
21 | ::-webkit-scrollbar-thumb:hover {
22 | background: rgb(243, 155, 23);
23 | }
24 |
25 | a {
26 | text-decoration: none;
27 | cursor: pointer;
28 | }
--------------------------------------------------------------------------------
/src/assets/components/buttons/loadingbutton.js:
--------------------------------------------------------------------------------
1 | import { Button, CircularProgress } from "@mui/material";
2 | const LoadingButton = ({ loading, size, children, ...props }) => {
3 | return (
4 |
10 | ) : (
11 | props.endIcon
12 | )
13 | }
14 | className="bookshlf-btn"
15 | >
16 | {children}
17 |
18 | );
19 | };
20 |
21 | export default LoadingButton;
22 |
--------------------------------------------------------------------------------
/src/components/search/searchresults.js:
--------------------------------------------------------------------------------
1 | import { Grid } from "@mui/material";
2 | import SearchBook from "./searchbook";
3 |
4 | const SearchResult = ({ books }) => {
5 | return (
6 |
12 | {books.map((book) => {
13 | return (
14 |
15 |
16 |
17 | );
18 | })}
19 |
20 | );
21 | };
22 |
23 | export default SearchResult;
24 |
--------------------------------------------------------------------------------
/src/service/auth/login.js:
--------------------------------------------------------------------------------
1 | import { login } from "../../api/endpoints";
2 | import { PostRequest } from "../../api/requests/postAPI";
3 | import axios from "../../api/axios";
4 |
5 | export const handleLogin = async (requestBody) => {
6 | const response = await PostRequest(login, requestBody);
7 | if (response.success) {
8 | axios.defaults.headers.common[
9 | "Authorization"
10 | ] = `Bearer ${response.data.token}`;
11 | localStorage.setItem(
12 | "bookshlf_user",
13 | JSON.stringify({
14 | authHeader: `Bearer ${response.data.token}`,
15 | })
16 | );
17 | }
18 | return response;
19 | };
20 |
--------------------------------------------------------------------------------
/src/api/requests/deleteAPI.js:
--------------------------------------------------------------------------------
1 | import axios from "../axios";
2 | import { PrintInUATEnvironment } from "../../assets/utils/commons";
3 |
4 | export const DeleteRequest = async (requestURL, data) => {
5 | const response = await axios
6 | .delete(requestURL, { data: data })
7 | .then((res) => {
8 | return { data: res.data, success: true };
9 | })
10 | .catch((err) => {
11 | return { data: err.response.data, success: false };
12 | });
13 | const Request = {
14 | type: "DELETE",
15 | url: requestURL,
16 | params: data,
17 | response: response,
18 | };
19 | PrintInUATEnvironment(Request);
20 | return response;
21 | };
22 |
--------------------------------------------------------------------------------
/src/api/requests/postAPI.js:
--------------------------------------------------------------------------------
1 | import axios from "../axios";
2 | import { PrintInUATEnvironment } from "../../assets/utils/commons";
3 |
4 | export const PostRequest = async (requestURL, requestBody) => {
5 | const response = await axios
6 | .post(requestURL, requestBody)
7 | .then((res) => {
8 | return { data: res.data, success: true };
9 | })
10 | .catch((err) => {
11 | return { data: err.response.data, success: false };
12 | });
13 | const Request = {
14 | type: "POST",
15 | url: requestURL,
16 | body: requestBody,
17 | response: response,
18 | };
19 | PrintInUATEnvironment(Request);
20 | return response;
21 | };
22 |
--------------------------------------------------------------------------------
/src/api/requests/getAPI.js:
--------------------------------------------------------------------------------
1 | import axios from "../axios";
2 | import { PrintInUATEnvironment } from "../../assets/utils/commons";
3 |
4 | export const GetRequest = async (requestURL, requestParams) => {
5 | const response = await axios
6 | .get(requestURL, { params: requestParams })
7 | .then((res) => {
8 | return { data: res.data, success: true };
9 | })
10 | .catch((err) => {
11 | return { data: err?.response?.data, success: false };
12 | });
13 | const Request = {
14 | type: "GET",
15 | url: requestURL,
16 | params: requestParams,
17 | response: response,
18 | };
19 | PrintInUATEnvironment(Request);
20 | return response;
21 | };
22 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Analytics/Analytics.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | // MUI Components
4 | import { Stack, Divider } from "@mui/material";
5 |
6 | // components
7 | import OrdersAnalytics from "./Orders/OrdersAnalytics";
8 |
9 | const Analytics = () => {
10 | return (
11 | }
14 | sx={{ minHeight: "calc(100vh - 48px)" }}
15 | >
16 | {/* Navigation */}
17 |
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | export default Analytics;
25 |
--------------------------------------------------------------------------------
/src/assets/components/container.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from "react-router-dom";
2 | import { Helmet } from "react-helmet-async";
3 | import { Stack } from "@mui/material";
4 | import "./base.css";
5 |
6 | import PageLoader from "./pageloader";
7 |
8 | const Container = ({
9 | title,
10 | children,
11 | isAutherized = true,
12 | loading = false,
13 | redirect = true,
14 | }) => {
15 | const navigate = useNavigate();
16 | if (!isAutherized) {
17 | navigate("/auth/login");
18 | }
19 | return (
20 | <>
21 |
22 | {title}
23 |
24 | {loading ? : children}
25 | >
26 | );
27 | };
28 |
29 | export default Container;
30 |
--------------------------------------------------------------------------------
/src/service/auth/signup.js:
--------------------------------------------------------------------------------
1 | import {
2 | register,
3 | verifyEmailOtp,
4 | verifyEmail,
5 | recoveryEmailOtp,
6 | } from "../../api/endpoints";
7 | import { PostRequest } from "../../api/requests/postAPI";
8 |
9 | export const handelSignup = async (requestBody) => {
10 | const response = await PostRequest(register, requestBody);
11 | return response;
12 | };
13 |
14 | export const handelSendOtp = async (type, requestBody) => {
15 | const url = type === "EMAIL_VERIFICATION" ? verifyEmailOtp : recoveryEmailOtp;
16 | const response = await PostRequest(url, requestBody);
17 | return response;
18 | };
19 |
20 | export const handleVerify = async (requestBody) => {
21 | const response = await PostRequest(verifyEmail, requestBody);
22 | return response;
23 | };
24 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | name: CI
3 |
4 | on:
5 | push:
6 | branches: [ "main" ]
7 | pull_request:
8 | branches: [ "main" ]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 | env:
15 | CI: false
16 | strategy:
17 | matrix:
18 | node-version: [14.x, 16.x, 18.x]
19 |
20 | steps:
21 | - uses: actions/checkout@v3
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v3
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | cache: 'npm'
27 | - run: npm install
28 | - run: npm run build
29 | - run: npm test --passWithNoTests
30 |
--------------------------------------------------------------------------------
/src/service/search/booksearch.js:
--------------------------------------------------------------------------------
1 | import { GetRequest } from "../../api/requests/getAPI";
2 | import { searchTitle, searchBook } from "../../api/endpoints";
3 |
4 | export const BookSearchTitle = async (bookTitle) => {
5 | const params = {
6 | q: bookTitle,
7 | };
8 | const result = await GetRequest(searchTitle, params);
9 | return result;
10 | };
11 |
12 | export const BookSearch = async (params) => {
13 | const result = await GetRequest(searchBook, params);
14 | return result;
15 | };
16 |
17 | export const BooksPerPage = () => {
18 | const windowSize = window.innerWidth;
19 | switch (windowSize) {
20 | case 450:
21 | return 8;
22 | case 600:
23 | return 12;
24 | case 900:
25 | return 15;
26 | case 1200:
27 | return 20;
28 | default:
29 | return 20;
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/src/components/search/pagination.js:
--------------------------------------------------------------------------------
1 | import { useNavigate, useParams } from "react-router-dom";
2 | import { Stack, Pagination } from "@mui/material";
3 |
4 | const BottomPagination = ({ page = 1, totalPages }) => {
5 | const { query, filters } = useParams();
6 | const navigate = useNavigate();
7 |
8 | // changing Page
9 | const changePage = (e, pageNo) => {
10 | navigate(`/search/${query}/${filters}/${pageNo}`);
11 | };
12 |
13 | return (
14 |
15 |
25 |
26 | );
27 | };
28 |
29 | export default BottomPagination;
30 |
--------------------------------------------------------------------------------
/src/assets/components/input/passwordfield.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { TextField, InputAdornment, IconButton } from "@mui/material";
3 | import { Visibility, VisibilityOff } from "@mui/icons-material";
4 |
5 | const InputPasswordField = (props) => {
6 | const [show, setShow] = useState(false);
7 |
8 | return (
9 |
16 | setShow((prev) => !prev)}>
17 | {show ? : }
18 |
19 |
20 | ),
21 | }}
22 | />
23 | );
24 | };
25 |
26 | export default InputPasswordField;
27 |
--------------------------------------------------------------------------------
/src/context/adminContext.js:
--------------------------------------------------------------------------------
1 | import { React, createContext, useState, useEffect } from "react";
2 |
3 | export const AdminContext = createContext();
4 |
5 | export const CurrentAdminProvider = (props) => {
6 | const localAdmin = JSON.parse(localStorage.getItem("bookshlf_admin"));
7 |
8 | const [admin, setAdmin] = useState({
9 | bookVerification: {
10 | data: [],
11 | totalPages: 0,
12 | isApproved: false,
13 | page: 1,
14 | noOfBooksInOnePage: 24,
15 | },
16 | order: {
17 | panel: 0,
18 | orderDetails: { data: [], page: 1, totalPages: 0 },
19 | },
20 | });
21 |
22 | useEffect(() => {
23 | if (localAdmin) {
24 | setAdmin(localAdmin);
25 | }
26 | }, []);
27 |
28 | return (
29 |
30 | {props.children}
31 |
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./app/app";
5 | import reportWebVitals from "./reportWebVitals";
6 | import { HelmetProvider } from "react-helmet-async";
7 | import { BrowserRouter } from "react-router-dom";
8 | // Context
9 | import { CurrentUserProvider } from "./context/userContext";
10 | import { CurrentAdminProvider } from "./context/adminContext";
11 |
12 | const root = ReactDOM.createRoot(document.getElementById("root"));
13 | root.render(
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | reportWebVitals();
27 |
--------------------------------------------------------------------------------
/src/components/home/NotFoundPage.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useNavigate } from "react-router-dom";
3 |
4 | // mui
5 | import { Button } from "@mui/material";
6 | import HomeIcon from "@mui/icons-material/Home";
7 |
8 | const NotFoundPage = () => {
9 | const navigate = useNavigate();
10 | return (
11 |
12 |
13 | 4
14 |
15 |
16 |
17 | 4
18 |
19 |
Error: 404 page not found
20 |
Sorry, the page you're looking for cannot be accessed
21 |
22 |
}
24 | variant="contained"
25 | size="small"
26 | onClick={() => navigate("/")}
27 | >
28 | Home
29 |
30 |
31 | );
32 | };
33 |
34 | export default NotFoundPage;
35 |
--------------------------------------------------------------------------------
/src/components/navbar/navbarlinks.js:
--------------------------------------------------------------------------------
1 | import { useLocation } from "react-router-dom";
2 | import { Stack } from "@mui/material";
3 | import NavLink from "../../assets/components/links/navlink";
4 |
5 | const NavbarItems = () => {
6 | const location = useLocation();
7 | const activePath = location.pathname;
8 | return (
9 |
16 |
17 |
22 |
27 |
28 | );
29 | };
30 |
31 | export default NavbarItems;
32 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Support/Support.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | // MUI Components
4 | import { Stack, Divider } from "@mui/material";
5 |
6 | // Custom CSS
7 | import "./Support.css";
8 |
9 | // Custom Components
10 | import SupportSideBar from "./SupportSideBar";
11 | import SupportContent from "./SupportContent";
12 |
13 | const Support = () => {
14 | // data States
15 | const [panel, setPanel] = useState(0);
16 | const [page, setPage] = useState(1);
17 |
18 | return (
19 | }
23 | spacing={1}
24 | >
25 |
26 |
32 |
33 | );
34 | };
35 |
36 | export default Support;
37 |
--------------------------------------------------------------------------------
/src/assets/components/links/links.css:
--------------------------------------------------------------------------------
1 | /* NavLink Css */
2 | .navlink {
3 | display: inline-block;
4 | color: #8f8f8f;
5 | text-transform: capitalize;
6 | font-size: 12px;
7 | cursor: pointer;
8 | }
9 |
10 | .navlink-active {
11 | color: #ffffff !important;
12 | }
13 |
14 | .navlink:after {
15 | display: block;
16 | padding: 2px;
17 | content: '';
18 | border-bottom: solid 1px #ffffff;
19 | transform: scaleX(0);
20 | transition: transform 250ms ease-in-out;
21 | }
22 |
23 | .navlink:hover:after {
24 | transform: scaleX(1);
25 | }
26 |
27 | .navlink-active:after {
28 | transform: scaleX(1);
29 | }
30 |
31 | .base-link.MuiTypography-root {
32 | font-family: 'DM Sans', sans-serif;
33 | color: #8f8f8f;
34 | text-decoration: none;
35 | cursor: pointer;
36 | font-size: 14px;
37 | }
38 |
39 | @media screen and (max-width: 600px) {
40 | .base-link.MuiTypography-root {
41 | font-size: 12px;
42 | }
43 | }
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Bookshlf",
3 | "name": "Bookshlf | The Bookstore which cares",
4 | "description": "Buy and Sell second-hand books at your doorstep",
5 | "manifest_version": 1,
6 | "icons": [
7 | {
8 | "src": "/images/favicon.ico",
9 | "sizes": "64x64 32x32 24x24 16x16",
10 | "type": "image/x-icon"
11 | },
12 | {
13 | "src": "/images/smallLogo.png",
14 | "sizes": "181x149",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "/images/smallLogoView.png",
19 | "sizes": "229x202",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "/images/logo.png",
24 | "sizes": "804x149",
25 | "type": "image/png"
26 | },
27 | {
28 | "src": "/images/logoView.png",
29 | "sizes": "900x232",
30 | "type": "image/png"
31 | }
32 | ],
33 | "start_url": ".",
34 | "display": "standalone",
35 | "theme_color": "#000000",
36 | "background_color": "#ffffff"
37 | }
38 |
--------------------------------------------------------------------------------
/src/api/endpoints.js:
--------------------------------------------------------------------------------
1 | // AUTH
2 | export const login = "/signIn";
3 | export const logout = "/signOut";
4 | export const register = "/signUp";
5 | export const verifyEmailOtp = "/sendVerifyEmailOtp";
6 | export const recoveryEmailOtp = "/sendResetPasswordOtp";
7 | export const verifyEmail = "/verifyEmail";
8 | export const passwordReset = "/resetPassword";
9 |
10 | // SEARCH
11 | export const searchTitle = "/searchTitle";
12 | export const searchBook = "/search";
13 |
14 | // WISHLIST
15 | export const addWishlist = "/addWishlistItem";
16 | export const deleteWishlist = "/deleteWishlistItem";
17 |
18 | // CART
19 | export const addCart = "/addCartItem";
20 | export const deleteCart = "/deleteCartItem";
21 |
22 | // ORDER
23 | export const orderDetails = "/getOrderDetails";
24 | export const orderList = "/getOrderList";
25 | export const orderCancel = "/cancelOrder";
26 |
27 | // USER
28 | export const userProfile = "/getUserProfile";
29 |
30 | // ADDRESS
31 | export const addressList = "/getAddressList";
32 |
--------------------------------------------------------------------------------
/public/images/smallLogo.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/components/BookDetails/BookDetails.css:
--------------------------------------------------------------------------------
1 | .book-details-snap .book-snapshots {
2 | width: 100px !important;
3 | height: 100px !important;
4 | cursor: pointer;
5 | }
6 |
7 | .book-details-snap .book-large-snapshot {
8 | width: 400px !important;
9 | height: 450px !important;
10 | }
11 | .book-details-tag-stack div {
12 | margin: 8px 8px 0px 8px !important;
13 | }
14 | .book-large-snapshot {
15 | background-color: rgba(0, 0, 0, 0.1);
16 | border-radius: 5px;
17 | }
18 | .book-large-snapshot img {
19 | object-fit: contain;
20 | }
21 | @media screen and (max-width: 600px) {
22 | .book-details-snap .book-snapshots {
23 | width: 70px !important;
24 | height: 70px !important;
25 | }
26 | .book-details-snap .book-large-snapshot {
27 | width: 200px !important;
28 | height: 250px !important;
29 | }
30 | .book-details-tag-stack {
31 | flex-wrap: wrap !important;
32 | justify-content: flex-start !important;
33 | align-items: flex-start !important;
34 | }
35 | .book-details-tag-stack div {
36 | margin: 4px !important;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/userpanel/usernav.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from "react-router-dom";
2 | import { Paper, Stack, Typography } from "@mui/material";
3 |
4 | import OrderIcon from "@mui/icons-material/LocalShipping";
5 | import AddressIcon from "@mui/icons-material/HomeWork";
6 |
7 | const UserNavItem = ({ logo, label }) => {
8 | const navigate = useNavigate();
9 | const handleClick = () => {
10 | navigate(`/user/${label}`);
11 | };
12 | return (
13 |
14 |
19 | {logo}
20 | {label}
21 |
22 |
23 | );
24 | };
25 |
26 | const UserNav = () => {
27 | return (
28 |
29 | } label="orders" />
30 | } label="address" />
31 |
32 | );
33 | };
34 | export default UserNav;
35 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/AdminPanel.js:
--------------------------------------------------------------------------------
1 | import { React, useContext } from "react";
2 | import { UserContext } from "../../context/userContext";
3 | import { Helmet } from "react-helmet-async";
4 |
5 | // Custom CSS
6 | import "./AdminPanel.css";
7 |
8 | // Components
9 | import { Box } from "@mui/material";
10 | import { Alert, AlertTitle } from "@mui/material";
11 | import Navigation from "./Navigation/AdminPanelNavbar";
12 |
13 | const AdminPanel = () => {
14 | const [user] = useContext(UserContext);
15 | return (
16 | <>
17 |
18 | Admin Panel | Bookshlf
19 |
20 |
21 | {user && user.roles?.includes("admin") ? (
22 |
23 | ) : (
24 |
25 |
26 | Access Denied
27 |
28 | You are Unauthorized to Access this Domain. Contact Admin for More
29 | Details
30 |
31 | )}
32 |
33 | >
34 | );
35 | };
36 | export default AdminPanel;
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Bookshlf
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/assets/components/pageloader.js:
--------------------------------------------------------------------------------
1 | import { Stack, Box, CircularProgress } from "@mui/material";
2 | const PageLoader = () => {
3 | return (
4 |
5 |
6 |
10 | theme.palette.grey[theme.palette.mode === "light" ? 200 : 800],
11 | }}
12 | size={40}
13 | thickness={4}
14 | value={100}
15 | />
16 |
21 | theme.palette.mode === "light" ? "#1a90ff" : "#308fe8",
22 | animationDuration: "550ms",
23 | position: "absolute",
24 | left: 0,
25 | "& .MuiCircularProgress-circle": {
26 | strokeLinecap: "round",
27 | },
28 | }}
29 | size={40}
30 | thickness={4}
31 | />
32 |
33 |
34 | );
35 | };
36 |
37 | export default PageLoader;
38 |
--------------------------------------------------------------------------------
/src/components/Footer/Footer.css:
--------------------------------------------------------------------------------
1 | .footer-container {
2 | background: linear-gradient(90deg, rgb(17, 16, 16) 0%, rgb(63, 62, 62) 100%);
3 | }
4 | .footer-subscription {
5 | width: 100%;
6 | background-color: #fff;
7 | padding: 12px;
8 | color: black;
9 | }
10 | .footer-link-items {
11 | width: 170px;
12 | font-family: "Roboto", sans-serif;
13 | font-weight: 900;
14 | }
15 | .footer-link-items > h6 {
16 | margin-bottom: 5px;
17 | color: #fff;
18 | }
19 | .footer-link-items a {
20 | color: #b1b1b1;
21 | text-decoration: none;
22 | font-size: 12px;
23 | }
24 | .footer-link-items a:hover {
25 | color: #ff4208;
26 | font-weight: bolder !important;
27 | }
28 | .footer-link-items .cool-link::after {
29 | content: "";
30 | display: block;
31 | width: 0;
32 | height: 2px;
33 | background: #b1b1b1;
34 | transition: width 0.3s;
35 | }
36 |
37 | .footer-link-items .cool-link:hover::after {
38 | width: 100%;
39 | background: #ff4208;
40 | }
41 | .footer-container3 {
42 | background-color: rgb(0, 0, 0);
43 | color: white;
44 | width: 100%;
45 | padding: 5px;
46 | font-family: "Roboto", sans-serif;
47 | font-size: 12px;
48 | }
49 |
--------------------------------------------------------------------------------
/src/assets/utils/date.js:
--------------------------------------------------------------------------------
1 | const monthNames = [
2 | "January",
3 | "February",
4 | "March",
5 | "April",
6 | "May",
7 | "June",
8 | "July",
9 | "August",
10 | "September",
11 | "October",
12 | "November",
13 | "December",
14 | ];
15 | const dayNames = [
16 | "Sunday",
17 | "Monday",
18 | "Tuesday",
19 | "Wednesday",
20 | "Thursday",
21 | "Friday",
22 | "Saturday",
23 | ];
24 |
25 | export const currentDate = () => {
26 | const d = new Date();
27 | const newdate = d.getDate();
28 | const day = d.getDay();
29 | const month = d.getMonth();
30 | const year = d.getFullYear();
31 |
32 | return {
33 | date: newdate,
34 | day: day,
35 | dayName: dayNames[day],
36 | month: month,
37 | monthName: monthNames[month],
38 | year: year,
39 | };
40 | };
41 |
42 | export const TimestampToDate = (date) => {
43 | const d = new Date(date);
44 | const newdate = d.getDate();
45 | const day = d.getDay();
46 | const month = d.getMonth();
47 | const year = d.getFullYear();
48 | return {
49 | date: newdate,
50 | dayName: dayNames[day],
51 | monthName: monthNames[month],
52 | year: year,
53 | };
54 | };
55 |
--------------------------------------------------------------------------------
/public/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://bookshlf.in
5 | 2022-01-25
6 |
7 |
8 | https://bookshlf.in/SearchResult/tag:ALL
9 | 2022-01-25
10 |
11 |
12 | https://bookshlf.in/Login
13 | 2022-01-25
14 |
15 |
16 | https://bookshlf.in/Signup
17 | 2022-01-25
18 |
19 |
20 | https://bookshlf.in/PasswordRecovery
21 | 2022-01-25
22 |
23 |
24 | https://bookshlf.in/About
25 | 2022-01-25
26 |
27 |
28 | https://bookshlf.in/Contact
29 | 2022-01-25
30 |
31 |
32 | https://bookshlf.in/TermsofUsePrivacyPolicy
33 | 2022-01-25
34 |
35 |
--------------------------------------------------------------------------------
/src/components/userpanel/userpanel.css:
--------------------------------------------------------------------------------
1 | .user-profile {
2 | padding: 15px 24px;
3 | background-color: #1E1E1E;
4 | width: 100%;
5 | border-radius: 12px;
6 | color: #FFFFFF;
7 | }
8 |
9 | .user-profile .MuiDivider-root {
10 | border-color: #FFFFFF !important;
11 | }
12 |
13 | .user-name {
14 | font-size: 48px !important;
15 | font-weight: bolder !important;
16 | }
17 |
18 | .user-email {
19 | font-size: 18px !important;
20 | }
21 |
22 | .user-id.MuiChip-root {
23 | font-family: 'DM Sans', sans-serif !important;
24 | border-radius: 5px;
25 | max-width: 300px;
26 | }
27 |
28 | .user-roles {
29 | font-size: 24px !important;
30 | }
31 |
32 | .user-role {
33 | text-transform: capitalize !important;
34 | border-radius: 5px !important;
35 | }
36 |
37 | .usernav-item {
38 | width: 100px;
39 | height: 100px;
40 | cursor: pointer;
41 | color: #F4A946 !important;
42 | border-radius: 12px !important;
43 | text-transform: capitalize !important;
44 | }
45 |
46 | .usernav-item:hover {
47 | background-color: #1E1E1E;
48 | transition: 0.3s;
49 | color: #FFFFFF;
50 | }
51 |
52 | @media screen and (max-width : 400px) {
53 | .user-name {
54 | font-size: 32px !important;
55 | }
56 |
57 | .user-email {
58 | font-size: 14px !important;
59 | }
60 | }
--------------------------------------------------------------------------------
/src/service/AdminPanel/Analytics/OrdersAnalytics.js:
--------------------------------------------------------------------------------
1 | import axios from "../../../api/axios";
2 |
3 | export const makeRequest = (month, year, setLoad, setOrder, setFinance) => {
4 | setLoad(true);
5 | axios
6 | .get("/admin-getMonthOrderStats", {
7 | params: {
8 | month: month,
9 | year: year,
10 | },
11 | })
12 | .then((res) => {
13 | setOrder({
14 | placed: res.data.totalOrders,
15 | confirmed: res.data.confirmed,
16 | packed: res.data.packed,
17 | shipped: res.data.shipped,
18 | delivered: res.data.delivered,
19 | rto: res.data.RTO,
20 | returned: res.data.returned,
21 | lost: res.data.lost,
22 | cancelled: res.data.cancelled,
23 | });
24 | setFinance({
25 | expectedRevenue: Math.round(res.data.expectedRevenue),
26 | actualRevenue: Math.round(res.data.totalRevenue),
27 | expectedProfit: Math.round(res.data.expectedProfit),
28 | deliveredProfit: Math.round(res.data.DeliveredProfit),
29 | rtoLoss: Math.round(res.data.RTOLoss),
30 | actualProfit: Math.round(res.data.totalProfit),
31 | });
32 | console.log(res.data);
33 | setLoad(false);
34 | })
35 | .catch((err) => {
36 | console.log(err.response.data);
37 | setLoad(false);
38 | });
39 | };
40 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Navigation/AdminAppBar.js:
--------------------------------------------------------------------------------
1 | import { useNavigate } from "react-router-dom";
2 |
3 | // Components
4 | import { AppBar, Toolbar } from "@mui/material";
5 | import { Typography, IconButton } from "@mui/material";
6 |
7 | // icons
8 | import MenuIcon from "@mui/icons-material/Menu";
9 | import HomeIcon from "@mui/icons-material/Home";
10 |
11 | // Custom Admin AppBar
12 | const AdminAppBar = ({ openSideBar, setOpenSideBar }) => {
13 | const navigate = useNavigate();
14 | return (
15 |
16 |
17 | setOpenSideBar(true)}
23 | >
24 |
25 |
26 |
32 | Admin Panel | Bookshlf
33 |
34 | navigate("/")}
40 | >
41 |
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | export default AdminAppBar;
49 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Book/Book.css:
--------------------------------------------------------------------------------
1 | .AdminBookNav.MuiAppBar-root {
2 | background: transparent;
3 | box-shadow: none;
4 | }
5 |
6 | .AdminBookNav .MuiToolbar-root {
7 | background: linear-gradient(195deg, rgb(73, 163, 241), rgb(26, 115, 232));
8 | padding: 0px 24px;
9 | }
10 |
11 | .AdminBookNav-btn {
12 | padding: 5px;
13 | margin-right: 0.5em;
14 | border-radius: 5px;
15 | cursor: pointer;
16 | }
17 |
18 | .AdminBookNav-btn:hover {
19 | background-color: rgba(255, 255, 255, 0.8);
20 | backdrop-filter: saturate(200%) blur(1.875rem);
21 | color: black;
22 | transition: 0.3s;
23 | }
24 |
25 | .AdminBookNav-btn-active {
26 | background-color: rgba(255, 255, 255, 0.8);
27 | backdrop-filter: saturate(200%) blur(1.875rem);
28 | color: black;
29 | }
30 |
31 | .AdminBookVerification .MuiTypography-root {
32 | font-size: 12px;
33 | }
34 |
35 | .admin-searchTagresult {
36 | max-height: 400px;
37 | max-width: 250px;
38 | overflow-y: auto;
39 | }
40 |
41 | .adminPanel-content .filepond--drop-label {
42 | min-height: 4em !important;
43 | background-color: #fff;
44 | border: 1px dotted rgba(0, 0, 0, 0.8);
45 | color: rgb(52, 52, 52) !important;
46 | border-radius: 5px;
47 | }
48 |
49 | .adminPanel-content .filepond--label-action {
50 | background-color: #bfbfbf;
51 | padding: 6px 10px;
52 | text-decoration: none !important;
53 | border-radius: 5px;
54 | }
--------------------------------------------------------------------------------
/src/components/userpanel/profile.js:
--------------------------------------------------------------------------------
1 | import { Fragment } from "react";
2 |
3 | // Components
4 | import { Stack, Divider, Typography } from "@mui/material";
5 | import { Chip } from "@mui/material";
6 |
7 | import { TimestampToDate } from "../../assets/utils/date";
8 |
9 | const Account = ({ user }) => {
10 | const registeredOn = TimestampToDate(user?.createdAt);
11 | return (
12 |
13 | {user.name}
14 | {user.email}
15 |
16 |
17 | Roles
18 |
19 | {user?.roles?.map((role) => (
20 |
21 |
28 |
29 | ))}
30 |
31 |
32 | User Since :{" "}
33 | {registeredOn.date +
34 | ", " +
35 | registeredOn.monthName +
36 | " " +
37 | registeredOn.year +
38 | " (" +
39 | registeredOn.dayName +
40 | ")"}
41 |
42 |
43 | );
44 | };
45 | export default Account;
46 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Navigation/AdminPanelNavbar.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useEffect } from "react";
2 | import { useParams, useNavigate } from "react-router-dom";
3 |
4 | // Components
5 | import { Drawer } from "@mui/material";
6 | import { Stack } from "@mui/material";
7 |
8 | // Custom components
9 | import AdminSideBar from "./AdminSideBar";
10 | import AdminAppBar from "./AdminAppBar";
11 | import AdminContentPanel from "./AdminContentPanel";
12 |
13 | const AdminNavbar = () => {
14 | // Hooks Call
15 | const navigate = useNavigate();
16 | const params = useParams();
17 |
18 | // States
19 | const [Panel, setPanel] = useState(Number(params.panel));
20 | const [openSideBar, setOpenSideBar] = useState(false);
21 |
22 | // update panel when text param changes
23 | useEffect(() => {
24 | setPanel(Number(params.panel));
25 | }, [params]);
26 |
27 | return (
28 |
29 |
30 | setOpenSideBar(false)}
34 | >
35 |
41 |
42 |
47 |
48 | );
49 | };
50 | export default AdminNavbar;
51 |
--------------------------------------------------------------------------------
/src/components/Checkout/CheckoutLoading.js:
--------------------------------------------------------------------------------
1 | import { Stack, Grid, Skeleton } from "@mui/material";
2 |
3 | const CheckoutLoading = () => {
4 | return (
5 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | export default CheckoutLoading;
49 |
--------------------------------------------------------------------------------
/src/assets/components/buttons/ordercancelbutton.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import { DeleteRequest } from "../../../api/requests/deleteAPI";
4 | import { orderCancel } from "../../../api/endpoints";
5 |
6 | import { Button, CircularProgress, Alert } from "@mui/material";
7 | import CancelIcon from "@mui/icons-material/Cancel";
8 |
9 | const OrderCancelButton = ({ orderId, className, props }) => {
10 | const navigate = useNavigate();
11 | const [loading, setLoading] = useState(false);
12 | const [alert, setAlert] = useState(false);
13 |
14 | const handelCancelOrder = () => {
15 | setLoading(true);
16 | DeleteRequest(orderCancel, { orderId: orderId })
17 | .then((response) => {
18 | setLoading(false);
19 | navigate(0);
20 | })
21 | .catch((error) => {
22 | setLoading(false);
23 | setAlert(true);
24 | setTimeout(() => {
25 | setAlert(false);
26 | }, 5000);
27 | });
28 | };
29 |
30 | return (
31 | <>
32 |
39 | ) : (
40 |
41 | )
42 | }
43 | onClick={handelCancelOrder}
44 | >
45 | Cancel Order
46 |
47 | {alert && Order Cancellation Failed!}
48 | >
49 | );
50 | };
51 |
52 | export default OrderCancelButton;
53 |
--------------------------------------------------------------------------------
/src/components/Order/tracking/tracking.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from "react";
2 | import { UserContext } from "../../../context/userContext";
3 | import { useParams } from "react-router-dom";
4 |
5 | import { GetRequest } from "../../../api/requests/getAPI";
6 | import { orderDetails } from "../../../api/endpoints";
7 |
8 | import "./tracking.css";
9 |
10 | import { Stack } from "@mui/material";
11 |
12 | import Container from "../../../assets/components/container";
13 | import Details from "./details";
14 | import OrderProgress from "./trackprogress";
15 |
16 | const Tracking = () => {
17 | const [user] = useContext(UserContext);
18 | const { orderId } = useParams();
19 |
20 | const [loading, setLoading] = useState(true);
21 | const [order, setOrder] = useState({});
22 |
23 | const getOrderDetails = () => {
24 | GetRequest(orderDetails, { orderId: orderId }).then((response) => {
25 | setOrder(response.data);
26 | setLoading(false);
27 | });
28 | };
29 |
30 | useEffect(() => {
31 | getOrderDetails();
32 | }, [orderId]);
33 |
34 | return (
35 |
36 |
46 |
47 |
48 |
49 |
50 | );
51 | };
52 |
53 | export default Tracking;
54 |
--------------------------------------------------------------------------------
/src/components/auth/recovery/recovery.css:
--------------------------------------------------------------------------------
1 | .password-recovery-bg input:-webkit-autofill {
2 | -webkit-box-shadow: 0 0 0px 1000px rgb(35, 47, 62) inset;
3 | -webkit-text-fill-color: rgb(255, 255, 255);
4 | }
5 | .password-recovery-bg input:-webkit-autofill:focus {
6 | -webkit-text-fill-color: rgb(255, 255, 255);
7 | -webkit-box-shadow: 0 0 0px 1000px rgb(35, 47, 62) inset;
8 | }
9 |
10 | .otp-input-field {
11 | width: 100%;
12 | height: 32px;
13 | border-radius: 0.25rem;
14 | font-size: 16px;
15 | font-family: "PT sans";
16 | text-align: center;
17 | background-color: #f3f6f9;
18 | color: #3f4254;
19 | outline: 0;
20 | border: 2px solid rgb(66, 66, 66);
21 | letter-spacing: 5px;
22 | }
23 | .otp-input-field:focus {
24 | box-shadow: 0 0 0 3px rgb(66 153 225 / 50%);
25 | transition: color 0.15s ease, background-color 0.15s ease,
26 | border-color 0.15s ease, box-shadow 0.15s ease;
27 | }
28 | .otp-input-field-mobile {
29 | display: none;
30 | width: 180px;
31 | height: 32px;
32 | border-radius: 0.25rem;
33 | font-size: 16px;
34 | font-family: "PT sans";
35 | letter-spacing: 6px;
36 | text-align: center;
37 | background-color: #f3f6f9;
38 | color: #3f4254;
39 | outline: 0;
40 | border: 2px solid rgb(66, 66, 66);
41 | }
42 | .otp-input-field-mobile:focus {
43 | box-shadow: 0 0 0 3px rgb(66 153 225 / 50%);
44 | transition: color 0.15s ease, background-color 0.15s ease,
45 | border-color 0.15s ease, box-shadow 0.15s ease;
46 | }
47 | @media screen and (max-width: 400px) {
48 | #otp {
49 | display: none !important;
50 | }
51 | .otp-input-field-mobile {
52 | display: block;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/service/Book/AdminBookPurchase/purchaseOrder.js:
--------------------------------------------------------------------------------
1 | // API
2 | import axios from "../../../api/axios";
3 |
4 | // Open Dialog
5 | export const handleOpen = (setOpen) => {
6 | setOpen(true);
7 | };
8 |
9 | // Close Dialog
10 | export const handleClose = (setOpen) => {
11 | setOpen(false);
12 | };
13 |
14 | // on Error
15 | export const handleError = (setError) => {
16 | setError(true);
17 | setTimeout(() => {
18 | setError(false);
19 | }, 3000);
20 | };
21 |
22 | // Purchase Order
23 | export const adminBookPurchase = (
24 | orderId,
25 | setOrderId,
26 | setOrderLoad,
27 | bookId,
28 | setSuccess,
29 | setOpen,
30 | setError
31 | ) => {
32 | console.log(orderId);
33 | setOrderId(orderId);
34 | setOrderLoad(true);
35 | axios
36 | .get("/admin-getOrderDetails", {
37 | params: { orderId: orderId },
38 | })
39 | .then((response) => {
40 | axios
41 | .post("/admin-purchaseBook", {
42 | bookId: bookId,
43 | customerId: response.data.customerId,
44 | customerAddressId: response.data.customerAddress._id,
45 | purchaseQty: 1,
46 | })
47 | .then((res) => {
48 | console.log("Order Placed!");
49 | setOrderLoad(false);
50 | setSuccess(true);
51 | setTimeout(() => {
52 | setOpen(false);
53 | }, 3000);
54 | })
55 | .catch((err) => {
56 | console.log(err.response.data);
57 | setOrderLoad(false);
58 | handleError(setError);
59 | });
60 | return response;
61 | })
62 | .catch((err) => {
63 | console.log(err);
64 | setOrderLoad(false);
65 | handleError(setError);
66 | });
67 | };
68 |
--------------------------------------------------------------------------------
/src/components/Wallet/Wallet.css:
--------------------------------------------------------------------------------
1 | .wallet-stack-item {
2 | font-family: "PT sans";
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | }
7 | .amount-icon {
8 | padding: 6px;
9 | background-color: rgba(0, 0, 0, 0.06);
10 | border-radius: 10px;
11 | font-family: "PT sans";
12 | margin: 10px 0px;
13 | }
14 | .wallet-stack-item .debit-amount,
15 | .wallet-stack-item .credit-amount {
16 | padding: 6px;
17 | font-size: 14px;
18 | font-family: "PT sans";
19 | }
20 | .wallet-stack-item .debit-amount {
21 | color: rgb(231, 39, 39);
22 | }
23 | .wallet-stack-item .credit-amount {
24 | color: forestgreen;
25 | }
26 |
27 | .Wallet-Accordian .MuiAccordionSummary-content {
28 | margin: 0px !important;
29 | }
30 |
31 | .Wallet-Accordian .MuiAccordionDetails-root {
32 | padding: 8px !important;
33 | }
34 |
35 | .Wallet-Accordian .MuiList-root {
36 | padding: 0px !important;
37 | }
38 |
39 | .Wallet-Accordian .MuiListItem-gutters {
40 | padding: 4px 6px !important;
41 | }
42 |
43 | .Wallet-Accordian .MuiListItemAvatar-root {
44 | min-width: 30px !important;
45 | }
46 | .Wallet-Accordian .MuiListItemText-root {
47 | margin: 0px !important;
48 | padding: 0px 6px;
49 | }
50 |
51 | .Wallet-Accordian .MuiTypography-root {
52 | font-size: 0.75rem !important;
53 | font-family: "PT sans" !important;
54 | }
55 |
56 | .Wallet-Accordian .MuiListItemText-secondary {
57 | font-family: "PT sans" !important;
58 | font-size: 0.65rem !important;
59 | }
60 |
61 | .Wallet-Accordian .MuiAlert-message {
62 | font-family: "PT sans";
63 | }
64 |
65 | .Wallet-Accordian .MuiChip-label {
66 | font-family: "PT sans" !important;
67 | font-size: 10px !important;
68 | letter-spacing: 0.5px !important;
69 | }
70 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/AdminPanel.css:
--------------------------------------------------------------------------------
1 | .adminPanel-container {
2 | min-height: 100vh;
3 | }
4 |
5 | .MuiPaper-root.adminPanel-sidebar {
6 | height: 100%;
7 | width: 250px;
8 | background: linear-gradient(195deg, rgb(66, 66, 74), rgb(25, 25, 25));
9 | border-radius: 0;
10 | color: white;
11 | transform: translateX(0px);
12 | transition: width 225ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, background-color 225ms cubic-bezier(0.4, 0, 0.6, 1) 0ms;
13 | box-shadow: rgb(0 0 0 / 5%) 0rem 1.25rem 1.6875rem;
14 | }
15 |
16 | .adminPanel-sidebar-logo {
17 | padding: 15px;
18 | height: 60px;
19 | }
20 |
21 | .MuiDivider-root.adminPanel-sidebar-divider {
22 | flex-shrink: 0;
23 | border-top: 0px solid rgba(0, 0, 0, 0.08);
24 | border-right: 0px solid rgba(0, 0, 0, 0.08);
25 | border-left: 0px solid rgba(0, 0, 0, 0.08);
26 | height: 0.0625rem;
27 | margin: 1rem 0px;
28 | border-bottom: none;
29 | opacity: 0.25;
30 | background-color: transparent;
31 | background-image: linear-gradient(to right, rgba(255, 255, 255, 0), rgb(255, 255, 255), rgba(255, 255, 255, 0)) !important;
32 | }
33 |
34 | .adminPanel-container .MuiAppBar-root {
35 | background: linear-gradient(195deg, rgb(66, 66, 74), rgb(25, 25, 25));
36 | }
37 |
38 | .adminPanel-sidebar-Nav {
39 | padding: 15px;
40 | width: 100%;
41 | }
42 |
43 | .adminPanel-navButton {
44 | padding: 0.8rem 1rem;
45 | border-radius: 0.375rem;
46 | transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, background-color 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
47 | cursor: pointer;
48 | }
49 |
50 | .adminPanel-navButton-active {
51 | background: linear-gradient(195deg, rgb(73, 163, 241), rgb(26, 115, 232));
52 | }
53 |
54 | .adminPanel-navButton:hover {
55 | background-color: rgba(255, 255, 255, 0.2);
56 | }
--------------------------------------------------------------------------------
/src/components/MicroComponents/customCopyText.js:
--------------------------------------------------------------------------------
1 | import { React, useState } from "react";
2 |
3 | import { Stack, Tooltip, Typography } from "@mui/material";
4 |
5 | // MUI Icons
6 | import CopyIcon from "@mui/icons-material/ContentCopy";
7 | import CopiedIcon from "@mui/icons-material/Check";
8 |
9 | const CopyableText = ({ text, fontSize }) => {
10 | const [copied, setcopied] = useState(false);
11 |
12 | const CopyText = () => {
13 | navigator.clipboard.writeText(text);
14 | setcopied(true);
15 | setTimeout(() => {
16 | setcopied(false);
17 | }, 3000);
18 | };
19 |
20 | return (
21 |
33 |
38 | {text}
39 |
40 |
49 |
50 | {!copied ? (
51 |
52 | ) : (
53 |
54 | )}
55 |
56 |
57 |
58 | );
59 | };
60 |
61 | export default CopyableText;
62 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Book/AdminFindBook.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useContext } from "react";
2 | import { AdminContext } from "../../../context/adminContext";
3 |
4 | // MUI Components
5 | import { Stack, Button, TextField } from "@mui/material";
6 |
7 | // Custom Components
8 | import BookDetails from "./BookVerification/BookDetails";
9 |
10 | const AdminFindBook = () => {
11 | // admin Context
12 | const [admin, setAdmin] = useContext(AdminContext);
13 |
14 | // States
15 | const [bookId, setBookId] = useState(admin?.AdminFindBook?.bookId);
16 | const [getBook, setGetBook] = useState(false);
17 |
18 | const handleGetBook = () => {
19 | setGetBook(true);
20 | setAdmin({
21 | ...admin,
22 | AdminFindBook: { ...admin.AdminFindBook, bookId: bookId },
23 | });
24 | localStorage.setItem(
25 | "bookshlf_admin",
26 | JSON.stringify({
27 | ...admin,
28 | AdminFindBook: { ...admin.AdminFindBook, bookId: bookId },
29 | })
30 | );
31 | };
32 | return (
33 |
43 |
44 | setBookId(e.target.value)}
50 | sx={{ minWidth: 300 }}
51 | />
52 |
55 |
56 | {getBook ? : null}
57 |
58 | );
59 | };
60 | export default AdminFindBook;
61 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Support/Support.css:
--------------------------------------------------------------------------------
1 | .admin-support {
2 | min-height: calc(100vh - 48px);
3 | padding: 0;
4 | }
5 |
6 | .admin-support-sidebar {
7 | min-width: 250px;
8 | max-width: 300px;
9 | }
10 |
11 | .MuiButton-root.admin-ComposeMailBtn {
12 | margin: 10px;
13 | border-radius: 16px;
14 | color: #001d35;
15 | height: 56px;
16 | padding: 0 24px 0 0;
17 | min-width: 150px;
18 | font-size: .875rem;
19 | background-color: #c2e7ff;
20 | box-shadow: 0 1px 2px 0 #0000, 0 1px 3px 1px #0000;
21 | }
22 |
23 | .MuiButton-root.admin-ComposeMailBtn:hover {
24 | transition: box-shadow .08s linear, min-width .15s cubic-bezier(0.4, 0, 0.2, 1);
25 | box-shadow: 0 1px 3px 0 rgb(60 64 67 / 30%), 0 4px 8px 3px rgb(60 64 67 / 15%);
26 | background-color: #c2e7ff;
27 | }
28 |
29 | .admin-sidebar-btn {
30 | box-shadow: inset 0 0 0 1px transparent;
31 | border-radius: 0 16px 16px 0;
32 | height: 32px;
33 | padding: 0 12px 0 26px;
34 | cursor: pointer;
35 | }
36 |
37 | .admin-sidebar-btn-active {
38 | background-color: #d3e3fd;
39 | }
40 |
41 | .admin-sidebar-btn:hover {
42 | background-color: rgba(0, 0, 0, 0.1);
43 | }
44 |
45 | .admin-sidebar-btn-active:hover {
46 | background-color: #d3e3fd;
47 | }
48 |
49 | .admin-supportContent {
50 | padding: 10px 0px;
51 | flex-grow: 1;
52 | }
53 |
54 | .admin-support-msg {
55 | padding: 10px;
56 | box-shadow: inset 0 -1px 0 0 rgb(100 121 143 / 12%);
57 | cursor: pointer;
58 | width: 100%;
59 | }
60 |
61 | .admin-support-msg:hover {
62 | box-shadow: inset 1px 0 0 #dadce0, inset -1px 0 0 #dadce0, 0 1px 2px 0 rgb(60 64 67 / 30%), 0 1px 3px 1px rgb(60 64 67 / 15%);
63 | z-index: 2;
64 | }
65 |
66 | .admin-support-msg-read {
67 | background-color: rgba(0, 0, 0, 0.08);
68 | }
--------------------------------------------------------------------------------
/src/assets/utils/commons.js:
--------------------------------------------------------------------------------
1 | export const isLocationAuth = (pathname) => {
2 | if (pathname.startsWith("/auth")) return true;
3 | return false;
4 | };
5 |
6 | export const isUATEnvironment = () => {
7 | if (process.env.REACT_APP_NODE_ENV === "uat") return true;
8 | return false;
9 | };
10 |
11 | export const PrintInUATEnvironment = (data) => {
12 | if (isUATEnvironment()) console.log(data);
13 | };
14 |
15 | export const userRoleCheck = (user, role) => {
16 | if (user?.roles?.includes(role)) return true;
17 | return false;
18 | };
19 |
20 | export const trimText = (text, maxLength) => {
21 | return text.length >= maxLength ? text.substr(0, maxLength) + "..." : text;
22 | };
23 |
24 | export const StringtoObject = (string, splitter = "&", delimiter = "=") => {
25 | if (string === undefined || string === "default") return {};
26 | const params = string.split(splitter);
27 | let result = {};
28 | params.map((param) => {
29 | const key = param.split(delimiter)[0];
30 | const value = param.split(delimiter)[1];
31 | result = {
32 | ...result,
33 | [key]: value,
34 | };
35 | return param;
36 | });
37 | return result;
38 | };
39 |
40 | export const StringtoArray = (string, splitter = "&") => {
41 | if (string === undefined || string === "default") return ["default"];
42 | return string.split(splitter);
43 | };
44 |
45 | export const isEnterKey = (e) => {
46 | return e.key === "Enter";
47 | };
48 |
49 | export const AddressFormat = (address = {}) => {
50 | return (
51 | address.address +
52 | ", " +
53 | address.city +
54 | " " +
55 | address.state +
56 | " (" +
57 | address.zipCode +
58 | ")"
59 | );
60 | };
61 |
62 | export const Sort = (data = [], key) => {
63 | data.sort((a, b) => {
64 | return a[key] < b[key] ? 1 : a[key] > b[key] ? -1 : 0;
65 | });
66 | };
67 |
--------------------------------------------------------------------------------
/src/components/search/search.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { useParams } from "react-router-dom";
3 | import "./search.css";
4 |
5 | // Components
6 | import { Stack } from "@mui/material";
7 |
8 | // Custom Components
9 | import Container from "../../assets/components/container";
10 | import SearchFilter from "./searchfilter";
11 | import SearchResult from "./searchresults";
12 | import Pagination from "./pagination";
13 | import BookshlfLoader from "../MicroComponents/BookshlfLoader";
14 |
15 | // Services
16 | import { StringtoObject } from "../../assets/utils/commons";
17 | import { BookSearch, BooksPerPage } from "../../service/search/booksearch";
18 |
19 | const Search = () => {
20 | // Calling Hooks
21 | const { query, filters, page = 1 } = useParams();
22 |
23 | // Functionality States
24 | const [loading, setLoading] = useState(false);
25 |
26 | // Data states
27 | const [books, setbooks] = useState([]);
28 | const [totalPages, settotalPages] = useState(1);
29 |
30 | useEffect(() => {
31 | const makeRequest = async () => {
32 | setLoading(true);
33 | const response = await BookSearch({
34 | ...StringtoObject(filters),
35 | q: query,
36 | noOfBooksInOnePage: BooksPerPage(),
37 | page: Number(page),
38 | });
39 | if (response.success) {
40 | setbooks(response.data.data);
41 | settotalPages(response.data.totalPages);
42 | }
43 | setLoading(false);
44 | };
45 | makeRequest();
46 | }, [query, page, filters]);
47 |
48 | return (
49 |
50 |
51 |
52 | {loading && }
53 | {!loading && }
54 | {!loading && }
55 |
56 |
57 | );
58 | };
59 |
60 | export default Search;
61 |
--------------------------------------------------------------------------------
/src/components/Order/tracking/tracking.css:
--------------------------------------------------------------------------------
1 | .track-box {
2 | background: #FDFDFD;
3 | box-shadow: 10px 10px 28px -2px rgba(0, 0, 0, 0.1);
4 | border-radius: 12px;
5 | width: 100%;
6 | }
7 |
8 | .tracking-dayname {
9 | font-weight: bold !important;
10 | font-size: 2em !important;
11 | color: #1E1E1E !important;
12 | }
13 |
14 | .tracking-monthyear {
15 | font-weight: bold !important;
16 | color: #1E1E1E !important;
17 | font-size: 1.2em !important;
18 | }
19 |
20 | .tracking-date {
21 | font-weight: bold !important;
22 | color: #F4A946 !important;
23 | font-size: 4em !important;
24 | }
25 |
26 | .order-current-status {
27 | text-transform: capitalize;
28 | font-weight: bold !important;
29 | color: #2d82f9 !important;
30 | font-size: 2em !important;
31 | }
32 |
33 | .order-cancel-btn {
34 | background-color: rgb(255, 86, 79) !important;
35 | color: #FDFDFD !important;
36 | font-family: "DM Sans", sans-serif !important;
37 | text-transform: capitalize !important;
38 | border-radius: 12px !important;
39 | padding: 10px 15px !important;
40 | }
41 |
42 | .track-order-image {
43 | height: 300px;
44 | width: 300px;
45 | object-fit: cover;
46 | border-radius: 12px;
47 | }
48 |
49 | .track-detail-title {
50 | font-size: 14px !important;
51 | font-weight: bold !important;
52 | }
53 |
54 | .track-detail-text {
55 | font-size: 12px !important;
56 | color: #0071f3 !important;
57 | }
58 |
59 | .track-box .Mui-active {
60 | color: #1692f1 !important;
61 | }
62 |
63 | .track-box .Mui-completed {
64 | color: rgb(4, 154, 4) !important;
65 | }
66 |
67 | .step-content {
68 | font-size: 12px !important;
69 | padding: 10px 15px;
70 | border: 1px solid rgba(0, 0, 0, 0.2) !important;
71 | border-radius: 12px;
72 | }
73 |
74 | @media screen and (max-width:600px) {
75 | .track-order-image {
76 | height: 200px;
77 | width: 200px;
78 | object-fit: cover;
79 | border-radius: 12px;
80 | }
81 | }
--------------------------------------------------------------------------------
/src/components/MicroComponents/Mail.js:
--------------------------------------------------------------------------------
1 | import { React, useState } from "react";
2 | import axios from "../../api/axios";
3 |
4 | // MUI Components
5 | import { Button, CircularProgress } from "@mui/material";
6 |
7 | const Btn = (props) => {
8 | const [load, setLoad] = useState(false);
9 | const [sent, setSent] = useState(false);
10 |
11 | const SendMail = () => {
12 | setLoad(true);
13 | // console.log(props.template);
14 | axios
15 | .post("/admin-sendEmail", {
16 | type: "SEND_MULTIPLE",
17 | emailData: {
18 | to: props.to,
19 | from: "shipment@bookshlf.in",
20 | cc: props.cc,
21 | bcc: "bookshlf.in@gmail.com",
22 | subject: props.subject,
23 | text: props.subject,
24 | html: props.template,
25 | },
26 | })
27 | .then((res) => {
28 | setLoad(false);
29 | setSent(true);
30 | })
31 | .catch((err) => {
32 | setLoad(false);
33 | // console.log(err.response.data);
34 | });
35 | };
36 | return (
37 | : <>>}
44 | >
45 | {sent ? "Send Again" : load ? "Sending" : props.label}
46 |
47 | );
48 | };
49 | const Form = (props) => {
50 | return Form
;
51 | };
52 | const Mail = (props) => {
53 | return (
54 |
55 | {props.type === "button" ? (
56 |
66 | ) : (
67 |
68 | )}
69 |
70 | );
71 | };
72 | export default Mail;
73 |
--------------------------------------------------------------------------------
/src/components/home/Categories.css:
--------------------------------------------------------------------------------
1 | .categories {
2 | padding-top: 10px;
3 | background-color: white;
4 | color: rgb(51, 51, 51);
5 | }
6 | .item {
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: center;
10 | align-items: center;
11 | padding: 10px;
12 | height: 230px;
13 | width: 100%;
14 | max-width: 350px;
15 | cursor: pointer;
16 | background-color: rgb(10, 37, 64);
17 | border-radius: 15px;
18 | box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.2);
19 | position: relative;
20 | border: 0.5px solid rgba(255, 255, 255, 0);
21 | color: rgb(255, 151, 65);
22 | }
23 | .item:hover {
24 | background-color: rgb(255, 151, 65);
25 | transition: 0.3s;
26 | color: rgb(51, 51, 51);
27 | border: 0.5px solid rgba(255, 255, 255, 0.3);
28 | }
29 | .item-h6 {
30 | font-size: 1em;
31 | margin-top: 100px;
32 | font-family: "Montserrat", sans-serif;
33 | letter-spacing: 2px;
34 | text-align: center;
35 | }
36 |
37 | @media screen and (max-width: 768px) {
38 | .categories h4 {
39 | font-size: 24px;
40 | font-weight: bolder !important;
41 | }
42 | .categories h6 {
43 | font-size: 12px !important;
44 | font-weight: bolder !important;
45 | }
46 | .categories .MuiAvatar-root {
47 | height: 50px;
48 | width: 50px;
49 | }
50 | .categories .MuiTypography-caption {
51 | font-size: 9px;
52 | padding: 6px 0px;
53 | width: 50px;
54 | }
55 | .item {
56 | height: 125px;
57 | width: 125px;
58 | }
59 | .item-h6 {
60 | font-size: 12px !important;
61 | margin-top: 40px;
62 | }
63 | }
64 | @media screen and (max-width: 350px) {
65 | .categories h6 {
66 | font-size: 9px !important;
67 | }
68 | .categories .MuiAvatar-root {
69 | height: 35px;
70 | width: 35px;
71 | top: 5px;
72 | }
73 | .categories .MuiTypography-caption {
74 | font-size: 9px;
75 | padding: 6px 0px;
76 | width: 50px;
77 | }
78 | .item {
79 | height: 125px;
80 | width: 125px;
81 | }
82 | .item-h6 {
83 | font-size: 12px !important;
84 | margin-top: 40px;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/Order/tracking/trackprogress.js:
--------------------------------------------------------------------------------
1 | import { Stack, Typography, Skeleton, Divider } from "@mui/material";
2 |
3 | import { TimestampToDate } from "../../../assets/utils/date";
4 | import OrderCancelButton from "../../../assets/components/buttons/ordercancelbutton";
5 | import TrackingStepper from "./trackingstepper";
6 |
7 | const TrackProgress = ({ order = {}, loading }) => {
8 | const { date, dayName, monthName, year } = TimestampToDate(
9 | order.expectedDeliveryDate
10 | );
11 |
12 | const orderCurrentStatus = order.status
13 | ? order.status[order.status.length - 1]
14 | : "UnKnown";
15 |
16 | return (
17 |
18 | {loading && (
19 |
25 | )}
26 | {!loading && (
27 |
28 |
33 | Estimated Delivery Date
34 | {orderCurrentStatus === "Order placed" && (
35 |
39 | )}
40 |
41 |
42 | {dayName}
43 |
44 | {monthName + ", " + year}
45 |
46 | {date}
47 |
48 |
49 | {orderCurrentStatus}
50 |
51 |
52 |
53 |
54 | )}
55 |
56 | );
57 | };
58 |
59 | export default TrackProgress;
60 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Support/SupportSideBar.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | // MUI Components
4 | import { Stack, Typography } from "@mui/material";
5 |
6 | // Custom Components
7 | import ComposeMail from "./ComposeMail";
8 |
9 | // MUI Icons
10 | import InboxIcon from "@mui/icons-material/Inbox";
11 | import GeneralIcon from "@mui/icons-material/Info";
12 | import FeedbackIcon from "@mui/icons-material/Feedback";
13 | import OrderhelpIcon from "@mui/icons-material/LocalShipping";
14 |
15 | const SidebarBtn = ({ panel, setPanel, value, Icon, txt }) => {
16 | return (
17 | setPanel(value)}
27 | >
28 | {Icon}
29 |
30 | {txt}
31 |
32 |
33 | );
34 | };
35 |
36 | const SupportSideBar = ({ panel, setPanel }) => {
37 | return (
38 |
39 |
40 | }
45 | txt="Inbox"
46 | />
47 | }
52 | txt="General Query"
53 | />
54 | }
59 | txt="Order Help"
60 | />
61 | }
66 | txt="Feedback"
67 | />
68 |
69 | );
70 | };
71 |
72 | export default SupportSideBar;
73 |
--------------------------------------------------------------------------------
/src/components/About/AboutSocial.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | // Mui Components
4 | import { Stack, IconButton } from "@mui/material";
5 |
6 | // Mui Icons
7 | import WebsiteIcon from "@mui/icons-material/Language";
8 | import GitHubIcon from "@mui/icons-material/GitHub";
9 | import FacebookIcon from "@mui/icons-material/Facebook";
10 | import YouTubeIcon from "@mui/icons-material/YouTube";
11 | import InstagramIcon from "@mui/icons-material/Instagram";
12 | import LinkedInIcon from "@mui/icons-material/LinkedIn";
13 |
14 | // Links
15 | const GITHUB_URL = "https://github.com/Bookshlf-in";
16 | const WEBSITE_URL = "https://bookshlf.in";
17 | const YOUTUBE_URL = "https://www.youtube.com/channel/UCvZJWq7cQ4-cGJFsCWIppGQ";
18 | const FACEBOOK_URL = "https://www.facebook.com/Bookshlf-109479771200918";
19 | const LINKEDIN_URL = "https://www.linkedin.com/in/bookshlf-by-aman-861073223/";
20 | const INSTAGRAM_URL = "https://instagram.com/_bookshlf";
21 |
22 | const AboutSocial = () => {
23 | // Opening Links
24 | const OpenLink = (link) => {
25 | window.open(link, "_blank").focus();
26 | };
27 |
28 | // Custom Icon Button Component
29 | const SocialLink = (props) => {
30 | return (
31 | OpenLink(props.url)}
34 | sx={{ color: "white" }}
35 | size="small"
36 | >
37 | {props.Icon}
38 |
39 | );
40 | };
41 |
42 | return (
43 |
47 |
48 | } />
49 | } />
50 | } />
51 |
52 |
53 | } />
54 | } />
55 | } />
56 |
57 |
58 | );
59 | };
60 | export default AboutSocial;
61 |
--------------------------------------------------------------------------------
/src/components/About/About.js:
--------------------------------------------------------------------------------
1 | import { React } from "react";
2 | import { Helmet } from "react-helmet-async";
3 | import "./About.css";
4 |
5 | // Components
6 | import { Box, Stack, Typography, Avatar } from "@mui/material";
7 |
8 | // About Components
9 | import AboutSocial from "./AboutSocial";
10 | import AboutTeam from "./AboutTeam";
11 |
12 | const Year = new Date().getFullYear();
13 | const About = () => {
14 | return (
15 | <>
16 |
17 | About | Bookshlf
18 |
22 |
23 |
24 |
29 |
35 |
45 | BOOKSHLF
46 |
47 |
48 |
55 | TEAM
56 |
57 |
58 |
63 | {Year}
64 |
65 |
66 |
67 | >
68 | );
69 | };
70 | export default About;
71 |
--------------------------------------------------------------------------------
/src/components/SellerPanel/SellerPanel.css:
--------------------------------------------------------------------------------
1 | .sellerPanel-container .MuiTabs-flexContainer {
2 | height: 100% !important;
3 | }
4 | .seller-register-banner {
5 | width: 100%;
6 | min-height: calc(100vh - 48px);
7 | background-color: rgba(27, 16, 95, 255);
8 | color: aliceblue;
9 | padding: 16px 24px;
10 | }
11 | .seller-register-banner-img {
12 | height: auto;
13 | width: 500px;
14 | }
15 | .seller-register-banner h2 {
16 | font-family: "Staatliches", sans-serif;
17 | letter-spacing: 0.05em;
18 | }
19 | .seller-register-banner span {
20 | font-family: "Montserrat", sans-serif;
21 | text-transform: capitalize;
22 | color: rgb(255, 255, 255, 0.8);
23 | }
24 | .seller-register-form {
25 | padding: 16px 24px;
26 | position: relative;
27 | width: 100%;
28 | min-height: calc(100vh - 48px);
29 | background-color: rgba(27, 16, 95, 255);
30 | }
31 | .seller-register-form .MuiOutlinedInput-root,
32 | .seller-register-form .MuiFormHelperText-root,
33 | .seller-register-form .MuiInputLabel-root {
34 | color: rgb(219, 219, 219) !important;
35 | }
36 | .seller-register-form .MuiOutlinedInput-notchedOutline {
37 | border-color: inherit;
38 | }
39 | .seller-register-form-back {
40 | position: absolute !important;
41 | top: 0;
42 | left: 0;
43 | }
44 | .iframe-container {
45 | position: relative;
46 | overflow: hidden;
47 | width: 100%;
48 | padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
49 | }
50 | .responsive-iframe {
51 | position: absolute;
52 | top: 0;
53 | left: 0;
54 | bottom: 0;
55 | right: 0;
56 | width: 100%;
57 | height: 100%;
58 | }
59 | @media screen and (max-width: 850px) {
60 | .seller-register-banner-img {
61 | height: auto;
62 | width: 300px;
63 | }
64 | }
65 | @media screen and (max-width: 600px) {
66 | .seller-register-banner-img {
67 | height: auto;
68 | width: 300px;
69 | }
70 | .seller-register-banner h2 {
71 | font-size: 2em;
72 | }
73 | }
74 | @media screen and (max-width: 400px) {
75 | .seller-register-banner-img {
76 | height: auto;
77 | width: 150px;
78 | }
79 | .seller-register-banner h2 {
80 | font-size: 16px;
81 | }
82 | .seller-register-banner span {
83 | font-size: 9px;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Book/BookVerification/AdminBookDelete.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useContext } from "react";
2 | import { AdminContext } from "../../../../context/adminContext";
3 |
4 | // API
5 | import axios from "../../../../api/axios";
6 |
7 | // MUI Components
8 | import { IconButton, CircularProgress } from "@mui/material";
9 |
10 | // icons
11 | import DeleteIcon from "@mui/icons-material/Delete";
12 |
13 | const AdminBookDelete = ({ bookId }) => {
14 | // Admin Context
15 | const [admin, setAdmin] = useContext(AdminContext);
16 |
17 | // Loading States
18 | const [deleteLoad, setDeleteLoad] = useState(false);
19 |
20 | // Deleting Books
21 | const handelDeleteBook = () => {
22 | setDeleteLoad(true);
23 | axios
24 | .delete("/admin-deleteBook", {
25 | data: {
26 | bookId: bookId,
27 | message: "Book is not appropriate and have many unavoidable errors",
28 | },
29 | })
30 | .then((response) => {
31 | console.log(response.data);
32 | setDeleteLoad(false);
33 | setAdmin({
34 | ...admin,
35 | bookVerification: {
36 | ...admin.bookVerification,
37 | data: admin.bookVerification.data.filter(
38 | (book) => book._id !== bookId
39 | ),
40 | },
41 | });
42 | localStorage.setItem(
43 | "bookshlf_admin",
44 | JSON.stringify({
45 | ...admin,
46 | bookVerification: {
47 | ...admin.bookVerification,
48 | data: admin.bookVerification.data.filter(
49 | (book) => book._id !== bookId
50 | ),
51 | },
52 | })
53 | );
54 | })
55 | .catch((error) => {
56 | setDeleteLoad(false);
57 | console.log(error.response.data);
58 | });
59 | };
60 |
61 | return (
62 |
68 | {deleteLoad ? (
69 |
70 | ) : (
71 |
72 | )}
73 |
74 | );
75 | };
76 |
77 | export default AdminBookDelete;
78 |
--------------------------------------------------------------------------------
/src/components/search/searchbook.js:
--------------------------------------------------------------------------------
1 | import { Link } from "react-router-dom";
2 |
3 | // Mui Components
4 | import { Box, Stack, Typography, Tooltip } from "@mui/material";
5 |
6 | // assets
7 | import BookButton from "../../assets/components/buttons/bookbutton";
8 | import WishlistButton from "../../assets/components/buttons/wishlistbutton";
9 | import CartButton from "../../assets/components/buttons/cartbutton";
10 |
11 | // services
12 | import { trimText } from "../../assets/utils/commons";
13 |
14 | const BookImage = ({ photo, title }) => {
15 | return (
16 |
17 |
18 |
24 |
25 |
26 | );
27 | };
28 |
29 | const BookTitle = ({ title }) => {
30 | return (
31 |
32 | {trimText(title, 60)}
33 |
34 | );
35 | };
36 |
37 | const BookPriceTag = ({ price }) => {
38 | return (
39 |
40 | Rs. {price}/-
41 |
42 | );
43 | };
44 |
45 | const SearchBook = ({ book }) => {
46 | return (
47 |
48 |
49 |
50 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Buy
68 |
69 |
70 |
71 |
72 |
73 | );
74 | };
75 |
76 | export default SearchBook;
77 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Navigation/AdminContentPanel.js:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import { UserContext } from "../../../context/userContext";
3 |
4 | // Components
5 | import { Stack, Alert } from "@mui/material";
6 |
7 | // Other Components
8 | import Books from "../Book/Book";
9 | import Seller from "../Sellers";
10 | import Orders from "../Order/Orders";
11 | import Support from "../Support/Support";
12 | import Users from "../Users";
13 | import Wallet from "../Billing/Wallet";
14 | import Analytics from "../Analytics/Analytics";
15 |
16 | const PermissionAlert = ({ user, permission, content }) => {
17 | return user.adminPermissions?.includes(permission) ? (
18 | content
19 | ) : (
20 |
21 | You Don't have permission to access the given content. Contact super admin
22 | for permission.
23 |
24 | );
25 | };
26 |
27 | const AdminContentPanel = ({ Panel, setPanel, navigate }) => {
28 | const [user] = useContext(UserContext);
29 | if (Panel === 7) navigate("/");
30 | return (
31 |
32 |
33 | {Panel === 0 ? (
34 | } />
35 | ) : Panel === 1 ? (
36 | }
40 | />
41 | ) : Panel === 2 ? (
42 | }
46 | />
47 | ) : Panel === 3 ? (
48 | }
52 | />
53 | ) : Panel === 4 ? (
54 | } />
55 | ) : Panel === 5 ? (
56 | }
60 | />
61 | ) : Panel === 6 ? (
62 | }
66 | />
67 | ) : null}
68 |
69 |
70 | );
71 | };
72 |
73 | export default AdminContentPanel;
74 |
--------------------------------------------------------------------------------
/src/route/router.js:
--------------------------------------------------------------------------------
1 | import { useRoutes } from "react-router-dom";
2 |
3 | // Components
4 | import Login from "../components/auth/login";
5 | import Recovery from "../components/auth/recovery/recovery";
6 | import Signup from "../components/auth/signup/signup";
7 | import Verify from "../components/auth/signup/verify";
8 | import Home from "../components/home/home";
9 | import Search from "../components/search/search";
10 | import OrderTracking from "../components/Order/tracking/tracking";
11 | import UserPanel from "../components/userpanel/userpanel";
12 | import Profile from "../components/userpanel/profile";
13 |
14 | const Router = () => {
15 | const routes = useRoutes([
16 | {
17 | path: "/auth/login",
18 | element: ,
19 | children: [
20 | {
21 | path: ":email",
22 | element: ,
23 | },
24 | ],
25 | },
26 | {
27 | path: "/auth/signup",
28 | element: ,
29 | children: [
30 | {
31 | path: ":email",
32 | element: ,
33 | },
34 | ],
35 | },
36 | {
37 | path: "/auth/verify",
38 | element: ,
39 | children: [
40 | {
41 | path: ":email",
42 | element: ,
43 | },
44 | ],
45 | },
46 | {
47 | path: "/auth/recovery",
48 | element: ,
49 | children: [
50 | {
51 | path: ":email",
52 | element: ,
53 | },
54 | ],
55 | },
56 | {
57 | path: "/",
58 | element: ,
59 | },
60 | {
61 | path: "/search",
62 | element: ,
63 | children: [
64 | {
65 | path: ":query",
66 | element: ,
67 | },
68 | {
69 | path: ":query/:filters",
70 | element: ,
71 | },
72 | {
73 | path: ":query/:filters/:page",
74 | element: ,
75 | },
76 | ],
77 | },
78 | {
79 | path: "/track/:orderId",
80 | element: ,
81 | },
82 | {
83 | path: "/user",
84 | element: ,
85 | children: [
86 | {
87 | path: ":panel",
88 | element: ,
89 | },
90 | ],
91 | },
92 | ]);
93 | return routes;
94 | };
95 |
96 | export default Router;
97 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Book/Book.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | // custom Styling
4 | import "./Book.css";
5 |
6 | // MUI Components
7 | import { AppBar, Toolbar } from "@mui/material";
8 | import { Stack, Typography } from "@mui/material";
9 |
10 | // custom Components
11 | import SellerBooks from "./SellerBooks";
12 | import BookVerification from "./BookVerification/BookVerification";
13 | import AdminFindBook from "./AdminFindBook";
14 | import BookshlfImageUploadUtility from "./ImageUploadUtility";
15 |
16 | const BookNavButton = ({ panel, setPanel, btnTxt, value }) => {
17 | const handleClick = () => {
18 | setPanel(value);
19 | };
20 | return (
21 |
29 |
30 | {btnTxt}
31 |
32 |
33 | );
34 | };
35 |
36 | const BookNavBar = ({ panel, setPanel }) => {
37 | return (
38 |
39 |
40 |
46 |
52 |
58 |
64 |
65 |
66 | );
67 | };
68 |
69 | const AdminBook = () => {
70 | const [panel, setPanel] = useState(0);
71 | return (
72 |
73 |
74 | {panel === 0 ? (
75 |
76 | ) : panel === 1 ? (
77 |
78 | ) : panel === 2 ? (
79 |
80 | ) : panel === 3 ? (
81 |
82 | ) : (
83 | <>>
84 | )}
85 |
86 | );
87 | };
88 |
89 | export default AdminBook;
90 |
--------------------------------------------------------------------------------
/src/components/userpanel/userpanel.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext, useCallback, Fragment } from "react";
2 | import { useParams, useNavigate } from "react-router-dom";
3 | import { UserContext } from "../../context/userContext";
4 | import "./userpanel.css";
5 |
6 | // API
7 | import { GetRequest } from "../../api/requests/getAPI";
8 | import { userProfile, addressList, orderList } from "../../api/endpoints";
9 |
10 | // Components
11 | import { Stack } from "@mui/material";
12 | import Container from "../../assets/components/container";
13 | import Profile from "./profile";
14 | import UserNav from "./usernav";
15 | import Address from "../AddressBook/Address";
16 |
17 | // Services
18 | import { Sort } from "../../assets/utils/commons";
19 |
20 | const Panels = {
21 | profile: "profile",
22 | orders: "orders",
23 | address: "address",
24 | };
25 |
26 | const UserPanel = () => {
27 | const navigate = useNavigate();
28 | const { panel } = useParams();
29 | const [user] = useContext(UserContext);
30 | const [account, setAccount] = useState({});
31 | const [orders, setOrders] = useState([]);
32 | const [address, setAddress] = useState([]);
33 |
34 | // Loading state
35 | const [loading, setLoading] = useState(true);
36 |
37 | useEffect(() => {
38 | if (!panel) navigate(`/user/${Panels.profile}`);
39 | }, [panel, navigate]);
40 |
41 | const FetchData = async () => {
42 | const profile = await GetRequest(userProfile);
43 | const addressBook = await GetRequest(addressList);
44 | const ordersList = await GetRequest(orderList);
45 | setOrders(ordersList.data);
46 | setAddress(Sort(addressBook.data, "updatedAt"));
47 | setAccount(profile.data);
48 | setLoading(false);
49 | };
50 |
51 | useEffect(() => {
52 | FetchData();
53 | }, []);
54 |
55 | const PanelSelector = () => {
56 | return (
57 |
58 | {Panels.profile === panel ? (
59 |
60 |
61 |
62 |
63 | ) : Panels.address === panel ? (
64 |
65 | ) : (
66 | Orders to be made
67 | )}
68 |
69 | );
70 | };
71 | return (
72 |
73 |
74 |
75 | );
76 | };
77 |
78 | export default UserPanel;
79 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
18 |
22 |
23 |
24 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Bookshlf
39 |
40 |
44 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/components/Checkout/CheckoutOrderReview.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { Stack, Typography, Divider, Chip } from "@mui/material";
3 | import RupeeIcon from "@mui/icons-material/CurrencyRupee";
4 |
5 | const CurrentAddress = ({ address, addressId }) => {
6 | const [currentAddress, setCurrentAddress] = useState(
7 | address.filter((adr) => adr._id === addressId)
8 | );
9 |
10 | useEffect(() => {
11 | setCurrentAddress(address.filter((adr) => adr._id === addressId));
12 | }, [address, addressId]);
13 | return (
14 |
23 |
24 |
25 |
26 | {currentAddress[0]?.address}
27 | {currentAddress[0]?.city}
28 | {currentAddress[0]?.state}
29 | {currentAddress[0]?.zipCode}
30 | {currentAddress[0]?.phoneNo}
31 |
32 |
33 | );
34 | };
35 |
36 | const CheckoutOrderReview = ({ address, addressId, checkout }) => {
37 | return (
38 |
39 | Shipping Address
40 |
41 | Payment Details
42 |
50 | Total Items :
51 |
52 | Order Total :
53 | }
55 | label={checkout.orderTotal}
56 | size="small"
57 | color="info"
58 | sx={{ width: 100 }}
59 | />
60 |
61 |
62 | );
63 | };
64 |
65 | export default CheckoutOrderReview;
66 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "website",
3 | "version": "2.0.0",
4 | "license": "MIT",
5 | "description": "Bookshlf frontend",
6 | "keywords": [
7 | "react",
8 | "html",
9 | "css",
10 | "javascript",
11 | "mui"
12 | ],
13 | "author": "Mrhb787",
14 | "private": true,
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/Bookshlf-in/Website.git"
18 | },
19 | "main": "app.js",
20 | "dependencies": {
21 | "@emotion/react": "^11.10.8",
22 | "@emotion/styled": "^11.10.8",
23 | "@mui/icons-material": "^5.11.6",
24 | "@mui/lab": "^5.0.0-alpha.131",
25 | "@mui/material": "^5.13.2",
26 | "@mui/x-data-grid": "^6.5.0",
27 | "apexcharts": "^3.36.3",
28 | "axios": "^1.3.5",
29 | "filepond": "^4.30.4",
30 | "react": "^18.2.0",
31 | "react-apexcharts": "^1.4.0",
32 | "react-dom": "^18.2.0",
33 | "react-filepond": "^7.1.1",
34 | "react-helmet-async": "^1.3.0",
35 | "react-router-dom": "^6.11.2",
36 | "web-vitals": "^3.3.1"
37 | },
38 | "scripts": {
39 | "start": "react-scripts start",
40 | "build": "react-scripts build",
41 | "test": "react-scripts test --passWithNoTests",
42 | "eject": "react-scripts eject",
43 | "prettier": "prettier --write ."
44 | },
45 | "eslintConfig": {
46 | "extends": [
47 | "react-app",
48 | "react-app/jest"
49 | ]
50 | },
51 | "browserslist": {
52 | "production": [
53 | ">0.2%",
54 | "not dead",
55 | "not op_mini all"
56 | ],
57 | "development": [
58 | "last 1 chrome version",
59 | "last 1 firefox version",
60 | "last 1 safari version"
61 | ]
62 | },
63 | "devDependencies": {
64 | "@blacklab/react-image-magnify": "^4.1.1",
65 | "@react-hook/resize-observer": "^1.2.6",
66 | "@svgr/plugin-svgo": "^8.0.1",
67 | "@svgr/webpack": "^8.0.1",
68 | "browser-image-compression": "^2.0.2",
69 | "css-select": "^5.1.0",
70 | "detect-it": "^4.0.1",
71 | "email-validator": "^2.0.4",
72 | "filepond-plugin-file-validate-type": "^1.2.6",
73 | "filepond-plugin-image-exif-orientation": "^1.0.11",
74 | "filepond-plugin-image-preview": "^4.6.10",
75 | "nth-check": "^2.1.1",
76 | "prettier": "2.8.8",
77 | "react-error-overlay": "^6.0.11",
78 | "react-otp-input": "^3.0.2",
79 | "react-popper": "^2.3.0",
80 | "react-scripts": "^5.0.1"
81 | },
82 | "overrides": {
83 | "@svgr/webpack": "$@svgr/webpack",
84 | "@svgr/plugin-svgo": "$@svgr/plugin-svgo"
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/assets/components/input/otpfield.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { Stack, Typography, Button } from "@mui/material";
3 | import { Alert, CircularProgress } from "@mui/material";
4 | import OtpInput from "react-otp-input";
5 | import Counter from "../../counter";
6 | import { handelSendOtp } from "../../../service/auth/signup";
7 |
8 | const OtpField = ({
9 | otp,
10 | setOtp,
11 | otpLength = 6,
12 | email,
13 | time = 60,
14 | type = "EMAIL_VERIFICATION",
15 | }) => {
16 | const [counter, setCounter] = useState(time);
17 | const [loading, setLoading] = useState(false);
18 | const [alert, setAlert] = useState({
19 | show: false,
20 | type: "success",
21 | msg: "OTP Sent",
22 | });
23 |
24 | const hideAlert = () => {
25 | setTimeout(() => {
26 | setAlert({ show: false, type: "success", msg: "OTP Sent" });
27 | }, 60000);
28 | };
29 |
30 | const sendOtp = async () => {
31 | setLoading(true);
32 | const response = await handelSendOtp(type, { email: email });
33 | if (response.success) {
34 | setAlert({ show: true, type: "success", msg: "OTP Sent" });
35 | setCounter(60);
36 | hideAlert();
37 | } else {
38 | handleOtpSendError(
39 | response.data.errors
40 | ? response.data.errors[0].error
41 | : response.data.error
42 | );
43 | }
44 | setLoading(false);
45 | };
46 |
47 | const handleOtpSendError = (error) => {
48 | setAlert({ show: true, type: "error", msg: error });
49 | };
50 |
51 | return (
52 |
53 | Enter OTP
54 | (
59 |
60 | )}
61 | />
62 | {counter > 0 ? (
63 |
64 | ) : (
65 | }
70 | onClick={sendOtp}
71 | >
72 | Send OTP
73 |
74 | )}
75 | {alert.show && (
76 |
77 | {alert.msg}
78 |
79 | )}
80 |
81 | );
82 | };
83 |
84 | export default OtpField;
85 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Support/SupportContent.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 |
3 | // API
4 | import axios from "../../../api/axios";
5 |
6 | // MUI Components
7 | import { Stack, Pagination, Alert } from "@mui/material";
8 | import { CircularProgress } from "@mui/material";
9 | import Message from "./Message";
10 |
11 | const SupportContent = ({ panel, setPanel, page, setPage }) => {
12 | // loading
13 | const [Loading, setLoading] = useState(false);
14 |
15 | // data states
16 | const [totalPages, setTotalPages] = useState(0);
17 | const [noOfMessagesInOnePage, setnoOfMessagesInOnePage] = useState(50);
18 | const [messagesList, setMessagesList] = useState([]);
19 |
20 | // fetch users messages
21 | const fetchMessages = () => {
22 | setLoading(true);
23 | const getURL = "/admin-getMessageList";
24 | let getParams = {
25 | page: page,
26 | noOfMessagesInOnePage: noOfMessagesInOnePage,
27 | };
28 | if (panel > 0) {
29 | getParams = {
30 | ...getParams,
31 | queryType:
32 | panel === 1 ? "GENERAL" : panel === 2 ? "ORDER_HELP" : "FEEDBACK",
33 | };
34 | }
35 |
36 | axios
37 | .get(getURL, {
38 | params: getParams,
39 | })
40 | .then((res) => {
41 | // console.log(res.data);
42 | setMessagesList(res.data.data);
43 | setTotalPages(res.data.totalPages);
44 | setLoading(false);
45 | })
46 | .catch((err) => {
47 | setLoading(false);
48 | console.log(err.response.data);
49 | });
50 | };
51 |
52 | useEffect(() => {
53 | fetchMessages();
54 | }, [panel, page]);
55 |
56 | return (
57 |
58 | setPage(pageNo)}
62 | color="primary"
63 | size="small"
64 | shape="rounded"
65 | />
66 |
70 | {Loading && }
71 | {!Loading && messagesList && messagesList.length ? (
72 | messagesList.map((message) => (
73 |
74 |
75 |
76 | ))
77 | ) : !Loading ? (
78 | No Messages Found
79 | ) : null}
80 |
81 |
82 | );
83 | };
84 |
85 | export default SupportContent;
86 |
--------------------------------------------------------------------------------
/src/components/Order/tracking/trackingstepper.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | import { Box, Typography } from "@mui/material";
4 | import { Step, Stepper, StepLabel, StepContent } from "@mui/material";
5 |
6 | const steps = [
7 | {
8 | id: "Order placed",
9 | label: "Order Placed",
10 | description:
11 | "Order has been placed and is currently pending the customer & seller confirmation",
12 | },
13 | {
14 | id: "Cancelled",
15 | label: "Order Cancelled",
16 | description: "Order has been cancelled",
17 | },
18 | {
19 | id: "Order Confirmed",
20 | label: "Order Confirmed",
21 | description:
22 | "Order is confirmed by customer and is pending from seller for packaging",
23 | },
24 | {
25 | id: "Packed",
26 | label: "Order Packed",
27 | description: "Order has been packed and is ready for shipment",
28 | },
29 | {
30 | id: "Shipped",
31 | label: "Order Shipped",
32 | description: "Shipement details manifested and order is being shipped",
33 | },
34 | {
35 | id: "enroute",
36 | label: "Order En Route",
37 | description: "Order has been shipped and is currently on the way",
38 | },
39 | {
40 | id: "Delivered",
41 | label: "Order Delivered",
42 | description: "Order has been successfully delivered",
43 | },
44 | {
45 | id: "RTO",
46 | label: "RTO",
47 | description:
48 | "Order has been Rejected and is currently being returned to seller",
49 | },
50 | {
51 | id: "Returned",
52 | label: "Returned",
53 | description: "Order has been Returned to seller",
54 | },
55 | ];
56 |
57 | const getActiveSteps = (status = []) => {
58 | return status.map((currentStatus) => {
59 | return steps.find((step) => step.id === currentStatus);
60 | });
61 | };
62 |
63 | const getActiveStep = (activeSteps = []) => {
64 | return activeSteps.length - 1;
65 | };
66 |
67 | const TrackingStepper = ({ status = ["Order placed"] }) => {
68 | const activeSteps = getActiveSteps(status);
69 | const [activeStep] = useState(getActiveStep(activeSteps));
70 |
71 | return (
72 |
73 |
74 | {activeSteps.map((step, index) => (
75 |
76 | {step.label}
77 |
78 |
79 | {step.description}
80 |
81 |
82 |
83 | ))}
84 |
85 |
86 | );
87 | };
88 | export default TrackingStepper;
89 |
--------------------------------------------------------------------------------
/src/components/Book/AddBook.css:
--------------------------------------------------------------------------------
1 | .add-book-form-lf fieldset,
2 | .add-book-form-rt fieldset {
3 | border-radius: 5px;
4 | padding: 12px 15px;
5 | }
6 |
7 | .add-book-form-rt {
8 | margin-top: 10px;
9 | }
10 |
11 | .add-book-form-lf fieldset legend {
12 | font-family: "Roboto", sans-serif;
13 | font-weight: bold;
14 | padding: 0px 5px;
15 | }
16 |
17 | .add-book-form-lf .MuiAlert-root {
18 | font-family: "pt sans";
19 | font-size: 0.65rem;
20 | padding: 0px 6px;
21 | justify-content: center;
22 | align-items: center;
23 | }
24 |
25 | .add-book-form-lf .searchTitleresult {
26 | position: absolute;
27 | left: 36px;
28 | top: 42px;
29 | background-color: rgba(255, 255, 255, 0.95);
30 | z-index: 200;
31 | max-height: 200px;
32 | width: 100%;
33 | max-width: 600px;
34 | overflow-y: auto;
35 | overflow-x: hidden;
36 | box-shadow: 6px 3px 3px rgba(0, 0, 0, 0.2);
37 | border-radius: 5px;
38 | }
39 |
40 | .add-book-form-lf .searchTagresult {
41 | position: absolute;
42 | left: 36px;
43 | top: 42px;
44 | background-color: rgba(255, 255, 255, 0.95);
45 | z-index: 200;
46 | max-height: 200px;
47 | width: 165px;
48 | overflow-y: auto;
49 | overflow-x: hidden;
50 | box-shadow: 6px 3px 3px rgba(0, 0, 0, 0.2);
51 | border-radius: 5px;
52 | }
53 |
54 | .searchTitleresult #result-title {
55 | padding: 6px;
56 | font-size: 12px;
57 | }
58 |
59 | .searchTagresult #result-tag {
60 | padding: 6px;
61 | }
62 |
63 | .add-book-bg .MuiAlert-message {
64 | font-family: "PT sans" !important;
65 | }
66 |
67 | /* ========= Filepond custom css =========== */
68 | .filepond--wrapper {
69 | width: 100% !important;
70 | }
71 |
72 | .filepond--drop-label {
73 | min-height: 4em !important;
74 | background-color: cornflowerblue;
75 | color: whitesmoke;
76 | border-radius: 5px;
77 | }
78 |
79 | .filepond--drop-label {
80 | color: whitesmoke !important;
81 | }
82 |
83 | .filepond--label-action {
84 | background-color: #333;
85 | padding: 6px 10px;
86 | text-decoration: none !important;
87 | border-radius: 5px;
88 | }
89 |
90 | .filepond--list.filepond--list {
91 | top: 10px !important;
92 | }
93 |
94 | @media (min-width: 30em) {
95 | .filepond--item {
96 | width: calc(50% - 0.5em);
97 | }
98 | }
99 |
100 | @media (min-width: 50em) {
101 | .filepond--item {
102 | width: calc(25% - 0.5em);
103 | }
104 | }
105 |
106 | /* ========= ============ =========== */
107 |
108 | @media screen and (max-width: 400px) {
109 |
110 | .add-book-form-lf,
111 | .add-book-form-rt {
112 | padding: 0px;
113 | }
114 | }
--------------------------------------------------------------------------------
/src/components/BookDetails/BookPurchaseAdmin.js:
--------------------------------------------------------------------------------
1 | // hooks
2 | import { useState } from "react";
3 |
4 | // MUI Components
5 | import { Button, Dialog, Stack, Typography } from "@mui/material";
6 | import { TextField, Alert, CircularProgress } from "@mui/material";
7 |
8 | // micro components
9 | import CopyableText from "../MicroComponents/customCopyText";
10 |
11 | // Methods
12 | import {
13 | handleOpen,
14 | handleClose,
15 | adminBookPurchase,
16 | } from "../../service/Book/AdminBookPurchase/purchaseOrder";
17 |
18 | const BookPurchaseAdmin = ({ bookId }) => {
19 | // states
20 | const [open, setOpen] = useState(false);
21 | const [orderId, setOrderId] = useState("");
22 | const [orderLoad, setOrderLoad] = useState(false);
23 | const [error, setError] = useState(false);
24 | const [success, setSuccess] = useState(false);
25 |
26 | // utitility function to call admin purchase
27 | const purchaseBook = (orderId) => {
28 | adminBookPurchase(
29 | orderId,
30 | setOrderId,
31 | setOrderLoad,
32 | bookId,
33 | setSuccess,
34 | setOpen,
35 | setError
36 | );
37 | };
38 |
39 | return (
40 |
41 |
48 |
80 |
81 | );
82 | };
83 |
84 | export default BookPurchaseAdmin;
85 |
--------------------------------------------------------------------------------
/src/components/home/home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Helmet } from "react-helmet-async";
3 | import "./home.css";
4 |
5 | // Home Components
6 | import Carousel from "../../assets/components/carousel";
7 | import Categories from "./Categories";
8 | import Benefits from "./Benefits";
9 | import Reviews from "../Reviews/CustomerReviews";
10 | import Footer from "../Footer/Footer";
11 |
12 | const Home = () => {
13 | return (
14 | <>
15 |
16 |
17 | Bookshlf | Buy and Sell Used Books, Second Hand Books Online
18 |
19 | {/* */}
20 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | >
67 | );
68 | };
69 | export default Home;
70 |
--------------------------------------------------------------------------------
/src/components/AddressBook/AddressDetails.js:
--------------------------------------------------------------------------------
1 | import { React, useState } from "react";
2 |
3 | //Mui Components
4 | import { Stack, Dialog, Chip, Typography } from "@mui/material";
5 |
6 | // Mui Icons
7 | import CallIcon from "@mui/icons-material/CallRounded";
8 | import HomeIcon from "@mui/icons-material/HomeRounded";
9 | import OfficeIcon from "@mui/icons-material/ApartmentRounded";
10 | import TempIcon from "@mui/icons-material/NotListedLocationRounded";
11 |
12 | const AddressDetails = (props) => {
13 | const [open, setOpen] = useState(false);
14 | const Details = (props) => {
15 | return (
16 |
17 | {props.value}
18 |
19 | );
20 | };
21 | // Details Popup
22 | const Popup = () => {
23 | return (
24 |
69 | );
70 | };
71 | return (
72 | <>
73 | {
81 | setOpen(true);
82 | }}
83 | >
84 | More Details
85 |
86 |
87 | >
88 | );
89 | };
90 |
91 | export default AddressDetails;
92 |
--------------------------------------------------------------------------------
/src/components/Checkout/CheckoutPayment.js:
--------------------------------------------------------------------------------
1 | import { Stack, Divider, Typography, Chip } from "@mui/material";
2 |
3 | import RupeeIcon from "@mui/icons-material/CurrencyRupee";
4 |
5 | const ContractString = (str) => {
6 | return str.length > 30 ? str.substr(0, 29) + "..." : str;
7 | };
8 | const CheckoutPayment = ({ checkout, checkoutType }) => {
9 | return (
10 | }
14 | sx={{ width: "100%", maxWidth: 600 }}
15 | >
16 |
17 | Item ({checkout.totalItems})
18 |
19 | Price ()
20 |
21 |
22 | {checkoutType !== "cart" ? (
23 |
24 |
25 | {ContractString(checkout.item.title)}
26 |
27 |
28 | () {checkout.item.price}
29 | /-
30 |
31 |
32 | ) : (
33 | checkout.items.map((item) => (
34 |
35 |
36 | {ContractString(item.title)}
37 |
38 |
39 | () {item.price}
40 |
41 |
42 | ))
43 | )}
44 |
45 | Items Subtotal
46 | }
48 | label={checkout.itemsSubtotal}
49 | size="small"
50 | sx={{ width: 100 }}
51 | />
52 |
53 |
54 | Shipping Charges
55 | }
57 | label={checkout.shippingCharges}
58 | size="small"
59 | sx={{ width: 100 }}
60 | />
61 |
62 |
63 | Order Total
64 | }
66 | label={checkout.orderTotal}
67 | size="small"
68 | color="success"
69 | sx={{ width: 100 }}
70 | />
71 |
72 |
73 | );
74 | };
75 |
76 | export default CheckoutPayment;
77 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/UserProfile.js:
--------------------------------------------------------------------------------
1 | import { React } from "react";
2 |
3 | // components
4 | import Stack from "@mui/material/Stack";
5 | import Box from "@mui/material/Box";
6 | import Chip from "@mui/material/Chip";
7 |
8 | // icons
9 | import EmailIcon from "@mui/icons-material/EmailRounded";
10 | import RolesIcon from "@mui/icons-material/SupervisorAccountRounded";
11 | import CheckIcon from "@mui/icons-material/CheckCircleRounded";
12 | import CancelIcon from "@mui/icons-material/CancelRounded";
13 | import PersonIcon from "@mui/icons-material/PersonRounded";
14 | import IDIcon from "@mui/icons-material/AssignmentIndRounded";
15 | import UpdateIcon from "@mui/icons-material//UpdateRounded";
16 | import TimeIcon from "@mui/icons-material/TimelapseRounded";
17 |
18 | const UserProfile = ({ data }) => {
19 | const userData = data;
20 |
21 | return (
22 |
32 |
33 |
34 | }
36 | label={userData.email}
37 | variant="filled"
38 | size="small"
39 | />
40 | : }
42 | label={userData.emailVerified ? "Verified" : "Not Verified"}
43 | color={userData.emailVerified ? "success" : "error"}
44 | size="small"
45 | variant="filled"
46 | />
47 |
48 |
49 |
50 | {userData.name}
51 |
52 |
53 |
54 | Roles :
55 | {userData.roles.map((role, idx) => (
56 |
63 | ))}
64 |
65 |
66 |
67 | ID :
68 |
74 |
75 |
76 |
77 | Last Updated :
78 | {userData.updatedAt.substr(0, 10)}
79 |
80 |
81 |
82 | Joined :
83 | {userData.createdAt.substr(0, 10)}
84 |
85 |
86 |
87 | );
88 | };
89 | export default UserProfile;
90 |
--------------------------------------------------------------------------------
/src/components/AdminPanel/Order/Orders.js:
--------------------------------------------------------------------------------
1 | import { useState, useContext } from "react";
2 | import { AdminContext } from "../../../context/adminContext";
3 |
4 | // custom Styling
5 | import "./Order.css";
6 |
7 | // MUI Components
8 | import { AppBar, Toolbar } from "@mui/material";
9 | import { Stack, Typography } from "@mui/material";
10 |
11 | // custom Components
12 | import AdminOrderList from "./AdminOrderList";
13 | import AdminFindOrder from "./AdminFindOrder";
14 | import AdminPlaceOrder from "./AdminPlaceOrder";
15 | const BookNavButton = ({ panel, setPanel, btnTxt, value, setAdmin, admin }) => {
16 | const handleClick = () => {
17 | setPanel(value);
18 | setAdmin({
19 | ...admin,
20 | order: {
21 | ...admin.order,
22 | panel: value,
23 | },
24 | });
25 | localStorage.setItem(
26 | "bookshlf_admin",
27 | JSON.stringify({
28 | ...admin,
29 | order: {
30 | ...admin.order,
31 | panel: value,
32 | },
33 | })
34 | );
35 | };
36 | return (
37 |
45 |
46 | {btnTxt}
47 |
48 |
49 | );
50 | };
51 |
52 | const BookNavBar = ({ panel, setPanel, setAdmin, admin }) => {
53 | return (
54 |
55 |
56 |
64 |
72 |
80 |
81 |
82 | );
83 | };
84 |
85 | const AdminBook = () => {
86 | // admin Context
87 | const [admin, setAdmin] = useContext(AdminContext);
88 | const [panel, setPanel] = useState(admin.order?.panel);
89 |
90 | return (
91 |
92 |
98 | {panel === 0 ? (
99 |
100 | ) : panel === 1 ? (
101 |
102 | ) : (
103 |
104 | )}
105 |
106 | );
107 | };
108 |
109 | export default AdminBook;
110 |
--------------------------------------------------------------------------------
/src/components/search/search.css:
--------------------------------------------------------------------------------
1 | .search-container {
2 | padding: 0px 100px;
3 | flex-grow: 1;
4 | width: 100%;
5 | }
6 |
7 | .search-filter {
8 | padding: 5px 0px;
9 | margin-bottom: 8px;
10 | }
11 |
12 | .search-filter .MuiInputLabel-root {
13 | font-family: "DM Sans", sans-serif !important;
14 | }
15 |
16 | .search-filter .MuiInputLabel-root.Mui-focused {
17 | color: #F4A946
18 | }
19 |
20 | .search-filter .MuiOutlinedInput-notchedOutline {
21 | border-color: #F4A946 !important;
22 | }
23 |
24 | .search-filter .MuiFormControl-root {
25 | max-width: 450px;
26 | }
27 |
28 | .search-filter .MuiOutlinedInput-root {
29 | border-radius: 15px;
30 | font-family: "DM Sans", sans-serif !important;
31 | border-color: #F4A946;
32 | }
33 |
34 | .search-book {
35 | width: 100%;
36 | height: 422px;
37 | background: #FDFDFD;
38 | box-shadow: 0px 4px 28px -2px rgba(0, 0, 0, 0.1);
39 | border-radius: 12px;
40 | padding: 8px;
41 | display: flex;
42 | align-items: center;
43 | flex-direction: column;
44 | gap: 8px;
45 | cursor: pointer;
46 | color: rgba(0, 0, 0);
47 | }
48 |
49 | .search-book-img-container {
50 | width: 100%;
51 | }
52 |
53 | .search-book-img {
54 | border-radius: 12px;
55 | width: 100%;
56 | height: 264px;
57 | object-fit: cover;
58 | }
59 |
60 | .search-book-title {
61 | min-height: 48px;
62 | }
63 |
64 | .search-book-cart-button.MuiButton-root {
65 | height: 30px;
66 | border-color: #F4A946;
67 | border-radius: 8px;
68 | color: #F4A946;
69 | }
70 |
71 | .search-book-cart-button.MuiButton-root:hover {
72 | border-color: rgb(244, 169, 70);
73 | background-color: rgb(244, 169, 70, 0.1);
74 | border-radius: 8px;
75 | color: #F4A946;
76 | }
77 |
78 | @media screen and (max-width:1200px) {
79 | .search-book {
80 | width: 100%;
81 | height: 380px;
82 | padding: 8px;
83 | gap: 8px;
84 | }
85 |
86 | .search-book-img {
87 | width: 100%;
88 | height: 220px;
89 | }
90 |
91 | .search-book-title.MuiTypography-root {
92 | font-size: 14px;
93 | min-height: 48px;
94 | }
95 | }
96 |
97 | @media screen and (max-width:900px) {
98 | .search-container {
99 | padding: 0px 24px;
100 | }
101 | }
102 |
103 | @media screen and (max-width:400px) {
104 | .search-container {
105 | padding: 0px;
106 | }
107 |
108 | .search-book {
109 | width: 100%;
110 | height: 100%;
111 | min-height: 320px;
112 | padding: 8px;
113 | }
114 |
115 | .search-book-img {
116 | width: 100%;
117 | height: 220px;
118 | }
119 |
120 | .searchbook-pricetag.MuiTypography-root {
121 | font-size: 14px;
122 | }
123 |
124 | .search-book-title.MuiTypography-root {
125 | font-size: 12px;
126 | min-height: 0;
127 | }
128 |
129 | .search-book-cart-button.MuiButton-root {
130 | height: 24px;
131 | }
132 | }
--------------------------------------------------------------------------------
/src/components/AdminPanel/Book/BookVerification/AdminBookApprove.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useContext } from "react";
2 | import { AdminContext } from "../../../../context/adminContext";
3 |
4 | // API
5 | import axios from "../../../../api/axios";
6 |
7 | // MUI Components
8 | import { Button, CircularProgress } from "@mui/material";
9 | import { Snackbar, Alert } from "@mui/material";
10 |
11 | // icons
12 | import CheckIcon from "@mui/icons-material/CheckCircle";
13 |
14 | const AdminBookApprove = ({ bookId }) => {
15 | // Admin Context
16 | const [admin, setAdmin] = useContext(AdminContext);
17 |
18 | // Loading States
19 | const [approveLoad, setApproveLoad] = useState(false);
20 | const [open, setOpen] = useState(false);
21 | const [approved, setApproved] = useState(false);
22 |
23 | // approving books
24 | const handleApproveBook = () => {
25 | setApproveLoad(true);
26 | axios
27 | .post("/admin-approveBook", {
28 | bookId: bookId,
29 | })
30 | .then((response) => {
31 | setApproveLoad(false);
32 | setOpen(true);
33 | setApproved(true);
34 | setAdmin({
35 | ...admin,
36 | bookVerification: {
37 | ...admin.bookVerification,
38 | data: admin.bookVerification.data.filter(
39 | (book) => book._id !== bookId
40 | ),
41 | },
42 | });
43 | localStorage.setItem(
44 | "bookshlf_admin",
45 | JSON.stringify({
46 | ...admin,
47 | bookVerification: {
48 | ...admin.bookVerification,
49 | data: admin.bookVerification.data.filter(
50 | (book) => book._id !== bookId
51 | ),
52 | },
53 | })
54 | );
55 | })
56 | .catch((error) => {
57 | setApproveLoad(false);
58 | setOpen(true);
59 | setApproved(false);
60 | console.log(error.response.data);
61 | });
62 | };
63 |
64 | const handleClose = (e, reason) => {
65 | if (reason === "clickaway") {
66 | return;
67 | }
68 | setOpen(false);
69 | };
70 |
71 | return (
72 |
73 |
83 | ) : (
84 |
85 | )
86 | }
87 | >
88 | Approve Book
89 |
90 |
91 | setOpen(false)}
93 | severity={approved ? "success" : "error"}
94 | sx={{ width: "100%", fontSize: "12px" }}
95 | variant="filled"
96 | >
97 | {approved ? "Book approved successfully" : "Some error occured"}
98 |
99 |
100 |
101 | );
102 | };
103 |
104 | export default AdminBookApprove;
105 |
--------------------------------------------------------------------------------
/src/context/userContext.js:
--------------------------------------------------------------------------------
1 | import { createContext, useState, useEffect } from "react";
2 | import { useNavigate } from "react-router-dom";
3 |
4 | // API
5 | import axios from "../api/axios";
6 |
7 | // User Context
8 | export const UserContext = createContext();
9 |
10 | export const CurrentUserProvider = (props) => {
11 | // Calling Hooks
12 | const navigate = useNavigate();
13 |
14 | // Fetching from browser local storage
15 | const [user, setUser] = useState(
16 | JSON.parse(localStorage.getItem("bookshlf_user"))
17 | );
18 |
19 | // function to logout if token is expired
20 | const Logout = () => {
21 | setUser(null);
22 | localStorage.removeItem("bookshlf_user");
23 | delete axios.defaults.headers.common["Authorization"];
24 | navigate(0);
25 | };
26 |
27 | // function to get count of wishlist & cart items
28 | const FetchCount = (roles) => {
29 | axios.get("/countWishlistItems").then((wishlist) => {
30 | axios.get("/countCartItems").then((cart) => {
31 | if (roles.includes("seller")) {
32 | axios
33 | .get("/getCurrentBalance")
34 | .then((balance) => {
35 | setUser((prev) => {
36 | return {
37 | ...prev,
38 | roles: roles,
39 | cartitems: cart.data.count,
40 | wishlist: wishlist.data.count,
41 | balance: Math.round(balance.data.walletBalance * 10) / 10,
42 | };
43 | });
44 | })
45 | .catch((error) => {
46 | setUser((prev) => {
47 | return {
48 | ...prev,
49 | roles: roles,
50 | cartitems: cart.data.count,
51 | wishlist: wishlist.data.count,
52 | balance: 0,
53 | };
54 | });
55 | });
56 | } else {
57 | setUser((prev) => {
58 | return {
59 | ...prev,
60 | roles: roles,
61 | cartitems: cart.data.count,
62 | wishlist: wishlist.data.count,
63 | };
64 | });
65 | }
66 | });
67 | });
68 | };
69 |
70 | // function to verify is token is valid
71 | const verifyToken = () => {
72 | axios
73 | .get("/getUserProfile")
74 | .then((response) => {
75 | // console.log(response.data);
76 | setUser((prev) => {
77 | return { ...prev, adminPermissions: response.data.adminPermissions };
78 | });
79 | FetchCount(response.data.roles);
80 | })
81 | .catch((error) => {
82 | Logout();
83 | });
84 | };
85 |
86 | useEffect(() => {
87 | // verifying token
88 | if (user) {
89 | // console.log(user);
90 | verifyToken();
91 | }
92 | }, [user?.authHeader]);
93 |
94 | useEffect(() => {
95 | // console.log("use effect called - local", user);
96 | localStorage.setItem("bookshlf_user", JSON.stringify(user));
97 | }, [user]);
98 |
99 | return (
100 |
101 | {props.children}
102 |
103 | );
104 | };
105 |
--------------------------------------------------------------------------------
/public/images/enviaLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/Checkout/CheckoutAddress.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | // api
4 | import axios from "../../api/axios";
5 |
6 | // Components
7 | import { Stack, Divider } from "@mui/material";
8 | import { Typography, Chip } from "@mui/material";
9 | import { InputLabel, MenuItem, FormControl, Select } from "@mui/material";
10 |
11 | // Micro Components
12 | import AddAddressPopOver from "../MicroComponents/AddAddressPopOver";
13 |
14 | const CurrentAddress = ({ address, addressId }) => {
15 | const [currentAddress, setCurrentAddress] = useState(
16 | address.filter((adr) => adr._id === addressId)
17 | );
18 |
19 | useEffect(() => {
20 | setCurrentAddress(address.filter((adr) => adr._id === addressId));
21 | }, [address, addressId]);
22 | return (
23 |
32 |
33 |
34 |
35 | {currentAddress[0]?.address}
36 | {currentAddress[0]?.city}
37 | {currentAddress[0]?.state}
38 | {currentAddress[0]?.zipCode}
39 | {currentAddress[0]?.phoneNo}
40 |
41 |
42 | );
43 | };
44 |
45 | const CheckoutAddress = ({ address, setAddress, addressId, setAddressId }) => {
46 | // Functionality States
47 | const [openPop, setOpenPop] = useState(false);
48 |
49 | // Getting Addresses
50 | const getAddressList = () => {
51 | axios.get("/getAddressList").then((response) => {
52 | setAddress(
53 | response.data.sort((a, b) => {
54 | return a.updatedAt < b.updatedAt
55 | ? 1
56 | : a.updatedAt > b.updatedAt
57 | ? -1
58 | : 0;
59 | })
60 | );
61 | });
62 | };
63 |
64 | useEffect(() => {
65 | getAddressList();
66 | }, []);
67 |
68 | return (
69 |
78 |
79 |
80 | Address
81 |
95 |
96 |
101 |
102 | );
103 | };
104 |
105 | export default CheckoutAddress;
106 |
--------------------------------------------------------------------------------
/src/app/app.js:
--------------------------------------------------------------------------------
1 | import { React } from "react";
2 | import { Routes, Route, useLocation } from "react-router-dom";
3 | import "./app.css";
4 |
5 | // Components
6 | import Navbar from "../components/navbar/navbar";
7 | import About from "../components/About/About";
8 | import Contact from "../components/Contact/Contact";
9 | import Cart from "../components/Cart/Cart";
10 | import Checkout from "../components/Checkout/Checkout";
11 | import Wishlist from "../components/Cart/Wishlist";
12 | import AddReviews from "../components/Reviews/AddReviews";
13 | import UserProfile from "../components/userpanel/usernav";
14 | import SellerPanel from "../components/SellerPanel/SellerPanel";
15 | import UpdateOrder from "../components/Order/UpdateOrder";
16 | import BookDetails from "../components/BookDetails/BookDetails";
17 | import Admin from "../components/AdminPanel/AdminPanel";
18 | import Blog from "../components/Blog/Blog";
19 | import AdminTrack from "../components/AdminPanel/Order/OrderTracking";
20 | import SellerProfile from "../components/SellerPanel/SellerProfile";
21 | import Wallet from "../components/Wallet/Wallet";
22 | import Terms from "../components/Footer/Terms";
23 | import Notify from "../assets/components/notify";
24 | import NotFoundPage from "../components/home/NotFoundPage";
25 |
26 | // external courier integrations
27 | import ICarry from "../components/AdminPanel/CourierIntegrations/iCarry";
28 | import Nimbuspost from "../components/AdminPanel/CourierIntegrations/Nimbuspost";
29 | import EnviaShipping from "../components/AdminPanel/CourierIntegrations/enviaShipping";
30 |
31 | import Router from "../route/router";
32 |
33 | const App = () => {
34 | const location = useLocation();
35 | return (
36 |
37 | {process.env.REACT_APP_NODE_ENV === "development" ? : null}
38 | {!location.pathname.startsWith("/admin") && }
39 |
40 | } />
41 | } />
42 | } />
43 | } />
44 | } />
45 | } />
46 | } />
47 | } />
48 | } />
49 | } />
50 | } />
51 | } />
52 | } />
53 | } />
54 | } />
55 | } />
56 | } />
57 | }
60 | />
61 | }
64 | />
65 | } status={404} />
66 |
67 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default App;
74 |
--------------------------------------------------------------------------------
/src/components/home/Categories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import "./Categories.css";
4 | // Components
5 | import { Stack, Avatar, Typography } from "@mui/material";
6 | const CategoryItem = (props) => {
7 | return (
8 |
9 |
23 |
24 | {props.label}
25 |
26 |
48 | Shop Now
49 |
50 |
51 | );
52 | };
53 | const Categories = () => {
54 | return (
55 |
56 |
57 |
62 | Featured Categories
63 |
64 |
65 |
66 |
72 |
77 |
82 |
87 |
88 |
94 |
99 |
104 |
109 |
110 |
111 |
112 | );
113 | };
114 | export default Categories;
115 |
--------------------------------------------------------------------------------
/src/components/auth/signup/verify.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useEffect } from "react";
2 | import { useNavigate, useParams } from "react-router-dom";
3 | import * as EmailValidator from "email-validator";
4 |
5 | // Components
6 | import { Stack, Typography, Alert } from "@mui/material";
7 |
8 | import Container from "../../../assets/components/container";
9 | import Textfield from "../../../assets/components/input/textfield";
10 | import LoadingButton from "../../../assets/components/buttons/loadingbutton";
11 | import Link from "../../../assets/components/links/link";
12 | import OtpField from "../../../assets/components/input/otpfield";
13 |
14 | // services
15 | import { handleVerify } from "../../../service/auth/signup";
16 |
17 | const Verify = () => {
18 | const navigate = useNavigate();
19 | const params = useParams();
20 | const [Otp, setOtp] = useState("");
21 | const [loading, setLoading] = useState(false);
22 | const [alert, setAlert] = useState({
23 | show: false,
24 | type: "success",
25 | msg: "OTP Sent",
26 | });
27 |
28 | const hideAlert = () => {
29 | setTimeout(() => {
30 | setAlert({ show: false, type: "success", msg: "OTP Sent" });
31 | }, 60000);
32 | };
33 |
34 | useEffect(() => {
35 | if (
36 | params.email === undefined ||
37 | params.email === "" ||
38 | !EmailValidator.validate(params.email)
39 | )
40 | navigate("/auth/signup");
41 | }, []);
42 |
43 | const handleVerifyEmail = async () => {
44 | setLoading(true);
45 | const response = await handleVerify({ email: params.email, otp: Otp });
46 | if (response.success) {
47 | setAlert({
48 | show: true,
49 | type: "success",
50 | msg: "Email Verified Successfully!",
51 | });
52 | setTimeout(() => {
53 | navigate(`/auth/login/${params.email}`);
54 | }, 3000);
55 | } else handleVerifyEmailError(response.data.errors);
56 | setLoading(false);
57 | };
58 |
59 | const handleVerifyEmailError = (errors) => {
60 | setAlert({ show: true, type: "error", msg: errors[0].error });
61 | hideAlert();
62 | };
63 |
64 | return (
65 |
66 |
67 | Account Verification
68 |
69 |
70 |
71 |
79 |
80 | Didn't Recieve OTP ? Check You Mail Spam!
81 |
82 |
83 |
89 | Verify
90 |
91 | {alert.show && {alert.msg}}
92 |
93 |
98 |
99 |
100 |
101 |
102 |
103 | );
104 | };
105 | export default Verify;
106 |
--------------------------------------------------------------------------------
/src/components/navbar/navbarsearch.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useCallback } from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import { debounce } from "../../api/debounce";
4 |
5 | // Components
6 | import { InputBase, MenuItem, ClickAwayListener } from "@mui/material";
7 | import { LinearProgress, Stack } from "@mui/material";
8 |
9 | // Icons
10 | import SearchIcon from "@mui/icons-material/Search";
11 |
12 | // Service
13 | import { BookSearchTitle } from "../../service/search/booksearch";
14 | import { trimText } from "../../assets/utils/commons";
15 |
16 | const NavProgress = () => {
17 | return (
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | const NavIcon = ({ navigate, search }) => {
25 | return (
26 | navigate(`/search/${search}`)}
29 | >
30 |
31 |
32 | );
33 | };
34 |
35 | const Searchbar = () => {
36 | const navigate = useNavigate();
37 |
38 | // functionality states
39 | const [searchFieldChanges, setsearchFieldChanges] = useState(false);
40 | const [openTitleMenu, setOpenTitleMenu] = useState(false);
41 |
42 | // Data States
43 | const [Search, setSearch] = useState("");
44 | const [resultTitles, setresultTitles] = useState([]);
45 |
46 | // Search on Enter
47 | const handleKeyPress = (event) => {
48 | if (event.key === "Enter") {
49 | event.preventDefault();
50 | setOpenTitleMenu(false);
51 | navigate(`/search/${Search === "" ? "tag:ALL" : Search}`);
52 | }
53 | };
54 |
55 | // book title search on input
56 | const handelBookTitleSearch = async (title) => {
57 | const response = await BookSearchTitle(title);
58 | if (response.success) {
59 | setresultTitles(response.data);
60 | setsearchFieldChanges(false);
61 | }
62 | };
63 |
64 | const DebounceSearch = useCallback(debounce(handelBookTitleSearch), []);
65 |
66 | // Searching Title
67 | const handelTitleAdd = (title) => {
68 | setOpenTitleMenu(false);
69 | setSearch(title);
70 | navigate(`/search/${title}`);
71 | };
72 |
73 | // Handle Change
74 | const handleChange = (e) => {
75 | setsearchFieldChanges(true);
76 | setSearch(e.target.value);
77 | setOpenTitleMenu(true);
78 | DebounceSearch(e.target.value);
79 | };
80 |
81 | return (
82 |
83 | {searchFieldChanges && }
84 |
91 |
92 | setOpenTitleMenu(false)}>
93 | {openTitleMenu ? (
94 |
95 | {resultTitles.map((book, idx) => (
96 |
105 | ))}
106 |
107 | ) : (
108 | <>>
109 | )}
110 |
111 |
112 | );
113 | };
114 | export default Searchbar;
115 |
--------------------------------------------------------------------------------
/src/components/Checkout/CheckoutOrderPlace.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import { Stack, Divider, Chip, Button, CircularProgress } from "@mui/material";
4 | import { Alert, Typography, Checkbox, Collapse } from "@mui/material";
5 | import ArrowBackIcon from "@mui/icons-material/ArrowBack";
6 | import LocalShippingIcon from "@mui/icons-material/LocalShipping";
7 | import CheckCircleIcon from "@mui/icons-material/CheckCircle";
8 |
9 | const CheckoutOrderPlace = ({ orderLoad, orderPlaced, handlePlaceOrder }) => {
10 | const navigate = useNavigate();
11 | const [checked, setChecked] = useState(false);
12 |
13 | const handleChange = () => {
14 | setChecked((prev) => !prev);
15 | };
16 |
17 | const handleClick = () => {
18 | handlePlaceOrder();
19 | };
20 | return (
21 | }
24 | sx={{ width: "100%", maxWidth: 600 }}
25 | >
26 |
30 |
31 | {orderPlaced
32 | ? "Order Placed Successfully!"
33 | : "Your Order Ready for Final Confirmation"}
34 |
35 |
36 |
37 | {!orderPlaced && (
38 |
39 |
46 | {!checked && (
47 |
48 |
49 | Please Confirm Here
50 |
51 | )}
52 |
58 |
59 | )}
60 | {!orderPlaced && (
61 |
62 |
63 |
64 | Click on PLACE ORDER to place your order
65 |
66 |
72 | ) : (
73 |
74 | )
75 | }
76 | color="success"
77 | onClick={handleClick}
78 | >
79 | {orderLoad ? "Placing Order..." : "Place Order"}
80 |
81 |
82 |
83 | )}
84 |
85 |
86 |
87 |
95 |
96 |
97 |
98 | );
99 | };
100 |
101 | export default CheckoutOrderPlace;
102 |
--------------------------------------------------------------------------------
/src/components/BookDetails/Booksnaps.js:
--------------------------------------------------------------------------------
1 | import { React, useState } from "react";
2 | import ReactImageMagnify from "@blacklab/react-image-magnify";
3 |
4 | // Components
5 | import Stack from "@mui/material/Stack";
6 | import Avatar from "@mui/material/Avatar";
7 | import YouTubeIcon from "@mui/icons-material/YouTube";
8 |
9 | const Booksnaps = (props) => {
10 | // data States
11 | const [snap, setSnap] = useState(0);
12 | const [showvideo, setShowvideo] = useState(false);
13 |
14 | // changing Snaps
15 | const handelClick = (snapNo) => {
16 | setSnap(snapNo);
17 | setShowvideo(false);
18 | };
19 |
20 | return (
21 |
27 |
37 | {props.snaps
38 | ? props.snaps.length
39 | ? props.snaps.map((snap, index) => (
40 | handelClick(index)}
45 | className="book-snapshots"
46 | variant="rounded"
47 | />
48 | ))
49 | : null
50 | : null}
51 | {props.video.length ? (
52 | setShowvideo((prev) => !prev)}
57 | >
58 |
59 |
60 | ) : (
61 | <>>
62 | )}
63 |
64 |
65 | {!showvideo ? (
66 |
91 | ) : null}
92 | {showvideo ? (
93 |
102 | ) : null}
103 |
104 |
105 | );
106 | };
107 | export default Booksnaps;
108 |
--------------------------------------------------------------------------------
/src/assets/components/buttons/cartbutton.js:
--------------------------------------------------------------------------------
1 | import { useState, useContext } from "react";
2 | import { UserContext } from "../../../context/userContext";
3 |
4 | import {
5 | Tooltip,
6 | Button,
7 | Snackbar,
8 | Alert,
9 | CircularProgress,
10 | } from "@mui/material";
11 |
12 | import AddCartIcon from "@mui/icons-material/AddShoppingCart";
13 | import FilledCartIcon from "@mui/icons-material/ShoppingCart";
14 |
15 | import { addCart, deleteCart } from "../../../api/endpoints";
16 | import { DeleteRequest } from "../../../api/requests/deleteAPI";
17 | import { PostRequest } from "../../../api/requests/postAPI";
18 |
19 | const CartButton = ({ book }) => {
20 | const [user, setUser] = useContext(UserContext);
21 | const [loading, setLoading] = useState(false);
22 | const [cart, setCart] = useState(book.cart);
23 | const [alert, setAlert] = useState({
24 | type: "success",
25 | show: false,
26 | msg: "",
27 | });
28 |
29 | const isLoggedIn = () => {
30 | return Boolean(user);
31 | };
32 |
33 | const addToCart = async () => {
34 | const response = await PostRequest(addCart, { bookId: book._id });
35 | if (response.success) {
36 | setUser({ ...user, cartitems: user.cartitems + 1 });
37 | showAlert("success", "Book added to cart");
38 | book.cart = true;
39 | setCart(true);
40 | } else showAlert("error", response.data.error);
41 | setLoading(false);
42 | };
43 |
44 | const deleteFromCart = async () => {
45 | const response = await DeleteRequest(deleteCart, {
46 | bookId: book._id,
47 | });
48 | if (response.success) {
49 | setUser({ ...user, cartitems: user.cartitems - 1 });
50 | showAlert("success", "Book removed from cart");
51 | book.cart = false;
52 | setCart(false);
53 | } else showAlert("error", response.data.error);
54 | setLoading(false);
55 | };
56 |
57 | const showAlert = (type, msg) => {
58 | setAlert({
59 | show: true,
60 | type: type,
61 | msg: msg,
62 | });
63 | setTimeout(() => {
64 | setAlert((prev) => {
65 | return { ...prev, show: false };
66 | });
67 | }, 5000);
68 | };
69 |
70 | const handleClose = (event, reason) => {
71 | if (reason === "clickaway") {
72 | return;
73 | }
74 | setAlert((prev) => {
75 | return { ...prev, show: false };
76 | });
77 | };
78 |
79 | const handleCart = async (e) => {
80 | setLoading(true);
81 | e.stopPropagation();
82 | e.preventDefault();
83 | if (isLoggedIn()) {
84 | if (!book.cart) addToCart();
85 | else deleteFromCart();
86 | } else {
87 | showAlert("error", "please login to add item to cart");
88 | setLoading(false);
89 | }
90 | };
91 |
92 | return (
93 | <>
94 |
95 |
109 |
110 |
111 |
116 | {alert.msg}
117 |
118 |
119 | >
120 | );
121 | };
122 |
123 | export default CartButton;
124 |
--------------------------------------------------------------------------------
/src/components/home/home.css:
--------------------------------------------------------------------------------
1 | .slider {
2 | height: calc(100vh - 120px);
3 | background-color: #28282865;
4 | position: relative;
5 | }
6 | .slider__imageContainer {
7 | width: 100%;
8 | height: 100%;
9 | overflow-x: hidden;
10 | }
11 | .slider__image {
12 | background-size: cover;
13 | background-position: center;
14 | width: 100%;
15 | height: 100%;
16 | }
17 |
18 | .slider .MuiSvgIcon-root {
19 | color: white !important;
20 | height: 15px;
21 | width: 15px;
22 | }
23 | .slider .MuiIconButton-root {
24 | padding: 5px;
25 | }
26 |
27 | .slider__bulletContainer {
28 | width: max-content;
29 | position: absolute;
30 | bottom: 0;
31 | left: 0;
32 | right: 0;
33 | margin: auto;
34 | }
35 | .slider__bulletContainer:hover {
36 | background-color: rgba(0, 0, 0, 0.4);
37 | }
38 | .slider__title {
39 | position: absolute;
40 | top: 10px;
41 | text-align: center;
42 | width: 100%;
43 | font-family: "Staatliches";
44 | font-size: 6em;
45 | color: rgba(255, 255, 255, 0.96);
46 | }
47 | .slider__body {
48 | text-align: center;
49 | width: 100%;
50 | font-family: "Staatliches";
51 | font-size: 0.33em;
52 | letter-spacing: 1px;
53 | color: rgba(255, 255, 255, 0.96);
54 | }
55 | .slider__btn {
56 | position: absolute;
57 | top: 50%;
58 | left: 50%;
59 | transform: translate(-50%, -50%);
60 | color: rgba(255, 255, 255, 0.96);
61 | }
62 | .slider__btn a {
63 | width: 250px;
64 | font-family: "Staatliches" !important;
65 | font-size: 2em;
66 | letter-spacing: 1px;
67 | background-color: orangered;
68 | }
69 |
70 | .slider__rightNavigation,
71 | .slider__leftNavigation {
72 | position: absolute;
73 | top: 50%;
74 | transform: translateY(-50%);
75 | background-color: rgba(0, 0, 0, 0.3);
76 | border-radius: 50%;
77 | }
78 | .slider__leftNavigation:hover,
79 | .slider__rightNavigation:hover {
80 | background-color: rgba(0, 0, 0, 0.4);
81 | cursor: pointer;
82 | }
83 | .slider__leftNavigation {
84 | left: 10px;
85 | }
86 | .slider__rightNavigation {
87 | right: 10px;
88 | }
89 |
90 | @media screen and (max-width: 600px) {
91 | .slider {
92 | height: 40vh;
93 | }
94 | .slider__title {
95 | top: 10px;
96 | font-size: 2em;
97 | }
98 | .slider__body {
99 | font-size: 0.5em;
100 | }
101 | .slider__btn {
102 | bottom: 30px;
103 | }
104 | }
105 |
106 | .error-404 {
107 | background-color: #313942;
108 | font-family: "Staatliches", sans-serif;
109 | letter-spacing: 2px;
110 | }
111 |
112 | .error-404 {
113 | align-items: center;
114 | display: flex;
115 | flex-direction: column;
116 | height: 100vh;
117 | justify-content: center;
118 | text-align: center;
119 | }
120 |
121 | .error-404 h1 {
122 | color: #e7ebf2;
123 | font-size: 12.5rem;
124 | letter-spacing: 0.1em;
125 | margin: 0.025em 0;
126 | text-shadow: 0.05em 0.05em 0 rgba(0, 0, 0, 0.25);
127 | white-space: nowrap;
128 | }
129 | @media (max-width: 30rem) {
130 | .error-404 h1 {
131 | font-size: 8.5rem;
132 | }
133 | .error-404 img {
134 | height: 150px;
135 | }
136 | }
137 | .error-404 h1 > span {
138 | -webkit-animation: spooky 2s alternate infinite linear;
139 | animation: spooky 2s alternate infinite linear;
140 | color: #528cce;
141 | display: inline-block;
142 | }
143 |
144 | .error-404 h2 {
145 | color: #e7ebf2;
146 | margin-bottom: 0.4em;
147 | }
148 |
149 | .error-404 p {
150 | color: #ccc;
151 | margin-top: 0;
152 | }
153 |
154 | @-webkit-keyframes spooky {
155 | from {
156 | transform: translatey(0.15em) scaley(0.95);
157 | }
158 | to {
159 | transform: translatey(-0.15em);
160 | }
161 | }
162 |
163 | @keyframes spooky {
164 | from {
165 | transform: translatey(0.15em) scaley(0.95);
166 | }
167 | to {
168 | transform: translatey(-0.15em);
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/components/AddressBook/AddressList.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useEffect } from "react";
2 | import axios from "../../api/axios";
3 |
4 | // Mui Components
5 | import { IconButton, Stack, Typography } from "@mui/material";
6 | import { CircularProgress } from "@mui/material";
7 |
8 | // Mui Icons
9 | import DeleteIcon from "@mui/icons-material/Delete";
10 | import HomeIcon from "@mui/icons-material/HomeRounded";
11 | import OfficeIcon from "@mui/icons-material/ApartmentRounded";
12 | import TempIcon from "@mui/icons-material/NotListedLocationRounded";
13 |
14 | // Address List Components
15 | import AddressDetails from "./AddressDetails";
16 |
17 | const AddressList = (props) => {
18 | const [adrList, setAdrList] = useState(props.address);
19 |
20 | useEffect(() => {
21 | setAdrList(props.address);
22 | }, [props.address]);
23 |
24 | const Address = (props) => {
25 | return (
26 |
40 |
45 | {props.value.label === "Home Address" ? (
46 |
47 | ) : props.value.label === "Office Address" ? (
48 |
49 | ) : (
50 |
51 | )}
52 |
53 |
54 |
55 | {props.value.label}
56 |
57 |
58 | {props.value.address.length > 50
59 | ? props.value.address.substr(0, 50) + "..."
60 | : props.value.address}
61 |
62 |
63 |
64 |
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | // Component for deleting Addresses
80 | const DeleteAddress = (props) => {
81 | const [deleteLoad, setdeleteLoad] = useState(false);
82 | const addressId = props.addressId;
83 |
84 | const handelDeleteAddress = () => {
85 | setdeleteLoad(true);
86 | axios
87 | .delete("/deleteAddress", {
88 | data: { addressId: addressId },
89 | })
90 | .then((response) => {
91 | setAdrList(adrList.filter((address) => address._id !== addressId));
92 | setdeleteLoad(false);
93 | })
94 | .catch((error) => {
95 | setdeleteLoad(false);
96 | });
97 | };
98 |
99 | return (
100 |
101 | {deleteLoad ? (
102 |
103 | ) : (
104 |
105 | )}
106 |
107 | );
108 | };
109 |
110 | return (
111 |
112 | {adrList?.length &&
113 | adrList.map((address) => )}
114 |
115 | );
116 | };
117 |
118 | export default AddressList;
119 |
--------------------------------------------------------------------------------
/src/assets/components/buttons/wishlistbutton.js:
--------------------------------------------------------------------------------
1 | import { useState, useContext } from "react";
2 | import { UserContext } from "../../../context/userContext";
3 |
4 | import {
5 | Tooltip,
6 | IconButton,
7 | Snackbar,
8 | Alert,
9 | CircularProgress,
10 | } from "@mui/material";
11 |
12 | // Icons
13 | import FilledWishlistIcon from "@mui/icons-material/Favorite";
14 | import WishlistIcon from "@mui/icons-material/FavoriteBorder";
15 |
16 | import { addWishlist, deleteWishlist } from "../../../api/endpoints";
17 | import { DeleteRequest } from "../../../api/requests/deleteAPI";
18 | import { PostRequest } from "../../../api/requests/postAPI";
19 |
20 | const WishlistButton = ({ book, size, fontSize }) => {
21 | const [user, setUser] = useContext(UserContext);
22 | const [loading, setLoading] = useState(false);
23 | const [wishlist, setWishlist] = useState(book.wishlist);
24 | const [alert, setAlert] = useState({
25 | type: "success",
26 | show: false,
27 | msg: "",
28 | });
29 |
30 | const isLoggedIn = () => {
31 | return Boolean(user);
32 | };
33 |
34 | const addToWishlist = async () => {
35 | const response = await PostRequest(addWishlist, { bookId: book._id });
36 | if (response.success) {
37 | setUser({ ...user, wishlist: user.wishlist + 1 });
38 | showAlert("success", "Book added to wishlist");
39 | book.wishlist = true;
40 | setWishlist(true);
41 | } else showAlert("error", response.data.error);
42 | setLoading(false);
43 | };
44 |
45 | const deleteFromWishlist = async () => {
46 | const response = await DeleteRequest(deleteWishlist, { bookId: book._id });
47 | if (response.success) {
48 | setUser({ ...user, wishlist: user.wishlist - 1 });
49 | showAlert("success", "Book removed from wishlist");
50 | book.wishlist = false;
51 | setWishlist(false);
52 | } else showAlert("error", response.data.error);
53 | setLoading(false);
54 | };
55 |
56 | const showAlert = (type, msg) => {
57 | setAlert({
58 | show: true,
59 | type: type,
60 | msg: msg,
61 | });
62 | setTimeout(() => {
63 | setAlert((prev) => {
64 | return { ...prev, show: false };
65 | });
66 | }, 5000);
67 | };
68 |
69 | const handleClose = (event, reason) => {
70 | if (reason === "clickaway") {
71 | return;
72 | }
73 | setAlert((prev) => {
74 | return { ...prev, show: false };
75 | });
76 | };
77 |
78 | const handelWishlist = async (e) => {
79 | e.stopPropagation();
80 | e.preventDefault();
81 | setLoading(true);
82 | if (isLoggedIn()) {
83 | if (!book.wishlist) addToWishlist();
84 | else deleteFromWishlist();
85 | } else {
86 | showAlert("error", "please login to add item to wishlist");
87 | setLoading(false);
88 | }
89 | };
90 |
91 | return (
92 | <>
93 |
94 |
95 | {loading ? (
96 |
97 | ) : wishlist ? (
98 |
103 | ) : (
104 |
105 | )}
106 |
107 |
108 |
109 |
114 | {alert.msg}
115 |
116 |
117 | >
118 | );
119 | };
120 |
121 | export default WishlistButton;
122 |
--------------------------------------------------------------------------------
/src/components/Checkout/CheckoutStepper.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import { styled } from "@mui/material/styles";
3 | import { Typography } from "@mui/material";
4 |
5 | import { Stepper, Step, StepLabel, StepConnector } from "@mui/material";
6 | import { stepConnectorClasses } from "@mui/material/StepConnector";
7 |
8 | import PaymentIcon from "@mui/icons-material/Payment";
9 | import ReviewIcon from "@mui/icons-material/Grading";
10 | import ShippingIcon from "@mui/icons-material/LocalShipping";
11 | import CheckIcon from "@mui/icons-material/CheckCircle";
12 |
13 | const CheckoutStepper = ({ panel }) => {
14 | // Custom Stepper
15 | const ColorlibConnector = styled(StepConnector)(({ theme }) => ({
16 | [`&.${stepConnectorClasses.alternativeLabel}`]: {
17 | top: 17,
18 | },
19 | [`&.${stepConnectorClasses.active}`]: {
20 | [`& .${stepConnectorClasses.line}`]: {
21 | backgroundImage:
22 | "linear-gradient( 95deg,rgb(242,113,33) 0%,rgb(233,64,87) 50%,rgb(138,35,135) 100%)",
23 | },
24 | },
25 | [`&.${stepConnectorClasses.completed}`]: {
26 | [`& .${stepConnectorClasses.line}`]: {
27 | backgroundImage:
28 | "linear-gradient( 95deg,rgb(242,113,33) 0%,rgb(233,64,87) 50%,rgb(138,35,135) 100%)",
29 | },
30 | },
31 | [`& .${stepConnectorClasses.line}`]: {
32 | height: 3,
33 | border: 0,
34 | backgroundColor:
35 | theme.palette.mode === "dark" ? theme.palette.grey[800] : "#eaeaf0",
36 | borderRadius: 1,
37 | },
38 | }));
39 |
40 | const ColorlibStepIconRoot = styled("div")(({ theme, ownerState }) => ({
41 | backgroundColor:
42 | theme.palette.mode === "dark" ? theme.palette.grey[700] : "#ccc",
43 | zIndex: 1,
44 | color: "#fff",
45 | width: 35,
46 | height: 35,
47 | display: "flex",
48 | borderRadius: "50%",
49 | justifyContent: "center",
50 | alignItems: "center",
51 | ...(ownerState.active && {
52 | backgroundImage:
53 | "linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)",
54 | boxShadow: "0 4px 10px 0 rgba(0,0,0,.25)",
55 | }),
56 | ...(ownerState.completed && {
57 | backgroundImage:
58 | "linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)",
59 | }),
60 | }));
61 |
62 | const ColorlibStepIcon = (props) => {
63 | const { active, completed, className } = props;
64 |
65 | const icons = {
66 | 1: ,
67 | 2: ,
68 | 3: ,
69 | 4: ,
70 | };
71 |
72 | return (
73 |
77 | {icons[String(props.icon)]}
78 |
79 | );
80 | };
81 |
82 | ColorlibStepIcon.propTypes = {
83 | active: PropTypes.bool,
84 | className: PropTypes.string,
85 | completed: PropTypes.bool,
86 | icon: PropTypes.node,
87 | };
88 |
89 | const PanelTitle = [
90 | "Shipping Address",
91 | "Payment Details",
92 | "Review Order",
93 | "Place Order",
94 | ];
95 |
96 | return (
97 | }
102 | >
103 | {PanelTitle.map((label) => (
104 |
105 |
106 | {label}
107 |
108 |
109 | ))}
110 |
111 | );
112 | };
113 |
114 | export default CheckoutStepper;
115 |
--------------------------------------------------------------------------------
/src/components/search/searchfilter.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { useNavigate, useParams } from "react-router-dom";
3 | import { Stack, Typography, Divider } from "@mui/material";
4 | import { FormControl, InputLabel, Select, MenuItem } from "@mui/material";
5 |
6 | // Custom Components
7 | import Pagination from "./pagination";
8 |
9 | const FILTERS = [
10 | "sortByPrice=asc",
11 | "sortByPrice=desc",
12 | "sortByDate=desc",
13 | "sortByDate=asc",
14 | ];
15 |
16 | const isPresent = (arr, filter) => {
17 | return arr.includes(filter);
18 | };
19 |
20 | const deleteParam = (filterArray, param) => {
21 | return filterArray.filter((p) => p !== param);
22 | };
23 |
24 | const handleFilters = (filters) => {
25 | if (filters === undefined || filters === "") return ["default"];
26 | return filters.split("&");
27 | };
28 |
29 | const SearchFilter = ({ page, totalPages }) => {
30 | const navigate = useNavigate();
31 | const { query, filters } = useParams();
32 | const [filter, setFilter] = useState(handleFilters(filters));
33 |
34 | const resolveParam = async (param) => {
35 | if (
36 | (isPresent(param, "default") && !isPresent(filter, "default")) ||
37 | param.length === 0
38 | ) {
39 | param = ["default"];
40 | } else if (isPresent(param, "default") && isPresent(filter, "default")) {
41 | param = deleteParam(param, "default");
42 | }
43 |
44 | if (isPresent(param, FILTERS[0]) && isPresent(param, FILTERS[1])) {
45 | // when selecting price filter
46 | if (isPresent(filter, FILTERS[1])) param = deleteParam(param, FILTERS[1]);
47 | else param = deleteParam(param, FILTERS[0]);
48 | }
49 |
50 | if (isPresent(param, FILTERS[2]) && isPresent(param, FILTERS[3])) {
51 | // when selecting date filter
52 | if (isPresent(filter, FILTERS[2])) param = deleteParam(param, FILTERS[2]);
53 | else param = deleteParam(param, FILTERS[3]);
54 | }
55 |
56 | return param;
57 | };
58 |
59 | const handleChange = async (e) => {
60 | let param = e.target.value;
61 | const finalParam = await resolveParam(param);
62 | setFilter(finalParam);
63 | navigate(`/search/${query}/${finalParam.join("&")}`);
64 | };
65 |
66 | useEffect(() => {
67 | if (filters === undefined) navigate(`/search/${query}/default`);
68 | setFilter(handleFilters(filters));
69 | }, [query, filters]);
70 |
71 | return (
72 |
73 |
77 |
78 | Filter
79 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | );
110 | };
111 |
112 | export default SearchFilter;
113 |
--------------------------------------------------------------------------------
/src/assets/components/base.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: 15px 24px;
3 | min-height: calc(100vh - 78px);
4 | width: 100%;
5 | background-color: #FDFDFD;
6 | align-items: center;
7 | justify-content: center;
8 | }
9 |
10 | .MuiTypography-root {
11 | font-family: 'DM Sans', sans-serif !important;
12 | }
13 |
14 | .MuiMenuItem-root {
15 | font-family: "DM Sans", sans-serif !important;
16 | }
17 |
18 | .bookshlf-input .MuiOutlinedInput-root {
19 | font-family: 'DM Sans', sans-serif;
20 | border-radius: 16px;
21 | }
22 |
23 | .bookshlf-input .MuiOutlinedInput-notchedOutline {
24 | border: 1px solid #8f8f8f;
25 | }
26 |
27 | .bookshlf-input .Mui-focused .MuiOutlinedInput-notchedOutline {
28 | border: 1px solid #F4A946 !important;
29 | }
30 |
31 | .bookshlf-input .Mui-focused.MuiInputLabel-root {
32 | color: #F4A946 !important;
33 | }
34 |
35 | .bookshlf-btn.MuiButton-root {
36 | font-family: 'DM Sans', sans-serif;
37 | color: #FFFFFF;
38 | background: #F4A946;
39 | border-radius: 57px;
40 | width: 160px;
41 | height: 48px;
42 | text-transform: capitalize;
43 | }
44 |
45 | .bookshlf-btn.MuiButton-root:hover {
46 | font-family: 'DM Sans', sans-serif;
47 | color: #FFFFFF;
48 | background: rgba(244, 169, 70, 0.85);
49 | border-radius: 57px;
50 | width: 160px;
51 | height: 48px;
52 | }
53 |
54 | .bookshlf-btn.MuiButton-root.Mui-disabled {
55 | background: rgba(0, 0, 0, 0.2);
56 | color: #FFFFFF;
57 | }
58 |
59 | .bookshlf-otp-container {
60 | position: relative;
61 | padding: 13px 15px;
62 | border: 1px solid rgba(0, 0, 0, 0.2);
63 | border-radius: 16px;
64 | width: 100%;
65 | justify-content: space-between;
66 | }
67 |
68 | .bookshlf-otp-label {
69 | position: absolute;
70 | font-size: 12px !important;
71 | top: -20px;
72 | }
73 |
74 | .bookshlf-otp-container>div {
75 | align-items: center;
76 | gap: 8px;
77 | }
78 |
79 | input.bookshlf-otp-input {
80 | height: 30px !important;
81 | width: 30px !important;
82 | border-radius: 8px;
83 | outline: none;
84 | border: 1px solid rgba(0, 0, 0, 0.2);
85 | }
86 |
87 | input.bookshlf-otp-input:focus {
88 | border: 2px solid #F4A946;
89 | }
90 |
91 | .otp-send-btn.MuiButton-root {
92 | color: #FFFFFF;
93 | font-family: 'DM Sans', sans-serif;
94 | background-color: #F4A946;
95 | padding: 5px 10px;
96 | border-radius: 16px;
97 | }
98 |
99 | .otp-send-btn.MuiButton-root:hover {
100 | background-color: rgba(244, 169, 70, 0.8);
101 | }
102 |
103 | .otp-send-btn.MuiButton-root.Mui-disabled {
104 | background: rgba(0, 0, 0, 0.2);
105 | color: #FFFFFF;
106 | }
107 |
108 | .otp-send-alert.MuiAlert-root {
109 | position: absolute;
110 | right: 10px;
111 | bottom: -30px;
112 | font-family: 'DM Sans', sans-serif;
113 | font-size: 10px;
114 | padding: 5px 10px;
115 | border-radius: 8px;
116 | }
117 |
118 | .otp-send-alert.MuiAlert-root .MuiAlert-icon {
119 | font-size: 12px;
120 | padding: 0;
121 | }
122 |
123 | .otp-send-alert.MuiAlert-root .MuiAlert-message {
124 | padding: 0;
125 | }
126 |
127 | .search-book-btn.MuiButton-root {
128 | height: 30px;
129 | background: #F4A946;
130 | border-radius: 8px;
131 | color: #000000;
132 | }
133 |
134 | .search-book-btn.MuiButton-root:hover {
135 | background: rgba(244, 169, 70, 0.7);
136 | }
137 |
138 | @media screen and (max-width:600px) {
139 | .container {
140 | padding: 10px 8px;
141 | }
142 |
143 | .bookshlf-otp-container.MuiStack-root {
144 | flex-direction: column;
145 | gap: 8px;
146 | justify-content: center;
147 | align-items: center;
148 | }
149 | }
150 |
151 | @media screen and (max-width:400px) {
152 | .search-book-btn.MuiButton-root {
153 | height: 24px;
154 |
155 | }
156 |
157 | .search-book-cart-button.MuiButton-root {
158 | height: 24px;
159 | }
160 |
161 | .search-book-cart-button.MuiButton-root svg {
162 | height: 16px;
163 | }
164 | }
--------------------------------------------------------------------------------
/src/components/navbar/navbarmenu.js:
--------------------------------------------------------------------------------
1 | import { React, useState, useContext } from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import { UserContext } from "../../context/userContext";
4 | import { AdminContext } from "../../context/adminContext";
5 |
6 | // Components
7 | import { Tooltip, Divider } from "@mui/material";
8 | import { Stack, IconButton, Menu, MenuItem } from "@mui/material";
9 |
10 | // Icons
11 | import UserIcon from "@mui/icons-material/AccountCircleOutlined";
12 | import AccountIcon from "@mui/icons-material/AccountCircleTwoTone";
13 | import OrderIcon from "@mui/icons-material/LocalShippingTwoTone";
14 | import AdminIcon from "@mui/icons-material/AdminPanelSettingsTwoTone";
15 | import BookIcon from "@mui/icons-material/MenuBookTwoTone";
16 | import SellBookIcon from "@mui/icons-material/ShoppingBag";
17 | import LogoutIcon from "@mui/icons-material/Logout";
18 | import { userRoleCheck } from "../../assets/utils/commons";
19 | import { Logout } from "../../service/auth/logout";
20 |
21 | const NavbarMenu = () => {
22 | const navigate = useNavigate();
23 |
24 | const [user, setUser] = useContext(UserContext);
25 | const [, setAdmin] = useContext(AdminContext);
26 |
27 | const [anchorEl, setAnchorEl] = useState(null);
28 |
29 | const handleClick = (event) => {
30 | setAnchorEl(event.currentTarget);
31 | };
32 |
33 | const handleClose = () => {
34 | setAnchorEl(null);
35 | };
36 |
37 | const handelNavigate = (path) => {
38 | setAnchorEl(null);
39 | navigate(path);
40 | };
41 |
42 | const handelLogout = async () => {
43 | const response = await Logout();
44 | if (response.success) {
45 | setUser(null);
46 | setAdmin(null);
47 | }
48 | };
49 |
50 | // Custom Menu Item
51 | const MenuStack = ({ Icon, label, path }) => {
52 | return (
53 |
65 | );
66 | };
67 |
68 | return (
69 |
70 |
71 |
72 |
73 |
74 |
75 |
125 |
126 | );
127 | };
128 | export default NavbarMenu;
129 |
--------------------------------------------------------------------------------
/src/components/home/Benefits.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | // Mui Components
4 | import { Stack, Typography, Avatar } from "@mui/material";
5 |
6 | const Styles = {
7 | Container: {
8 | padding: "36px 10px",
9 | paddingTop: 0,
10 | backgroundColor: "whitsmoke",
11 | },
12 | Heading: {
13 | fontSize: "2.2em",
14 | fontFamily: "Staatliches",
15 | },
16 | Benefit: {
17 | padding: "6px",
18 | height: 100,
19 | width: "100%",
20 | maxWidth: 100,
21 | position: "relative",
22 | borderRadius: "15px",
23 | cursor: "pointer",
24 | },
25 | BenefitLabel: {
26 | fontFamily: "Staatliches",
27 | fontSize: "0.7em",
28 | letterSpacing: "0.08em",
29 | "@media screen and (max-width:600px)": {
30 | fontSize: "0.6em",
31 | },
32 | },
33 | BenefitLogo: {
34 | position: "absolute",
35 | top: 0,
36 | left: 0,
37 | height: "100%",
38 | width: "100%",
39 | "@media screen and (max-width:600px)": {
40 | paddingRight: 0,
41 | paddingBottom: 0,
42 | },
43 | },
44 | BenefitLogoImg: {
45 | height: 40,
46 | width: 40,
47 | marginTop: "-15px",
48 | marginLeft: "-15px",
49 | "@media screen and (max-width:600px)": {
50 | marginTop: "-15px",
51 | marginLeft: "25px",
52 | },
53 | },
54 | };
55 |
56 | const Backgrounds = [
57 | "rgb(229,126,37)",
58 | "rgb(206,172,154)",
59 | "rgb(117,132,242)",
60 | "rgb(232,184,0)",
61 | "rgb(139,155,169)",
62 | "rgb(255,65,85)",
63 | ];
64 | const Colors = ["#fff", "#fff", "#fff", "#fff", "#fff", "#fff"];
65 | const Benefit = (props) => {
66 | return (
67 |
73 |
77 | {props.label}
78 |
79 |
84 |
90 |
91 |
92 | );
93 | };
94 | const Benefits = () => {
95 | return (
96 |
97 |
98 | Benefits
99 |
100 |
104 |
110 |
115 |
120 |
125 |
126 |
132 |
137 |
142 |
147 |
148 |
149 |
150 | );
151 | };
152 | export default Benefits;
153 |
--------------------------------------------------------------------------------