diff --git a/backend/config/config.js b/backend/config/config.js index f403568..4af6acc 100644 --- a/backend/config/config.js +++ b/backend/config/config.js @@ -28,9 +28,14 @@ const mailServices = { smtpHost: process.env.SMTP_HOST, smtpPort: process.env.SMTP_PORT, }; +// mail services +const productDetails = { + resultPerPage: process.env.RESULT_PER_PAGE, +}; export const { serverMode, serverPort } = server; export const { dbUri, dbName } = database; export const { jwtSecret, jwtExpire, cookieExpire } = jwtInformation; export const { smtpMail, smtpPassword, smtpService, smtpHost, smtpPort } = mailServices; +export const { resultPerPage } = productDetails; diff --git a/backend/controllers/product.controller.js b/backend/controllers/product.controller.js index d058272..c7e0ba7 100644 --- a/backend/controllers/product.controller.js +++ b/backend/controllers/product.controller.js @@ -4,11 +4,11 @@ import { Product } from "../models/product.model.js"; import catchAysncErrors from "../middleware/catchAysncErrors.js"; import ErrorHander from "../utils/error-handler.js"; import ApiFeatures from "../utils/api-feature.js"; +import { resultPerPage } from "../config/config.js"; // Get all Product export const getAllProductDetails = catchAysncErrors(async (req, res, next) => { - const resultPerPage = 8; const productCount = await Product.countDocuments(); const apiFeatures = new ApiFeatures(Product.find(), req.query) .search() diff --git a/backend/server.js b/backend/server.js index e1f18ca..d08f628 100644 --- a/backend/server.js +++ b/backend/server.js @@ -14,7 +14,9 @@ process.on("uncaughtException", (err) => { server.use("/api/v1", app); server.listen(serverPort, () => { - console.log(`server is running on port ${serverPort} in ${serverMode} mode`); + console.log( + `server is running on port \x1b[44m${serverPort}\x1b[0m in \x1b[47m${serverMode}\x1b[0m mode` + ); }); process.on("unhandledRejection", (err) => { diff --git a/frontend/src/App.js b/frontend/src/App.js index 62afe7b..2e00576 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,50 +1,55 @@ import React from 'react'; +import { lazy, Suspense } from 'react'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; -import MainLayout from './layout/MainLayout'; -import Home from './pages/home/Home'; -import AuthAdmin from './custom-hooks/AuthAdmin'; -import SellerPage from './pages/seller/Seller'; -import AdminProfile from './pages/profle/AdminProfile'; -import CreateProduct from './pages/seller/CreateProduct'; -import NewProductReport from './pages/seller/NewProductReport'; +const MainLayout = lazy(() => import('./layout/MainLayout')); +const Home = lazy(() => import('./pages/home/Home')); +const SellerPage = lazy(() => import('./pages/seller/Seller')); +const AdminProfile = lazy(() => import('./pages/profle/AdminProfile')); +const CreateProduct = lazy(() => import('./pages/seller/CreateProduct')); +const NewProductReport = lazy(() => import('./pages/seller/NewProductReport')); +const AdminDashBoard = lazy( + () => import('./pages/admin-dashboard/AdminDashBoard') +); import _404 from './components/_404'; -import AdminDashBoard from './pages/admin-dashboard/AdminDashBoard'; +import AuthAdmin from './custom-hooks/AuthAdmin'; const App = () => { return ( - - - } /> - } /> - } /> - - - - } - /> - - - - } - /> - - - - } - /> - } /> - - + Loading...}> + + + } /> + } /> + } /> + + + + } + /> + + + + } + /> + + + + } + /> + } /> + + + ); }; diff --git a/frontend/src/components/home/carousel/SliderComponent.jsx b/frontend/src/components/home/carousel/SliderComponent.jsx index 0b9c6b0..18a51c2 100644 --- a/frontend/src/components/home/carousel/SliderComponent.jsx +++ b/frontend/src/components/home/carousel/SliderComponent.jsx @@ -20,7 +20,7 @@ const SliderComponent = ({ testimonial }) => {

{testimonial.sale_discount}

{testimonial.sale_title}

{testimonial.sale_para}

