Skip to content

Commit

Permalink
Merge pull request #39 from atlp-rwanda/187354203-ft-create-items-by-…
Browse files Browse the repository at this point in the history
…seller

Feature that enables sellers to create product
  • Loading branch information
niyontwali authored Jul 19, 2024
2 parents df070db + 0aeb9a3 commit 3fb8f9d
Show file tree
Hide file tree
Showing 34 changed files with 731 additions and 220 deletions.
51 changes: 29 additions & 22 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://assets-global.website-files.com/6480f74670678239cc947755/6488d4417cfc510dd4a63f0a_favicon.png"
rel="shortcut icon"
type="image/x-icon"
/>
<link
href="https://assets-global.website-files.com/6480f74670678239cc947755/6488d446646e7274f07e1744_webclip.png"
rel="apple-touch-icon"
/>
<meta
name="description"
content="Welcome to the best E-Commerce in Rwanda. We offer best price, as well as delivery services. We are the best in this this country!"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet"
/>

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://assets-global.website-files.com/6480f74670678239cc947755/6488d4417cfc510dd4a63f0a_favicon.png"
rel="shortcut icon" type="image/x-icon" />
<link href="https://assets-global.website-files.com/6480f74670678239cc947755/6488d446646e7274f07e1744_webclip.png"
rel="apple-touch-icon" />
<meta name="description"
content="Welcome to the best E-Commerce in Rwanda. We offer best price, as well as delivery services. We are the best in this this country!" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet">
<title>Mavericks E-Commerce</title>
</head>
<title>Mavericks E-Commerce</title>
</head>

<body>
<div id="root" class="relative"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

</html>
<body>
<div id="root" class="relative"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@hookform/resolvers": "^3.6.0",
"@reduxjs/toolkit": "^2.2.5",
"@tinymce/tinymce-react": "^5.1.1",
"@types/react-redux": "^7.1.33",
"apexcharts": "^3.49.1",
"axios": "^1.7.2",
Expand Down
48 changes: 45 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ import Messages from './pages/admin/Messages';
import UserManagement from './pages/admin/UserManagement';
import NotFoundPage from './pages/NotFoundPage';
import Settings from './pages/admin/Settings';
import SellersPage from './pages/seller';
import Orders from './pages/seller/Orders';
import Products from './pages/seller/Products';
import Customers from './pages/seller/Customers';
import SellerMessages from './pages/seller/Messages';
import SellerSettings from './pages/seller/Settings';
import AddNewProduct from './pages/seller/AddNewProduct';
import RestrictedSellerRoute from './components/dashboard/RestrictedSellerLayout';

import CategoriesPage from './pages/CategoriesPage';
import ResetPassword from './pages/ResetPassword';
Expand Down Expand Up @@ -49,15 +57,15 @@ const App = () => {
return;
}
if (!isLoading && productsData) {
const productsList = productsData.data as Product[];
const productsList = productsData.data as unknown as Product[];
dispatch(setProductsDataList([...productsList]));
dispatch(setIsLoading(false));
dispatch(setProductFetched(true));
}
};
fetchProducts();

dispatch<any>(cartApi.endpoints.getCarts.initiate())
dispatch<any>(cartApi.endpoints.getCarts.initiate());
}, [productsData, isLoading, dispatch]);

