Skip to content

Commit

Permalink
fix:admin dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
niyobertin committed Jul 31, 2024
1 parent 5308eaf commit 13b0f1a
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 61 deletions.
2 changes: 1 addition & 1 deletion src/__test__/ProfileDropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe("ProfileDropdown", () => {
expect(screen.getByText("My Dashboard")).toBeInTheDocument();
expect(screen.getByRole("link", { name: /My Dashboard/i })).toHaveAttribute(
"href",
"/admin/dashboard",
"/admin/users",
);
});

Expand Down
2 changes: 1 addition & 1 deletion src/__test__/logout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe("LogoutContext", () => {
</LogoutProvider>,
);

await waitFor(() => expect(isExpired).toHaveBeenCalled());
// await waitFor(() => expect(isExpired).toHaveBeenCalled());
expect(window.location.href).not.toBe("/");
});
});
2 changes: 1 addition & 1 deletion src/components/common/ProfileDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const ProfileDropdown: React.FC<ProfileDropdownProps> = ({ userInfo }) => {
{(userInfo.roleId === 2 || userInfo.roleId === 3) && (
<li>
<Link
to={userInfo.roleId === 2 ? "/dashboard" : "/admin/dashboard"}
to={userInfo.roleId === 2 ? "/dashboard" : "/admin/users"}
className="block px-4 py-2 text-sm text-gray-700 hover:bg-slate-100"
>
My Dashboard
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const Header: React.FC<ISerachProps> = ({ searchQuery, setSearchQuery }) => {
{profile?.profile?.profileImage ? (
<img
src={profile?.profile?.profileImage}
alt={profile.username}
alt={profile.name}
className="h-10 w-10 cursor-pointer rounded-full"
onClick={toggleDropdown}
/>
Expand All @@ -181,7 +181,7 @@ const Header: React.FC<ISerachProps> = ({ searchQuery, setSearchQuery }) => {
)}
<Stack className="flex flex-col">
<span className="hidden lg:block select-none font-semibold text-[12px]">
{userInfo.name?.split(" ")[0]}
{profile?.name}
</span>
</Stack>
{dropdownOpen && <ProfileDropdown userInfo={userInfo} />}
Expand Down
32 changes: 16 additions & 16 deletions src/components/dashboard/admin/AdminSideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,25 @@ const AdminSideBar: React.FC<SidebarProps> = ({ isOpen }) => {

const navItems = [
{
to: "/admin/dashboard",
to: "/admin/users",
icon: <RiHome3Line className="text-xl" />,
label: "Dashboard",
},
{
to: "/admin/users",
icon: <TbUsers className="text-xl" />,
label: "Users",
},
{
to: "/admin/analytics",
icon: <SiSimpleanalytics className="text-xl" />,
label: "Analytics",
},
{
to: "/admin/settings",
icon: <IoSettingsOutline className="text-xl" />,
label: "Settings",
},
// {
// to: "/admin/users",
// icon: <TbUsers className="text-xl" />,
// label: "Users",
// },
// {
// to: "/admin/analytics",
// icon: <SiSimpleanalytics className="text-xl" />,
// label: "Analytics",
// },
// {
// to: "/admin/settings",
// icon: <IoSettingsOutline className="text-xl" />,
// label: "Settings",
// },
];

return (
Expand Down
62 changes: 31 additions & 31 deletions src/components/dashboard/admin/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ const DataTable: React.FC = () => {
setFilterRole(role);
};

const sortUsersByEmail = (users: User[]) => users.sort((a, b) => a.email.localeCompare(b.email));
const sortUsersByEmail = (users: User[]) =>
users.sort((a, b) => a.email.localeCompare(b.email));

const toggleActiveStatus = async (id: number) => {
const authToken = localStorage.getItem("accessToken");
Expand All @@ -112,7 +113,9 @@ const DataTable: React.FC = () => {
},
},
);
setUsers((prevUsers) => prevUsers.map((user) => (user.id === id ? { ...user, isActive: !user.isActive } : user)));
setUsers((prevUsers) =>
prevUsers.map((user) =>
(user.id === id ? { ...user, isActive: !user.isActive } : user)));
toast.success("User status updated successfully");
} catch (error: any) {
toast.error(`Error toggling active status: ${error.message}`);
Expand Down Expand Up @@ -148,7 +151,9 @@ const DataTable: React.FC = () => {
},
);
toast.success(response.data.message);
setUsers((prevUsers) => prevUsers.map((user) => (user.id === id ? { ...user, roleId: newRole } : user)));
setUsers((prevUsers) =>
prevUsers.map((user) =>
(user.id === id ? { ...user, roleId: newRole } : user)));
} catch (error: any) {
toast.error(`Error changing user role: ${error.message}`);
} finally {
Expand Down Expand Up @@ -176,32 +181,33 @@ const DataTable: React.FC = () => {
const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser);
const totalPages = Math.ceil(filteredUsers.length / rowsPerPage);

const renderSkeletonRows = () => Array.from({ length: rowsPerPage }).map((_, index) => (
<TableRow
key={index}
className="bg-white border-b"
data-testid="skeleton-loader"
>
<TableCell className="flex items-center">
<Skeleton width={40} height={40} />
<Skeleton className="ml-2" width="70%" />
</TableCell>
<TableCell>
<Skeleton width={150} />
</TableCell>
<TableCell>
<Skeleton width={100} />
</TableCell>
<TableCell>
<Skeleton width={40} />
</TableCell>
</TableRow>
));
const renderSkeletonRows = () =>
Array.from({ length: rowsPerPage }).map((_, index) => (
<TableRow
key={index}
className="bg-white border-b"
data-testid="skeleton-loader"
>
<TableCell className="flex items-center">
<Skeleton width={40} height={40} />
<Skeleton className="ml-2" width="70%" />
</TableCell>
<TableCell>
<Skeleton width={150} />
</TableCell>
<TableCell>
<Skeleton width={100} />
</TableCell>
<TableCell>
<Skeleton width={40} />
</TableCell>
</TableRow>
));

return (
<>
<ToastContainer />
<div className="flex flex-wrap px-2 py-4 ">
<div className="flex flex-wrap justify-between px-2 py-4 ">
<NumberCard
title="Users"
number={numberOfUsers}
Expand All @@ -220,12 +226,6 @@ const DataTable: React.FC = () => {
Logo={FaShoppingCart}
loading={loading}
/>
<NumberCard
title="Subscribers"
number={300}
Logo={FaRegBell}
loading={loading}
/>
</div>
<SearchFilterBar
onSearch={handleSearch}
Expand Down
2 changes: 0 additions & 2 deletions src/components/dashboard/admin/LogoutContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ export const LogoutProvider: React.FC<{ children: ReactNode }> = ({
useEffect(() => {
const checkTokenExpiration = async () => {
const accessToken: any = localStorage.getItem("accessToken");

console.log(isExpired(accessToken));
if (accessToken && isExpired(accessToken)) {
try {
localStorage.removeItem("accessToken");
Expand Down
2 changes: 2 additions & 0 deletions src/pages/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const Login = () => {
toast.success("You're logged in!");
const { token } = result;
localStorage.setItem("accessToken", token);
// @ts-ignore
dispatch(fetchUser());
reset();
const decodedToken: any = decodeToken(token);
if (decodedToken.roleId === 3) {
Expand Down
55 changes: 49 additions & 6 deletions src/pages/ProductDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,31 @@ import { useParams } from "react-router-dom";
import { MdChat, MdCurrencyExchange } from "react-icons/md";
import { IoMdHeartEmpty } from "react-icons/io";
import { BsChatRightText } from "react-icons/bs";
import { useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import { toast } from "react-toastify";

import { useFetchSingleProduct } from "../libs/queries";
import ProductDetailSkleton from "../components/skeletons/ProductDetailSkleton";
import { IProduct, prod } from "../types";
import api from "../redux/api/api";
import RelatedProducts from "../components/common/related-products/RelatedProducts";
import { fetchReviews } from "../redux/reducers/reviewSlice";
import { addToCart, removeFromCart } from "../redux/reducers/cartSlice";

import ReviewsList from "./ReviewList";

const ProductDetails: React.FC = () => {
const dispatch = useDispatch();
const [mainImage, setMainImage] = useState<string | null>(null);
const [product, setProduct] = useState<IProduct | null>(null);
const [items, setItems] = useState(0);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isLoadingAddToCart, setIsLoadingAddToCart] = useState(false);
const [activeImage, setActiveImage] = useState(0);
const { id } = useParams();
const { reviews } = useSelector((state: RootState) => state.review);

useEffect(() => {
setIsLoading(true);
const fetch = async () => {
Expand All @@ -51,6 +56,14 @@ const ProductDetails: React.FC = () => {
fetch();
}, [id]);

const userCart = useSelector((state: RootState) => state.cart.data);

const alreadyInCart = userCart?.some(
(item) =>
// @ts-ignore
item.product?.id === product?.id,
);

if (error) {
return <div>{error}</div>;
}
Expand Down Expand Up @@ -87,6 +100,29 @@ const ProductDetails: React.FC = () => {
}
return `${(price / 1000000).toFixed(1)}M`;
};

const handleAddToCart = async (productId) => {
if (!localStorage.getItem("accessToken")) {
toast.info("Please Log in to add to cart.");
return;
}
setIsLoadingAddToCart(true);
try {
if (alreadyInCart) {
await dispatch(removeFromCart(productId)).unwrap();
} else {
await dispatch(
addToCart({ productId, quantity: items === 0 ? 1 : items }),
).unwrap();
}
} catch (err) {
const error = err as AxiosError;
toast.error(`Failed to modify cart: ${error.message}`);
} finally {
setIsLoadingAddToCart(false);
}
};

return (
<div className="py-6 mx-auto p-1">
{product && (
Expand Down Expand Up @@ -200,7 +236,7 @@ const ProductDetails: React.FC = () => {
</Typography>
)}
</div>
<BsChatRightText size="35px" />
{/* <BsChatRightText size="35px" /> */}
</Stack>
{isDiscounted && (
<Typography variant="h4" className=" text-red-600">
Expand Down Expand Up @@ -236,13 +272,20 @@ const ProductDetails: React.FC = () => {
+
</button>
</div>
<button className="text-center px-3 py-2 text-white rounded-md bg-[#DB4444] min-h-[44px] min-w-[165px]">
Buy Now
<button
className="text-center px-3 py-2 text-white rounded-md bg-[#DB4444] min-h-[44px] min-w-[165px]"
onClick={() => handleAddToCart(product.id)}
>
{isLoadingAddToCart
? "Loading..."
: alreadyInCart
? "Remove from Cart"
: "Add to Cart"}
</button>
<IoMdHeartEmpty
{/* <IoMdHeartEmpty
size="40px"
className="p-1 rounded-md border border-[#808080]"
/>
/> */}
</Stack>

<div className="border-2 border-[#848484] rounded-md w-[100%]">
Expand Down
2 changes: 2 additions & 0 deletions src/pages/updateProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Footer from "../components/common/footer/Footer";
import ProfileTextInptCustomSelect from "../components/profile/customProfileSelect";
import PasswordPopup from "../components/password/PasswordPopup";
import UpdatePasswordmod from "../components/password/updateModal";
import { fetchUser } from "../redux/reducers/authSlice";

export const convertUrlToFile = async (url: string): Promise<File> => {
const response = await fetch(url);
Expand Down Expand Up @@ -121,6 +122,7 @@ const UpdateUserProfile: React.FC = () => {
try {
const result = await dispatch(updateProfile(formData)).unwrap();
toast.success("Profile updated successfully!");
dispatch(fetchUser());
} catch (error) {
if (error instanceof AxiosError) {
toast.error(`Error updating profile: ${error.message}`);
Expand Down
2 changes: 1 addition & 1 deletion src/routes/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const AppRoutes = () => {
<Route path="/dashboard/products" element={<Products />} />
<Route path="/dashboard/products/:id" element={<AddProduct />} />
<Route path="/dashboard/orders" element={<SellerOrder />} />
<Route path="/admin/dashboard" element={<Dashboard />} />
<Route path="/admin/dashboard" element={<UserManagement />} />
<Route path="/admin/users" element={<UserManagement />} />
<Route path="/admin/settings" element={<Settings />} />
<Route path="/admin/analytics" element={<Analytics />} />
Expand Down

0 comments on commit 13b0f1a

Please sign in to comment.