From d8039523d2dc3019c57c3f8928f97777a138f30a Mon Sep 17 00:00:00 2001 From: "Prince NZAMUWE(Fudji Bokande)" <134228300+princenzmw@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:35:34 +0200 Subject: [PATCH] [Finishes #187788139] Controll sellers on admin dashboard --- src/App.tsx | 10 ++ src/assets/404_page.png | Bin 0 -> 30037 bytes .../dashboard/ConfirmDisableModal.tsx | 41 +++++ src/components/dashboard/RoleChangeModal.tsx | 69 ++++++++ src/components/dashboard/Sidebar.tsx | 15 +- src/components/dashboard/UsersTable.tsx | 159 ++++++++++++++++++ src/components/dashboard/VendorsTable.tsx | 159 ++++++++++++++++++ src/pages/NotFoundPage.tsx | 38 +++++ src/pages/admin/Sellers.tsx | 115 ++++++++++++- src/pages/admin/UserManagement.tsx | 112 ++++++++++++ src/services/roleApi.ts | 18 ++ src/services/userApi.ts | 30 +++- src/types/Types.ts | 18 ++ 13 files changed, 779 insertions(+), 5 deletions(-) create mode 100644 src/assets/404_page.png create mode 100644 src/components/dashboard/ConfirmDisableModal.tsx create mode 100644 src/components/dashboard/RoleChangeModal.tsx create mode 100644 src/components/dashboard/UsersTable.tsx create mode 100644 src/components/dashboard/VendorsTable.tsx create mode 100644 src/pages/NotFoundPage.tsx create mode 100644 src/pages/admin/UserManagement.tsx create mode 100644 src/services/roleApi.ts diff --git a/src/App.tsx b/src/App.tsx index 19593e4..7b8e9d3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,6 +18,8 @@ import Category from './pages/admin/Category'; import Sellers from './pages/admin/Sellers'; import Buyers from './pages/admin/Buyers'; import Messages from './pages/admin/Messages'; +import UserManagement from './pages/admin/UserManagement'; +import NotFoundPage from './pages/NotFoundPage'; import Settings from './pages/admin/Settings'; import CategoriesPage from './pages/CategoriesPage'; @@ -125,6 +127,10 @@ const App = () => { path: 'messages', element: , }, + { + path: 'users', + element: , + }, { path: 'settings', element: , @@ -135,6 +141,10 @@ const App = () => { path: 'search', element: , }, + { + path: '*', + element: , + }, ]); return ( <> diff --git a/src/assets/404_page.png b/src/assets/404_page.png new file mode 100644 index 0000000000000000000000000000000000000000..a33c594840e5cd69decb5bb97ee8655fc5d99ec7 GIT binary patch literal 30037 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 literal 0 HcmV?d00001 diff --git a/src/components/dashboard/ConfirmDisableModal.tsx b/src/components/dashboard/ConfirmDisableModal.tsx new file mode 100644 index 0000000..43a131d --- /dev/null +++ b/src/components/dashboard/ConfirmDisableModal.tsx @@ -0,0 +1,41 @@ +import React from 'react'; + +interface ConfirmDisableModalProps { + sellerName: string; + onClose: () => void; + onConfirm: () => void; +} + +const ConfirmDisableModal: React.FC = ({ sellerName, onClose, onConfirm }) => { + const handleBackgroundClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + onClose(); + } + }; + + return ( +
+
+

Confirm Disable

+

+ Are you sure you want to disable the seller account for {sellerName}?
+
+ This action will change their role to buyer. +

+
+ + +
+
+
+ ); +}; + +export default ConfirmDisableModal; \ No newline at end of file diff --git a/src/components/dashboard/RoleChangeModal.tsx b/src/components/dashboard/RoleChangeModal.tsx new file mode 100644 index 0000000..6c98b65 --- /dev/null +++ b/src/components/dashboard/RoleChangeModal.tsx @@ -0,0 +1,69 @@ +import React, { useState } from 'react'; + +interface Role { + id: string; + name: string; +} + +interface RoleChangeModalProps { + isOpen: boolean; + onClose: () => void; + onConfirm: (roleId: string) => void; + user: any; + roles: Role[]; +} + +const RoleChangeModal: React.FC = ({ isOpen, onClose, onConfirm, user, roles }) => { + const [selectedRoleId, setSelectedRoleId] = useState(''); + + if (!isOpen || !user) return null; + + const handleConfirm = () => { + if (selectedRoleId) { + onConfirm(selectedRoleId); + } + onClose(); + }; + + return ( +
+
+

+ Change Role for{' '} + + {user.firstName} {user.lastName} + +

+

Current Role: {user.Role.name}

+
+ + +
+
+ + +
+
+
+ ); +}; + +export default RoleChangeModal; diff --git a/src/components/dashboard/Sidebar.tsx b/src/components/dashboard/Sidebar.tsx index 786aba3..3f36707 100644 --- a/src/components/dashboard/Sidebar.tsx +++ b/src/components/dashboard/Sidebar.tsx @@ -1,4 +1,4 @@ -import { FaRegListAlt, FaUserFriends, FaUserTie, FaRegEnvelope, FaCog } from 'react-icons/fa'; +import { FaRegListAlt, FaUserFriends, FaUserTie, FaRegEnvelope, FaCog, FaUsers } from 'react-icons/fa'; import { FiLogOut } from 'react-icons/fi'; import { RxDashboard } from 'react-icons/rx'; import logo from '../../assets/Rectangle 2487.png'; @@ -97,6 +97,19 @@ export default function Sidebar({ isOpen, toggleSidebar }: { isOpen: boolean; to Messages +
  • + + `flex items-center py-2.5 px-4 rounded transition duration-200 hover:bg-[#E5E7EB] ${ + isActive ? 'bg-skyBlue text-skyBlueText hover:bg-skyBlue' : 'text-[#8F8183]' + }` + } + > + + Users + +
  • React.ReactNode; +} + +interface TableProps { + data: any[]; + columns: Column[]; + itemsPerPage: number; +} + +const getInitials = (firstName: string, lastName: string) => + `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase(); + +const getRandomColor = () => { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +}; + +const Table: React.FC = ({ data, columns, itemsPerPage }) => { + const [currentPage, setCurrentPage] = useState(1); + const [sortColumn, setSortColumn] = useState(null); + const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); + const [searchTerm, setSearchTerm] = useState(''); + + const filteredData = useMemo( + () => + data.filter(item => + columns.some(column => String(item[column.key]).toLowerCase().includes(searchTerm.toLowerCase())) + ), + [data, columns, searchTerm] + ); + + const sortedData = useMemo(() => { + if (!sortColumn) return filteredData; + return [...filteredData].sort((a, b) => { + if (a[sortColumn] < b[sortColumn]) return sortDirection === 'asc' ? -1 : 1; + if (a[sortColumn] > b[sortColumn]) return sortDirection === 'asc' ? 1 : -1; + return 0; + }); + }, [filteredData, sortColumn, sortDirection]); + + const paginatedData = useMemo(() => { + const startIndex = (currentPage - 1) * itemsPerPage; + return sortedData.slice(startIndex, startIndex + itemsPerPage); + }, [sortedData, currentPage, itemsPerPage]); + + const totalPages = Math.ceil(sortedData.length / itemsPerPage); + + const handleSort = (column: string) => { + if (column === sortColumn) { + setSortDirection(prev => (prev === 'asc' ? 'desc' : 'asc')); + } else { + setSortColumn(column); + setSortDirection('asc'); + } + }; + + const handleSearch = (e: React.ChangeEvent) => { + setSearchTerm(e.target.value); + setCurrentPage(1); + }; + + const renderCell = (item: any, column: Column) => { + if (column.isImage) { + return item[column.key] ? ( + {`${item.firstName} + ) : ( +
    + {getInitials(item.firstName, item.lastName)} +
    + ); + } + if (column.render) return column.render(item); + return column.key.includes('.') + ? column.key.split('.').reduce((obj, key) => obj && obj[key], item) + : item[column.key]; + }; + + return ( +
    +
    + +
    + + + + {columns.map(column => ( + + ))} + + + + {paginatedData.map((item, index) => ( + + {columns.map(column => ( + + ))} + + ))} + +
    !column.isImage && handleSort(column.key)} + className={`pl-4 py-4 text-left text-sm font-bold text-[#6B7280] uppercase tracking-wider ${!column.isImage ? 'cursor-pointer' : ''}`} + > + {column.label} + {!column.isImage && sortColumn === column.key && {sortDirection === 'asc' ? ' ▲' : ' ▼'}} +
    + {renderCell(item, column)} +
    +
    +
    + Showing {(currentPage - 1) * itemsPerPage + 1} to {Math.min(currentPage * itemsPerPage, sortedData.length)} of{' '} + {sortedData.length} entries +
    +
    + + +
    +
    +
    + ); +}; + +export default Table; diff --git a/src/components/dashboard/VendorsTable.tsx b/src/components/dashboard/VendorsTable.tsx new file mode 100644 index 0000000..39b6398 --- /dev/null +++ b/src/components/dashboard/VendorsTable.tsx @@ -0,0 +1,159 @@ +import React, { useState, useMemo } from 'react'; + +interface Column { + key: string; + label: string; + isImage?: boolean; + render?: (item: any) => React.ReactNode; +} + +interface TableProps { + data: any[]; + columns: Column[]; + itemsPerPage: number; +} + +const getInitials = (firstName: string, lastName: string) => + `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase(); + +const getRandomColor = () => { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +}; + +const Table: React.FC = ({ data, columns, itemsPerPage }) => { + const [currentPage, setCurrentPage] = useState(1); + const [sortColumn, setSortColumn] = useState(null); + const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); + const [searchTerm, setSearchTerm] = useState(''); + + const filteredData = useMemo( + () => + data.filter(item => + columns.some(column => String(item[column.key]).toLowerCase().includes(searchTerm.toLowerCase())) + ), + [data, columns, searchTerm] + ); + + const sortedData = useMemo(() => { + if (!sortColumn) return filteredData; + return [...filteredData].sort((a, b) => { + if (a[sortColumn] < b[sortColumn]) return sortDirection === 'asc' ? -1 : 1; + if (a[sortColumn] > b[sortColumn]) return sortDirection === 'asc' ? 1 : -1; + return 0; + }); + }, [filteredData, sortColumn, sortDirection]); + + const paginatedData = useMemo(() => { + const startIndex = (currentPage - 1) * itemsPerPage; + return sortedData.slice(startIndex, startIndex + itemsPerPage); + }, [sortedData, currentPage, itemsPerPage]); + + const totalPages = Math.ceil(sortedData.length / itemsPerPage); + + const handleSort = (column: string) => { + if (column === sortColumn) { + setSortDirection(prev => (prev === 'asc' ? 'desc' : 'asc')); + } else { + setSortColumn(column); + setSortDirection('asc'); + } + }; + + const handleSearch = (e: React.ChangeEvent) => { + setSearchTerm(e.target.value); + setCurrentPage(1); + }; + + const renderCell = (item: any, column: Column) => { + if (column.isImage) { + return item[column.key] ? ( + {`${item.firstName} + ) : ( +
    + {getInitials(item.firstName, item.lastName)} +
    + ); + } + if (column.render) return column.render(item); + return column.key.includes('.') + ? column.key.split('.').reduce((obj, key) => obj && obj[key], item) + : item[column.key]; + }; + + return ( +
    +
    + +
    + + + + {columns.map(column => ( + + ))} + + + + {paginatedData.map((item, index) => ( + + {columns.map(column => ( + + ))} + + ))} + +
    !column.isImage && handleSort(column.key)} + className={`pl-4 py-4 text-left text-sm font-bold text-[#6B7280] uppercase tracking-wider ${!column.isImage ? 'cursor-pointer' : ''}`} + > + {column.label} + {!column.isImage && sortColumn === column.key && {sortDirection === 'asc' ? ' ▲' : ' ▼'}} +
    + {renderCell(item, column)} +
    +
    +
    + Showing {(currentPage - 1) * itemsPerPage + 1} to {Math.min(currentPage * itemsPerPage, sortedData.length)} of{' '} + {sortedData.length} entries +
    +
    + + +
    +
    +
    + ); +}; + +export default Table; diff --git a/src/pages/NotFoundPage.tsx b/src/pages/NotFoundPage.tsx new file mode 100644 index 0000000..47ea344 --- /dev/null +++ b/src/pages/NotFoundPage.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import photo404 from '../assets/404_page.png'; +import { FaHome, FaArrowLeft } from 'react-icons/fa'; + +const NotFoundPage: React.FC = () => { + const navigate = useNavigate(); + + return ( +
    +
    + page not found +

    Not Found

    +

    + Oops! ... Looks like this page does not exist in MAVERICKS +

    +
    + + {/* Add Home icon */} + Go Home + + +
    +
    +
    + ); +}; + +export default NotFoundPage; diff --git a/src/pages/admin/Sellers.tsx b/src/pages/admin/Sellers.tsx index 3651d71..f8bee62 100644 --- a/src/pages/admin/Sellers.tsx +++ b/src/pages/admin/Sellers.tsx @@ -1,3 +1,112 @@ -export default function Sellers() { - return
    Sellers
    ; -} +// src/pages/admin/Sellers.tsx +import React, { useState, useEffect } from 'react'; +import Table from '../../components/dashboard/VendorsTable'; +import { BiLoader } from 'react-icons/bi'; +import { useGetRolesQuery } from '../../services/roleApi'; +import { useGetSellersQuery, useUpdateUserRoleMutation } from '../../services/userApi'; +import ConfirmDisableModal from '../../components/dashboard/ConfirmDisableModal'; +import { User as Seller } from '../../types/Types'; + +const Sellers: React.FC = () => { + const { + data: sellersData, + isLoading: sellersLoading, + isError: sellersError, + refetch: refetchSellers, + } = useGetSellersQuery(undefined, { + pollingInterval: 30000, + }); + const { data: rolesData, isLoading: rolesLoading, isError: rolesError } = useGetRolesQuery(); + const [updateUserRole] = useUpdateUserRoleMutation(); + + const [selectedSeller, setSelectedSeller] = useState(null); + + const loading = sellersLoading || rolesLoading; + const error = sellersError || rolesError; + + const sellers = sellersData?.message || []; + const roles = rolesData?.data || []; + + useEffect(() => { + refetchSellers(); + }, [refetchSellers]); + + const handleOpenModal = (seller: Seller) => { + setSelectedSeller(seller); + }; + + const handleCloseModal = () => { + setSelectedSeller(null); + }; + + const handleDisableSeller = async () => { + if (selectedSeller) { + try { + const buyerRole = roles.find(role => role.name.toLowerCase() === 'buyer'); + if (!buyerRole) { + console.error('Buyer role not found'); + return; + } + await updateUserRole({ userId: selectedSeller.id, roleId: buyerRole.id }).unwrap(); + refetchSellers(); + handleCloseModal(); + } catch (error) { + console.error('Failed to disable seller:', error); + } + } + }; + + const columns = [ + { key: 'photoUrl', label: 'Photo', isImage: true, sortable: false }, + { key: 'firstName', label: 'First Name', sortable: true }, + { key: 'lastName', label: 'Last Name', sortable: true }, + { key: 'email', label: 'Email', sortable: true }, + { key: 'phoneNumber', label: 'Phone', sortable: true }, + { key: 'gender', label: 'Gender', sortable: true }, + { + key: 'Role.name', + label: 'Role', + render: (seller: Seller) => seller.Role.name, + sortable: false, + }, + { + key: 'action', + label: 'Action', + render: (seller: Seller) => ( + + ), + sortable: false, + }, + ]; + + if (loading) + return ( +
    + +
    + ); + if (error) { + return
    Error fetching data. Please try again.
    ; + } + + return ( +
    +

    Seller Management

    + + {selectedSeller && ( + + )} + + ); +}; + +export default Sellers; diff --git a/src/pages/admin/UserManagement.tsx b/src/pages/admin/UserManagement.tsx new file mode 100644 index 0000000..d3d022d --- /dev/null +++ b/src/pages/admin/UserManagement.tsx @@ -0,0 +1,112 @@ +// src/pages/admin/UserManagement.tsx +import React, { useState, useEffect } from 'react'; +import Table from '../../components/dashboard/UsersTable'; +import { BiLoader } from 'react-icons/bi'; +import { useGetRolesQuery } from '../../services/roleApi'; +import { useGetUsersQuery, useUpdateUserRoleMutation } from '../../services/userApi'; +import RoleChangeModal from '../../components/dashboard/RoleChangeModal'; +import { User } from '../../types/Types'; + +const UserManagement: React.FC = () => { + const { data: usersData, isLoading: usersLoading, isError: usersError } = useGetUsersQuery(); + const { data: rolesData, isLoading: rolesLoading, isError: rolesError } = useGetRolesQuery(); + const [updateUserRole] = useUpdateUserRoleMutation(); + + const [users, setUsers] = useState([]); + const [selectedUser, setSelectedUser] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + + useEffect(() => { + if (usersData?.message) { + setUsers(usersData.message); + } + }, [usersData]); + + const loading = usersLoading || rolesLoading; + const error = usersError || rolesError; + + const roles = rolesData?.data || []; + + const handleOpenModal = (user: User) => { + setSelectedUser(user); + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setSelectedUser(null); + setIsModalOpen(false); + }; + + const handleRoleChange = async (newRoleId: string) => { + if (selectedUser) { + try { + await updateUserRole({ userId: selectedUser.id, roleId: newRoleId }).unwrap(); + setUsers(prevUsers => + prevUsers.map(user => + user.id === selectedUser.id + ? { + ...user, + Role: { ...user.Role, id: newRoleId, name: roles.find(r => r.id === newRoleId)?.name || '' }, + } + : user + ) + ); + handleCloseModal(); + } catch (error) { + console.error('Failed to update user role:', error); + } + } + }; + + const columns = [ + { key: 'photoUrl', label: 'Photo', isImage: true }, + { key: 'firstName', label: 'First Name' }, + { key: 'lastName', label: 'Last Name' }, + { key: 'email', label: 'Email' }, + { key: 'phoneNumber', label: 'Phone' }, + { key: 'gender', label: 'Gender' }, + { + key: 'role', + label: 'Role', + render: (user: User) => user.Role.name + }, + { + key: 'action', + label: 'Action', + render: (user: User) => ( + + ), + }, + ]; + + if (loading) + return ( +
    + +
    + ); + if (error) { + return
    Error fetching data. Please try again.
    ; + } + + return ( +
    +

    User Management

    +
    + + + ); +}; + +export default UserManagement; diff --git a/src/services/roleApi.ts b/src/services/roleApi.ts new file mode 100644 index 0000000..21c4f52 --- /dev/null +++ b/src/services/roleApi.ts @@ -0,0 +1,18 @@ +import { mavericksApi } from '.'; +import { Role } from '../types/Types'; + +export const roleApi = mavericksApi.injectEndpoints({ + endpoints: builder => ({ + getRoles: builder.query<{ data: Role[] }, void>({ + query: () => ({ + url: 'roles', + headers: { + Authorization: `Bearer ${localStorage.getItem('token')}`, + }, + }), + }), + }), + overrideExisting: false, +}); + +export const { useGetRolesQuery } = roleApi; diff --git a/src/services/userApi.ts b/src/services/userApi.ts index 7072975..b6b8c74 100644 --- a/src/services/userApi.ts +++ b/src/services/userApi.ts @@ -1,4 +1,5 @@ import { mavericksApi } from '.'; +import { User } from '../types/Types'; export const userApi = mavericksApi.injectEndpoints({ endpoints: builder => ({ @@ -7,8 +8,35 @@ export const userApi = mavericksApi.injectEndpoints({ url: `users/user/${id}`, }), }), + getUsers: builder.query<{ message: User[] }, void>({ + query: () => ({ + url: 'users', + headers: { + Authorization: `Bearer ${localStorage.getItem('token')}`, + }, + }), + }), + getSellers: builder.query({ + query: () => ({ + url: 'users/role/seller', + headers: { + Authorization: localStorage.getItem('token') || '', + }, + }), + }), + updateUserRole: builder.mutation({ + query: ({ userId, roleId }) => ({ + url: `users/role/${userId}`, + method: 'PUT', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}`, + 'Content-Type': 'application/json', + }, + body: { roleId }, + }), + }), }), overrideExisting: false, }); -export const { useGetUserByIdQuery } = userApi; +export const { useGetUserByIdQuery, useGetUsersQuery,useGetSellersQuery, useUpdateUserRoleMutation } = userApi; diff --git a/src/types/Types.ts b/src/types/Types.ts index 25aeaa0..ec6df7f 100644 --- a/src/types/Types.ts +++ b/src/types/Types.ts @@ -54,3 +54,21 @@ export interface NotificationProps { updatedAt: string; isRead: boolean; } + +export interface User { + id: string; + firstName: string; + lastName: string; + email: string; + phoneNumber: string; + photoUrl: string | null; + gender: string; + Role: { + name: string; + }; +}; + +export interface Role { + id: string; + name: string; +} \ No newline at end of file