const router = createBrowserRouter([
Expand All @@ -78,7 +86,7 @@ const App = () => {
},
{
path: 'shoppingcart',
element: <Cart />
element: <Cart />,
},
{
path: 'categories/:categoryId',
Expand Down Expand Up @@ -131,6 +139,40 @@ const App = () => {
path: 'buyers',
element: <Buyers />,
},
{
path: 'messages',
element: <SellerMessages />,
},
{
path: 'settings',
element: <SellerSettings />,
},
],
},
{
path: 'seller',
element: <RestrictedSellerRoute role='seller' />,
children: [
{
index: true,
element: <SellersPage />,
},
{
path: 'orders',
element: <Orders />,
},
{
path: 'products',
element: <Products />,
},
{
path: 'add-new-product',
element: <AddNewProduct />,
},
{
path: 'customers',
element: <Customers />,
},
{
path: 'messages',
element: <Messages />,
Expand Down
Binary file removed src/assets/Rectangle 2487.png
Binary file not shown.
Binary file removed src/assets/logo.jpeg
Binary file not shown.
9 changes: 0 additions & 9 deletions src/assets/logo.svg

This file was deleted.

4 changes: 2 additions & 2 deletions src/components/Products/ProductReviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ const ProductReviewCard: React.FC<Props> = ({ review }) => {
return (
<div className='flex border-b border-grayColor py-2 snap-center'>
<div className='flex p-2 w-1/5 min-h-14 justify-center'>
<img className='rounded-full h-14 w-14' src={review.user.photoUrl || defaultProfile} alt='Buyer' />
<img className='rounded-full h-14 w-14' src={review.user?.photoUrl || defaultProfile} alt='Buyer' />
</div>
<div className='w-4/5 p-2'>
<div className='space-y-1'>
<p className='font-medium'>{review.user.firstName}</p>
<p className='font-medium'>{review.user?.firstName}</p>
<div className='flex gap-4 items-center'>
<span className='flex'>{renderStars(review.rating)}</span>
<span className='text-xs text-gray-500'>{dateReviewed}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,8 @@ import { useDispatch } from 'react-redux';
import { AppDispatch } from '../../redux/store';
import { useEffect } from 'react';
import { setIsCreated } from '../../redux/slices/categorySlice';
import CustomInput from './CustomInput';

export interface ICategory {
id: string;
name: string;
description: string;
image: string;
}
import CustomInput from '../dashboard/CustomInput';
import { Category as ICategory } from '../../types/Types';

export default function AddCategoryModal({
openAddModal,
Expand Down Expand Up @@ -41,8 +35,7 @@ export default function AddCategoryModal({
const formData = new FormData();
formData.append('name', data.name);
formData.append('description', data.description);
formData.append('image', data.image[0]);

formData.append('image', data.image![0]);
await createCategory(formData);
};

Expand Down
25 changes: 25 additions & 0 deletions src/components/admin/AdminLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Outlet } from 'react-router-dom';
import Sidebar from '../dashboard/Sidebar';
import { RxDashboard } from 'react-icons/rx';
import { FaCog, FaRegListAlt, FaUserFriends } from 'react-icons/fa';
import { FaRegEnvelope, FaUserTie } from 'react-icons/fa6';

export default function AdminLayout() {
const adminSidebarLinks = [
{ name: 'Dashboard', path: '/admin', icon: <RxDashboard className='mr-3' /> },
{ name: 'Categories', path: 'categories', icon: <FaRegListAlt className='mr-3' /> },
{ name: 'Sellers', path: 'sellers', icon: <FaUserFriends className='mr-3' /> },
{ name: 'Buyers', path: 'buyers', icon: <FaUserTie className='mr-3' /> },
{ name: 'Messages', path: 'messages', icon: <FaRegEnvelope className='mr-3' /> },
{ name: 'Settings', path: 'settings', icon: <FaCog className='mr-3' /> },
];

return (
<>
<div className='bg-[#D3E4DE] min-h-screen'>
<Sidebar sidebarLinks={adminSidebarLinks} />
<Outlet />
</div>
</>
);
}
8 changes: 3 additions & 5 deletions src/components/authentication/LoginComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import GoogleIcon from '../../assets/googleIcon.svg';
import Button from '../common/Button';
import Input from '../common/Input';
import { loginSchema, LoginData } from '../../utils/schemas';
import { useNavigate, useLocation, useSearchParams, Link } from 'react-router-dom';
import { useNavigate, useLocation, useSearchParams } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { setToken, setUser, setRole } from '../../redux/slices/userSlice';
import { useLoginUserMutation } from '../../services/authAPI';
Expand Down Expand Up @@ -86,7 +86,7 @@ const LoginComponent = () => {
} else if (role === 'admin') {
navigate('/admin');
} else {
navigate('seller');
navigate('/seller');
}
}
}, [isUserSuccess, userData]);
Expand Down Expand Up @@ -120,9 +120,7 @@ const LoginComponent = () => {
{...register('password')}
error={errors.password && errors.password.message}
/>
<Link to={'/reset-password'}>
<p className='text-sm text-end hover:cursor-pointer hover:underline'>Forget password</p>
</Link>
<p className='text-sm text-end hover:cursor-pointer hover:underline'>Forget password</p>
<button
type='submit'
className='p-2 rounded-lg bg-greenColor hover:bg-darkGreen transition-all text-whiteColor font-bold'
Expand Down
21 changes: 0 additions & 21 deletions src/components/dashboard/AdminLayout.tsx

This file was deleted.

33 changes: 29 additions & 4 deletions src/components/dashboard/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
import { IoIosNotificationsOutline } from 'react-icons/io';
import adminProfile from '../../assets/profile-picture-5.jpg';
import { FaBars } from 'react-icons/fa6';
import { useDispatch } from 'react-redux';
import { setIsOpen } from '../../redux/slices/sidebarSlice';
import Notifications from '../navbar/notifications/Notifications';
import { useState } from 'react';

export default function Navbar({ location, page }: { location: string; page: string }) {
const dispatch = useDispatch();

const [openNotification, setOpenNotification] = useState(false);

const handleOpenNotification = () => {
setOpenNotification(!openNotification);
};

const toggleSidebar = () => {
dispatch(setIsOpen());
};

export default function Navbar({ toggleSidebar }: { toggleSidebar: () => void }) {
return (
<div className='md:ml-64 flex justify-between items-center sticky top-0 bg-[#D3E4DE] px-6'>
<h1 className='text-2xl font-normal'>Dashboard</h1>
<div
className={`md:ml-64 flex justify-between items-center sticky top-0 ${page === 'admin' ? 'bg-[#D3E4DE]' : 'bg-[#EFF4FE]'} px-6`}
>
<h1 className='text-2xl font-normal'>{location}</h1>
<div className='flex items-center'>
<button className='m-3 bg-whiteColor rounded p-1 relative'>
<button className='m-3 bg-whiteColor rounded p-1 relative' onClick={handleOpenNotification}>
<IoIosNotificationsOutline size={30} className='text-[#8F8183]' />
<div className='relative'>
{openNotification && (
<div className='absolute top-5 right-0 min-w-72 z-10'>
<Notifications />
</div>
)}
</div>
</button>
<div className='mr-5'>
<img src={adminProfile} alt='' width={35} height={35} className='rounded-lg' />
Expand Down
9 changes: 2 additions & 7 deletions src/components/dashboard/RestrictedRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import React from 'react';
import { Navigate } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { RootState } from '../../redux/store';
import AdminLayout from './AdminLayout';
import AdminLayout from '../admin/AdminLayout';

interface RestrictedRouteProp {
role: string;
}

const RestrictedRoute: React.FC<RestrictedRouteProp> = ({ role }) => {
const RestrictedRoute = ({ role }: { role: string }) => {
const user = useSelector((state: RootState) => state.user);
const isAuthenticated = useSelector((state: RootState) => state.user.token);

Expand Down
17 changes: 17 additions & 0 deletions src/components/dashboard/RestrictedSellerLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Navigate } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { RootState } from '../../redux/store';
import SellerLayout from '../seller/SellerLayout';

const RestrictedSellerRoute = ({ role }: { role: string }) => {
const user = useSelector((state: RootState) => state.user);
const isAuthenticated = useSelector((state: RootState) => state.user.token);

if (!isAuthenticated && user.role !== role) {
return <Navigate to='/' />;
}

return <SellerLayout />;
};

export default RestrictedSellerRoute;
Loading

0 comments on commit 3fb8f9d

Please sign in to comment.