├── .gitignore
├── .env
├── README.md
├── public
└── index.html
├── src
├── utils
│ ├── debounce.ts
│ ├── EnvProvider.ts
│ ├── constants.ts
│ └── CatSubcatBrands.ts
├── Redux
│ ├── CartSlice
│ │ ├── module
│ │ │ ├── clearCart.ts
│ │ │ ├── setLoading.ts
│ │ │ ├── setError.ts
│ │ │ ├── initialState.ts
│ │ │ └── setCartData.ts
│ │ └── slice.ts
│ ├── OrderSlice
│ │ ├── module
│ │ │ ├── clearOrder.ts
│ │ │ ├── setLoading.ts
│ │ │ ├── setError.ts
│ │ │ ├── initialState.ts
│ │ │ └── setOrderData.ts
│ │ └── slice.ts
│ ├── ProductsSlice
│ │ ├── modules
│ │ │ ├── setLoading.ts
│ │ │ ├── setError.ts
│ │ │ ├── addToProductCache.ts
│ │ │ ├── setProductData.ts
│ │ │ └── initialState.ts
│ │ └── slice.ts
│ ├── UserSlice
│ │ ├── module
│ │ │ ├── setLoading.ts
│ │ │ ├── logout.ts
│ │ │ ├── setError.ts
│ │ │ ├── initialState.ts
│ │ │ └── setUserData.ts
│ │ └── slice.ts
│ ├── CheckOutSlice
│ │ ├── module
│ │ │ ├── setLoading.ts
│ │ │ ├── onChangeCheckout.ts
│ │ │ ├── setError.ts
│ │ │ └── intialState.ts
│ │ └── slice.ts
│ ├── FilterSlice
│ │ ├── modules
│ │ │ ├── initialState.ts
│ │ │ └── applyFilters.ts
│ │ └── slice.ts
│ └── ReduxStore.ts
├── components
│ ├── BrandsFilter
│ │ └── index.tsx
│ ├── Logo
│ │ └── index.tsx
│ ├── DesktopFilters
│ │ └── index.tsx
│ ├── CardOrderDetail
│ │ └── index.tsx
│ ├── SelectFilter
│ │ └── index.tsx
│ ├── TypeAndSelect
│ │ └── index.tsx
│ ├── SearchQuerryFilter
│ │ └── index.tsx
│ ├── CartData
│ │ └── index.tsx
│ ├── OrderSection
│ │ └── index.tsx
│ ├── ProductLists
│ │ └── index.tsx
│ ├── BrandsFilterOptions
│ │ └── index.tsx
│ ├── Categoryfilter
│ │ └── index.tsx
│ ├── ProductCartCalculation
│ │ └── index.tsx
│ ├── SubCategoryFilter
│ │ └── index.tsx
│ ├── MinMaxPriceFilter
│ │ └── index.tsx
│ ├── UserMenu
│ │ └── index.tsx
│ ├── RattingFilter
│ │ └── index.tsx
│ ├── Navbar
│ │ └── index.tsx
│ ├── Hamburgur
│ │ └── index.tsx
│ ├── SignInPage
│ │ └── index.tsx
│ ├── CartAndOrderProduct
│ │ └── index.tsx
│ ├── PaymentForm
│ │ └── index.tsx
│ ├── Review
│ │ └── index.tsx
│ ├── SignUpPage
│ │ └── index.tsx
│ ├── ProductCard
│ │ └── index.tsx
│ ├── CheckoutData
│ │ └── index.tsx
│ └── AddressForm
│ │ └── index.tsx
├── index.tsx
├── View
│ ├── Home
│ │ └── index.tsx
│ ├── Auth
│ │ └── index.tsx
│ └── CartAndCheckOut
│ │ └── index.tsx
├── HOC
│ └── index.tsx
├── app.css
├── App.tsx
└── api
│ └── apiService.ts
├── package.json
├── webpack.config.js
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | yarn.lock
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | LOCAL_SERVER_URL = http://localhost:3000
2 | PRODUCTION_SERVER_URL = http://localhost:3000
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ecomm-frontend
2 |
3 | # For authentication
4 | ```
5 | Email Example : deepak@gmail.com
6 | passsword Example : Deepak@123
7 | ```
8 | # password should have
9 | - One cap.
10 | - One small.
11 | - One numaric
12 | - One special charac.
13 |
14 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/utils/debounce.ts:
--------------------------------------------------------------------------------
1 | export default function debounce(callback: Function, delay: number = 500) {
2 | let timeoutId: NodeJS.Timeout;
3 |
4 | return function (...args: any[]) {
5 | clearTimeout(timeoutId);
6 |
7 | timeoutId = setTimeout(() => {
8 | callback(...args);
9 | }, delay);
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/src/Redux/CartSlice/module/clearCart.ts:
--------------------------------------------------------------------------------
1 | import { cartSliceInitialStateInterface } from "./initialState";
2 |
3 | const clearCart = (
4 | state: cartSliceInitialStateInterface
5 | ): cartSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | cartData: [],
9 | };
10 | };
11 |
12 | export default clearCart;
13 |
--------------------------------------------------------------------------------
/src/Redux/OrderSlice/module/clearOrder.ts:
--------------------------------------------------------------------------------
1 | import { orderSliceInitialStateInterface } from "./initialState";
2 |
3 | const clearOrder = (
4 | state: orderSliceInitialStateInterface
5 | ): orderSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | orderedProducts: [],
9 | };
10 | };
11 |
12 | export default clearOrder;
13 |
--------------------------------------------------------------------------------
/src/Redux/ProductsSlice/modules/setLoading.ts:
--------------------------------------------------------------------------------
1 | import { productSliceInitialStateI } from "./initialState";
2 |
3 | const setLoading = (
4 | state: productSliceInitialStateI
5 | ): productSliceInitialStateI => {
6 | return {
7 | ...state,
8 | loading: true,
9 | message: "",
10 | status: false,
11 | };
12 | };
13 |
14 | export default setLoading;
15 |
--------------------------------------------------------------------------------
/src/Redux/CartSlice/module/setLoading.ts:
--------------------------------------------------------------------------------
1 | import { cartSliceInitialStateInterface } from "./initialState";
2 |
3 | const setLoading = (
4 | state: cartSliceInitialStateInterface
5 | ): cartSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | loading: true,
9 | message: "",
10 | status: false,
11 | };
12 | };
13 |
14 | export default setLoading;
15 |
--------------------------------------------------------------------------------
/src/Redux/UserSlice/module/setLoading.ts:
--------------------------------------------------------------------------------
1 | import { userSliceInitialStateInterface } from "./initialState";
2 |
3 | const setLoading = (
4 | state: userSliceInitialStateInterface
5 | ): userSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | loading: true,
9 | message: "",
10 | status: false,
11 | };
12 | };
13 |
14 | export default setLoading;
15 |
--------------------------------------------------------------------------------
/src/Redux/OrderSlice/module/setLoading.ts:
--------------------------------------------------------------------------------
1 | import { orderSliceInitialStateInterface } from "./initialState";
2 |
3 | const setLoading = (
4 | state: orderSliceInitialStateInterface
5 | ): orderSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | loading: true,
9 | message: "",
10 | status: false,
11 | };
12 | };
13 |
14 | export default setLoading;
15 |
--------------------------------------------------------------------------------
/src/Redux/CheckOutSlice/module/setLoading.ts:
--------------------------------------------------------------------------------
1 | import { checkOuSliceInitialStateInterface } from "./intialState";
2 |
3 | const setLoading = (
4 | state: checkOuSliceInitialStateInterface
5 | ): checkOuSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | loading: true,
9 | message: "",
10 | status: false,
11 | };
12 | };
13 |
14 | export default setLoading;
15 |
--------------------------------------------------------------------------------
/src/Redux/FilterSlice/modules/initialState.ts:
--------------------------------------------------------------------------------
1 | export interface filterSliceInitialStateI {
2 | category?: string;
3 | subcategory?: string;
4 | brand?: string;
5 | averageRating?: number;
6 | avgtype?: string;
7 | name?: string;
8 | querry?: string;
9 | minPrice?: string;
10 | maxPrice?: string;
11 | _id?:string
12 | }
13 |
14 | export const filterSliceInitialState: filterSliceInitialStateI = {};
15 |
--------------------------------------------------------------------------------
/src/Redux/UserSlice/module/logout.ts:
--------------------------------------------------------------------------------
1 | import { userSliceInitialStateInterface } from "./initialState";
2 |
3 | const logout = (
4 | state: userSliceInitialStateInterface
5 | ): userSliceInitialStateInterface => {
6 | return {
7 | ...state,
8 | userData: {
9 | email: "",
10 | name: "",
11 | token: "",
12 | userId: "",
13 | },
14 | };
15 | };
16 |
17 | export default logout;
18 |
--------------------------------------------------------------------------------
/src/utils/EnvProvider.ts:
--------------------------------------------------------------------------------
1 | interface EnvProviderI {
2 | SERVER_BASE_URL: string;
3 | }
4 |
5 | export const EnvProvider = (): EnvProviderI => {
6 | if (process.env.NODE_ENV === "production") {
7 | return {
8 | SERVER_BASE_URL: process.env.PRODUCTION_SERVER_URL as string,
9 | };
10 | } else {
11 | return {
12 | SERVER_BASE_URL: process.env.LOCAL_SERVER_URL as string,
13 | };
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/src/Redux/CheckOutSlice/module/onChangeCheckout.ts:
--------------------------------------------------------------------------------
1 | import { checkOuSliceInitialStateInterface } from "./intialState";
2 |
3 | const onChangeCheckout = (
4 | state: checkOuSliceInitialStateInterface,
5 | action: { payload: Partial }
6 | ): checkOuSliceInitialStateInterface => {
7 | return {
8 | ...state,
9 | ...action.payload,
10 | };
11 | };
12 |
13 | export default onChangeCheckout;
14 |
--------------------------------------------------------------------------------
/src/Redux/FilterSlice/modules/applyFilters.ts:
--------------------------------------------------------------------------------
1 | import { filterSliceInitialStateI } from "./initialState";
2 | import { PayloadAction } from "@reduxjs/toolkit";
3 |
4 | const applyFilters = (
5 | state: filterSliceInitialStateI,
6 | action: PayloadAction
7 | ): filterSliceInitialStateI => {
8 | return {
9 | ...state,
10 | ...action.payload,
11 | };
12 | };
13 |
14 | export default applyFilters;
15 |
--------------------------------------------------------------------------------
/src/Redux/ProductsSlice/modules/setError.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { productSliceInitialStateI } from "./initialState";
3 |
4 | const setError = (
5 | state: productSliceInitialStateI,
6 | action: { payload: apiResponse }
7 | ): productSliceInitialStateI => {
8 | return {
9 | ...state,
10 | loading: false,
11 | message: action.payload.message,
12 | status: action.payload.status,
13 | };
14 | };
15 |
16 | export default setError;
17 |
--------------------------------------------------------------------------------
/src/Redux/CartSlice/module/setError.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { cartSliceInitialStateInterface } from "./initialState";
3 |
4 | const setError = (
5 | state: cartSliceInitialStateInterface,
6 | action: { payload: apiResponse }
7 | ): cartSliceInitialStateInterface => {
8 | return {
9 | ...state,
10 | loading: false,
11 | message: action.payload.message,
12 | status: action.payload.status,
13 | };
14 | };
15 |
16 | export default setError;
17 |
--------------------------------------------------------------------------------
/src/Redux/UserSlice/module/setError.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { userSliceInitialStateInterface } from "./initialState";
3 |
4 | const setError = (
5 | state: userSliceInitialStateInterface,
6 | action: { payload: apiResponse }
7 | ): userSliceInitialStateInterface => {
8 | return {
9 | ...state,
10 | loading: false,
11 | message: action.payload.message,
12 | status: action.payload.status,
13 | };
14 | };
15 |
16 | export default setError;
17 |
--------------------------------------------------------------------------------
/src/Redux/FilterSlice/slice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { filterSliceInitialState } from "./modules/initialState";
3 | import applyFilters from "./modules/applyFilters";
4 |
5 | const filterSlice = createSlice({
6 | name: "filterSlice",
7 | initialState: filterSliceInitialState,
8 | reducers: {
9 | applyFiltersReducer: applyFilters,
10 | },
11 |
12 | });
13 |
14 | export const { applyFiltersReducer } = filterSlice.actions;
15 | export default filterSlice.reducer;
16 |
--------------------------------------------------------------------------------
/src/Redux/OrderSlice/module/setError.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { orderSliceInitialStateInterface } from "./initialState";
3 |
4 | const setError = (
5 | state: orderSliceInitialStateInterface,
6 | action: { payload: apiResponse }
7 | ): orderSliceInitialStateInterface => {
8 | return {
9 | ...state,
10 | loading: false,
11 | message: action.payload.message,
12 | status: action.payload.status,
13 | };
14 | };
15 |
16 | export default setError;
17 |
--------------------------------------------------------------------------------
/src/components/BrandsFilter/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import Stack from "@mui/material/Stack";
3 | import FormLabel from "@mui/material/FormLabel";
4 | import BrandsFilterOptions from "../BrandsFilterOptions";
5 |
6 | const BrandsFilter: React.FC = () => {
7 | return (
8 |
9 | Brand's
10 |
11 |
12 | );
13 | };
14 |
15 | export default memo(BrandsFilter);
16 |
--------------------------------------------------------------------------------
/src/Redux/CheckOutSlice/module/setError.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { checkOuSliceInitialStateInterface } from "./intialState";
3 |
4 | const setError = (
5 | state: checkOuSliceInitialStateInterface,
6 | action: { payload: apiResponse }
7 | ): checkOuSliceInitialStateInterface => {
8 | return {
9 | ...state,
10 | loading: false,
11 | message: action.payload.message,
12 | status: action.payload.status,
13 | };
14 | };
15 |
16 | export default setError;
17 |
--------------------------------------------------------------------------------
/src/Redux/CartSlice/module/initialState.ts:
--------------------------------------------------------------------------------
1 | export interface cartDataInterface {
2 | productId: string;
3 | productCount: number;
4 | productTotal: number;
5 | userId: string;
6 | }
7 | export interface cartSliceInitialStateInterface {
8 | loading: boolean;
9 | status: boolean;
10 | message: string;
11 | cartData: cartDataInterface[];
12 | }
13 |
14 | export const cartSliceInitialState: cartSliceInitialStateInterface = {
15 | cartData: [],
16 | loading: false,
17 | message: "",
18 | status: true,
19 | };
20 |
--------------------------------------------------------------------------------
/src/Redux/ProductsSlice/modules/addToProductCache.ts:
--------------------------------------------------------------------------------
1 | import { productCardI, productSliceInitialStateI } from "./initialState";
2 | import { PayloadAction } from "@reduxjs/toolkit";
3 |
4 | const addToProductCache = (
5 | state: productSliceInitialStateI,
6 | action: PayloadAction
7 | ): productSliceInitialStateI => {
8 | return {
9 | ...state,
10 | productCache: {
11 | ...state.productCache,
12 | [action.payload._id as string]: action.payload,
13 | },
14 | };
15 | };
16 |
17 | export default addToProductCache;
18 |
--------------------------------------------------------------------------------
/src/components/Logo/index.tsx:
--------------------------------------------------------------------------------
1 | import { Typography } from "@mui/material";
2 | import React from "react";
3 | import { useNavigate } from "react-router-dom";
4 |
5 | const Logo: React.FC = () => {
6 | const router = useNavigate();
7 | const handleClick = () => router("/");
8 | return (
9 |
17 | App Logo
18 |
19 | );
20 | };
21 |
22 | export default Logo;
23 |
--------------------------------------------------------------------------------
/src/Redux/UserSlice/module/initialState.ts:
--------------------------------------------------------------------------------
1 | export interface userDataInterface {
2 | email: string;
3 | name: string;
4 | token: string;
5 | userId: string;
6 | }
7 |
8 | export interface userSliceInitialStateInterface {
9 | loading: boolean;
10 | status: boolean;
11 | message: string;
12 | userData: userDataInterface;
13 | }
14 |
15 | export const userSliceInitialState: userSliceInitialStateInterface = {
16 | loading: false,
17 | message: "",
18 | status: false,
19 | userData: {
20 | email: "",
21 | name: "",
22 | token: "",
23 | userId: "",
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/src/Redux/CartSlice/module/setCartData.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { cartSliceInitialStateInterface } from "./initialState";
3 | import { PayloadAction } from "@reduxjs/toolkit";
4 |
5 | const getCartData = (
6 | state: cartSliceInitialStateInterface,
7 | action: PayloadAction
8 | ): cartSliceInitialStateInterface => {
9 | return {
10 | ...state,
11 | loading: false,
12 | cartData: action.payload.data,
13 | message: action.payload.message,
14 | status: action.payload.status,
15 | };
16 | };
17 |
18 | export default getCartData;
19 |
--------------------------------------------------------------------------------
/src/Redux/ProductsSlice/modules/setProductData.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { productSliceInitialStateI } from "./initialState";
3 | import { PayloadAction } from "@reduxjs/toolkit";
4 |
5 | const setProductData = (
6 | state: productSliceInitialStateI,
7 | action: PayloadAction
8 | ): productSliceInitialStateI => {
9 | return {
10 | ...state,
11 | loading: false,
12 | products: action.payload.data,
13 | message: action.payload.message,
14 | status: action.payload.status,
15 | };
16 | };
17 |
18 | export default setProductData;
19 |
--------------------------------------------------------------------------------
/src/Redux/UserSlice/module/setUserData.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { userSliceInitialStateInterface } from "./initialState";
3 | import { PayloadAction } from "@reduxjs/toolkit";
4 |
5 | const getCartData = (
6 | state: userSliceInitialStateInterface,
7 | action: PayloadAction
8 | ): userSliceInitialStateInterface => {
9 | return {
10 | ...state,
11 | loading: false,
12 | message: action.payload.message,
13 | status: action.payload.status,
14 | userData: action.payload.data,
15 | };
16 | };
17 |
18 | export default getCartData;
19 |
--------------------------------------------------------------------------------
/src/Redux/OrderSlice/module/initialState.ts:
--------------------------------------------------------------------------------
1 | import { cartDataInterface } from "../../CartSlice/module/initialState";
2 |
3 | export interface OrderedProductInterface extends cartDataInterface {
4 | OrderId: string;
5 | ExpectedDelivery: string;
6 | }
7 | export interface orderSliceInitialStateInterface {
8 | loading: boolean;
9 | status: boolean;
10 | message: string;
11 | orderedProducts: OrderedProductInterface[];
12 | }
13 |
14 | export const orderSliceInitialState: orderSliceInitialStateInterface = {
15 | loading: false,
16 | message: "",
17 | orderedProducts: [],
18 | status: false,
19 | };
20 |
--------------------------------------------------------------------------------
/src/Redux/OrderSlice/module/setOrderData.ts:
--------------------------------------------------------------------------------
1 | import { apiResponse } from "../../../api/apiService";
2 | import { orderSliceInitialStateInterface } from "./initialState";
3 | import { PayloadAction } from "@reduxjs/toolkit";
4 |
5 | const getCartData = (
6 | state: orderSliceInitialStateInterface,
7 | action: PayloadAction
8 | ): orderSliceInitialStateInterface => {
9 | return {
10 | ...state,
11 | loading: false,
12 | orderedProducts: action.payload.data,
13 | message: action.payload.message,
14 | status: action.payload.status,
15 | };
16 | };
17 |
18 | export default getCartData;
19 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createRoot } from "react-dom/client";
3 | import { RouterProvider } from "react-router-dom";
4 | import AppRoute from "./App";
5 | import { Provider } from "react-redux";
6 | import reduxStore from "./Redux/ReduxStore";
7 |
8 | const container: HTMLElement | null = document.getElementById("root");
9 | if (container) {
10 | const root = createRoot(container);
11 | root.render(
12 |
13 |
14 |
15 | );
16 | } else {
17 | throw new Error("Target container is not dom element");
18 | }
19 |
--------------------------------------------------------------------------------
/src/View/Home/index.tsx:
--------------------------------------------------------------------------------
1 | import Stack from "@mui/material/Stack";
2 | import React, { memo } from "react";
3 | const DesktopFilters = React.lazy(
4 | () => import("../../components/DesktopFilters")
5 | );
6 | const ProductLists = React.lazy(() => import("../../components/ProductLists"));
7 |
8 | const HomePage: React.FC = () => {
9 | return (
10 |
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export default memo(HomePage);
27 |
--------------------------------------------------------------------------------
/src/View/Auth/index.tsx:
--------------------------------------------------------------------------------
1 | import Stack from "@mui/material/Stack";
2 | import React, { memo, useState } from "react";
3 |
4 | const SignInPage = React.lazy(() => import("../../components/SignInPage"));
5 | const SignUpPage = React.lazy(() => import("../../components/SignUpPage"));
6 |
7 | const Authentication: React.FC = () => {
8 | const [IsalreadyUser, setIsalreadyUser] = useState(true);
9 | const toggle = () => setIsalreadyUser((prev) => !prev);
10 | return (
11 |
12 | {IsalreadyUser ? (
13 |
14 | ) : (
15 |
16 | )}
17 |
18 | );
19 | };
20 |
21 | export default memo(Authentication);
22 |
--------------------------------------------------------------------------------
/src/Redux/ReduxStore.ts:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import productSlice from "./ProductsSlice/slice";
3 | import filterSlice from "./FilterSlice/slice";
4 | import cartSlice from "./CartSlice/slice";
5 | import CheckoutSlice from "./CheckOutSlice/slice";
6 | import orderSlice from "./OrderSlice/slice";
7 | import UserSlice from "./UserSlice/slice";
8 |
9 | const reduxStore = configureStore({
10 | reducer: {
11 | productSlice,
12 | filterSlice,
13 | cartSlice,
14 | CheckoutSlice,
15 | orderSlice,
16 | UserSlice,
17 | },
18 | });
19 |
20 | export type RootState = ReturnType;
21 | export type AppDispatch = typeof reduxStore.dispatch;
22 |
23 | export default reduxStore;
24 |
--------------------------------------------------------------------------------
/src/HOC/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode } from "react";
2 | import { useSelector } from "react-redux";
3 | import { RootState } from "../Redux/ReduxStore";
4 | import { userSliceInitialStateInterface } from "../Redux/UserSlice/module/initialState";
5 | import { Navigate, useLocation } from "react-router-dom";
6 |
7 | const PrivateRoute: React.FC<{ children: ReactNode }> = ({ children }) => {
8 | const { userData } = useSelector(
9 | (store) => store.UserSlice
10 | ) as userSliceInitialStateInterface;
11 |
12 | const loc = useLocation();
13 |
14 | return userData.token ? (
15 | children
16 | ) : (
17 |
18 | );
19 | };
20 |
21 | export default PrivateRoute;
22 |
--------------------------------------------------------------------------------
/src/Redux/CheckOutSlice/slice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { CheckoutInitialState } from "./module/intialState";
3 | import setLoading from "./module/setLoading";
4 | import setError from "./module/setError";
5 | import onChangeCheckout from "./module/onChangeCheckout";
6 |
7 | const CheckoutSlice = createSlice({
8 | name: "cartSlice",
9 | initialState: CheckoutInitialState,
10 | reducers: {
11 | setCartLoadingReducer: setLoading,
12 | setCartErrorReducer: setError,
13 | onChangeCheckoutReducer: onChangeCheckout,
14 | },
15 | });
16 |
17 | export const {
18 | onChangeCheckoutReducer,
19 | setCartLoadingReducer,
20 | setCartErrorReducer,
21 | } = CheckoutSlice.actions;
22 | export default CheckoutSlice.reducer;
23 |
--------------------------------------------------------------------------------
/src/components/DesktopFilters/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import Stack from "@mui/material/Stack";
3 | import SearchQuerryFilter from "../SearchQuerryFilter";
4 | import MinMaxPriceFilter from "../MinMaxPriceFilter";
5 | import RattingFilter from "../RattingFilter";
6 | import BrandsFilter from "../BrandsFilter";
7 |
8 | const DesktopFilters: React.FC = () => {
9 | return (
10 |
19 | {" "}
20 |
21 |
22 |
23 |
24 |
25 | );
26 | };
27 |
28 | export default memo(DesktopFilters);
29 |
--------------------------------------------------------------------------------
/src/Redux/UserSlice/slice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { userSliceInitialState } from "./module/initialState";
3 | import setLoading from "./module/setLoading";
4 | import getCartData from "./module/setUserData";
5 | import setError from "./module/setError";
6 | import logout from "./module/logout";
7 |
8 | const cartSlice = createSlice({
9 | name: "cartSlice",
10 | initialState: userSliceInitialState,
11 | reducers: {
12 | setUserLoadingReducer: setLoading,
13 | setUserErrorReducer: setError,
14 | setUserDataReducer: getCartData,
15 | logoutReducer: logout,
16 | },
17 | });
18 |
19 | export const {
20 | setUserDataReducer,
21 | setUserLoadingReducer,
22 | setUserErrorReducer,
23 | logoutReducer,
24 | } = cartSlice.actions;
25 | export default cartSlice.reducer;
26 |
--------------------------------------------------------------------------------
/src/Redux/CartSlice/slice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { cartSliceInitialState } from "./module/initialState";
3 | import setLoading from "./module/setLoading";
4 | import getCartData from "./module/setCartData";
5 | import setError from "./module/setError";
6 | import clearCart from "./module/clearCart";
7 |
8 | const cartSlice = createSlice({
9 | name: "cartSlice",
10 | initialState: cartSliceInitialState,
11 | reducers: {
12 | setCartLoadingReducer: setLoading,
13 | setCartErrorReducer: setError,
14 | setCartDataReducer: getCartData,
15 | clearCartReducer: clearCart,
16 | },
17 | });
18 |
19 | export const {
20 | setCartDataReducer,
21 | setCartLoadingReducer,
22 | setCartErrorReducer,
23 | clearCartReducer,
24 | } = cartSlice.actions;
25 | export default cartSlice.reducer;
26 |
--------------------------------------------------------------------------------
/src/Redux/OrderSlice/slice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { orderSliceInitialState } from "./module/initialState";
3 | import setLoading from "./module/setLoading";
4 | import setOrderData from "./module/setOrderData";
5 | import setError from "./module/setError";
6 | import clearOrder from "./module/clearOrder";
7 |
8 | const orderSlice = createSlice({
9 | name: "orderSlice",
10 | initialState: orderSliceInitialState,
11 | reducers: {
12 | setOrderLoadingReducer: setLoading,
13 | setOrderErrorReducer: setError,
14 | setOrdertDataReducer: setOrderData,
15 | clearOrderReducer: clearOrder,
16 | },
17 | });
18 |
19 | export const {
20 | setOrderErrorReducer,
21 | setOrderLoadingReducer,
22 | setOrdertDataReducer,
23 | clearOrderReducer,
24 | } = orderSlice.actions;
25 | export default orderSlice.reducer;
26 |
--------------------------------------------------------------------------------
/src/utils/constants.ts:
--------------------------------------------------------------------------------
1 | export interface priceRangeI {
2 | label: string;
3 | value: string;
4 | }
5 |
6 | export const minPriceRange: priceRangeI[] = [
7 | { label: "100", value: "100" },
8 | { label: "1000", value: "1000" },
9 | { label: "10000", value: "10000" },
10 | { label: "100000", value: "100000" },
11 | ];
12 | export const maxPriceRange: priceRangeI[] = [
13 | { label: "1000", value: "1000" },
14 | { label: "10000", value: "10000" },
15 | { label: "100000", value: "100000" },
16 | ];
17 |
18 | export interface RattingRangeI extends priceRangeI {}
19 | export const RattingRange: RattingRangeI[] = [
20 | { label: "5", value: "5" },
21 | { label: "4", value: "4" },
22 | { label: "3", value: "3" },
23 | { label: "2", value: "2" },
24 | { label: "1", value: "1" },
25 | ];
26 |
27 | export const steps = ["Shipping address", "Payment details", "Review your order"];
28 |
--------------------------------------------------------------------------------
/src/Redux/ProductsSlice/slice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { productsInitialState } from "./modules/initialState";
3 | import setLoading from "../ProductsSlice/modules/setLoading";
4 | import setError from "./modules/setError";
5 | import setProductData from "./modules/setProductData";
6 | import addToProductCache from "./modules/addToProductCache";
7 |
8 | const productSlice = createSlice({
9 | name: "productSlice",
10 | initialState: productsInitialState,
11 | reducers: {
12 | setProductLoadingReducer: setLoading,
13 | setProductErrorReducer: setError,
14 | setProductDataReducer: setProductData,
15 | addToProductCacheReducer: addToProductCache,
16 | },
17 | });
18 |
19 | export const {
20 | setProductLoadingReducer,
21 | setProductErrorReducer,
22 | setProductDataReducer,
23 | addToProductCacheReducer,
24 | } = productSlice.actions;
25 | export default productSlice.reducer;
26 |
--------------------------------------------------------------------------------
/src/Redux/ProductsSlice/modules/initialState.ts:
--------------------------------------------------------------------------------
1 | export interface productCardI {
2 | _id: string;
3 | name: string;
4 | description: string;
5 | category: string;
6 | subcategory: string;
7 | brand: string;
8 | price: number;
9 | quantityAvailable: number;
10 | image: string;
11 | averageRating: number;
12 | totalRatings: number;
13 | comments: [
14 | {
15 | userId: string;
16 | username: string;
17 | comment: string;
18 | rating: number;
19 | timestamp: string;
20 | }
21 | ];
22 | }
23 | export interface productSliceInitialStateI {
24 | loading: boolean;
25 | message: string;
26 | status: boolean;
27 | products: productCardI[];
28 | productCache: {
29 | [key: string]: productCardI; // optimised
30 | };
31 | }
32 |
33 | export const productsInitialState: productSliceInitialStateI = {
34 | loading: false,
35 | message: "",
36 | products: [],
37 | productCache: {},
38 | status: true,
39 | };
40 |
--------------------------------------------------------------------------------
/src/View/CartAndCheckOut/index.tsx:
--------------------------------------------------------------------------------
1 | import Stack from "@mui/material/Stack";
2 | import React, { memo } from "react";
3 | import CartData from "../../components/CartData";
4 | import CheckoutData from "../../components/CheckoutData";
5 | import OrderSection from "../../components/OrderSection";
6 |
7 | const CartAndCheckout: React.FC = () => {
8 | return (
9 |
10 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | };
35 |
36 | export default memo(CartAndCheckout);
37 |
--------------------------------------------------------------------------------
/src/components/CardOrderDetail/index.tsx:
--------------------------------------------------------------------------------
1 | import { Stack, Typography } from "@mui/material";
2 | import React from "react";
3 |
4 | interface componentInterface {
5 | ExpectedDelivery: string;
6 | }
7 | const CardOrderDetail: React.FC = ({
8 | ExpectedDelivery,
9 | }) => {
10 | return (
11 |
17 | {" "}
18 | CardOrderDetail:{" "}
19 | {Date.now() >= parseInt(ExpectedDelivery) ? (
20 |
25 | Order Delivered
26 |
27 | ) : (
28 |
33 | Dispatched
34 |
35 | )}
36 |
37 | );
38 | };
39 |
40 | export default CardOrderDetail;
41 |
--------------------------------------------------------------------------------
/src/components/SelectFilter/index.tsx:
--------------------------------------------------------------------------------
1 | import { Autocomplete, TextField } from "@mui/material";
2 | import React from "react";
3 | import { priceRangeI } from "../../utils/constants";
4 |
5 | interface ComponentProps {
6 | options: { label: string; value: string }[];
7 | defaultValue: string | undefined;
8 | onChange: (
9 | event: React.SyntheticEvent,
10 | value: string | priceRangeI | null
11 | ) => void;
12 | disabled: boolean;
13 | label: string;
14 | }
15 |
16 | const SelectFilter: React.FC = ({
17 | options,
18 | defaultValue,
19 | onChange,
20 | disabled,
21 | label,
22 | }) => {
23 | const optionLabels = options.map((option) => option.label);
24 |
25 | return (
26 | option}
32 | defaultValue={defaultValue}
33 | renderInput={(params) => (
34 |
35 | )}
36 | />
37 | );
38 | };
39 |
40 | export default SelectFilter;
41 |
--------------------------------------------------------------------------------
/src/components/TypeAndSelect/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import { priceRangeI } from "../../utils/constants";
3 | import TextField from "@mui/material/TextField";
4 | import Autocomplete from "@mui/material/Autocomplete";
5 | interface ComponentProps {
6 | label: string;
7 | defaultValue: string | undefined;
8 | onChange: (
9 | event: React.SyntheticEvent,
10 | value: string | priceRangeI | null
11 | ) => void;
12 | options: priceRangeI[];
13 | }
14 |
15 | const TypeAndSelect: React.FC = ({
16 | label,
17 | onChange,
18 | options,
19 | defaultValue,
20 | }) => {
21 | const defaultOption = options.find((option) => option.value === defaultValue);
22 | const defaultLabel = defaultOption ? defaultOption.label : defaultValue || "";
23 |
24 | return (
25 | option.label)}
29 | renderInput={(params) => (
30 |
31 | )}
32 | onChange={onChange}
33 | fullWidth
34 | />
35 | );
36 | };
37 |
38 | export default memo(TypeAndSelect);
39 |
--------------------------------------------------------------------------------
/src/components/SearchQuerryFilter/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { ChangeEvent, memo } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import TextField from "@mui/material/TextField";
4 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
5 | import { filterSliceInitialStateI } from "../../Redux/FilterSlice/modules/initialState";
6 | import { applyFiltersReducer } from "../../Redux/FilterSlice/slice";
7 | import debounce from "../../utils/debounce";
8 |
9 | const SearchQuerryFilter: React.FC = () => {
10 | const { querry } = useSelector(
11 | (store) => store.filterSlice
12 | ) as filterSliceInitialStateI;
13 |
14 | const dispatch = useDispatch();
15 |
16 | const handleQuerryChange = debounce(
17 | (event: ChangeEvent) => {
18 | dispatch(
19 | applyFiltersReducer({
20 | querry: event.target.value,
21 | })
22 | );
23 | },
24 | 300
25 | );
26 |
27 | return (
28 |
38 | );
39 | };
40 |
41 | export default memo(SearchQuerryFilter);
42 |
--------------------------------------------------------------------------------
/src/components/CartData/index.tsx:
--------------------------------------------------------------------------------
1 | import Stack from "@mui/material/Stack";
2 | import Typography from "@mui/material/Typography";
3 | import React, { memo } from "react";
4 | import { RootState } from "../../Redux/ReduxStore";
5 | import { useSelector } from "react-redux";
6 | import { cartSliceInitialStateInterface } from "../../Redux/CartSlice/module/initialState";
7 | import CartAndOrderProduct from "../CartAndOrderProduct";
8 |
9 | const CartData: React.FC = () => {
10 | const { cartData } = useSelector(
11 | (store) => store.cartSlice
12 | ) as cartSliceInitialStateInterface;
13 |
14 | return (
15 |
21 |
22 | Cart
23 |
24 |
25 | {cartData.map((cartitem) => {
26 | const { productCount, productId, productTotal } = cartitem;
27 | return (
28 |
35 | );
36 | })}
37 |
38 |
39 | );
40 | };
41 |
42 | export default memo(CartData);
43 |
--------------------------------------------------------------------------------
/src/Redux/CheckOutSlice/module/intialState.ts:
--------------------------------------------------------------------------------
1 | export type AddressInterface = {
2 | firstName: string;
3 | lastName: string;
4 | addressline: string;
5 | city: string;
6 | state: string;
7 | zipcode: string;
8 | country: string;
9 | };
10 | export interface paymentsInterface {
11 | cardNumber: string;
12 | cardName: string;
13 | ExpiryDate: string;
14 | cvv: string;
15 | }
16 |
17 | export interface checkOuSliceInitialStateInterface {
18 | loading: boolean;
19 | status: boolean;
20 | message: string;
21 | address: AddressInterface;
22 | payment: paymentsInterface;
23 | }
24 |
25 | export const CheckoutInitialState: checkOuSliceInitialStateInterface = {
26 | address: localStorage.getItem("address")
27 | ? JSON.parse(localStorage.getItem("address") as string)
28 | : {
29 | addressline: "Indranager, Bangalore",
30 | city: "Bangalore",
31 | country: "INDIA",
32 | firstName: "Deepak",
33 | lastName: "Mandal",
34 | state: "Karnataka",
35 | zipcode: "560075",
36 | },
37 | loading: false,
38 | message: "",
39 | payment: localStorage.getItem("payment")
40 | ? JSON.parse(localStorage.getItem("payment") as string)
41 | : {
42 | cardName: "Deepak Mandal",
43 | cardNumber: "1111 2222 3333",
44 | cvv: 123,
45 | ExpiryDate: "24/04",
46 | },
47 | status: false,
48 | };
49 |
--------------------------------------------------------------------------------
/src/app.css:
--------------------------------------------------------------------------------
1 | /* App.css */
2 |
3 | body,
4 | html {
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | .container {
10 | width: 100vw;
11 | height: 100vh;
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: space-between;
15 | }
16 |
17 | .header,
18 | .footer {
19 | --tw-bg-opacity: 1;
20 | background-color: rgb(31 41 55 / var(--tw-bg-opacity));
21 | --tw-text-opacity: 1;
22 | color: rgb(255 255 255 / var(--tw-text-opacity));
23 | text-align: center;
24 | padding-top: 1rem /* 16px */;
25 | padding-bottom: 1rem /* 16px */;
26 | }
27 |
28 | .title {
29 | font-size: 1.875rem /* 30px */;
30 | line-height: 2.25rem /* 36px */;
31 | }
32 | .main {
33 | max-width: 42rem /* 672px */;
34 | margin-left: auto;
35 | margin-right: auto;
36 | padding: 1rem /* 16px */;
37 | }
38 | .section-title {
39 | font-size: 1.5rem /* 24px */;
40 | line-height: 2rem /* 32px */;
41 | }
42 |
43 | .code-block {
44 | --tw-bg-opacity: 1;
45 | background-color: rgb(229 231 235 / var(--tw-bg-opacity));
46 | padding: 0.5rem /* 8px */;
47 | }
48 |
49 | .links-container {
50 | text-align: center;
51 | margin-top: 20px;
52 | }
53 |
54 | .link {
55 | display: inline-block;
56 | margin: 8px;
57 | padding: 8px 16px;
58 | text-decoration: none;
59 | color: #fff;
60 | background-color: #333;
61 | border-radius: 4px;
62 | }
63 |
64 | .link:hover {
65 | background-color: #555;
66 | }
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webelight-frontend",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.tsx",
6 | "author": "Deepak Mandal",
7 | "license": "ISC",
8 | "scripts": {
9 | "build": "webpack --mode production",
10 | "build:dev": "webpack --mode development",
11 | "build:start": "cd dist && PORT=7001 npx serve",
12 | "start": "webpack serve --open --mode development",
13 | "start:live": "webpack serve --open --mode development --live-reload --hot"
14 | },
15 | "devDependencies": {
16 | "@babel/core": "7.23.7",
17 | "@babel/preset-env": "^7.15.8",
18 | "@babel/preset-react": "^7.14.5",
19 | "@babel/preset-typescript": "^7.23.3",
20 | "@types/react": "^18.2.48",
21 | "@types/react-dom": "^18.2.18",
22 | "babel-loader": "^8.2.2",
23 | "css-loader": "^6.3.0",
24 | "file-loader": "^6.2.0",
25 | "html-webpack-plugin": "^5.3.2",
26 | "sass-loader": "^14.0.0",
27 | "style-loader": "^3.3.0",
28 | "webpack": "^5.90.2",
29 | "webpack-cli": "^5.1.4",
30 | "webpack-dev-server": "^4.3.1"
31 | },
32 | "dependencies": {
33 | "@emotion/react": "^11.11.3",
34 | "@emotion/styled": "^11.11.0",
35 | "@mui/icons-material": "^5.15.10",
36 | "@mui/material": "^5.15.10",
37 | "@reduxjs/toolkit": "^2.2.1",
38 | "axios": "^1.8.2",
39 | "dotenv": "^16.3.1",
40 | "framer-motion": "^10.18.0",
41 | "process": "^0.11.10",
42 | "react": "^18.2.0",
43 | "react-dom": "^18.2.0",
44 | "react-redux": "^9.1.0",
45 | "react-router-dom": "^6.22.0",
46 | "sass": "^1.70.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/OrderSection/index.tsx:
--------------------------------------------------------------------------------
1 | import Typography from "@mui/material/Typography";
2 | import Stack from "@mui/material/Stack";
3 | import React, { memo } from "react";
4 | import { useSelector } from "react-redux";
5 | import { RootState } from "../../Redux/ReduxStore";
6 | import { orderSliceInitialStateInterface } from "../../Redux/OrderSlice/module/initialState";
7 | import CartAndOrderProduct from "../CartAndOrderProduct";
8 |
9 | const OrderSection: React.FC = () => {
10 | const { orderedProducts } = useSelector(
11 | (store) => store.orderSlice
12 | ) as orderSliceInitialStateInterface;
13 | return (
14 |
20 |
21 | Orders
22 |
23 |
24 | {orderedProducts?.map((orderedItem) => {
25 | const {
26 | ExpectedDelivery,
27 | OrderId,
28 | productCount,
29 | productId,
30 | productTotal,
31 | } = orderedItem;
32 |
33 | return (
34 |
43 | );
44 | })}
45 |
46 |
47 | );
48 | };
49 |
50 | export default memo(OrderSection)
51 |
--------------------------------------------------------------------------------
/src/components/ProductLists/index.tsx:
--------------------------------------------------------------------------------
1 | import Stack from "@mui/material/Stack";
2 | import React, { memo } from "react";
3 | import { useSelector } from "react-redux";
4 | import { RootState } from "../../Redux/ReduxStore";
5 | import CategoryFilter from "../Categoryfilter";
6 | import SubCategoryFilter from "../SubCategoryFilter";
7 | import { productSliceInitialStateI } from "../../Redux/ProductsSlice/modules/initialState";
8 | import ProductCard from "../ProductCard";
9 | import { cartSliceInitialStateInterface } from "../../Redux/CartSlice/module/initialState";
10 |
11 | const ProductLists: React.FC = () => {
12 | const { products } = useSelector(
13 | (store) => store.productSlice
14 | ) as productSliceInitialStateI;
15 |
16 | const { cartData } = useSelector(
17 | (store) => store.cartSlice
18 | ) as cartSliceInitialStateInterface;
19 | return (
20 |
26 |
32 |
33 |
34 |
35 |
36 | {products.map((product) => {
37 | return (
38 | cart.productId == product._id)
43 | ?.productCount || 0
44 | }
45 | />
46 | );
47 | })}
48 |
49 |
50 | );
51 | };
52 |
53 | export default memo(ProductLists);
54 |
--------------------------------------------------------------------------------
/src/components/BrandsFilterOptions/index.tsx:
--------------------------------------------------------------------------------
1 | import FormControlLabel from "@mui/material/FormControlLabel";
2 | import Radio from "@mui/material/Radio";
3 | import RadioGroup from "@mui/material/RadioGroup";
4 | import React, { ChangeEvent, memo } from "react";
5 | import { useDispatch, useSelector } from "react-redux";
6 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
7 | import { filterSliceInitialStateI } from "../../Redux/FilterSlice/modules/initialState";
8 | import { applyFiltersReducer } from "../../Redux/FilterSlice/slice";
9 | import { CategoryLists } from "../../utils/CatSubcatBrands";
10 |
11 | const BrandsFilterOptions: React.FC = () => {
12 | const { subcategory, brand, category } = useSelector(
13 | (store) => store.filterSlice
14 | ) as filterSliceInitialStateI;
15 |
16 | const dispatch = useDispatch();
17 |
18 | const handleApplyBrands = (event: ChangeEvent) => {
19 | dispatch(
20 | applyFiltersReducer({
21 | brand: event.target.value,
22 | })
23 | );
24 | };
25 |
26 | const Categories = CategoryLists.find((item) => item.name == category) || {
27 | name: undefined,
28 | subCategories: [],
29 | };
30 |
31 | const subCategories = Categories.subCategories.find(
32 | (item) => item.name == subcategory
33 | );
34 |
35 | const brands = subCategories?.brands || [];
36 | return (
37 |
43 | {brands.map((brand) => {
44 | return (
45 | }
49 | label={brand}
50 | />
51 | );
52 | })}
53 |
54 | );
55 | };
56 |
57 | export default memo(BrandsFilterOptions);
58 |
--------------------------------------------------------------------------------
/src/components/Categoryfilter/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import SelectFilter from "../SelectFilter";
3 | import { useDispatch, useSelector } from "react-redux";
4 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
5 | import { filterSliceInitialStateI } from "../../Redux/FilterSlice/modules/initialState";
6 | import { priceRangeI } from "../../utils/constants";
7 | import { CategoryLists } from "../../utils/CatSubcatBrands";
8 | import { applyFiltersReducer } from "../../Redux/FilterSlice/slice";
9 |
10 | const CategoryFilter = () => {
11 | const { category } = useSelector(
12 | (store) => store.filterSlice
13 | ) as filterSliceInitialStateI;
14 |
15 | const dispatch = useDispatch();
16 |
17 | const handleApplyCatSubCate = (
18 | event: React.SyntheticEvent,
19 | value: string | priceRangeI | null
20 | ) => {
21 | if (value === null) {
22 | dispatch(
23 | applyFiltersReducer({
24 | category: undefined,
25 | subcategory: undefined,
26 | brand: undefined,
27 | })
28 | );
29 | } else if (typeof value == "string") {
30 | dispatch(
31 | applyFiltersReducer({
32 | category: value,
33 | subcategory: undefined,
34 | brand: undefined,
35 | })
36 | );
37 | } else {
38 | dispatch(
39 | applyFiltersReducer({
40 | category: value.value,
41 | subcategory: undefined,
42 | brand: undefined,
43 | })
44 | );
45 | }
46 | };
47 | return (
48 | {
51 | return {
52 | label: item.name,
53 | value: item.name,
54 | };
55 | })}
56 | label={"Select category"}
57 | disabled={false}
58 | defaultValue={category}
59 | />
60 | );
61 | };
62 |
63 | export default memo(CategoryFilter);
64 |
--------------------------------------------------------------------------------
/src/components/ProductCartCalculation/index.tsx:
--------------------------------------------------------------------------------
1 | import { Stack, Typography } from "@mui/material";
2 | import React from "react";
3 |
4 | interface componentInterface {
5 | price: number;
6 | productCount: number;
7 | }
8 | const ProductCartCalculation: React.FC = ({
9 | price,
10 | productCount,
11 | }) => {
12 | return (
13 |
19 |
20 |
27 | Per Item Price:{" "}
28 |
29 |
36 | ${price?.toFixed(2)}
37 |
38 | /
39 |
46 | No of Item:
47 |
48 |
55 | {productCount}
56 |
57 |
58 |
59 |
60 |
67 | Total:
68 |
69 |
76 | {productCount * +price?.toFixed(2)}
77 |
78 |
79 |
80 | );
81 | };
82 |
83 | export default ProductCartCalculation;
84 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const htmlWebpackPlugin = require("html-webpack-plugin");
3 | const webpack = require("webpack");
4 |
5 | // dotenv configuration settings
6 | const dotenv = require("dotenv").config({ path: __dirname + "/.env" });
7 | const isProduction = process.env.NODE_ENV === "production";
8 |
9 | module.exports = {
10 | resolve: {
11 | extensions: [".js", ".jsx", ".ts", ".tsx"],
12 | },
13 | entry: "./src/index.tsx",
14 | output: {
15 | path: path.resolve(__dirname, "dist"),
16 | },
17 | plugins: [
18 | new htmlWebpackPlugin({
19 | template: "./public/index.html",
20 | }),
21 | new webpack.DefinePlugin({
22 | "process.env": JSON.stringify({
23 | ...dotenv.parsed,
24 | NODE_ENV: JSON.stringify(isProduction ? "production" : "development"),
25 | }),
26 | }),
27 | ],
28 | module: {
29 | rules: [
30 | {
31 | test: /.(js|jsx|ts|tsx)$/,
32 | exclude: /node_modules/,
33 | use: {
34 | loader: "babel-loader",
35 | options: {
36 | presets: [
37 | "@babel/preset-env",
38 | "@babel/preset-react",
39 | "@babel/preset-typescript",
40 | ],
41 | },
42 | },
43 | },
44 | {
45 | test: /\.(css|scss)$/,
46 | use: ["style-loader", "css-loader", "sass-loader"],
47 | },
48 | {
49 | test: /\.(png|jpe?g|gif|svg)$/i,
50 | use: [
51 | {
52 | loader: "file-loader",
53 | options: {
54 | name: "[name].[ext]",
55 | outputPath: "images",
56 | },
57 | },
58 | ],
59 | },
60 | {
61 | test: /\.(woff|woff2|eot|ttf|otf)$/i,
62 | use: [
63 | {
64 | loader: "file-loader",
65 | options: {
66 | name: "[name].[ext]",
67 | outputPath: "fonts",
68 | },
69 | },
70 | ],
71 | },
72 | ],
73 | },
74 | devServer: {
75 | port: 7000,
76 | open: true,
77 | hot: true,
78 | },
79 | };
80 |
--------------------------------------------------------------------------------
/src/components/SubCategoryFilter/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
4 | import { filterSliceInitialStateI } from "../../Redux/FilterSlice/modules/initialState";
5 | import { priceRangeI } from "../../utils/constants";
6 | import { applyFiltersReducer } from "../../Redux/FilterSlice/slice";
7 | import SelectFilter from "../SelectFilter";
8 | import { CategoryLists } from "../../utils/CatSubcatBrands";
9 |
10 | const SubCategoryFilter: React.FC = () => {
11 | const { subcategory, category } = useSelector(
12 | (store) => store.filterSlice
13 | ) as filterSliceInitialStateI;
14 |
15 | const dispatch = useDispatch();
16 |
17 | const handleApplyCatSubCate = (
18 | event: React.SyntheticEvent,
19 | value: string | priceRangeI | null
20 | ) => {
21 | if (value == null) {
22 | dispatch(
23 | applyFiltersReducer({
24 | subcategory: undefined,
25 | brand : undefined
26 | })
27 | );
28 | } else if (typeof value == "string") {
29 | dispatch(
30 | applyFiltersReducer({
31 | subcategory: value,
32 | brand : undefined
33 | })
34 | );
35 | } else {
36 | dispatch(
37 | applyFiltersReducer({
38 | subcategory: value.value,
39 | brand : undefined
40 | })
41 | );
42 | }
43 | };
44 |
45 | const SelectedCategory = CategoryLists.find(
46 | (item) => item.name == category
47 | ) || {
48 | name: "none",
49 | subCategories: [],
50 | };
51 |
52 | const options: { label: string; value: string }[] =
53 | SelectedCategory.subCategories.map((item) => {
54 | return {
55 | label: item.name,
56 | value: item.name,
57 | };
58 | });
59 |
60 | return (
61 |
68 | );
69 | };
70 |
71 | export default memo(SubCategoryFilter);
72 |
--------------------------------------------------------------------------------
/src/components/MinMaxPriceFilter/index.tsx:
--------------------------------------------------------------------------------
1 | import Stack from "@mui/material/Stack";
2 | import Typography from "@mui/material/Typography";
3 | import React, { memo } from "react";
4 | import TypeAndSelect from "../TypeAndSelect";
5 | import {
6 | maxPriceRange,
7 | minPriceRange,
8 | priceRangeI,
9 | } from "../../utils/constants";
10 | import { useDispatch, useSelector } from "react-redux";
11 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
12 | import { filterSliceInitialStateI } from "../../Redux/FilterSlice/modules/initialState";
13 | import { applyFiltersReducer } from "../../Redux/FilterSlice/slice";
14 |
15 | const MinMaxPriceFilter: React.FC = () => {
16 | const { minPrice, maxPrice } = useSelector(
17 | (store) => store.filterSlice
18 | ) as filterSliceInitialStateI;
19 |
20 | const dispatch = useDispatch();
21 |
22 | const handleOnChange = (
23 | event: React.SyntheticEvent,
24 | value: string | priceRangeI | null,
25 | key: "minPrice" | "maxPrice"
26 | ) => {
27 | if (value == null) {
28 | dispatch(
29 | applyFiltersReducer({
30 | [key]: undefined,
31 | })
32 | );
33 | } else if (typeof value == "string") {
34 | dispatch(
35 | applyFiltersReducer({
36 | [key]: value,
37 | })
38 | );
39 | } else {
40 | dispatch(
41 | applyFiltersReducer({
42 | [key]: value.value,
43 | })
44 | );
45 | }
46 | };
47 |
48 | return (
49 |
50 | handleOnChange(event, value, "minPrice")}
54 | options={minPriceRange}
55 | />
56 |
57 | to
58 |
59 | handleOnChange(event, value, "maxPrice")}
63 | options={maxPriceRange}
64 | />
65 |
66 | );
67 | };
68 |
69 | export default memo(MinMaxPriceFilter);
70 |
--------------------------------------------------------------------------------
/src/components/UserMenu/index.tsx:
--------------------------------------------------------------------------------
1 | import { Box, Button, Menu, MenuItem, Stack, Typography } from "@mui/material";
2 | import React, { useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import AccountCircleIcon from "@mui/icons-material/AccountCircle";
5 | import { useDispatch } from "react-redux";
6 | import { AppDispatch } from "../../Redux/ReduxStore";
7 | import { logoutReducer } from "../../Redux/UserSlice/slice";
8 | import { clearCartReducer } from "../../Redux/CartSlice/slice";
9 | import { clearOrderReducer } from "../../Redux/OrderSlice/slice";
10 |
11 | const UserMenu = () => {
12 | const [anchorEl, setAnchorEl] = useState(null);
13 | const open = Boolean(anchorEl);
14 | const handleClick = (event: React.MouseEvent) => {
15 | setAnchorEl(event.currentTarget);
16 | };
17 |
18 | const route = useNavigate();
19 | const dispatch = useDispatch();
20 | const handleClose = () => {
21 | setAnchorEl(null);
22 | };
23 | const handleLogin = () => {
24 | route("/auth", {
25 | // replace: true,
26 | });
27 | handleClose();
28 | };
29 | const handleLogout = () => {
30 | dispatch(logoutReducer());
31 | dispatch(clearCartReducer());
32 | dispatch(clearOrderReducer());
33 | handleClose();
34 | };
35 | return (
36 |
37 |
43 |
52 | User
53 |
54 |
60 |
61 |
74 |
75 | );
76 | };
77 |
78 | export default UserMenu;
79 |
--------------------------------------------------------------------------------
/src/components/RattingFilter/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import TypeAndSelect from "../TypeAndSelect";
3 | import { RattingRange, priceRangeI } from "../../utils/constants";
4 | import { useDispatch, useSelector } from "react-redux";
5 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
6 | import { filterSliceInitialStateI } from "../../Redux/FilterSlice/modules/initialState";
7 | import Stack from "@mui/material/Stack";
8 | import { applyFiltersReducer } from "../../Redux/FilterSlice/slice";
9 | import SelectFilter from "../SelectFilter";
10 |
11 | const RattingFilter = () => {
12 | const { averageRating } = useSelector(
13 | (store) => store.filterSlice
14 | ) as filterSliceInitialStateI;
15 |
16 | const dispatch = useDispatch();
17 |
18 | const handleOnChange = (
19 | event: React.SyntheticEvent,
20 | value: string | priceRangeI | null
21 | ) => {
22 | if (value == null) {
23 | dispatch(
24 | applyFiltersReducer({
25 | averageRating: undefined,
26 | })
27 | );
28 | } else if (typeof value == "string") {
29 | dispatch(
30 | applyFiltersReducer({
31 | averageRating: parseFloat(value),
32 | })
33 | );
34 | } else {
35 | dispatch(
36 | applyFiltersReducer({
37 | averageRating: parseFloat(value.value),
38 | })
39 | );
40 | }
41 | };
42 |
43 | const handleApplyCatSubCate = (
44 | event: React.SyntheticEvent,
45 | value: string | priceRangeI | null
46 | ) => {
47 | if (value === null) {
48 | dispatch(
49 | applyFiltersReducer({
50 | avgtype: undefined,
51 | })
52 | );
53 | } else if (typeof value == "string") {
54 | dispatch(
55 | applyFiltersReducer({
56 | avgtype: value,
57 | })
58 | );
59 | } else {
60 | dispatch(
61 | applyFiltersReducer({
62 | avgtype: value.value,
63 | })
64 | );
65 | }
66 | };
67 | return (
68 |
69 |
85 |
91 |
92 | );
93 | };
94 |
95 | export default RattingFilter;
96 |
--------------------------------------------------------------------------------
/src/components/Navbar/index.tsx:
--------------------------------------------------------------------------------
1 | import { Box, Stack, TextField, Typography } from "@mui/material";
2 | import React from "react";
3 | import Logo from "../Logo";
4 | import UserMenu from "../UserMenu";
5 | import ShoppingCartIcon from "@mui/icons-material/ShoppingCart";
6 | import Hamburgur from "../Hamburgur";
7 | import { useNavigate } from "react-router-dom";
8 |
9 | const Navbar: React.FC = () => {
10 | const router = useNavigate();
11 |
12 | const handleCartRoute = () => {
13 | router("/cart");
14 | };
15 | return (
16 |
23 |
36 |
42 |
43 |
53 |
66 |
67 |
68 |
69 |
81 |
90 | Cart
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | );
101 | };
102 |
103 | export default Navbar;
104 |
--------------------------------------------------------------------------------
/src/components/Hamburgur/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Box,
3 | Button,
4 | Divider,
5 | List,
6 | ListItem,
7 | ListItemButton,
8 | ListItemIcon,
9 | ListItemText,
10 | Stack,
11 | SwipeableDrawer,
12 | TextField,
13 | } from "@mui/material";
14 | import React, { useState } from "react";
15 | import MenuIcon from "@mui/icons-material/Menu";
16 | import ShoppingCartIcon from "@mui/icons-material/ShoppingCart";
17 | import AccountCircleIcon from "@mui/icons-material/AccountCircle";
18 | import { useNavigate } from "react-router-dom";
19 | const hamburgerPaths = [
20 | {
21 | name: "User",
22 | Icon: ,
23 | path: "/auth",
24 | },
25 | {
26 | name: "cart",
27 | Icon: ,
28 | path: "/cart",
29 | },
30 | ];
31 | const Hamburgur: React.FC = () => {
32 | const [isOpen, setIsOpen] = useState(false);
33 | const toggleDrawer = (bool: boolean) => {
34 | setIsOpen((prev) => (prev = bool));
35 | };
36 | const Router = useNavigate();
37 | const handleRoute = (route: string) => {
38 | Router(route);
39 | toggleDrawer(false);
40 | };
41 | return (
42 |
48 |
55 | toggleDrawer(false)}
59 | onOpen={() => toggleDrawer(true)}
60 | sx={{
61 | width: "100%",
62 | height: "100%",
63 | }}
64 | >
65 | todo need to work here
66 |
74 |
80 | {hamburgerPaths.map((text, index) => (
81 |
82 |
83 | {text.Icon}
84 | handleRoute(text.path)}
86 | primary={text.name}
87 | />
88 |
89 |
90 | ))}
91 |
92 |
93 |
107 |
108 |
109 |
110 | );
111 | };
112 |
113 | export default Hamburgur;
114 |
115 | {
116 | /* */
121 | }
122 |
--------------------------------------------------------------------------------
/src/components/SignInPage/index.tsx:
--------------------------------------------------------------------------------
1 | import Typography from "@mui/material/Typography";
2 | import TextField from "@mui/material/TextField";
3 | import Link from "@mui/material/Link";
4 | import Grid from "@mui/material/Grid";
5 | import FormControlLabel from "@mui/material/FormControlLabel";
6 | import Container from "@mui/material/Container";
7 | import Checkbox from "@mui/material/Checkbox";
8 | import Button from "@mui/material/Button";
9 | import Box from "@mui/material/Box";
10 | import Avatar from "@mui/material/Avatar";
11 | import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
12 | import React, { memo } from "react";
13 | import { useDispatch } from "react-redux";
14 | import { AppDispatch } from "../../Redux/ReduxStore";
15 | import {
16 | setUserDataReducer,
17 | setUserErrorReducer,
18 | setUserLoadingReducer,
19 | } from "../../Redux/UserSlice/slice";
20 | import { SignInApiService, apiResponse } from "../../api/apiService";
21 | import { useNavigate } from "react-router-dom";
22 |
23 | interface pageProps {
24 | toggle: () => void;
25 | }
26 |
27 | const SignInPage: React.FC = ({ toggle }) => {
28 | const dispatch = useDispatch();
29 |
30 | const route = useNavigate();
31 |
32 | const handleSubmit = async (event: React.FormEvent) => {
33 | event.preventDefault();
34 | const data = new FormData(event.currentTarget);
35 |
36 | if (!data.get("email")) {
37 | alert("Please Enter Email");
38 | return;
39 | }
40 | if (!data.get("password")) {
41 | alert("Please Enter password");
42 | return;
43 | }
44 |
45 | dispatch(setUserLoadingReducer());
46 | const response: apiResponse = await SignInApiService({
47 | email: data.get("email") as string,
48 | password: data.get("password") as string,
49 | });
50 | if (response.status) {
51 | dispatch(setUserDataReducer(response));
52 | route("/");
53 | } else {
54 | dispatch(setUserErrorReducer(response));
55 | }
56 | };
57 |
58 | return (
59 |
60 |
68 |
69 |
70 |
71 |
72 | Sign in
73 |
74 |
75 |
85 |
95 | }
97 | label="Remember me"
98 | />
99 |
107 |
108 |
109 | Forgot password?
110 |
111 |
112 |
113 | {"Don't have an account? Sign Up"}
114 |
115 |
116 |
117 |
118 |
119 |
120 | );
121 | };
122 |
123 | export default memo(SignInPage);
124 |
--------------------------------------------------------------------------------
/src/components/CartAndOrderProduct/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, useEffect } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
4 | import { productSliceInitialStateI } from "../../Redux/ProductsSlice/modules/initialState";
5 | import { GetFilteredDataApiService, apiResponse } from "../../api/apiService";
6 | import {
7 | Card,
8 | CardContent,
9 | CardMedia,
10 | Typography,
11 | Grid,
12 | Stack,
13 | } from "@mui/material";
14 | import ProductCartCalculation from "../ProductCartCalculation";
15 | import { addToProductCacheReducer } from "../../Redux/ProductsSlice/slice";
16 | import CardOrderDetail from "../CardOrderDetail";
17 |
18 | interface pageProps {
19 | productCount: number;
20 | productId: string;
21 | productTotal: number;
22 | OrderId?: string;
23 | ExpectedDelivery?: string;
24 | type: "Cart" | "Order";
25 | }
26 | let isFirst: boolean = true;
27 | const CartAndOrderProduct: React.FC = ({
28 | type,
29 | productCount,
30 | productId,
31 | ExpectedDelivery,
32 | }) => {
33 | const { productCache } = useSelector(
34 | (store) => store.productSlice
35 | ) as productSliceInitialStateI;
36 | const dispatch = useDispatch();
37 |
38 | useEffect(() => {
39 | isFirst &&
40 | (async function () {
41 | const response: apiResponse = await GetFilteredDataApiService({
42 | _id: productId,
43 | });
44 | isFirst = false
45 | dispatch(addToProductCacheReducer(response.data[0]));
46 | })();
47 | }, []);
48 |
49 | return (
50 |
51 |
52 |
57 |
66 |
79 |
80 |
81 |
82 |
83 | {productCache[productId]?.name}
84 |
85 |
86 | {productCache[productId]?.description}
87 |
88 |
89 | Category: {productCache[productId]?.category} | Subcategory:{" "}
90 | {productCache[productId]?.subcategory}
91 |
92 |
93 | Brand: {productCache[productId]?.brand}
94 |
95 |
96 | Average Rating: {productCache[productId]?.averageRating} (
97 | {productCache[productId]?.totalRatings} ratings)
98 |
99 |
100 | {type == "Order" ? (
101 |
102 | ) : (
103 |
107 | )}
108 |
109 |
110 |
111 |
112 | );
113 | };
114 |
115 | export default memo(CartAndOrderProduct);
116 |
--------------------------------------------------------------------------------
/src/components/PaymentForm/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import Typography from "@mui/material/Typography";
3 | import Grid from "@mui/material/Grid";
4 | import TextField from "@mui/material/TextField";
5 | import FormControlLabel from "@mui/material/FormControlLabel";
6 | import Checkbox from "@mui/material/Checkbox";
7 | import { useDispatch, useSelector } from "react-redux";
8 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
9 | import {
10 | checkOuSliceInitialStateInterface,
11 | paymentsInterface,
12 | } from "../../Redux/CheckOutSlice/module/intialState";
13 | import { onChangeCheckoutReducer } from "../../Redux/CheckOutSlice/slice";
14 |
15 | export default function PaymentForm() {
16 | const { payment } = useSelector(
17 | (store) => store.CheckoutSlice
18 | ) as checkOuSliceInitialStateInterface;
19 | const { ExpiryDate, cardNumber, cvv, cardName } = payment;
20 |
21 | const dispatch = useDispatch();
22 |
23 | const onChange = ({
24 | key,
25 | value,
26 | }: {
27 | key: keyof paymentsInterface;
28 | value: string;
29 | }) => {
30 | dispatch(
31 | onChangeCheckoutReducer({
32 | payment: {
33 | ...payment,
34 | [key]: value,
35 | },
36 | })
37 | );
38 | };
39 | return (
40 |
41 |
42 | Payment method
43 |
44 |
45 |
46 | ) =>
54 | onChange({
55 | key: "cardName",
56 | value: event.target.value,
57 | })
58 | }
59 | defaultValue={cardName}
60 | />
61 |
62 |
63 | ) =>
71 | onChange({
72 | key: "cardNumber",
73 | value: event.target.value,
74 | })
75 | }
76 | defaultValue={cardNumber}
77 | />
78 |
79 |
80 | ) =>
88 | onChange({
89 | key: "ExpiryDate",
90 | value: event.target.value,
91 | })
92 | }
93 | defaultValue={ExpiryDate}
94 | />
95 |
96 |
97 | ) =>
106 | onChange({
107 | key: "cvv",
108 | value: event.target.value,
109 | })
110 | }
111 | defaultValue={cvv}
112 | />
113 |
114 |
115 | }
117 | label="Remember credit card details for next time"
118 | />
119 |
120 |
121 |
122 | );
123 | }
124 |
--------------------------------------------------------------------------------
/src/components/Review/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Typography from "@mui/material/Typography";
3 | import List from "@mui/material/List";
4 | import ListItem from "@mui/material/ListItem";
5 | import ListItemText from "@mui/material/ListItemText";
6 | import Grid from "@mui/material/Grid";
7 | import { useSelector } from "react-redux";
8 | import { RootState } from "../../Redux/ReduxStore";
9 | import {
10 | cartDataInterface,
11 | cartSliceInitialStateInterface,
12 | } from "../../Redux/CartSlice/module/initialState";
13 | import {
14 | productCardI,
15 | productSliceInitialStateI,
16 | } from "../../Redux/ProductsSlice/modules/initialState";
17 | import { checkOuSliceInitialStateInterface } from "../../Redux/CheckOutSlice/module/intialState";
18 |
19 | export default function Review() {
20 | const { address, payment } = useSelector(
21 | (store) => store.CheckoutSlice
22 | ) as checkOuSliceInitialStateInterface;
23 | const { addressline, city, country, firstName, lastName, state, zipcode } =
24 | address;
25 | const { ExpiryDate, cardNumber, cardName } = payment;
26 |
27 | const { cartData } = useSelector(
28 | (store) => store.cartSlice
29 | ) as cartSliceInitialStateInterface;
30 |
31 | const { productCache } = useSelector(
32 | (store) => store.productSlice
33 | ) as productSliceInitialStateI;
34 |
35 | return (
36 |
37 |
38 | Order summary
39 |
40 |
41 | {cartData.map(({ productId, productCount }: cartDataInterface) => (
42 |
43 |
50 |
51 | {" "}
52 | {productCount} * {productCache[productId]?.price}
53 |
54 |
55 | ))}
56 |
57 |
58 |
62 | {/* count total ammount */}
63 | {cartData.reduce((_, { productCount, productTotal }) => {
64 | return _ + productCount * productTotal;
65 | }, 0)}
66 |
67 |
68 |
69 |
70 |
71 |
72 | Shipping
73 |
74 | {`${firstName} ${lastName}`}
75 |
76 | {[addressline, city, state, zipcode, country].join(", ")}
77 |
78 |
79 |
80 |
81 | Payment details
82 |
83 |
84 |
85 | Card type
86 |
87 |
88 | Visa
89 |
90 |
91 |
92 |
93 | Card holder
94 |
95 |
96 | {cardName}
97 |
98 |
99 |
100 |
101 | Card number
102 |
103 |
104 | {cardNumber}
105 |
106 |
107 |
108 |
109 | Expiry date
110 |
111 |
112 | {ExpiryDate}
113 |
114 |
115 |
116 |
117 |
118 | );
119 | }
120 |
--------------------------------------------------------------------------------
/src/components/SignUpPage/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Avatar,
3 | Box,
4 | Button,
5 | Checkbox,
6 | Container,
7 | FormControlLabel,
8 | Grid,
9 | TextField,
10 | Typography,
11 | Link,
12 | } from "@mui/material";
13 | import React from "react";
14 | import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
15 | import { useDispatch } from "react-redux";
16 | import { AppDispatch } from "../../Redux/ReduxStore";
17 | import {
18 | setUserDataReducer,
19 | setUserErrorReducer,
20 | setUserLoadingReducer,
21 | } from "../../Redux/UserSlice/slice";
22 | import { SignUpApiService, apiResponse } from "../../api/apiService";
23 | import { useNavigate } from "react-router-dom";
24 |
25 | interface pageProps {
26 | toggle: () => void;
27 | }
28 |
29 | const SignUpPage: React.FC = ({ toggle }) => {
30 | const dispatch = useDispatch();
31 | const route = useNavigate();
32 |
33 | const handleSubmit = async (event: React.FormEvent) => {
34 | event.preventDefault();
35 | const data = new FormData(event.currentTarget);
36 |
37 | if (!data.get("email")) {
38 | alert("Please Enter Email");
39 | return;
40 | }
41 | if (!data.get("password")) {
42 | alert("Please Enter password");
43 | return;
44 | }
45 | if (!data.get("firstName")) {
46 | alert("Please Enter firstName");
47 | return;
48 | }
49 | if (!data.get("lastName")) {
50 | alert("Please Enter lastName");
51 | return;
52 | }
53 |
54 | dispatch(setUserLoadingReducer());
55 |
56 | const response: apiResponse = await SignUpApiService({
57 | email: data.get("email") as string,
58 | password: data.get("password") as string,
59 | name: `${data.get("firstName") as string} ${
60 | data.get("lastName") as string
61 | }`,
62 | });
63 |
64 | if (response.status) {
65 | dispatch(setUserDataReducer(response));
66 | route("/");
67 | } else {
68 | dispatch(setUserErrorReducer(response));
69 | }
70 | };
71 |
72 | return (
73 |
74 |
82 |
83 |
84 |
85 |
86 | Sign up
87 |
88 |
89 |
90 |
91 |
100 |
101 |
102 |
110 |
111 |
112 |
120 |
121 |
122 |
131 |
132 |
133 | }
135 | label="I want to receive inspiration, marketing promotions and updates via email."
136 | />
137 |
138 |
139 |
147 |
148 |
149 |
150 | Already have an account? Sign in
151 |
152 |
153 |
154 |
155 |
156 |
157 | );
158 | };
159 |
160 | export default SignUpPage;
161 |
--------------------------------------------------------------------------------
/src/components/ProductCard/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import IconButton from "@mui/material/IconButton";
3 | import Button from "@mui/material/Button";
4 | import Typography from "@mui/material/Typography";
5 | import CardMedia from "@mui/material/CardMedia";
6 | import CardContent from "@mui/material/CardContent";
7 | import CardActions from "@mui/material/CardActions";
8 | import CardActionArea from "@mui/material/CardActionArea";
9 | import Card from "@mui/material/Card";
10 | import AddShoppingCartIcon from "@mui/icons-material/AddShoppingCart";
11 | import RemoveIcon from "@mui/icons-material/Remove";
12 | import AddIcon from "@mui/icons-material/Add";
13 | import { productCardI } from "../../Redux/ProductsSlice/modules/initialState";
14 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
15 | import { useDispatch, useSelector } from "react-redux";
16 | import {
17 | setCartDataReducer,
18 | setCartErrorReducer,
19 | setCartLoadingReducer,
20 | } from "../../Redux/CartSlice/slice";
21 | import { AddtoCartApiService, apiResponse } from "../../api/apiService";
22 | import { userSliceInitialStateInterface } from "../../Redux/UserSlice/module/initialState";
23 | import { useNavigate } from "react-router-dom";
24 |
25 | interface componentInterface {
26 | product: productCardI;
27 | productCount: number;
28 | }
29 |
30 | const ProductCard: React.FC = ({
31 | product,
32 | productCount,
33 | }) => {
34 | const route = useNavigate();
35 | const { name, price, image, averageRating, _id } = product;
36 |
37 | const { userData } = useSelector(
38 | (store) => store.UserSlice
39 | ) as userSliceInitialStateInterface;
40 |
41 | const dispatch = useDispatch();
42 |
43 | const handleDecrement = async () => {
44 | if (!userData.token) {
45 | route("/auth");
46 | return;
47 | }
48 | dispatch(setCartLoadingReducer());
49 | const response: apiResponse = await AddtoCartApiService({
50 | payload: {
51 | productCount: productCount - 1,
52 | productId: _id,
53 | productTotal: (productCount + 1) * price,
54 | userId: userData.userId,
55 | },
56 | headers: {
57 | Authorization: userData.token,
58 | },
59 | });
60 | if (response.status) {
61 | dispatch(setCartDataReducer(response));
62 | } else {
63 | dispatch(setCartErrorReducer(response));
64 | }
65 | };
66 | const handleIncrement = async () => {
67 | if (!userData.token) {
68 | route("/auth");
69 | return;
70 | }
71 |
72 | dispatch(setCartLoadingReducer());
73 | const response: apiResponse = await AddtoCartApiService({
74 | payload: {
75 | productCount: productCount + 1,
76 | productId: _id,
77 | productTotal: (productCount + 1) * price,
78 | userId: userData.userId,
79 | },
80 | headers: {
81 | Authorization: userData.token,
82 | },
83 | });
84 | if (response.status) {
85 | dispatch(setCartDataReducer(response));
86 | } else {
87 | dispatch(setCartErrorReducer(response));
88 | }
89 | };
90 |
91 | return (
92 |
100 |
101 |
114 |
115 |
116 | {name}
117 |
118 | Price: ${price.toFixed(2)}
119 |
120 | Average Rating: {averageRating}
121 |
122 |
123 |
124 |
125 | {productCount > 0 ? (
126 | <>
127 |
128 |
129 |
130 | {productCount}
131 |
132 |
133 |
134 | >
135 | ) : (
136 | }
140 | onClick={handleIncrement}
141 | >
142 | Add to Cart
143 |
144 | )}
145 |
146 |
147 | );
148 | };
149 |
150 | export default memo(ProductCard);
151 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense, useEffect } from "react";
2 | import "./app.css";
3 | import Stack from "@mui/material/Stack";
4 | import { Outlet, createHashRouter } from "react-router-dom";
5 |
6 | const HomePage = lazy(() => import("./View/Home"));
7 | const Authentication = lazy(() => import("./View/Auth"));
8 | const CartAndCheckout = lazy(() => import("./View/CartAndCheckOut"));
9 | const PrivateRoute = lazy(() => import("./HOC"));
10 | const Navbar = lazy(() => import("./components/Navbar"));
11 |
12 | import { useDispatch, useSelector } from "react-redux";
13 | import { AppDispatch, RootState } from "./Redux/ReduxStore";
14 | import { filterSliceInitialStateI } from "./Redux/FilterSlice/modules/initialState";
15 | import {
16 | setProductDataReducer,
17 | setProductErrorReducer,
18 | setProductLoadingReducer,
19 | } from "./Redux/ProductsSlice/slice";
20 | import {
21 | GetCartDataApiService,
22 | GetFilteredDataApiService,
23 | apiResponse,
24 | getOrdersDataApiService,
25 | } from "./api/apiService";
26 | import {
27 | setCartDataReducer,
28 | setCartErrorReducer,
29 | setCartLoadingReducer,
30 | } from "./Redux/CartSlice/slice";
31 | import {
32 | setOrderErrorReducer,
33 | setOrderLoadingReducer,
34 | setOrdertDataReducer,
35 | } from "./Redux/OrderSlice/slice";
36 | import { userSliceInitialStateInterface } from "./Redux/UserSlice/module/initialState";
37 |
38 | let isfirst: boolean = true;
39 |
40 | const App: React.FC = () => {
41 | const dispatch = useDispatch();
42 | const { userData } = useSelector(
43 | (store) => store.UserSlice
44 | ) as userSliceInitialStateInterface;
45 |
46 | const {
47 | averageRating,
48 | avgtype,
49 | brand,
50 | category,
51 | maxPrice,
52 | minPrice,
53 | name,
54 | querry,
55 | subcategory,
56 | } = useSelector(
57 | (store) => store.filterSlice
58 | ) as filterSliceInitialStateI;
59 |
60 | useEffect(() => {
61 | (async function () {
62 | dispatch(setProductLoadingReducer());
63 |
64 | const payload = isfirst
65 | ? undefined
66 | : {
67 | averageRating,
68 | avgtype,
69 | brand,
70 | category,
71 | maxPrice,
72 | minPrice,
73 | name,
74 | querry,
75 | subcategory,
76 | };
77 |
78 | isfirst = false;
79 | const response: apiResponse = await GetFilteredDataApiService(payload);
80 | if (response.status) {
81 | dispatch(setProductDataReducer(response));
82 | } else {
83 | dispatch(setProductErrorReducer(response));
84 | }
85 | })();
86 | }, [
87 | averageRating,
88 | avgtype,
89 | brand,
90 | category,
91 | maxPrice,
92 | minPrice,
93 | name,
94 | querry,
95 | subcategory,
96 | ]);
97 |
98 | useEffect(() => {
99 | userData.token &&
100 | (async function () {
101 | dispatch(setCartLoadingReducer());
102 | const response: apiResponse = await GetCartDataApiService({
103 | userId: userData.userId,
104 | headers: {
105 | Authorization: userData.token,
106 | },
107 | });
108 | if (response.status) {
109 | dispatch(setCartDataReducer(response));
110 | } else {
111 | dispatch(setCartErrorReducer(response));
112 | }
113 | })();
114 | }, []);
115 |
116 | useEffect(() => {
117 | // getOrder
118 | userData.token &&
119 | (async function () {
120 | dispatch(setOrderLoadingReducer());
121 |
122 | const response: apiResponse = await getOrdersDataApiService({
123 | userId: userData.userId,
124 | headers: {
125 | Authorization: userData.token,
126 | },
127 | });
128 |
129 | if (response.status) {
130 | dispatch(setOrdertDataReducer(response));
131 | } else {
132 | dispatch(setOrderErrorReducer(response));
133 | }
134 | })();
135 | }, []);
136 |
137 | return (
138 |
144 |
145 |
146 |
147 | );
148 | };
149 |
150 | const AppRoute = createHashRouter([
151 | {
152 | path: "/",
153 | element: ,
154 | children: [
155 | {
156 | path: "/",
157 | element: (
158 |
159 | {" "}
160 |
161 |
162 | ),
163 | },
164 |
165 | {
166 | path: "/cart",
167 | element: (
168 |
169 |
170 | {" "}
171 |
172 |
173 |
174 | ),
175 | },
176 | ],
177 | },
178 | {
179 | path: "/auth",
180 | element: (
181 |
182 | {" "}
183 |
184 |
185 | ),
186 | },
187 | ]);
188 |
189 | export default AppRoute;
190 |
--------------------------------------------------------------------------------
/src/components/CheckoutData/index.tsx:
--------------------------------------------------------------------------------
1 | import Typography from "@mui/material/Typography"
2 | import Stepper from "@mui/material/Stepper"
3 | import StepLabel from "@mui/material/StepLabel"
4 | import Step from "@mui/material/Step"
5 | import Stack from "@mui/material/Stack"
6 | import Button from "@mui/material/Button"
7 | import Box from "@mui/material/Box"
8 |
9 | import React, { useState } from "react";
10 | import AddressForm from "../AddressForm";
11 | import PaymentForm from "../PaymentForm";
12 | import Review from "../Review";
13 | import { cartSliceInitialStateInterface } from "../../Redux/CartSlice/module/initialState";
14 | import { useDispatch, useSelector } from "react-redux";
15 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
16 | import { OrderedProductInterface } from "../../Redux/OrderSlice/module/initialState";
17 | import {
18 | setOrderErrorReducer,
19 | setOrderLoadingReducer,
20 | setOrdertDataReducer,
21 | } from "../../Redux/OrderSlice/slice";
22 | import {
23 | ClearCartDataApiService,
24 | OrderProductApiService,
25 | apiResponse,
26 | } from "../../api/apiService";
27 | import {
28 | setCartDataReducer,
29 | setCartErrorReducer,
30 | setCartLoadingReducer,
31 | } from "../../Redux/CartSlice/slice";
32 | import { steps } from "../../utils/constants";
33 | import { userSliceInitialStateInterface } from "../../Redux/UserSlice/module/initialState";
34 |
35 | function getStepContent(step: number) {
36 | switch (step) {
37 | case 0:
38 | return ;
39 | case 1:
40 | return ;
41 | case 2:
42 | return ;
43 | default:
44 | throw new Error("Unknown step");
45 | }
46 | }
47 |
48 | const CheckoutData: React.FC = () => {
49 | const [activeStep, setActiveStep] = useState(0);
50 | const [orderID, setorderID] = useState("");
51 |
52 | const { cartData } = useSelector(
53 | (store) => store.cartSlice
54 | ) as cartSliceInitialStateInterface;
55 |
56 | const { userData } = useSelector(
57 | (store) => store.UserSlice
58 | ) as userSliceInitialStateInterface;
59 |
60 | const dispatch = useDispatch();
61 |
62 | const handleCartOrder = async () => {
63 | const OrderId = `ORD_${Date.now()}`;
64 | setorderID(orderID);
65 | const ExpectedDelivery = `${Date.now() + 48 * 60 * 60 * 1000}`;
66 |
67 | const ProductDetails: OrderedProductInterface[] = cartData.map((cart) => ({
68 | ...cart,
69 | ExpectedDelivery,
70 | OrderId,
71 | }));
72 |
73 | dispatch(setOrderLoadingReducer());
74 | const response: apiResponse = await OrderProductApiService({
75 | payload: {
76 | userId: userData.userId,
77 | requestOrders: ProductDetails,
78 | },
79 | headers: {
80 | Authorization: userData.token,
81 | },
82 | });
83 | if (response.status) {
84 | dispatch(setOrdertDataReducer(response));
85 | } else {
86 | dispatch(setOrderErrorReducer(response));
87 | }
88 | // clear cart data as item purchaged
89 | dispatch(setCartLoadingReducer());
90 | const clearCartResponse: apiResponse = await ClearCartDataApiService({
91 | userId: userData.userId,
92 | headers: {
93 | Authorization: userData.token,
94 | },
95 | });
96 |
97 | if (clearCartResponse.status) {
98 | dispatch(setCartDataReducer(clearCartResponse));
99 | } else {
100 | dispatch(setCartErrorReducer(clearCartResponse));
101 | }
102 | };
103 | const handleNext = async () => {
104 | if (activeStep === steps.length - 1) {
105 | await handleCartOrder();
106 | }
107 | setActiveStep(activeStep + 1);
108 | };
109 |
110 | const handleBack = () => {
111 | setActiveStep(activeStep - 1);
112 | };
113 |
114 | return (
115 |
121 |
122 | Checkout
123 |
124 |
125 | {steps.map((label) => (
126 |
127 | {label}
128 |
129 | ))}
130 |
131 |
132 | {/* steps */}
133 |
134 | {activeStep === steps.length ? (
135 |
136 |
137 | Thank you for your order.
138 |
139 |
140 | Your order number is {orderID}. We have emailed your order
141 | confirmation, and will send you an update when your order has
142 | shipped.
143 |
144 |
145 | ) : (
146 |
147 | {getStepContent(activeStep)}
148 |
149 | {activeStep !== 0 && (
150 |
153 | )}
154 |
161 |
162 |
163 | )}
164 |
165 | );
166 | };
167 |
168 | export default CheckoutData;
169 |
--------------------------------------------------------------------------------
/src/api/apiService.ts:
--------------------------------------------------------------------------------
1 | import axios, { AxiosError, AxiosHeaders } from "axios";
2 | import { EnvProvider } from "../utils/EnvProvider";
3 | import { filterSliceInitialStateI } from "../Redux/FilterSlice/modules/initialState";
4 | import {
5 | cartDataInterface,
6 | cartSliceInitialStateInterface,
7 | } from "../Redux/CartSlice/module/initialState";
8 | import { OrderedProductInterface } from "../Redux/OrderSlice/module/initialState";
9 |
10 | const AxiosInstance = axios.create({
11 | baseURL: EnvProvider().SERVER_BASE_URL,
12 | headers: {
13 | "Content-Type": "application/json",
14 | },
15 | });
16 |
17 | export interface apiResponse {
18 | statusCode: number;
19 | message: string;
20 | status: boolean;
21 | data?: any;
22 | }
23 |
24 | export const GetFilteredDataApiService = async (
25 | payload: undefined | filterSliceInitialStateI
26 | ) => {
27 | let requestBody = {};
28 | if (payload !== undefined) requestBody = payload;
29 | try {
30 | const response: apiResponse = await AxiosInstance.post(
31 | "/products/filter",
32 | requestBody
33 | );
34 |
35 | if (!response.status) {
36 | throw response;
37 | }
38 | return response.data;
39 | } catch (err) {
40 | return (err as AxiosError).response?.data as apiResponse;
41 | }
42 | };
43 | // payload: cartDataInterface
44 | export const AddtoCartApiService = async (payload: {
45 | payload: cartDataInterface;
46 | headers: {
47 | Authorization: string;
48 | };
49 | }) => {
50 | let requestBody = {};
51 | if (payload !== undefined) requestBody = payload.payload;
52 | try {
53 | const response: apiResponse = await AxiosInstance.post(
54 | "/cart/add",
55 | requestBody,
56 | {
57 | headers: {
58 | ...payload.headers,
59 | },
60 | }
61 | );
62 |
63 | if (!response.status) {
64 | throw response;
65 | }
66 | return response.data;
67 | } catch (err) {
68 | return (err as AxiosError).response?.data as apiResponse;
69 | }
70 | };
71 | export const ClearCartDataApiService = async (payload: {
72 | userId: string;
73 | headers: {
74 | Authorization: string;
75 | };
76 | }) => {
77 | try {
78 | const response: apiResponse = await AxiosInstance.post(
79 | "/cart/clear",
80 | payload,
81 | {
82 | headers: {
83 | ...payload.headers,
84 | },
85 | }
86 | );
87 |
88 | if (!response.status) {
89 | throw response;
90 | }
91 | return response.data;
92 | } catch (err) {
93 | return (err as AxiosError).response?.data as apiResponse;
94 | }
95 | };
96 | export const GetCartDataApiService = async (payload: {
97 | userId: string;
98 | headers: {
99 | Authorization: string;
100 | };
101 | }) => {
102 | try {
103 | const response: apiResponse = await AxiosInstance.post(
104 | "/cart/getCartData",
105 | payload,
106 | {
107 | headers: {
108 | ...payload.headers,
109 | },
110 | }
111 | );
112 | if (!response.status) {
113 | throw response;
114 | }
115 | return response.data;
116 | } catch (err) {
117 | return (err as AxiosError).response?.data as apiResponse;
118 | }
119 | };
120 |
121 | export const OrderProductApiService = async (
122 | // orderData: OrderedProductInterface[]
123 |
124 | {
125 | payload,
126 | headers,
127 | }: {
128 | payload: {
129 | userId: string;
130 | requestOrders: OrderedProductInterface[];
131 | };
132 | headers: {
133 | Authorization: string;
134 | };
135 | }
136 | ) => {
137 | try {
138 | const response: apiResponse = await AxiosInstance.post(
139 | "/order/placeOrder",
140 | payload,
141 | {
142 | headers: {
143 | ...headers,
144 | },
145 | }
146 | );
147 | if (!response.status) {
148 | throw response;
149 | }
150 | return response.data;
151 | } catch (err) {
152 | return (err as AxiosError).response?.data as apiResponse;
153 | }
154 | };
155 | export const getOrdersDataApiService = async (payload: {
156 | userId: string;
157 | headers: {
158 | Authorization: string;
159 | };
160 | }) => {
161 | try {
162 | const response: apiResponse = await AxiosInstance.post(
163 | "/order/getOrder",
164 | payload,
165 | {
166 | headers: {
167 | ...payload.headers,
168 | },
169 | }
170 | );
171 | if (!response.status) {
172 | throw response;
173 | }
174 | return response.data;
175 | } catch (err) {
176 | return (err as AxiosError).response?.data as apiResponse;
177 | }
178 | };
179 | export const SignInApiService = async (requestBody: {
180 | email: string;
181 | password: string;
182 | }) => {
183 | try {
184 | const response: apiResponse = await AxiosInstance.post(
185 | "/user/login",
186 | requestBody
187 | );
188 | if (!response.status) {
189 | throw response;
190 | }
191 | return response.data;
192 | } catch (err) {
193 | return (err as AxiosError).response?.data as apiResponse;
194 | }
195 | };
196 | export const SignUpApiService = async (requestBody: {
197 | email: string;
198 | password: string;
199 | name: string;
200 | }) => {
201 | try {
202 | const response: apiResponse = await AxiosInstance.post(
203 | "/user/signup",
204 | requestBody
205 | );
206 | if (!response.status) {
207 | throw response;
208 | }
209 | return response.data;
210 | } catch (err) {
211 | return (err as AxiosError).response?.data as apiResponse;
212 | }
213 | };
214 |
--------------------------------------------------------------------------------
/src/components/AddressForm/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Grid from "@mui/material/Grid";
3 | import Typography from "@mui/material/Typography";
4 | import TextField from "@mui/material/TextField";
5 | import FormControlLabel from "@mui/material/FormControlLabel";
6 | import Checkbox from "@mui/material/Checkbox";
7 | import { useDispatch, useSelector } from "react-redux";
8 | import { AppDispatch, RootState } from "../../Redux/ReduxStore";
9 | import {
10 | AddressInterface,
11 | checkOuSliceInitialStateInterface,
12 | } from "../../Redux/CheckOutSlice/module/intialState";
13 | import { onChangeCheckoutReducer } from "../../Redux/CheckOutSlice/slice";
14 |
15 | export default function AddressForm() {
16 | const { address } = useSelector(
17 | (store) => store.CheckoutSlice
18 | ) as checkOuSliceInitialStateInterface;
19 |
20 | const dispatch = useDispatch();
21 | const { firstName, addressline, city, country, lastName, state, zipcode } =
22 | address;
23 |
24 | const onChange = ({
25 | key,
26 | value,
27 | }: {
28 | key: keyof AddressInterface;
29 | value: string;
30 | }) => {
31 | dispatch(
32 | onChangeCheckoutReducer({
33 | address: {
34 | ...address,
35 | [key]: value,
36 | },
37 | })
38 | );
39 | };
40 | return (
41 |
42 |
43 | Shipping address
44 |
45 |
46 |
47 | ) =>
57 | onChange({
58 | key: "firstName",
59 | value: event.target.value,
60 | })
61 | }
62 | />
63 |
64 |
65 | ) =>
75 | onChange({
76 | key: "lastName",
77 | value: event.target.value,
78 | })
79 | }
80 | />
81 |
82 |
83 | ) =>
93 | onChange({
94 | key: "addressline",
95 | value: event.target.value,
96 | })
97 | }
98 | />
99 |
100 |
101 | ) =>
111 | onChange({
112 | key: "city",
113 | value: event.target.value,
114 | })
115 | }
116 | />
117 |
118 |
119 | ) =>
127 | onChange({
128 | key: "state",
129 | value: event.target.value,
130 | })
131 | }
132 | />
133 |
134 |
135 | ) =>
145 | onChange({
146 | key: "zipcode",
147 | value: event.target.value,
148 | })
149 | }
150 | />
151 |
152 |
153 | ) =>
163 | onChange({
164 | key: "country",
165 | value: event.target.value,
166 | })
167 | }
168 | />
169 |
170 |
171 |
174 | }
175 | label="Use this address for payment details"
176 | />
177 |
178 |
179 |
180 | );
181 | }
182 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Enable incremental compilation */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | "jsx": "react-jsx", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 |
26 | /* Modules */
27 | "module": "commonjs", /* Specify what module code is generated. */
28 | // "rootDir": "./", /* Specify the root folder within your source files. */
29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
36 | // "resolveJsonModule": true, /* Enable importing .json files */
37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */
38 |
39 | /* JavaScript Support */
40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
43 |
44 | /* Emit */
45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50 | // "outDir": "./", /* Specify an output folder for all emitted files. */
51 | // "removeComments": true, /* Disable emitting comments. */
52 | // "noEmit": true, /* Disable emitting files from a compilation. */
53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
61 | // "newLine": "crlf", /* Set the newline character for emitting files. */
62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
68 |
69 | /* Interop Constraints */
70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
72 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
74 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
75 |
76 | /* Type Checking */
77 | "strict": true, /* Enable all strict type-checking options. */
78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
96 |
97 | /* Completeness */
98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
100 | },
101 | "include": ["src"],
102 | "exclude": ["node_modules"]
103 | }
--------------------------------------------------------------------------------
/src/utils/CatSubcatBrands.ts:
--------------------------------------------------------------------------------
1 | // CATEGORY'S
2 | export const ELECTRONICS = "Electronics";
3 | export const GROCERY = "Grocery";
4 | export const CLOTHING_AND_APPAREL = "Clothing and Apparel";
5 | export const HOME_AND_KITCHEN = "Home and Kitchen";
6 | export const HEALTH_AND_BEAUTY = "Health and Beauty";
7 | export const SPORTS_AND_OUTDOORS = "Sports and Outdoors";
8 | export const BOOKS_AND_MEDIA = "Books and Media";
9 | export const TOYS_AND_GAMES = "Toys and Games";
10 |
11 | // SUBCATEGORY'S
12 | export const MOBILES = "Mobiles";
13 | export const LAPTOPS = "Laptops";
14 | export const TABLETS = "Tablets";
15 | export const ACCESSORIES = "Accessories";
16 | export const FRUITS_AND_VEGETABLES = "Fruits & Vegetables";
17 | export const SNACKS = "Snacks";
18 | export const BEVERAGES = "Beverages";
19 | export const CANNED_GOODS = "Canned Goods";
20 | export const MENS_CLOTHING = "Men's Clothing";
21 | export const WOMENS_CLOTHING = "Women's Clothing";
22 | export const KIDS_CLOTHING = "Kid's Clothing";
23 | export const FURNITURE = "Furniture";
24 | export const COOKWARE = "Cookware";
25 | export const HOME_DECOR = "Home Decor";
26 | export const APPLIANCES = "Appliances";
27 | export const SKINCARE = "Skincare";
28 | export const HAIRCARE = "Haircare";
29 | export const MAKEUP = "Makeup";
30 | export const PERSONAL_CARE = "Personal Care";
31 | export const FITNESS_EQUIPMENT = "Fitness Equipment";
32 | export const OUTDOOR_GEAR = "Outdoor Gear";
33 | export const ATHLETIC_CLOTHING = "Athletic Clothing";
34 | export const CAMPING_GEAR = "Camping Gear";
35 | export const ACTION_FIGURES = "Action Figures";
36 | export const BOARD_GAMES = "Board Games";
37 | export const OUTDOOR_TOYS = "Outdoor Toys";
38 | export const FICTION = "Fiction";
39 | export const NON_FICTION = "Non-Fiction";
40 | export const CHILDRENS_BOOKS = "Children's Books";
41 |
42 | // BRAND'S
43 | // Mobiles
44 | export const APPLE = "Apple";
45 | export const SAMSUNG = "Samsung";
46 | export const XIAOMI = "Xiaomi";
47 | export const HUAWEI = "Huawei";
48 | export const ONEPLUS = "OnePlus";
49 |
50 | // Laptops
51 | export const HP = "HP";
52 | export const DELL = "Dell";
53 | export const LENOVO = "Lenovo";
54 | // export const APPLE = "Apple";
55 | export const ASUS = "Asus";
56 |
57 | // Tablets
58 |
59 | // export const APPLE = "Apple";
60 | // export const SAMSUNG = "Samsung";
61 | export const MICROSOFT = "Microsoft";
62 | // export const HUAWEI = "Huawei";
63 |
64 | // Accessories
65 | export const LOGITECH = "Logitech";
66 | export const JBL = "JBL";
67 | export const BELKIN = "Belkin";
68 | export const ANKER = "Anker";
69 | export const SONY = "Sony";
70 |
71 | export const Fruits_Vegetables = "Fruits & Vegetables";
72 | // Snacks
73 | export const LAYS = "Lay's";
74 | export const DORITOS = "Doritos";
75 | export const PRINGLES = "Pringles";
76 | export const HERSHEY = "Hershey's";
77 | export const PLANTERS = "Planters";
78 |
79 | // Beverages
80 | export const COCA_COLA = "Coca-Cola";
81 | export const PEPSI = "Pepsi";
82 | export const STARBUCKS = "Starbucks";
83 | export const NESTLE = "Nestlé";
84 | export const RED_BULL = "Red Bull";
85 |
86 | // Canned Goods
87 | export const CAMPBELL = "Campbell's";
88 | export const DEL_MONTE = "Del Monte";
89 | export const HEINZ = "Heinz";
90 | export const LIBBYS = "Libby's";
91 | export const PROGRESSO = "Progresso";
92 |
93 | // Men's Clothing
94 | export const NIKE = "Nike";
95 | export const ADIDAS = "Adidas";
96 | export const LEVI = "Levi's";
97 | export const RALPH_LAUREN = "Ralph Lauren";
98 | export const TOMMY_HILFIGER = "Tommy Hilfiger";
99 |
100 | // Women's Clothing
101 | export const ZARA = "Zara";
102 | export const FOREVER_21 = "Forever 21";
103 | export const GAP = "Gap";
104 |
105 | // Kid's Clothing
106 | export const CARTERS = "Carter's";
107 | export const GAP_KIDS = "Gap Kids";
108 | export const OLD_NAVY_KIDS = "Old Navy Kids";
109 | export const HM_KIDS = "H&M Kids";
110 | export const GYMBOREE = "Gymboree";
111 |
112 | // Furniture
113 | export const IKEA = "IKEA";
114 | export const ASHLEY_FURNITURE = "Ashley Furniture";
115 | export const WAYFAIR = "Wayfair";
116 | export const CRATE_AND_BARREL = "Crate and Barrel";
117 | export const POTTERY_BARN = "Pottery Barn";
118 |
119 | // Cookware
120 | export const CALPHALON = "Calphalon";
121 | export const CUISINART = "Cuisinart";
122 | export const ALL_CLAD = "All-Clad";
123 | export const LE_CREUSET = "Le Creuset";
124 | export const LODGE = "Lodge";
125 |
126 | // Home Decor
127 | export const WEST_ELM = "West Elm";
128 | // export const CRATE_AND_BARREL = "Crate and Barrel";
129 | // export const POTTERY_BARN = "Pottery Barn";
130 | export const ANTHROPOLOGIE = "Anthropologie";
131 | export const HOME_GOODS = "HomeGoods";
132 |
133 | // Appliances
134 | export const LG = "LG Appliances";
135 | export const WHIRLPOOL = "Whirlpool";
136 | export const KITCHEN_AID = "KitchenAid";
137 | export const GE = "GE Appliances";
138 |
139 | // Skincare
140 | export const CETAPHIL = "Cetaphil";
141 | export const NEUTROGENA = "Neutrogena";
142 | export const OLAY = "Olay";
143 | export const LA_ROCHE_POSAY = "La Roche-Posay";
144 | export const AVEENO = "Aveeno";
145 |
146 | // Haircare
147 | export const PANTENE = "Pantene";
148 | export const HEAD_AND_SHOULDERS = "Head & Shoulders";
149 | export const LOREAL = "L'Oréal";
150 | export const GARNIER = "Garnier";
151 | export const TRESEMME = "Tresemme";
152 |
153 | // Makeup
154 | export const MAYBELLINE = "Maybelline New York";
155 | export const MAC = "MAC Cosmetics";
156 | export const COVER_GIRL = "CoverGirl";
157 | export const REVLON = "Revlon";
158 |
159 | // Personal Care
160 | export const DOVE = "Dove";
161 | export const COLGATE = "Colgate";
162 | export const NIVEA = "Nivea";
163 | export const GILLETTE = "Gillette";
164 | export const JOHNSON_AND_JOHNSON = "Johnson & Johnson";
165 |
166 | // Fitness Equipment
167 | export const NORDIC_TRACK = "NordicTrack";
168 | export const BOWFLEX = "Bowflex";
169 | export const PELOTON = "Peloton";
170 | export const LIFE_FITNESS = "Life Fitness";
171 | export const SCHWINN = "Schwinn";
172 |
173 | // Outdoor Gear
174 | export const THE_NORTH_FACE = "The North Face";
175 | export const PATAGONIA = "Patagonia";
176 | export const COLUMBIA = "Columbia";
177 | export const REI = "REI";
178 | export const MARMOT = "Marmot";
179 |
180 | // Athletic Clothing
181 | export const UNDER_ARMOUR = "Under Armour";
182 | export const LULULEMON = "Lululemon";
183 | export const PUMA = "Puma";
184 |
185 | // Camping Gear
186 | export const COLEMAN = "Coleman";
187 | export const KELTY = "Kelty";
188 |
189 | // Action Figures
190 | export const HASBRO = "Hasbro";
191 | export const MATTEL = "Mattel";
192 | export const FUNKO = "Funko";
193 | export const MCFARLANE_TOYS = "McFarlane Toys";
194 | export const BANDAI = "Bandai";
195 |
196 | // Board Games
197 | export const RAVENSBURGER = "Ravensburger";
198 | export const ASMODEE = "Asmodee";
199 | export const CATAN_STUDIO = "Catan Studio";
200 |
201 | // Outdoor Toys
202 | export const LITTLE_TIKES = "Little Tikes";
203 | export const STEP_2 = "Step2";
204 | export const RADIO_FLYER = "Radio Flyer";
205 | export const NERF = "Nerf";
206 | export const BUNCH_O_BALLOONS = "Bunch O Balloons";
207 |
208 | // Fiction
209 | export const PENGUIN_RANDOM_HOUSE = "Penguin Random House";
210 | export const HARPER_COLLINS = "HarperCollins";
211 | export const SIMON_AND_SCHUSTER = "Simon & Schuster";
212 | export const HACHETTE_BOOK_GROUP = "Hachette Book Group";
213 | export const BARNES_AND_NOBLE = "Barnes & Noble";
214 |
215 | // Non-Fiction
216 | // export const PENGUIN_RANDOM_HOUSE = "Penguin Random House";
217 | // export const HARPER_COLLINS = "HarperCollins";
218 | // export const SIMON_AND_SCHUSTER = "Simon & Schuster";
219 | // export const HACHETTE_BOOK_GROUP = "Hachette Book Group";
220 | export const OXFORD_UNIVERSITY_PRESS = "Oxford University Press";
221 |
222 | // Children's Books
223 | export const SCHOLASTIC = "Scholastic";
224 | export const PENGUIN_RANDOM_HOUSE_CHILDRENS = "Penguin Random House Children's";
225 | export const HARPER_COLLINS_CHILDRENS_BOOKS = "HarperCollins Children's Books";
226 | export const SIMON_AND_SCHUSTER_CHILDRENS_PUBLISHING =
227 | "Simon & Schuster Children's Publishing";
228 | export const CANDLEWICK_PRESS = "Candlewick Press";
229 |
230 | interface CategoryListsI {
231 | name: string;
232 | subCategories: {
233 | name: string;
234 | brands: string[];
235 | }[];
236 | }
237 |
238 | // category and subcategory
239 | export const CategoryLists: CategoryListsI[] = [
240 | {
241 | name: ELECTRONICS,
242 | subCategories: [
243 | {
244 | name: MOBILES,
245 | brands: [APPLE, SAMSUNG, XIAOMI, HUAWEI, ONEPLUS],
246 | },
247 | {
248 | name: LAPTOPS,
249 | brands: [HP, DELL, LENOVO, APPLE, ASUS],
250 | },
251 | {
252 | name: TABLETS,
253 | brands: [APPLE, SAMSUNG, MICROSOFT, HUAWEI],
254 | },
255 | {
256 | name: ACCESSORIES,
257 | brands: [LOGITECH, JBL, BELKIN, ANKER, SONY],
258 | },
259 | ],
260 | },
261 | {
262 | name: GROCERY,
263 | subCategories: [
264 | {
265 | name: FRUITS_AND_VEGETABLES,
266 | brands: [Fruits_Vegetables],
267 | },
268 | {
269 | name: SNACKS,
270 | brands: [LAYS, DORITOS, PRINGLES, HERSHEY, PLANTERS],
271 | },
272 | {
273 | name: BEVERAGES,
274 | brands: [COCA_COLA, PEPSI, STARBUCKS, NESTLE, RED_BULL],
275 | },
276 | {
277 | name: CANNED_GOODS,
278 | brands: [CAMPBELL, DEL_MONTE, HEINZ, LIBBYS, PROGRESSO],
279 | },
280 | ],
281 | },
282 | {
283 | name: CLOTHING_AND_APPAREL,
284 | subCategories: [
285 | {
286 | name: MENS_CLOTHING,
287 | brands: [NIKE, ADIDAS, LEVI, RALPH_LAUREN, TOMMY_HILFIGER],
288 | },
289 | {
290 | name: WOMENS_CLOTHING,
291 | brands: [ZARA, FOREVER_21, GAP, NIKE],
292 | },
293 | {
294 | name: KIDS_CLOTHING,
295 | brands: [CARTERS, GAP_KIDS, OLD_NAVY_KIDS, GYMBOREE],
296 | },
297 | ],
298 | },
299 | {
300 | name: HOME_AND_KITCHEN,
301 | subCategories: [
302 | {
303 | name: FURNITURE,
304 | brands: [
305 | IKEA,
306 | ASHLEY_FURNITURE,
307 | WAYFAIR,
308 | CRATE_AND_BARREL,
309 | POTTERY_BARN,
310 | ],
311 | },
312 | {
313 | name: COOKWARE,
314 | brands: [CALPHALON, CUISINART, ALL_CLAD, LODGE],
315 | },
316 | {
317 | name: HOME_DECOR,
318 | brands: [
319 | WEST_ELM,
320 | CRATE_AND_BARREL,
321 | POTTERY_BARN,
322 | ANTHROPOLOGIE,
323 | HOME_GOODS,
324 | ],
325 | },
326 | {
327 | name: APPLIANCES,
328 | brands: [LG, WHIRLPOOL, KITCHEN_AID, GE],
329 | },
330 | ],
331 | },
332 | {
333 | name: HEALTH_AND_BEAUTY,
334 | subCategories: [
335 | {
336 | name: SKINCARE,
337 | brands: [CETAPHIL, NEUTROGENA, OLAY, LA_ROCHE_POSAY, AVEENO],
338 | },
339 | {
340 | name: HAIRCARE,
341 | brands: [PANTENE, HEAD_AND_SHOULDERS, LOREAL, GARNIER, TRESEMME],
342 | },
343 | {
344 | name: MAKEUP,
345 | brands: [MAYBELLINE, MAC, COVER_GIRL, REVLON],
346 | },
347 | {
348 | name: PERSONAL_CARE,
349 | brands: [DOVE, COLGATE, NIVEA, GILLETTE, JOHNSON_AND_JOHNSON],
350 | },
351 | ],
352 | },
353 | {
354 | name: SPORTS_AND_OUTDOORS,
355 | subCategories: [
356 | {
357 | name: FITNESS_EQUIPMENT,
358 | brands: [NORDIC_TRACK, BOWFLEX, PELOTON, LIFE_FITNESS, SCHWINN],
359 | },
360 | {
361 | name: OUTDOOR_GEAR,
362 | brands: [THE_NORTH_FACE, PATAGONIA, COLUMBIA, REI, MARMOT],
363 | },
364 | {
365 | name: ATHLETIC_CLOTHING,
366 | brands: [UNDER_ARMOUR, LULULEMON, PUMA],
367 | },
368 | {
369 | name: CAMPING_GEAR,
370 | brands: [COLEMAN, KELTY],
371 | },
372 | ],
373 | },
374 | {
375 | name: TOYS_AND_GAMES,
376 | subCategories: [
377 | {
378 | name: ACTION_FIGURES,
379 | brands: [HASBRO, MATTEL, FUNKO, MCFARLANE_TOYS, BANDAI],
380 | },
381 | {
382 | name: BOARD_GAMES,
383 | brands: [RAVENSBURGER, ASMODEE, CATAN_STUDIO],
384 | },
385 | {
386 | name: OUTDOOR_TOYS,
387 | brands: [LITTLE_TIKES, STEP_2, RADIO_FLYER, NERF, BUNCH_O_BALLOONS],
388 | },
389 | ],
390 | },
391 | {
392 | name: BOOKS_AND_MEDIA,
393 | subCategories: [
394 | {
395 | name: FICTION,
396 | brands: [
397 | PENGUIN_RANDOM_HOUSE,
398 | HARPER_COLLINS,
399 | SIMON_AND_SCHUSTER,
400 | HACHETTE_BOOK_GROUP,
401 | BARNES_AND_NOBLE,
402 | ],
403 | },
404 | {
405 | name: NON_FICTION,
406 | brands: [
407 | PENGUIN_RANDOM_HOUSE,
408 | HARPER_COLLINS,
409 | SIMON_AND_SCHUSTER,
410 | HACHETTE_BOOK_GROUP,
411 | OXFORD_UNIVERSITY_PRESS,
412 | ],
413 | },
414 | {
415 | name: CHILDRENS_BOOKS,
416 | brands: [
417 | SCHOLASTIC,
418 | PENGUIN_RANDOM_HOUSE_CHILDRENS,
419 | HARPER_COLLINS_CHILDRENS_BOOKS,
420 | SIMON_AND_SCHUSTER_CHILDRENS_PUBLISHING,
421 | CANDLEWICK_PRESS,
422 | ],
423 | },
424 | ],
425 | },
426 | ];
427 |
--------------------------------------------------------------------------------