added channels products
This commit is contained in:
34
src/app/api/channelsApi.js
Normal file
34
src/app/api/channelsApi.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { baseApi } from "./baseApi";
|
||||||
|
|
||||||
|
export const channelsApi = baseApi.injectEndpoints({
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
getChannelProducts: builder.query({
|
||||||
|
query: (params) => {
|
||||||
|
// params: { channelId, page, limit, min_price, max_price, sorting }
|
||||||
|
const {
|
||||||
|
channelId,
|
||||||
|
page = 1,
|
||||||
|
limit = 24,
|
||||||
|
min_price,
|
||||||
|
max_price,
|
||||||
|
sorting,
|
||||||
|
} = params;
|
||||||
|
const urlParams = new URLSearchParams();
|
||||||
|
urlParams.append("page", page);
|
||||||
|
urlParams.append("limit", limit);
|
||||||
|
if (min_price) urlParams.append("min_price", min_price);
|
||||||
|
if (max_price) urlParams.append("max_price", max_price);
|
||||||
|
if (sorting) urlParams.append("sorting", sorting);
|
||||||
|
return `/channels/${channelId}/products?${urlParams.toString()}`;
|
||||||
|
},
|
||||||
|
transformResponse: (response) => ({
|
||||||
|
data: response.data || response,
|
||||||
|
pagination: response.pagination || {},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
overrideExisting: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { useGetChannelProductsQuery, useLazyGetChannelProductsQuery } =
|
||||||
|
channelsApi;
|
||||||
@@ -15,6 +15,9 @@ export const filtersApi = baseApi.injectEndpoints({
|
|||||||
if (params?.brand_id) {
|
if (params?.brand_id) {
|
||||||
queryParams.append("brand_id", String(params.brand_id))
|
queryParams.append("brand_id", String(params.brand_id))
|
||||||
}
|
}
|
||||||
|
if (params?.channel_id) {
|
||||||
|
queryParams.append("channel_id", String(params.channel_id))
|
||||||
|
}
|
||||||
|
|
||||||
return `/filters?${queryParams.toString()}`
|
return `/filters?${queryParams.toString()}`
|
||||||
},
|
},
|
||||||
@@ -22,6 +25,7 @@ export const filtersApi = baseApi.injectEndpoints({
|
|||||||
return {
|
return {
|
||||||
categories: response.data?.categories || [],
|
categories: response.data?.categories || [],
|
||||||
brands: response.data?.brands || [],
|
brands: response.data?.brands || [],
|
||||||
|
channels: response.data?.channels || [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keepUnusedDataFor: 300,
|
keepUnusedDataFor: 300,
|
||||||
@@ -40,7 +44,9 @@ export const filtersApi = baseApi.injectEndpoints({
|
|||||||
if (queryArgs.brand_id) {
|
if (queryArgs.brand_id) {
|
||||||
parts.push(`brd:${queryArgs.brand_id}`);
|
parts.push(`brd:${queryArgs.brand_id}`);
|
||||||
}
|
}
|
||||||
|
if (queryArgs.channel_id) {
|
||||||
|
parts.push(`chn:${queryArgs.channel_id}`);
|
||||||
|
}
|
||||||
return parts.length > 0 ? parts.join('|') : 'no-params';
|
return parts.length > 0 ? parts.join('|') : 'no-params';
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -66,7 +72,9 @@ export const filtersApi = baseApi.injectEndpoints({
|
|||||||
if (arg.brand_id) {
|
if (arg.brand_id) {
|
||||||
tags.push({ type: "Filters", id: `brd-${arg.brand_id}` });
|
tags.push({ type: "Filters", id: `brd-${arg.brand_id}` });
|
||||||
}
|
}
|
||||||
|
if (arg.channel_id) {
|
||||||
|
tags.push({ type: "Filters", id: `chn-${arg.channel_id}` });
|
||||||
|
}
|
||||||
return tags;
|
return tags;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -87,24 +87,31 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 1336px;
|
width: 1336px;
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
// max-width: calc(100vw - 32px);
|
max-width: calc(100vw - 32px);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- LEFT LIST ----
|
// ---- LEFT LIST ----
|
||||||
.categoriesList {
|
.categoriesList {
|
||||||
width: 270px;
|
width: 270px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-right: 1px solid rgba(255, 255, 255, 0.12);
|
border-right: 1px solid #e5e7eb;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 6px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #f9fafb;
|
||||||
}
|
}
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
background: rgba(255, 255, 255, 0.2);
|
background: #d1d5db;
|
||||||
border-radius: 2px;
|
border-radius: 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #9ca3af;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,13 +126,13 @@
|
|||||||
transition: background-color 0.12s, color 0.12s;
|
transition: background-color 0.12s, color 0.12s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.08);
|
background-color: #f3f4f6;
|
||||||
color: #000;
|
color: #e63946;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: rgba(255, 255, 255, 0.15);
|
background-color: #f3f4f6;
|
||||||
color: #000;
|
color: #e63946;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -138,7 +145,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chevron {
|
.chevron {
|
||||||
color: rgba(255, 255, 255, 0.4);
|
color: #9ca3af;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,11 +158,18 @@
|
|||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 6px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #f9fafb;
|
||||||
}
|
}
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar-thumb {
|
||||||
background: #d1d5db;
|
background: #d1d5db;
|
||||||
border-radius: 2px;
|
border-radius: 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #9ca3af;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const useCategoryData = ({
|
|||||||
categoryId,
|
categoryId,
|
||||||
collectionId,
|
collectionId,
|
||||||
brandId,
|
brandId,
|
||||||
|
channelId, // EKLE
|
||||||
selectedFilterCategory,
|
selectedFilterCategory,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -23,8 +24,9 @@ const useCategoryData = ({
|
|||||||
if (categoryId) return { category_id: categoryId };
|
if (categoryId) return { category_id: categoryId };
|
||||||
if (collectionId) return { collection_id: collectionId };
|
if (collectionId) return { collection_id: collectionId };
|
||||||
if (brandId) return { brand_id: brandId };
|
if (brandId) return { brand_id: brandId };
|
||||||
|
if (channelId) return { channel_id: channelId };
|
||||||
return null;
|
return null;
|
||||||
}, [categoryId, collectionId, brandId, selectedFilterCategory, searchQuery]);
|
}, [categoryId, collectionId, brandId, channelId, selectedFilterCategory, searchQuery]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: filtersData,
|
data: filtersData,
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { useState, useEffect, useRef, useCallback } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
useLazyGetAllCategoryProductsPaginatedQuery,
|
useLazyGetAllCategoryProductsPaginatedQuery,
|
||||||
useGetCategoryProductsQuery,
|
useGetCategoryProductsQuery,
|
||||||
} from "../../../app/api/categories";
|
} from "../../../app/api/categories";
|
||||||
import { useLazyGetBrandProductsQuery } from "../../../app/api/brandsApi";
|
import { useLazyGetBrandProductsQuery } from "../../../app/api/brandsApi";
|
||||||
import { useLazyGetCollectionProductsPaginatedQuery } from "../../../app/api/collectionsApi";
|
import { useLazyGetCollectionProductsPaginatedQuery } from "../../../app/api/collectionsApi";
|
||||||
|
import { useLazyGetChannelProductsQuery } from "../../../app/api/channelsApi"; // EKLE
|
||||||
|
|
||||||
const useCategoryProducts = ({
|
const useCategoryProducts = ({
|
||||||
categoryId,
|
categoryId,
|
||||||
collectionId,
|
collectionId,
|
||||||
brandId,
|
brandId,
|
||||||
|
channelId,
|
||||||
selectedCategory,
|
selectedCategory,
|
||||||
isSubCategory,
|
isSubCategory,
|
||||||
currentPage,
|
currentPage,
|
||||||
@@ -27,8 +29,6 @@ const useCategoryProducts = ({
|
|||||||
const [isFetching, setIsFetching] = useState(false);
|
const [isFetching, setIsFetching] = useState(false);
|
||||||
|
|
||||||
const activeRequestId = useRef(0);
|
const activeRequestId = useRef(0);
|
||||||
// Tüm parametreleri ref'te tut — stale closure'ı tamamen engelle
|
|
||||||
const paramsRef = useRef({});
|
|
||||||
|
|
||||||
const shouldUseBaseQuery =
|
const shouldUseBaseQuery =
|
||||||
categoryId &&
|
categoryId &&
|
||||||
@@ -36,7 +36,8 @@ const useCategoryProducts = ({
|
|||||||
!searchQuery &&
|
!searchQuery &&
|
||||||
!selectedFilterCategory &&
|
!selectedFilterCategory &&
|
||||||
!brandId &&
|
!brandId &&
|
||||||
!collectionId;
|
!collectionId &&
|
||||||
|
!channelId;
|
||||||
|
|
||||||
const { data: baseQueryData, isFetching: baseQueryFetching } =
|
const { data: baseQueryData, isFetching: baseQueryFetching } =
|
||||||
useGetCategoryProductsQuery(
|
useGetCategoryProductsQuery(
|
||||||
@@ -54,8 +55,17 @@ const useCategoryProducts = ({
|
|||||||
const [fetchCategoryPaginated] = useLazyGetAllCategoryProductsPaginatedQuery();
|
const [fetchCategoryPaginated] = useLazyGetAllCategoryProductsPaginatedQuery();
|
||||||
const [fetchBrandPaginated] = useLazyGetBrandProductsQuery();
|
const [fetchBrandPaginated] = useLazyGetBrandProductsQuery();
|
||||||
const [fetchCollectionPaginated] = useLazyGetCollectionProductsPaginatedQuery();
|
const [fetchCollectionPaginated] = useLazyGetCollectionProductsPaginatedQuery();
|
||||||
|
const [fetchChannelPaginated] = useLazyGetChannelProductsQuery();
|
||||||
|
|
||||||
|
// ✅ Ref'e al — dependency array'den çıkar, stale closure yok
|
||||||
|
const fetchersRef = useRef({});
|
||||||
|
fetchersRef.current = {
|
||||||
|
fetchCategoryPaginated,
|
||||||
|
fetchBrandPaginated,
|
||||||
|
fetchCollectionPaginated,
|
||||||
|
fetchChannelPaginated,
|
||||||
|
};
|
||||||
|
|
||||||
// Base query handler
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!shouldUseBaseQuery || !baseQueryData) return;
|
if (!shouldUseBaseQuery || !baseQueryData) return;
|
||||||
const data = baseQueryData.data || [];
|
const data = baseQueryData.data || [];
|
||||||
@@ -69,11 +79,23 @@ const useCategoryProducts = ({
|
|||||||
setHasMore(hasNextPage);
|
setHasMore(hasNextPage);
|
||||||
}, [baseQueryData, currentPage, shouldUseBaseQuery]);
|
}, [baseQueryData, currentPage, shouldUseBaseQuery]);
|
||||||
|
|
||||||
// Her fetch çağrısını doğrudan effect içinde yap — useCallback kaldırıldı
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (shouldUseBaseQuery || searchQuery) return;
|
if (shouldUseBaseQuery || searchQuery) return;
|
||||||
|
|
||||||
// Parametreleri snapshot al
|
|
||||||
|
console.log("🔥 LAZY EFFECT TRIGGERED", {
|
||||||
|
shouldUseBaseQuery,
|
||||||
|
categoryId,
|
||||||
|
collectionId,
|
||||||
|
brandId,
|
||||||
|
channelId,
|
||||||
|
isSubCategory,
|
||||||
|
selectedFilterCategory,
|
||||||
|
selectedCategory,
|
||||||
|
});
|
||||||
|
|
||||||
const snapshot = {
|
const snapshot = {
|
||||||
currentPage,
|
currentPage,
|
||||||
selectedFilterCategory,
|
selectedFilterCategory,
|
||||||
@@ -81,6 +103,7 @@ const useCategoryProducts = ({
|
|||||||
isSubCategory,
|
isSubCategory,
|
||||||
brandId,
|
brandId,
|
||||||
collectionId,
|
collectionId,
|
||||||
|
channelId,
|
||||||
selectedFilterBrand,
|
selectedFilterBrand,
|
||||||
minPrice,
|
minPrice,
|
||||||
maxPrice,
|
maxPrice,
|
||||||
@@ -92,6 +115,13 @@ const useCategoryProducts = ({
|
|||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
try {
|
try {
|
||||||
|
const {
|
||||||
|
fetchCategoryPaginated,
|
||||||
|
fetchBrandPaginated,
|
||||||
|
fetchCollectionPaginated,
|
||||||
|
fetchChannelPaginated,
|
||||||
|
} = fetchersRef.current; // ✅ ref'ten oku
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
page: snapshot.currentPage,
|
page: snapshot.currentPage,
|
||||||
limit: 24,
|
limit: 24,
|
||||||
@@ -123,6 +153,11 @@ const useCategoryProducts = ({
|
|||||||
collectionId: snapshot.collectionId,
|
collectionId: snapshot.collectionId,
|
||||||
...params,
|
...params,
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
} else if (snapshot.channelId) {
|
||||||
|
result = await fetchChannelPaginated({
|
||||||
|
channelId: snapshot.channelId,
|
||||||
|
...params,
|
||||||
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestId !== activeRequestId.current) return;
|
if (requestId !== activeRequestId.current) return;
|
||||||
@@ -159,7 +194,6 @@ const useCategoryProducts = ({
|
|||||||
|
|
||||||
run();
|
run();
|
||||||
}, [
|
}, [
|
||||||
// useCallback YOK — her dependency değişince effect direkt çalışır
|
|
||||||
shouldUseBaseQuery,
|
shouldUseBaseQuery,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
currentPage,
|
currentPage,
|
||||||
@@ -168,13 +202,12 @@ const useCategoryProducts = ({
|
|||||||
isSubCategory,
|
isSubCategory,
|
||||||
brandId,
|
brandId,
|
||||||
collectionId,
|
collectionId,
|
||||||
|
channelId,
|
||||||
selectedFilterBrand,
|
selectedFilterBrand,
|
||||||
minPrice,
|
minPrice,
|
||||||
maxPrice,
|
maxPrice,
|
||||||
sorting,
|
sorting,
|
||||||
fetchCategoryPaginated,
|
// ✅ fetcher fonksiyonlar dependency'den tamamen çıktı
|
||||||
fetchBrandPaginated,
|
|
||||||
fetchCollectionPaginated,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const isLoading = shouldUseBaseQuery ? baseQueryFetching : isFetching;
|
const isLoading = shouldUseBaseQuery ? baseQueryFetching : isFetching;
|
||||||
@@ -189,3 +222,4 @@ const useCategoryProducts = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default useCategoryProducts;
|
export default useCategoryProducts;
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,19 @@ import MobilePhoneCard from "./components/Mobilephonecard";
|
|||||||
|
|
||||||
const CategoryPage = () => {
|
const CategoryPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { categoryId, collectionId, brandId } = useParams();
|
const { categoryId, collectionId, brandId, channelId } = useParams();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const routeKey = useMemo(
|
const routeKey = useMemo(
|
||||||
() => `${categoryId || "x"}-${collectionId || "x"}-${brandId || "x"}`,
|
() => `${categoryId || "x"}-${collectionId || "x"}-${brandId || "x"}-${channelId || "x"}`,
|
||||||
[categoryId, collectionId, brandId],
|
[categoryId, collectionId, brandId, channelId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const getSavedState = (key, defaultVal) => {
|
const getSavedState = (key, defaultVal) => {
|
||||||
|
if (location.state?.clearFilters) {
|
||||||
|
return defaultVal;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const saved = sessionStorage.getItem(`category_${key}_${routeKey}`);
|
const saved = sessionStorage.getItem(`category_${key}_${routeKey}`);
|
||||||
if (saved) return JSON.parse(saved);
|
if (saved) return JSON.parse(saved);
|
||||||
@@ -92,6 +95,7 @@ const CategoryPage = () => {
|
|||||||
categoryId,
|
categoryId,
|
||||||
collectionId,
|
collectionId,
|
||||||
brandId,
|
brandId,
|
||||||
|
channelId,
|
||||||
selectedFilterCategory: filterState.selectedFilterCategory,
|
selectedFilterCategory: filterState.selectedFilterCategory,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
});
|
});
|
||||||
@@ -105,6 +109,7 @@ const CategoryPage = () => {
|
|||||||
} = useCategoryProducts({
|
} = useCategoryProducts({
|
||||||
categoryId,
|
categoryId,
|
||||||
collectionId,
|
collectionId,
|
||||||
|
channelId,
|
||||||
brandId,
|
brandId,
|
||||||
selectedCategory,
|
selectedCategory,
|
||||||
isSubCategory,
|
isSubCategory,
|
||||||
@@ -137,10 +142,12 @@ const CategoryPage = () => {
|
|||||||
|
|
||||||
prevRouteRef.current = routeKey;
|
prevRouteRef.current = routeKey;
|
||||||
|
|
||||||
const savedPageState = getSavedStateByKey(routeKey, "pageState");
|
const shouldClear = location.state?.clearFilters;
|
||||||
const savedFilterState = getSavedStateByKey(routeKey, "filterState");
|
|
||||||
const savedProducts = getSavedStateByKey(routeKey, "products");
|
const savedPageState = shouldClear ? null : getSavedStateByKey(routeKey, "pageState");
|
||||||
const savedHasMore = getSavedStateByKey(routeKey, "hasMore");
|
const savedFilterState = shouldClear ? null : getSavedStateByKey(routeKey, "filterState");
|
||||||
|
const savedProducts = shouldClear ? null : getSavedStateByKey(routeKey, "products");
|
||||||
|
const savedHasMore = shouldClear ? null : getSavedStateByKey(routeKey, "hasMore");
|
||||||
|
|
||||||
if (savedPageState && savedFilterState && savedProducts) {
|
if (savedPageState && savedFilterState && savedProducts) {
|
||||||
setPageState(savedPageState);
|
setPageState(savedPageState);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useParams, useNavigate } from "react-router-dom";
|
import { useParams, useNavigate, Link } from "react-router-dom";
|
||||||
import styles from "./ProductPage.module.scss";
|
import styles from "./ProductPage.module.scss";
|
||||||
import { IoMdHeartEmpty, IoMdHeart } from "react-icons/io";
|
import { IoMdHeartEmpty, IoMdHeart } from "react-icons/io";
|
||||||
import { FaShoppingCart } from "react-icons/fa";
|
import { FaShoppingCart } from "react-icons/fa";
|
||||||
@@ -366,12 +366,14 @@ const ProductPage = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{product.channel?.[0]?.name && (
|
{product.channel?.[0]?.name && (
|
||||||
<div className={styles.metaItem}>
|
|
||||||
|
<Link to={`/channel/${product.channel[0].id}`} state={{ clearFilters: true }} className={styles.metaItem}>
|
||||||
<span className={styles.metaLabel}>{t("order.channel")}</span>
|
<span className={styles.metaLabel}>{t("order.channel")}</span>
|
||||||
<span className={styles.metaValue}>
|
<span className={styles.metaValue}>
|
||||||
{product.channel[0].name}
|
{product.channel[0].name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</Link>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{product.properties?.length > 0 && (
|
{product.properties?.length > 0 && (
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export default function Router() {
|
|||||||
{ path: "/category/:categoryId", element: <Category /> },
|
{ path: "/category/:categoryId", element: <Category /> },
|
||||||
{ path: "/search", element: <Category /> },
|
{ path: "/search", element: <Category /> },
|
||||||
{ path: "/collections/:collectionId", element: <Category /> },
|
{ path: "/collections/:collectionId", element: <Category /> },
|
||||||
|
{ path: "/channel/:channelId", element: <Category /> },
|
||||||
{ path: "/product/:productId", element: <ProductDetail /> },
|
{ path: "/product/:productId", element: <ProductDetail /> },
|
||||||
{ path: "/profile", element: <ProfileMenu /> },
|
{ path: "/profile", element: <ProfileMenu /> },
|
||||||
{ path: "/orders", element: <Orders /> },
|
{ path: "/orders", element: <Orders /> },
|
||||||
|
|||||||
Reference in New Issue
Block a user