Skip to content

Commit 2b075ef

Browse files
committed
fix:admin dashboard
1 parent 6deee64 commit 2b075ef

File tree

5 files changed

+98
-55
lines changed

5 files changed

+98
-55
lines changed

Diff for: src/__test__/ProfileDropdown.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe("ProfileDropdown", () => {
6666
expect(screen.getByText("My Dashboard")).toBeInTheDocument();
6767
expect(screen.getByRole("link", { name: /My Dashboard/i })).toHaveAttribute(
6868
"href",
69-
"/admin/dashboard",
69+
"/admin/users",
7070
);
7171
});
7272

Diff for: src/components/common/ProfileDropdown.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const ProfileDropdown: React.FC<ProfileDropdownProps> = ({ userInfo }) => {
3636
{(userInfo.roleId === 2 || userInfo.roleId === 3) && (
3737
<li>
3838
<Link
39-
to={userInfo.roleId === 2 ? "/dashboard" : "/admin/dashboard"}
39+
to={userInfo.roleId === 2 ? "/dashboard" : "/admin/users"}
4040
className="block px-4 py-2 text-sm text-gray-700 hover:bg-slate-100"
4141
>
4242
My Dashboard

Diff for: src/components/dashboard/admin/AdminSideBar.tsx

+16-16
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,25 @@ const AdminSideBar: React.FC<SidebarProps> = ({ isOpen }) => {
2020

2121
const navItems = [
2222
{
23-
to: "/admin/dashboard",
23+
to: "/admin/users",
2424
icon: <RiHome3Line className="text-xl" />,
2525
label: "Dashboard",
2626
},
27-
{
28-
to: "/admin/users",
29-
icon: <TbUsers className="text-xl" />,
30-
label: "Users",
31-
},
32-
{
33-
to: "/admin/analytics",
34-
icon: <SiSimpleanalytics className="text-xl" />,
35-
label: "Analytics",
36-
},
37-
{
38-
to: "/admin/settings",
39-
icon: <IoSettingsOutline className="text-xl" />,
40-
label: "Settings",
41-
},
27+
// {
28+
// to: "/admin/users",
29+
// icon: <TbUsers className="text-xl" />,
30+
// label: "Users",
31+
// },
32+
// {
33+
// to: "/admin/analytics",
34+
// icon: <SiSimpleanalytics className="text-xl" />,
35+
// label: "Analytics",
36+
// },
37+
// {
38+
// to: "/admin/settings",
39+
// icon: <IoSettingsOutline className="text-xl" />,
40+
// label: "Settings",
41+
// },
4242
];
4343

4444
return (

Diff for: src/components/dashboard/admin/DataTable.tsx

+31-31
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ const DataTable: React.FC = () => {
9696
setFilterRole(role);
9797
};
9898

99-
const sortUsersByEmail = (users: User[]) => users.sort((a, b) => a.email.localeCompare(b.email));
99+
const sortUsersByEmail = (users: User[]) =>
100+
users.sort((a, b) => a.email.localeCompare(b.email));
100101

101102
const toggleActiveStatus = async (id: number) => {
102103
const authToken = localStorage.getItem("accessToken");
@@ -112,7 +113,9 @@ const DataTable: React.FC = () => {
112113
},
113114
},
114115
);
115-
setUsers((prevUsers) => prevUsers.map((user) => (user.id === id ? { ...user, isActive: !user.isActive } : user)));
116+
setUsers((prevUsers) =>
117+
prevUsers.map((user) =>
118+
(user.id === id ? { ...user, isActive: !user.isActive } : user)));
116119
toast.success("User status updated successfully");
117120
} catch (error: any) {
118121
toast.error(`Error toggling active status: ${error.message}`);
@@ -148,7 +151,9 @@ const DataTable: React.FC = () => {
148151
},
149152
);
150153
toast.success(response.data.message);
151-
setUsers((prevUsers) => prevUsers.map((user) => (user.id === id ? { ...user, roleId: newRole } : user)));
154+
setUsers((prevUsers) =>
155+
prevUsers.map((user) =>
156+
(user.id === id ? { ...user, roleId: newRole } : user)));
152157
} catch (error: any) {
153158
toast.error(`Error changing user role: ${error.message}`);
154159
} finally {
@@ -176,32 +181,33 @@ const DataTable: React.FC = () => {
176181
const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser);
177182
const totalPages = Math.ceil(filteredUsers.length / rowsPerPage);
178183

179-
const renderSkeletonRows = () => Array.from({ length: rowsPerPage }).map((_, index) => (
180-
<TableRow
181-
key={index}
182-
className="bg-white border-b"
183-
data-testid="skeleton-loader"
184-
>
185-
<TableCell className="flex items-center">
186-
<Skeleton width={40} height={40} />
187-
<Skeleton className="ml-2" width="70%" />
188-
</TableCell>
189-
<TableCell>
190-
<Skeleton width={150} />
191-
</TableCell>
192-
<TableCell>
193-
<Skeleton width={100} />
194-
</TableCell>
195-
<TableCell>
196-
<Skeleton width={40} />
197-
</TableCell>
198-
</TableRow>
199-
));
184+
const renderSkeletonRows = () =>
185+
Array.from({ length: rowsPerPage }).map((_, index) => (
186+
<TableRow
187+
key={index}
188+
className="bg-white border-b"
189+
data-testid="skeleton-loader"
190+
>
191+
<TableCell className="flex items-center">
192+
<Skeleton width={40} height={40} />
193+
<Skeleton className="ml-2" width="70%" />
194+
</TableCell>
195+
<TableCell>
196+
<Skeleton width={150} />
197+
</TableCell>
198+
<TableCell>
199+
<Skeleton width={100} />
200+
</TableCell>
201+
<TableCell>
202+
<Skeleton width={40} />
203+
</TableCell>
204+
</TableRow>
205+
));
200206

201207
return (
202208
<>
203209
<ToastContainer />
204-
<div className="flex flex-wrap px-2 py-4 ">
210+
<div className="flex flex-wrap justify-between px-2 py-4 ">
205211
<NumberCard
206212
title="Users"
207213
number={numberOfUsers}
@@ -220,12 +226,6 @@ const DataTable: React.FC = () => {
220226
Logo={FaShoppingCart}
221227
loading={loading}
222228
/>
223-
<NumberCard
224-
title="Subscribers"
225-
number={300}
226-
Logo={FaRegBell}
227-
loading={loading}
228-
/>
229229
</div>
230230
<SearchFilterBar
231231
onSearch={handleSearch}

Diff for: src/pages/ProductDetails.tsx

+49-6
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,31 @@ import { useParams } from "react-router-dom";
1414
import { MdChat, MdCurrencyExchange } from "react-icons/md";
1515
import { IoMdHeartEmpty } from "react-icons/io";
1616
import { BsChatRightText } from "react-icons/bs";
17-
import { useSelector } from "react-redux";
17+
import { useDispatch, useSelector } from "react-redux";
18+
import { toast } from "react-toastify";
1819

1920
import { useFetchSingleProduct } from "../libs/queries";
2021
import ProductDetailSkleton from "../components/skeletons/ProductDetailSkleton";
2122
import { IProduct, prod } from "../types";
2223
import api from "../redux/api/api";
2324
import RelatedProducts from "../components/common/related-products/RelatedProducts";
2425
import { fetchReviews } from "../redux/reducers/reviewSlice";
26+
import { addToCart, removeFromCart } from "../redux/reducers/cartSlice";
2527

2628
import ReviewsList from "./ReviewList";
2729

2830
const ProductDetails: React.FC = () => {
31+
const dispatch = useDispatch();
2932
const [mainImage, setMainImage] = useState<string | null>(null);
3033
const [product, setProduct] = useState<IProduct | null>(null);
3134
const [items, setItems] = useState(0);
3235
const [error, setError] = useState("");
3336
const [isLoading, setIsLoading] = useState(false);
37+
const [isLoadingAddToCart, setIsLoadingAddToCart] = useState(false);
3438
const [activeImage, setActiveImage] = useState(0);
3539
const { id } = useParams();
3640
const { reviews } = useSelector((state: RootState) => state.review);
41+
3742
useEffect(() => {
3843
setIsLoading(true);
3944
const fetch = async () => {
@@ -51,6 +56,14 @@ const ProductDetails: React.FC = () => {
5156
fetch();
5257
}, [id]);
5358

59+
const userCart = useSelector((state: RootState) => state.cart.data);
60+
61+
const alreadyInCart = userCart?.some(
62+
(item) =>
63+
// @ts-ignore
64+
item.product?.id === product?.id,
65+
);
66+
5467
if (error) {
5568
return <div>{error}</div>;
5669
}
@@ -87,6 +100,29 @@ const ProductDetails: React.FC = () => {
87100
}
88101
return `${(price / 1000000).toFixed(1)}M`;
89102
};
103+
104+
const handleAddToCart = async (productId) => {
105+
if (!localStorage.getItem("accessToken")) {
106+
toast.info("Please Log in to add to cart.");
107+
return;
108+
}
109+
setIsLoadingAddToCart(true);
110+
try {
111+
if (alreadyInCart) {
112+
await dispatch(removeFromCart(productId)).unwrap();
113+
} else {
114+
await dispatch(
115+
addToCart({ productId, quantity: items === 0 ? 1 : items }),
116+
).unwrap();
117+
}
118+
} catch (err) {
119+
const error = err as AxiosError;
120+
toast.error(`Failed to modify cart: ${error.message}`);
121+
} finally {
122+
setIsLoadingAddToCart(false);
123+
}
124+
};
125+
90126
return (
91127
<div className="py-6 mx-auto p-1">
92128
{product && (
@@ -200,7 +236,7 @@ const ProductDetails: React.FC = () => {
200236
</Typography>
201237
)}
202238
</div>
203-
<BsChatRightText size="35px" />
239+
{/* <BsChatRightText size="35px" /> */}
204240
</Stack>
205241
{isDiscounted && (
206242
<Typography variant="h4" className=" text-red-600">
@@ -236,13 +272,20 @@ const ProductDetails: React.FC = () => {
236272
+
237273
</button>
238274
</div>
239-
<button className="text-center px-3 py-2 text-white rounded-md bg-[#DB4444] min-h-[44px] min-w-[165px]">
240-
Buy Now
275+
<button
276+
className="text-center px-3 py-2 text-white rounded-md bg-[#DB4444] min-h-[44px] min-w-[165px]"
277+
onClick={() => handleAddToCart(product.id)}
278+
>
279+
{isLoadingAddToCart
280+
? "Loading..."
281+
: alreadyInCart
282+
? "Remove from Cart"
283+
: "Add to Cart"}
241284
</button>
242-
<IoMdHeartEmpty
285+
{/* <IoMdHeartEmpty
243286
size="40px"
244287
className="p-1 rounded-md border border-[#808080]"
245-
/>
288+
/> */}
246289
</Stack>
247290

248291
<div className="border-2 border-[#848484] rounded-md w-[100%]">

0 commit comments

Comments
 (0)