diff --git a/src/assets/styles/Product.scss b/src/assets/styles/Product.scss index 8f09ba52..9cfc5c5e 100644 --- a/src/assets/styles/Product.scss +++ b/src/assets/styles/Product.scss @@ -5,10 +5,11 @@ margin-top: 2rem; box-shadow: 0.1rem 0.1rem 0.5rem rgba(0, 0, 0, 0.2); background-color: $secondary-color-light; + transform: none; &:hover { - transform: scale(1.05); + transform: scale(1.05) !important; box-shadow: 1rem 1rem 1rem rgba(0, 0, 0, 0.3); - transition: all 0.3s ease-in-out;; + transition: transform 0.1s ease !important; } .product-image-container { diff --git a/src/assets/styles/Sample.scss b/src/assets/styles/Sample.scss index 0eacaf31..e594b0a7 100644 --- a/src/assets/styles/Sample.scss +++ b/src/assets/styles/Sample.scss @@ -169,7 +169,7 @@ @media screen and (max-width: 900px) { .sampleImages1 { - height: 20rem; + height: 10rem; .sample2 { .arrow { .icon-arrow { @@ -187,7 +187,7 @@ .menShoe, .phones, .womenShoe, .accessories { img { - height: 9.5rem; + height: 8.5rem; } p { font-size: 1rem; @@ -204,7 +204,8 @@ @media screen and (max-width: 480px) { .sampleImages1 { - height: 15rem; + gap: 0.5rem; + height: 12rem; .sample2 { .arrow { .icon-arrow { @@ -221,8 +222,10 @@ } .menShoe, .phones, .womenShoe, .accessories { + height: 5.5rem; + padding: 0; img { - height: 7rem; + height: 100%; } p { font-size: 0.8rem; diff --git a/src/assets/styles/SellerLayout.scss b/src/assets/styles/SellerLayout.scss index 477a4cc4..e81e0cfe 100644 --- a/src/assets/styles/SellerLayout.scss +++ b/src/assets/styles/SellerLayout.scss @@ -1,279 +1,297 @@ .seller__wrapper { - height: 100vh; + height: 100vh; + display: flex; + + .left__side { + width: 26rem; display: flex; - - .left__side { - width: 26rem; - display: flex; + .icons__side { + display: flex; + flex-direction: column; + background-color: $primary-color; + height: 100%; + width: 6.5rem; - .icons__side { - display: flex; - flex-direction: column; - background-color: $primary-color; - height: 100%; - width: 6.5rem; - - .icons { - display: flex; - flex-direction: column; - align-items: center; - height: 100%; - width: 100%; - gap: 34rem; - - .icons__upper { - margin-top: 10rem; - display: flex; - flex-direction: column; - gap: 3rem; - - .icon { - color: $white-color; - font-size: 2rem; - } - } + .icons { + display: flex; + flex-direction: column; + align-items: center; + height: 100%; + width: 100%; + justify-content: space-between; - .icons__bottom { - height: 4rem; - display: flex; - align-items: center; + .icons__upper { + margin-top: 10rem; + display: flex; + flex-direction: column; + gap: 3rem; - .icon { - color: $white-color; - font-size: 3rem; - } - } - } + .icon { + color: $white-color; + font-size: 2rem; + } } - .dashboard__lower__link h2 { - cursor: pointer; + .icons__bottom { + height: 4rem; + display: flex; + align-items: center; + margin-bottom: 3rem; + + .icon { + color: $white-color; + font-size: 3rem; + } } + } + } - .dashboard__items { - display: flex; - flex-direction: column; - height: 100%; - width: 19.5rem; - margin-left: .1rem; - - .dashboard__side { - display: flex; - flex-direction: column; - height: 100%; - width: 100%; - gap: 37.5rem; - - .dashboard__links { - display: flex; - flex-direction: column; - margin-top: 11rem; - height: 5rem; - gap: 3.5rem; - - .text_content { - color: $text-color; - font-size: 1.8rem; - transition: all 0.5s ease-in-out; - text-decoration: none; - } - } + .dashboard__lower__link h2 { + cursor: pointer; + } - .dashboard__lower__link { - height: 4rem; - display: flex; - align-items: center; - - .text_content { - color: $text-color; - font-size: 1.8rem; - transition: all 0.5s ease-in-out; - text-decoration: none; - } - } - } + .dashboard__items { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + margin-left: 1.5rem; + + .dashboard__side { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + justify-content: space-between; + + .dashboard__links { + display: flex; + flex-direction: column; + margin-top: 10rem; + width: 15rem; + gap: 3rem; + + .text_content { + color: $text-color; + font-size: 1.8rem; + text-decoration: none; + padding: 1rem; + border-radius: .5rem; + transition: background-color 0.3s, color 0.3s; + display: block; + + + &:hover { + background-color: $menu-hover; + color: $white !important; + width: 15rem !important ; + } + } + } + + .dashboard__lower__link { + height: 4rem; + display: flex; + margin-bottom: 3rem; - .active { - display: flex; + .text_content { + color: $text-color; + font-size: 1.9rem; + text-decoration: none; + padding: 1rem; + border-radius: .5rem; + transition: background-color 0.3s, color 0.3s; + display: block; + + &:hover { background-color: $menu-hover; + color: $white !important; width: 15rem; - padding: 1rem 1rem; - transition: all 0.5s ease-in-out; - align-items: center; - border-radius: .5rem; + } } } - } + } - .main__seller__content__dashboard { + .active { display: flex; - flex-direction: column; - flex: 1; - max-height: 100vh; - + background-color: $menu-hover; + color: $white !important; + padding: 1rem; + border-radius: .5rem; + width: 15rem; + } } + } - .main__seller__dashboard { - display: flex; - flex: 1; - width: 100%; - min-height: calc(100vh - 120px); - max-height: calc(100vh - 120px); - background-color: $container-color; - padding: 20px; - - .outlet { - flex: 0 0 60%; - border-radius: 20px; - min-height: 95%; - max-height: 95%; - min-width: 70%; - max-width: 70%; - padding: 2rem; - overflow-y: scroll; - scroll-behavior: smooth; - background-color: white; - - &::-webkit-scrollbar { - display: none; - } - } + .main__seller__content__dashboard { + display: flex; + flex-direction: column; + flex: 1; + max-height: 100vh; + } - .right__side { - flex: 0 0 20%; - min-width: 20%; - max-width: 20%; - min-height: 100%; - max-height: 100%; - display: flex; - flex-direction: column; - gap: 25px; - padding: 0 20px; - - .right-profile { - background-color: $white-color; - height: 40%; - border-radius: 20px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - padding: 2rem; - .profile-image { - border-radius: 50%; - height: 6rem; - border: 0.2rem solid #FF6D18; - width: 6rem; - object-fit: cover; - margin-bottom: 1rem; - } - .profile-name { - font-size: 1.8rem; - font-weight: 600; - color: $text-color; - margin: 0; - } - .profile-edit { - font-size: 1.4rem; - color: $text-color; - background-color: #ffede2; - margin: 0; - cursor: pointer; - border: none; - color: $primary-color; - border-radius: 2rem; - padding: 0.5rem 1.8rem; - margin-top: 1rem; - font-size: 1.4rem; - .icon-edit { - color: $primary-color; - margin-left: 1rem; - } - } - .progress-bar-container { - display: flex; - align-items: center; - font-size: 1.4rem; - margin-top: 1rem; - color: $text-color; - .order-progress { - color: #57ce57; - margin-left: 0.5rem; - margin-right: 0.5rem; - } - } - - .progress-bar { - width: 3rem; - height: 1rem; - background-color: #e0e0e0; - border-radius: 0.5rem; - overflow: hidden; - } - - .progress-bar-fill { - height: 100%; - transition: width 0.3s ease; - } - } + .main__seller__dashboard { + display: flex; + flex: 1; + width: 100%; + min-height: calc(100vh - 120px); + max-height: calc(100vh - 120px); + background-color: $container-color; + padding: 20px; + + .outlet { + background-color: white; + flex: 0 0 60%; + border-radius: 20px; + min-height: 95%; + max-height: 95%; + min-width: 70%; + max-width: 70%; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + padding: 2rem; + overflow-y: scroll; + scroll-behavior: smooth; + + &::-webkit-scrollbar { + display: none; + } + } + + .right__side { + flex: 0 0 20%; + min-width: 20%; + max-width: 20%; + min-height: 100%; + max-height: 100%; + display: flex; + flex-direction: column; + gap: 25px; + padding: 0 20px; - .right-products { - .loader { - display: flex; - justify-content: center; - align-items: center; - height: 50vh; + .right-profile { + background-color: $white-color; + height: 40%; + border-radius: 20px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + padding: 2rem; + .profile-image { + border-radius: 50%; + height: 6rem; + border: 0.2rem solid #FF6D18; + width: 6rem; + object-fit: cover; + margin-bottom: 1rem; + } + .profile-name { + font-size: 1.8rem; + font-weight: 600; + color: $text-color; + margin: 0; + } + .profile-edit { + font-size: 1.4rem; + color: $text-color; + background-color: #ffede2; + margin: 0; + cursor: pointer; + border: none; + color: $primary-color; + border-radius: 2rem; + padding: 0.5rem 1.8rem; + margin-top: 1rem; + font-size: 1.4rem; + .icon-edit { + color: $primary-color; + margin-left: 1rem; + } + } + .progress-bar-container { + display: flex; + align-items: center; + font-size: 1.4rem; + margin-top: 1rem; + color: $text-color; + .order-progress { + color: $primary-color; + margin-left: 0.5rem; + margin-right: 0.5rem; } - background-color: $white-color; - height: 60%; - overflow-y: scroll; - scroll-behavior: smooth; - border-radius: 20px; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - padding: 1rem; - &::-webkit-scrollbar { - display: none; } - .right-header { - font-size: 1.4rem; - color: #000; + + .progress-bar { + width: 3rem; + height: 1rem; + background-color: #e0e0e0; + border-radius: 0.5rem; + overflow: hidden; } - .product-header{ - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.3rem 0.9rem; - border-radius: 2rem; - margin-top: 1rem; - background-color: #d9d9d9; - color: #FF6D18; + + .progress-bar-fill { + height: 100%; + transition: width 0.3s ease; } - } - } - } + } + + .right-products { + .loader { + display: flex; + justify-content: center; + align-items: center; + height: 50vh; + } + background-color: $white-color; + height: 60%; + overflow-y: scroll; + scroll-behavior: smooth; + border-radius: 20px; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + padding: 1rem; + &::-webkit-scrollbar { + display: none; + } + .right-header { + font-size: 1.4rem; + color: #000; + } + .product-header{ + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.3rem 0.9rem; + border-radius: 2rem; + margin-top: 1rem; + background-color: #d9d9d9; + color: #FF6D18; + } + } + } + } } .seller-dashboard-container { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 100%; - gap: 30px; - + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + gap: 30px; + .statisticCards { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; - + .card { transition: margin-top 0.3s ease; } - + .card:hover { margin-top: -20px; } @@ -285,7 +303,7 @@ background-color: #fff; overflow: hidden; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); - + .chart-header { display: flex; @@ -306,23 +324,23 @@ align-items: center; flex-direction: row; gap: 20px; - + .dot { height: 10px; width: 10px; border-radius: 50%; - + &.completed { background-color: #ff7300; } - + &.cancelled { background-color: #bfbfbf; } } } } - + .monthDropDown { .dropdown-button { background-color: #ff7300; @@ -332,7 +350,7 @@ border-radius: 5px; cursor: pointer; font-size: 14px; - + .arrow-down { margin-left: 5px; } @@ -343,41 +361,41 @@ } @media (max-width: 1024px) { - .seller__wrapper { - .left__side { - width: 6.5rem; + .seller__wrapper { + .left__side { + width: 6.5rem; - .dashboard__items { - display: none; - } - } + .dashboard__items { + display: none; + } + } - .main__seller__content__dashboard { - flex: 1; - padding: auto; - padding-left: 0px; - } + .main__seller__content__dashboard { + flex: 1; + padding: auto; + padding-left: 0px; + } - .main__seller__dashboard { - padding: 12px; + .main__seller__dashboard { + padding: 12px; - .outlet { - max-width: calc(100vw - 3.5rem); - overflow-y: scroll; - } + .outlet { + max-width: calc(100vw - 3.5rem); + overflow-y: scroll; + } - .right__side { - display: none; - } - } - } + .right__side { + display: none; + } + } + } } .seller-loading { - width: 100%; - height: 100vh; - display: flex; - justify-content: center; - align-items: center; + width: 100%; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; } \ No newline at end of file diff --git a/src/assets/styles/SellerProduct.scss b/src/assets/styles/SellerProduct.scss index a80453b3..38002fd0 100644 --- a/src/assets/styles/SellerProduct.scss +++ b/src/assets/styles/SellerProduct.scss @@ -12,7 +12,6 @@ max-width: 100%; max-height: 100%; - .seller-product-header { display: flex; flex-direction: row; diff --git a/src/assets/styles/SellerSideProduct.scss b/src/assets/styles/SellerSideProduct.scss index 0a3b3513..f8a50099 100644 --- a/src/assets/styles/SellerSideProduct.scss +++ b/src/assets/styles/SellerSideProduct.scss @@ -25,7 +25,7 @@ margin-left: 1rem; &__title { - font-size: 16px; + font-size: 1rem; font-weight: bold; } } @@ -37,7 +37,7 @@ border-radius: 0.5rem; &.available { - color: rgb(3, 216, 3); + color: rgb(3, 71, 3); background-color: rgba(3, 216, 3, 0.3); } diff --git a/src/assets/styles/adminDashboard.scss b/src/assets/styles/adminDashboard.scss index dc90dee6..78639605 100644 --- a/src/assets/styles/adminDashboard.scss +++ b/src/assets/styles/adminDashboard.scss @@ -41,10 +41,21 @@ cursor: pointer; } + .text_content:hover { + display: flex; + color: $white; + background-color: $menu-hover; + width: 15rem; + padding: 1rem; + border-radius: .5rem; + } + .active { display: flex; background-color: $menu-hover; + color: $white !important; width: 15rem; + color:$white; padding: 1rem 1rem; transition: all 0.5s ease-in-out; align-items: center; diff --git a/src/components/cards/cards.tsx b/src/components/cards/cards.tsx index c509f70c..844752ac 100644 --- a/src/components/cards/cards.tsx +++ b/src/components/cards/cards.tsx @@ -8,7 +8,7 @@ const Card = ({ title, value, percentage, isPositive, onClick }) => {

{title}

-

{value}

+

{value}

{isPositive ? '+' : '-'}{percentage}%

diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 2b01887b..c0723a0a 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -24,6 +24,7 @@ import logo from "../../../public/assets/images/logo.png"; import useSocket from '../../hooks/useSocket'; import { toast } from 'react-toastify'; import { PulseLoader } from 'react-spinners'; + const Header: React.FC = () => { const dispatch = useAppDispatch(); const navigate = useNavigate(); @@ -32,22 +33,16 @@ const Header: React.FC = () => { const [isMenuOpen, setIsMenuOpen] = useState(false); const [isNotificationOpen, setIsNotificationOpen] = useState(false); const location = useLocation(); - const { - isAuthenticated, - user, - token: tokenLogin, - } = useAppSelector((state) => state.auth); + const { isAuthenticated, user, token: tokenLogin } = useAppSelector((state) => state.auth); const { notifications } = useAppSelector((state) => state.notification); const [token, setToken] = useState(''); const [is2FAEnabled, setIs2FAEnabled] = useState(false); const [is2FALoading, setIs2FALoading] = useState(false); const navEl = useRef(null); - - const User: any = { ...user }; - - const { cartCounter, cartTotalMoney } = useAppSelector((state) => state.cart) + const { cartCounter, cartTotalMoney } = useAppSelector((state) => state.cart); useSocket(); const categories = Array.from({ length: 5 }, (_, i) => i + 1); + useEffect(() => { if (tokenLogin?.trim()) { setToken(tokenLogin); @@ -61,7 +56,6 @@ const Header: React.FC = () => { async function getUserDetail() { if (token?.trim()) await dispatch(getUserDetails(token)); } - getUserDetail(); }, [token, dispatch]); @@ -93,9 +87,7 @@ const Header: React.FC = () => { } } - const unreadCount = notifications - ? notifications.filter((notification) => !notification.isRead).length - : 0; + const unreadCount = notifications ? notifications.filter((notification) => !notification.isRead).length : 0; function formatName(name: string) { const trimmedName = name?.trim(); @@ -106,32 +98,25 @@ const Header: React.FC = () => { const switch2FA = async () => { const successMessage = `2FA ${is2FAEnabled ? "Disabled" : "Enabled, Login now."}`; setIs2FALoading(true); - const res = await dispatch(change2FAStatus({ newStatus: !is2FAEnabled })) + const res = await dispatch(change2FAStatus({ newStatus: !is2FAEnabled })); setIs2FALoading(false); if (res.type === "auth/change-2fa-status/fulfilled") { - toast.success((!is2FAEnabled ? `${res.payload.message}, Login now.` : res.payload.message) || successMessage) - if (!is2FAEnabled) { navigate('/logout') } - setIs2FAEnabled(res.payload.data.user.is2FAEnabled || !is2FAEnabled) - } - else { - toast.error(res.payload) + toast.success((!is2FAEnabled ? `${res.payload.message}, Login now.` : res.payload.message) || successMessage); + if (!is2FAEnabled) { navigate('/logout'); } + setIs2FAEnabled(res.payload.data.user.is2FAEnabled || !is2FAEnabled); + } else { + toast.error(res.payload); } - } + }; - useEffect(() => { if (user) setIs2FAEnabled(user.is2FAEnabled) }, [user]) + useEffect(() => { if (user) setIs2FAEnabled(user.is2FAEnabled); }, [user]); return (
- Ecommerce logo -

- e-Commerce Ninjas -

+ Ecommerce logo +

e-Commerce Ninjas

@@ -156,30 +141,18 @@ const Header: React.FC = () => {
-
- - Shopping Categories - - - +
+ Shopping Categories +
{isOpen && (
)} @@ -188,13 +161,8 @@ const Header: React.FC = () => {
{isAuthenticated && (
- - - {unreadCount} - + + {unreadCount} {isNotificationOpen && (
@@ -202,26 +170,17 @@ const Header: React.FC = () => { )}
)} -
{isAuthenticated ? (
- - - {cartCounter} - + + {cartCounter}
) : (
- - - 0 - + + 0
)}
@@ -237,20 +196,16 @@ const Header: React.FC = () => {
-
- {user && User.profilePicture ? ( - +
+ {user && user.profilePicture ? ( + User Profile ) : ( )} - {user ? 'Hi, ' : 'User'} {user - ? formatName(User?.firstName || User?.email?.split('@')[0]) + ? formatName(user?.firstName || user?.email?.split('@')[0]) : "Account"} {isAuthenticated && isOpen2 && ( @@ -275,12 +230,11 @@ const Header: React.FC = () => {
  • - + Logout
  • - @@ -237,21 +253,35 @@ function UserLogin() { aria-describedby="alert-dialog-description" PaperProps={{ style: { - borderRadius: '12px', - padding: '24px', - maxWidth: '400px', + borderRadius: "12px", + padding: "24px", + maxWidth: "400px", }, }} > - + Verify OTP - - Please enter the 6-digit OTP sent to your email to verify your account. + + Please enter the 6-digit OTP sent to your email to verify your + account. - - {otp.map((digit, index) => ( + + {otp?.map((digit, index) => ( handleOtpChange(index, e.target.value)} inputProps={{ maxLength: 1, - style: { textAlign: 'center', fontSize: '1.5rem' } + style: { textAlign: "center", fontSize: "1.5rem" }, }} sx={{ - width: '40px', - '& .MuiOutlinedInput-root': { - '& fieldset': { - borderColor: '#ff6d18', + width: "40px", + "& .MuiOutlinedInput-root": { + "& fieldset": { + borderColor: "#ff6d18", }, - '&:hover fieldset': { - borderColor: '#e65b00', + "&:hover fieldset": { + borderColor: "#e65b00", }, - '&.Mui-focused fieldset': { - borderColor: '#e65b00', + "&.Mui-focused fieldset": { + borderColor: "#e65b00", }, }, }} /> ))} - { - otpError && - - {otpError} + {otpError && ( + + {typeof(otpError) === "string" ? otpError : null} - } + )} - + - -

    or Login with

    -
    - -

    Login with google

    -
    -

    - New to e-commerce Ninjas?{" "} - - Register - -

    -
    -
    - - ); -} - -export default SellerLogin; \ No newline at end of file diff --git a/src/pages/admin/Dashboard.tsx b/src/pages/admin/Dashboard.tsx index 8f4fbf85..92a8f307 100644 --- a/src/pages/admin/Dashboard.tsx +++ b/src/pages/admin/Dashboard.tsx @@ -10,14 +10,17 @@ import { logout } from "../../store/features/auth/authSlice"; import { toast } from "react-toastify"; import { Backdrop, Box, CircularProgress, Typography } from "@mui/material"; import { Meta } from "../../components/Meta"; +import useAdminAuthCheck from "../../hooks/useAdminAuthCheck"; +import { disconnect } from "../../utils/socket/socket"; export const AdminDashboard = () => { const dispatch = useAppDispatch(); + // const isAuthorized = useAdminAuthCheck(); const { isLoading, message, isError } = useAppSelector( (state) => state.admin ); - + const [isActive, setIsActive] = useState(() => { return parseInt(localStorage.getItem("activeTab")) || 1; }); @@ -33,6 +36,7 @@ export const AdminDashboard = () => { const handleLogout = () => { dispatch(logout()); + disconnect(); setTimeout(() => { navigate("/"); }, 2000); @@ -41,7 +45,7 @@ export const AdminDashboard = () => { useEffect(() => { if (isError && message === "Not authorized") { toast.info("You are not authorized to access this page"); - navigate("/admin"); + navigate("/login"); return; } }, [isError, message, navigate]); @@ -67,7 +71,7 @@ export const AdminDashboard = () => { className={`text_content ${isActive === 1 ? "active" : ""}`} onClick={() => handleClick(1, "/admin/dashboard")} > - Admin Dashboard + Dashboard
    diff --git a/src/pages/admin/Login.tsx b/src/pages/admin/Login.tsx deleted file mode 100644 index 2f07886e..00000000 --- a/src/pages/admin/Login.tsx +++ /dev/null @@ -1,176 +0,0 @@ -/* eslint-disable */ - -import React, { useEffect, useRef, useState } from "react"; -import { BiSolidShow } from "react-icons/bi"; -import { BiSolidHide } from "react-icons/bi"; - -import { useAppDispatch, useAppSelector } from "../../store/store"; -import { loginUser } from "../../store/features/auth/authSlice"; -import { Link, Navigate, useLocation, useNavigate } from "react-router-dom"; -import { toast } from "react-toastify"; -import { PulseLoader } from "react-spinners"; -import { useFormik } from "formik"; -import * as Yup from "yup"; -import { Meta } from "../../components/Meta"; -import { joinRoom } from "../../utils/socket/socket"; - -const LoginSchema = Yup.object().shape({ - email: Yup.string() - .email("Email must be valid") - .required("Email is required"), - password: Yup.string().required("Password is required"), -}); - -function AdminLogin() { - const [isClicked, setIsClicked] = useState(false); - const [isFocused, setIsFocused] = useState(false); - const [isVisible, setIsVisible] = useState(false); - const navigate = useNavigate(); - const location = useLocation(); - const dispatch = useAppDispatch(); - const { - isLoading, - isError, - isSuccess, - isAuthenticated, - token, - error, - message, - } = useAppSelector((state) => state.auth); - - const formik = useFormik({ - initialValues: { - email: "", - password: "", - }, - validationSchema: LoginSchema, - onSubmit: (values) => { - dispatch(loginUser(values)); - }, - }); - - useEffect(() => { - if (isSuccess && isAuthenticated && token) { - localStorage.setItem("token", token); - navigate("/admin/dashboard"); - formik.resetForm(); - joinRoom(token); - } - }, [token, isAuthenticated, error, isError, isSuccess]); - if (isAuthenticated && localStorage.getItem("token")) { - return ; - } - - function handleIsFocused() { - setIsFocused(true); - setIsClicked(false); - } - - function handleIsVisible() { - setIsVisible((isVisible) => !isVisible); - } - - return ( - <> - -
    -
    -
    -

    Admin Dashboard

    -

    - Access the Admin Dashboard to view insightful statistics and - manage users efficiently. -

    - login picture -
    -
    -
    -
    - Ecommerce logo -

    - e-Commerce Ninjas -

    -
    -

    Welcome back

    -

    Please login to your account

    -
    -
    -
    - setIsClicked(false)} - onBlur={formik.handleBlur} - /> -
    -
    - - {isFocused ? ( - isVisible ? ( - - ) : ( - - ) - ) : ( - "" - )} -

    - - Forgot password - -

    -
    - {formik.touched.email && formik.errors.email ? ( -

    {formik.errors.email}

    - ) : formik.touched.password && formik.errors.password ? ( -

    {formik.errors.password}

    - ) : isError && isClicked ? ( -

    {error}

    - ) : null} - -
    -
    -
    -
    - - ); -} - -export default AdminLogin; diff --git a/src/pages/seller/SellerCollection.tsx b/src/pages/seller/SellerCollection.tsx index 835555c7..978051a2 100644 --- a/src/pages/seller/SellerCollection.tsx +++ b/src/pages/seller/SellerCollection.tsx @@ -53,16 +53,18 @@ export default function SellerCollection() { setItemToDelete(null) } catch (error) { console.error('Error deleting item:', error); - }finally{ - if(isSuccess) - toast.success(message) + } + finally{ + if(isSuccess){ + // toast.success(message) + } } }; useEffect(() => { if (isUpdate && isUpdateSuccess) { - toast.success(updateMessage); + // toast.success(updateMessage); dispatch(fetchSellerCollectionProduct()); } else if (updateError && !isUpdateSuccess) toast.error(updateError) diff --git a/src/pages/seller/SellerDashboard.tsx b/src/pages/seller/SellerDashboard.tsx index a92aa074..5a3525e1 100644 --- a/src/pages/seller/SellerDashboard.tsx +++ b/src/pages/seller/SellerDashboard.tsx @@ -16,14 +16,13 @@ import { sellerGetAllProducts, sellerGetOrderHistory, } from "../../store/features/product/sellerCollectionProductsSlice"; -import { useNavigate } from 'react-router-dom'; +import { useNavigate } from "react-router-dom"; import productSlice from "../../store/features/product/productSlice"; - - const SellerDashboard = () => { - - + const { OrderHistory, message, data, isError } = useAppSelector( + (state) => state?.sellerCollectionProducts + ); const predefinedMonths = [ { name: "Jan", Completed: 0, Cancelled: 0 }, { name: "Feb", Completed: 0, Cancelled: 0 }, @@ -45,46 +44,66 @@ const SellerDashboard = () => { }; const dispatch = useAppDispatch(); - const navigate = useNavigate(); + const navigate = useNavigate(); const [numberOfProducts, setNumberOfProducts] = useState(null); const [orderStats, setOrderStats] = useState([]); const [numberOfOrders, setNumberOfOrders] = useState(null); const [selectedMonth, setSelectedMonth] = useState("All"); - + const [revenue, setRevenue] = useState(0); + const [percentage, setPercentage] = useState(0); + const [orderPercentage, setOrderPercentage] = useState(0); + const [productPercentage,SetProductPercentage] = useState(0); + useEffect(() => { + dispatch(sellerGetOrderHistory()); + dispatch(fetchSellerCollectionProduct()); + }, [dispatch]); useEffect(() => { try { const countData = async () => { - const orderHistoryResponse = await dispatch(sellerGetOrderHistory()); - const orderNumber = orderHistoryResponse.payload.data.order.length; - setNumberOfOrders(orderNumber); - const porductResponse = await dispatch(fetchSellerCollectionProduct()); - const data:any = porductResponse.payload; - const numberOfProduct = data.data.products.length; - setNumberOfProducts(numberOfProduct); - - const aggregatedData = orderHistoryResponse.payload.data.order.reduce( - (acc, order) => { - const monthName = getMonthName(order.orderDate); - const month = acc.find((m) => m.name === monthName); - if (month) { - if (order.status === "completed") { - month.Completed += 1; - } else if (order.status === "canceled") { - month.Cancelled += 1; + console.log(OrderHistory); + if (OrderHistory) { + const orderNumber = OrderHistory.order.length; + setNumberOfOrders(orderNumber); + const numberOfProduct = data.products.length; + setNumberOfProducts(numberOfProduct); + const aggregatedData = OrderHistory.order.reduce( + (acc, order) => { + const monthName = getMonthName(order.orderDate); + const month = acc.find((m) => m.name === monthName); + if (month) { + if (order.status === "completed") { + month.Completed += 1; + } else if (order.status === "canceled") { + month.Cancelled += 1; + } } - } - return acc; - }, - [...predefinedMonths] - ); - setOrderStats(aggregatedData); + return acc; + }, + [...predefinedMonths] + ); + setOrderStats(aggregatedData); + setRevenue(20000) + setPercentage(10) + setOrderPercentage(80) + SetProductPercentage(76) + } + if ( isError && OrderHistory == null && message === "No shop found"){ + setNumberOfOrders(0); + setNumberOfProducts(0); + setOrderStats(predefinedMonths); + setRevenue(0) + setPercentage(0) + setPercentage(0) + setOrderPercentage(0) + SetProductPercentage(0) + } }; countData(); } catch (error) { console.error("Failed to fetch data:", error); } - }, [dispatch]); + }, [OrderHistory,isError,message]); const MonthDropDown = () => { const [isOpen, setIsOpen] = useState(false); @@ -145,64 +164,72 @@ const SellerDashboard = () => { return ( <>
    -
    - - - navigate("/seller/products")} -/> -
    -
    -
    -
    -

    Overview sales

    -
    - Completed - Cancelled +
    + + + navigate("/seller/products")} + /> +
    +
    +
    +
    +

    Overview sales

    +
    + Completed + Cancelled +
    +
    - + + + + + + + + + +
    - - - - - - - - - - -
    ); }; -export default SellerDashboard; \ No newline at end of file +export default SellerDashboard; diff --git a/src/router.tsx b/src/router.tsx index 70eb2253..aeb7693a 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -11,25 +11,21 @@ import { ResendEmail } from './components/ResendEmail'; import GoogleCallback from './components/GoogleCallback'; import SendResetPasswordLink from './pages/SendResetPasswordLink'; import ResetPassword from './pages/ResetPassword'; -import { ProtectedRoute } from './utils/protectRoute/ProtectedRoute'; +import { ProtectedRoute } from "./utils/protectRoute/ProtectedRoute"; import ViewProduct from './pages/ViewProduct'; -import UserLogin from './pages/UserLogin'; -import SellerLogin from './pages/SellerLogin'; -import AdminLogin from './pages/admin/Login'; +import Login from './pages/Login'; import UserViewCart from './pages/UserViewCart'; -import Search from './pages/Search'; -import SellerViewProduct from './pages/seller/SellerViewProduct'; -import SellerCollection from './pages/seller/SellerCollection'; -import { SellerLayout } from './components/layout/SellerLayout'; -import SellerDashboard from './pages/seller/SellerDashboard'; -import { AdminDashboard } from './pages/admin/Dashboard'; -import { OverViewDashboard } from './pages/admin/OverView'; -import Users from './pages/admin/Users'; +import Search from "./pages/Search"; +import SellerViewProduct from "./pages/seller/SellerViewProduct"; +import SellerCollection from "./pages/seller/SellerCollection"; +import { SellerLayout } from "./components/layout/SellerLayout"; +import SellerDashboard from "./pages/seller/SellerDashboard"; +import { AdminDashboard } from "./pages/admin/Dashboard"; +import { OverViewDashboard } from "./pages/admin/OverView"; +import Users from "./pages/admin/Users"; import Logout from './components/layout/Logout'; import UserProfile from './pages/UserEditProfile'; import ProductsPage from './pages/Products'; -import UserVIewOrders from './pages/UserViewOrders'; -import TrackOrder from './pages/trackOrder'; const AppRouter: React.FC = () => { return (
    @@ -39,52 +35,20 @@ const AppRouter: React.FC = () => { } /> } /> } /> - } /> + } /> } /> } /> - } - /> - } - /> - } - /> - } - /> + } /> + } /> } /> - } - /> + } /> } /> } /> } /> } /> - } /> - } /> - - - - } - /> + }/> } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + }> } /> @@ -99,15 +63,8 @@ const AppRouter: React.FC = () => { } /> - } /> - - - - } - > + } /> + }> } /> } /> @@ -117,4 +74,4 @@ const AppRouter: React.FC = () => { ); }; -export default AppRouter; +export default AppRouter; \ No newline at end of file diff --git a/src/store/features/auth/authSlice.tsx b/src/store/features/auth/authSlice.tsx index b413c5c7..ca24d007 100644 --- a/src/store/features/auth/authSlice.tsx +++ b/src/store/features/auth/authSlice.tsx @@ -17,7 +17,9 @@ const initialState: AuthService = { isAuthenticated: false, error: "", userId: "", - fail: false + fail: false, + isOtpFail:false, + isOtpSuccess:false, }; type IUserEmailAndPassword = Pick; @@ -187,6 +189,8 @@ const userSlice = createSlice({ state.isAuthenticated = false; state.error = ""; state.fail= false; + state.isOtpFail = false; + state.isOtpSuccess = false; }, changingProfile: (state, action: any)=>{ (state.user as any).profilePicture = action.payload @@ -323,13 +327,14 @@ const userSlice = createSlice({ if(state.message !== "Check your Email for OTP Confirmation"){ state.isAuthenticated = true; state.token = action.payload.data.token; + state.user = action.payload.data.user; } }) .addCase(loginUser.rejected, (state, action: PayloadAction) => { state.isError = true; state.isLoading = false; state.isSuccess = false; - state.error = action.payload + state.error = action.payload; }) .addCase(logout.pending, (state) => { state.isError = false; @@ -374,12 +379,20 @@ const userSlice = createSlice({ }) .addCase(verifyOTP.fulfilled, (state, action: PayloadAction) => { - state.isError = false; + state.isOtpFail = false; state.isLoading = false; state.isAuthenticated = true; - state.isSuccess = true; + state.isOtpSuccess = true; state.message = action.payload.message; state.token = action.payload.data.token; + console.log(action.payload) + }) + .addCase(verifyOTP.rejected, (state, action: PayloadAction) => { + state.isOtpFail = true; + state.isLoading = false; + state.isOtpSuccess = false; + state.message = action.payload; + toast.error(action.payload) }) }, diff --git a/src/store/features/product/sellerCollectionProductsSlice.tsx b/src/store/features/product/sellerCollectionProductsSlice.tsx index a14d4290..82409155 100644 --- a/src/store/features/product/sellerCollectionProductsSlice.tsx +++ b/src/store/features/product/sellerCollectionProductsSlice.tsx @@ -5,6 +5,7 @@ import { ISellerCollectionProductInitialResponse, ISellerCollectionProductRespon import { getErrorMessage } from "../../../utils/axios/axiosInstance"; const initialState: ISellerCollectionProductInitialResponse = { + message: "", data: { products: null, previousPage: 0, @@ -15,7 +16,7 @@ const initialState: ISellerCollectionProductInitialResponse = { isLoading: false, isError: false, isSuccess: false, - message: '' + OrderHistory: null } export const fetchSellerCollectionProduct = createAsyncThunk("products/fetchSellerCollectionProducts", async (_,thunkApi) => { @@ -86,16 +87,16 @@ const sellerCollectionProductsSlice = createSlice({ state.isError = null; state.isSuccess = false; }) - .addCase(sellerGetOrderHistory.fulfilled, (state, action: PayloadAction) => { + .addCase(sellerGetOrderHistory.fulfilled, (state, action: PayloadAction) => { state.isLoading = false; state.isSuccess = true; - state.data = action.payload.data; + state.OrderHistory = action.payload.data; }) .addCase(sellerGetOrderHistory.rejected, (state, action: PayloadAction) => { state.isLoading = false; - state.isError = false; + state.isError = true; state.isSuccess = false; - state.message = action.payload.message || null + state.message = action.payload; }); } }) diff --git a/src/utils/axios/axiosInstance.ts b/src/utils/axios/axiosInstance.ts index 171626ef..3b432f3e 100644 --- a/src/utils/axios/axiosInstance.ts +++ b/src/utils/axios/axiosInstance.ts @@ -31,4 +31,4 @@ const getErrorMessage = (msg: unknown): string => { return "An unknown error occurred"; }; -export { axiosInstance, getErrorMessage }; +export { axiosInstance, getErrorMessage }; \ No newline at end of file diff --git a/src/utils/types/store.d.ts b/src/utils/types/store.d.ts index ff0cb46d..c003b4f0 100644 --- a/src/utils/types/store.d.ts +++ b/src/utils/types/store.d.ts @@ -78,6 +78,8 @@ export interface AuthService { token: string; userId?: any; fail:boolean; + isOtpFail:boolean; + isOtpSuccess:boolean; } export interface IEmail { @@ -231,5 +233,6 @@ export interface ISellerCollectionProductInitialResponse { isError: boolean; isSuccess: boolean; isLoading: boolean; - message: string | null; + message: string; + OrderHistory: null } \ No newline at end of file diff --git a/webpack.dev.config.ts b/webpack.dev.config.ts index 1b684fa0..ffb303f6 100644 --- a/webpack.dev.config.ts +++ b/webpack.dev.config.ts @@ -97,7 +97,7 @@ const config: Configuration = { historyApiFallback: { disableDotRule: true, }, - port: 9000, + port: 5000, open: true, hot: true, },