- + diff --git a/frontend/src/components/home/search-box/SearchBox.jsx b/frontend/src/components/home/search-box/SearchBox.jsx index ab1b306..822c388 100644 --- a/frontend/src/components/home/search-box/SearchBox.jsx +++ b/frontend/src/components/home/search-box/SearchBox.jsx @@ -17,12 +17,14 @@ const SearchBox = () => { className={styles.inputBtn} placeholder="Search for products" onChange={(e) => setInput(e.target.value)} + autoComplete="on" required /> diff --git a/frontend/src/pages/admin-dashboard/body/BodyLayout.jsx b/frontend/src/pages/admin-dashboard/body/BodyLayout.jsx index 490a68e..8364ced 100644 --- a/frontend/src/pages/admin-dashboard/body/BodyLayout.jsx +++ b/frontend/src/pages/admin-dashboard/body/BodyLayout.jsx @@ -5,8 +5,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { toggleAdminLeftDashboard } from '../../../redux/admin/adminLeftMenuSlice'; import AdminProfile from './AdminProfile'; import CardItemd from './CardItemd'; -import ListOfProducts from './ListOfProducts'; import ListOfUser from './list-of-user/ListOfUser'; +import ListOfProducts from './list-of-products/ListOfProducts'; const DataDetails = [ { diff --git a/frontend/src/pages/admin-dashboard/body/ListOfProducts.jsx b/frontend/src/pages/admin-dashboard/body/ListOfProducts.jsx deleted file mode 100644 index 68dc5f1..0000000 --- a/frontend/src/pages/admin-dashboard/body/ListOfProducts.jsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -const ListOfProducts = () => { - return
ListOfProducts
; -}; - -export default ListOfProducts; diff --git a/frontend/src/pages/admin-dashboard/body/list-of-products/ListOfProducts.jsx b/frontend/src/pages/admin-dashboard/body/list-of-products/ListOfProducts.jsx new file mode 100644 index 0000000..3b4e7b0 --- /dev/null +++ b/frontend/src/pages/admin-dashboard/body/list-of-products/ListOfProducts.jsx @@ -0,0 +1,40 @@ +import React, { useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { getAllProduct } from '../../../../redux/auth/authSlice'; +import UserTable from './ProductsTable'; +import { FiMaximize } from 'react-icons/fi'; +import { FaMinus } from 'react-icons/fa'; + +const ListOfProducts = () => { + const { allProduct } = useSelector((state) => state.auth); + const dispatch = useDispatch(); + useEffect(() => { + if (!allProduct) { + dispatch(getAllProduct()); + } + }, [allProduct, dispatch]); + const [isOpen, setIsOpen] = useState(true); + + const handleToggle = () => { + setIsOpen((val) => !val); + }; + return ( +
+
+

All Products

+ {isOpen ? ( + + ) : ( + + )} +
+
+ {allProduct && } +
+
+ ); +}; + +export default ListOfProducts; diff --git a/frontend/src/pages/admin-dashboard/body/list-of-products/ProductsTable.jsx b/frontend/src/pages/admin-dashboard/body/list-of-products/ProductsTable.jsx new file mode 100644 index 0000000..e7c9b43 --- /dev/null +++ b/frontend/src/pages/admin-dashboard/body/list-of-products/ProductsTable.jsx @@ -0,0 +1,41 @@ +import React from 'react'; + +const ProductsTable = ({ data, isOpen }) => { + console.log(data); + return ( +
+ + + + + + + + + + + + + + {data.map((prod) => ( +
+
+ + + + + + + + + + ))} + +
NameDescriptionPriceRatingImageCategoryStockReviewsCreated At
{prod.name}{prod.description}{prod.price}{prod.rating} + {prod.name} + {prod.category}{prod.stock}{prod.reviews}{prod.createdAt}
+
+ ); +}; + +export default ProductsTable; diff --git a/frontend/src/pages/admin-dashboard/body/list-of-user/ListOfUser.jsx b/frontend/src/pages/admin-dashboard/body/list-of-user/ListOfUser.jsx index 2def868..352e8b9 100644 --- a/frontend/src/pages/admin-dashboard/body/list-of-user/ListOfUser.jsx +++ b/frontend/src/pages/admin-dashboard/body/list-of-user/ListOfUser.jsx @@ -28,8 +28,8 @@ const ListOfUser = () => { )} -
- {users && } + {/*
*/} +
{users && }
); }; diff --git a/frontend/src/pages/admin-dashboard/body/list-of-user/UserTable.jsx b/frontend/src/pages/admin-dashboard/body/list-of-user/UserTable.jsx index 1f1e689..3393d8d 100644 --- a/frontend/src/pages/admin-dashboard/body/list-of-user/UserTable.jsx +++ b/frontend/src/pages/admin-dashboard/body/list-of-user/UserTable.jsx @@ -1,113 +1,34 @@ import React from 'react'; -import { useTable, useSortBy, useFilters } from 'react-table'; +import { FaUser } from 'react-icons/fa'; const UserTable = ({ data, isOpen }) => { - const columns = React.useMemo( - () => [ - { - Header: 'Avatar', - accessor: 'avatar.url', - Cell: ({ cell: { value } }) => ( - avatar - ), - }, - { - Header: 'Name', - accessor: 'name', - Filter: DefaultColumnFilter, - }, - { - Header: 'Email', - accessor: 'email', - }, - { - Header: 'Role', - accessor: 'role', - }, - { - Header: 'Created At', - accessor: 'createdAt', - Cell: ({ cell: { value } }) => ( - {new Date(value).toLocaleString()} - ), - }, - ], - [] - ); - - const defaultColumn = React.useMemo( - () => ({ - Filter: DefaultColumnFilter, - }), - [] - ); - - const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = - useTable( - { - columns, - data, - defaultColumn, - }, - useFilters, - useSortBy - ); - + console.log(data); return ( - - - {headerGroups.map((headerGroup, headerGroupIdx) => ( - - {headerGroup.headers.map((column, columnIdx) => ( - - ))} - - ))} - - - {rows.map((row, rowIdx) => { - prepareRow(row); - return ( - - {row.cells.map((cell, cellIdx) => ( - - ))} - - ); - })} - -
- {column.render('Header')} - - {column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''} - -
{column.canFilter ? column.render('Filter') : null}
-
- {cell.render('Cell')} -
+
+ + + + + + + + + + {data.map((user) => ( +
+
+ + + + + + ))} + +
AvatarNameEmail NameRole NameCreated At
+ + {user.name}{user.email}{user.role}{user.createdAt}
+
); }; -const DefaultColumnFilter = ({ - column: { filterValue, setFilter }, - isOpen, -}) => ( - { - setFilter(e.target.value || undefined); - }} - placeholder={`Search...`} - className={`${isOpen ? 'search' : 'close-search'}`} - /> -); - export default UserTable; diff --git a/frontend/src/redux/auth/authSlice.js b/frontend/src/redux/auth/authSlice.js index f517fa7..630edf2 100644 --- a/frontend/src/redux/auth/authSlice.js +++ b/frontend/src/redux/auth/authSlice.js @@ -216,7 +216,7 @@ const authSlice = createSlice({ state.error = action.payload; }) - // for USER PROFILE + // for get all products detainls .addCase(getAllProduct.pending, (state) => { state.isLoading = true; state.error = null; diff --git a/frontend/src/style/component/admin-dashboard/_admin__dashboard__main.scss b/frontend/src/style/component/admin-dashboard/_admin__dashboard__main.scss index 6bfd6ad..3f6d85a 100644 --- a/frontend/src/style/component/admin-dashboard/_admin__dashboard__main.scss +++ b/frontend/src/style/component/admin-dashboard/_admin__dashboard__main.scss @@ -1,24 +1,28 @@ .admin__dashboard__main { display: flex; position: relative; - .left__navbar, - .left__navbar__close { - max-width: 210px; - position: sticky; - width: 100%; + + .left__navbar { + min-width: 210px; + // position: sticky; + // width: 100%; transition: all 0.3s ease; height: 100vh; box-shadow: 1px 1px 15px 3px #745a5a; } .left__navbar__close { - max-width: 70px; - width: 15%; + width: 70px !important; + // position: sticky; + transition: all 0.3s ease; + box-shadow: 1px 1px 15px 3px #745a5a; + // max-width: 70px; + // width: 15%; .left__open__navbar__admin_dashboard { .hr-line-admin { height: 0.5px; background-color: $primary-green; - width: 100vw; + // width: 100vw; max-width: 70px; transition: max-width 0.3s ease; } @@ -65,7 +69,7 @@ } } .right__body { - width: 100%; + width: calc(100% - 210px); z-index: 10; } } diff --git a/frontend/src/style/component/admin-dashboard/_body__admin__dashboard__layout.scss b/frontend/src/style/component/admin-dashboard/_body__admin__dashboard__layout.scss index f301b2e..5a28579 100644 --- a/frontend/src/style/component/admin-dashboard/_body__admin__dashboard__layout.scss +++ b/frontend/src/style/component/admin-dashboard/_body__admin__dashboard__layout.scss @@ -59,7 +59,7 @@ grid-template-columns: 1fr 1fr; } @include small-device { - grid-template-columns: 1fr 1fr; + grid-template-columns: 1fr; } } } diff --git a/frontend/src/style/component/admin-dashboard/_left__open__navbar__admin_dashboard.scss b/frontend/src/style/component/admin-dashboard/_left__open__navbar__admin_dashboard.scss index 30cacd5..141c5a1 100644 --- a/frontend/src/style/component/admin-dashboard/_left__open__navbar__admin_dashboard.scss +++ b/frontend/src/style/component/admin-dashboard/_left__open__navbar__admin_dashboard.scss @@ -1,9 +1,8 @@ .left__open__navbar__admin_dashboard { - height: 100%; - width: 100%; + // height: 100%; + // width: 100%; background-color: #333; color: #fff; - transition: transform 0.3s ease; .close__hide { opacity: 0; @@ -19,8 +18,7 @@ .hr-line-admin { height: 0.5px; background-color: $primary-green; - width: 100vw; - max-width: 210px; + width: 100%; transition: max-width 0.3s ease; } .nav-list { @@ -38,7 +36,6 @@ margin: 4px; margin-left: 20px; width: 100%; - max-width: 190px; text-transform: capitalize; cursor: pointer; .icon { diff --git a/frontend/src/style/component/admin-dashboard/list/_list__of__users.scss b/frontend/src/style/component/admin-dashboard/list/_list__of__users.scss index 502c935..86f8471 100644 --- a/frontend/src/style/component/admin-dashboard/list/_list__of__users.scss +++ b/frontend/src/style/component/admin-dashboard/list/_list__of__users.scss @@ -1,33 +1,100 @@ .list__of__users, +.list__of__product, .list__of__users__close { - border: 1px solid black; - border-radius: 6px; - margin-top: 1rem; - width: 100%; - color: white; - background-color: rgb(51, 45, 45); - height: 100%; - transition: all 0.3s ease-in; - overflow-y: scroll; + width: 65rem; + max-width: 100%; + + margin: 1rem auto; + .header { - background-color: rgb(51, 45, 45); + background-color: rgb(88, 85, 85); display: flex; justify-content: space-between; align-items: center; padding: 5px 5px; + border-radius: 5px 5px 0 0; } - .headings { - width: 20px; - } - .body { - opacity: 1; + .user__table { + background-color: rgb(134, 132, 132); + padding: 0.5rem; + border-radius: 0 0 5px 5px; transition: opacity 0.3s ease; + + @media screen and (max-width: 1080px) { + overflow: scroll; + } + + table { + display: flex; + min-width: 990px; + flex-direction: column; + .t-head, + .t-body { + display: grid; + grid-template-columns: 0.5fr 1fr 1.5fr 0.5fr 1fr; + td, + th { + width: 100%; + word-wrap: break-word; + text-wrap: wrap; + text-align: start; + } + } + } } - .close-body { + + .table_hide { opacity: 0; transition: opacity 0.3s ease; + padding: 0rem; + table { + display: none; + } + .prod__image { + img { + height: 50px; + width: 50px; + border-radius: 50%; + } + } + } +} + +.list__of__product { + width: 65rem; + max-width: 100%; + + .header { + background-color: #259faf; + p { + color: #fff; + } } - .search { - width: 100%; + + .user__table { + @media screen and (max-width: 1080px) { + overflow: scroll; + } + background-color: #36cadd; + table { + min-width: 990px; + .t-body, + .t-head { + grid-template-columns: 1.2fr 1.5fr 1fr 1fr 1fr 0.7fr 0.3fr 1fr 1fr; + td, + th { + padding-left: 0.2rem; + } + th { + margin-bottom: 0.5rem; + } + } + + img { + height: 50px; + width: 50px; + border-radius: 50%; + } + } } } diff --git a/package.json b/package.json index e19ae81..030bb86 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node backend/server.js", - "dev": "nodemon backend/server.js", + "start": "SERVER_MODE=Production node backend/server.js", + "dev": "SERVER_MODE=Development nodemon backend/server.js", "lint:backend": "eslint . --ext .js,.jsx,.ts,.tsx", "lint:frontend": "cd frontend && eslint src --ext .js,.jsx", "lint": "npm run lint:backend && npm run lint:frontend",