fixed some bugs

This commit is contained in:
@jcarymuhammedow
2026-04-17 18:38:16 +05:00
parent 68382648a8
commit 6ef7aa3c47
15 changed files with 171 additions and 39 deletions

View File

@@ -7,13 +7,14 @@ export const categoriesApi = baseApi.injectEndpoints({
}),
getCategoryProducts: builder.query({
query: ({ categoryId, page = 1, limit, brands, min_price, max_price }) => {
query: ({ categoryId, page = 1, limit, brands, min_price, max_price, sorting }) => {
const params = new URLSearchParams();
params.append('page', page);
if (limit) params.append('limit', limit);
if (brands) params.append('brands', brands);
if (min_price) params.append('min_price', min_price);
if (max_price) params.append('max_price', max_price);
if (sorting) params.append('sorting', sorting);
return `categories/${categoryId}/products?${params.toString()}`;
},

View File

@@ -30,13 +30,14 @@ export const collectionsApi = baseApi.injectEndpoints({
}),
getCollectionProductsPaginated: builder.query({
query: ({ collectionId, page = 1, limit = 6, brands, min_price, max_price }) => {
query: ({ collectionId, page = 1, limit = 6, brands, min_price, max_price, sorting }) => {
const params = new URLSearchParams();
params.append('page', page);
if (limit) params.append('limit', limit);
if (brands) params.append('brands', brands);
if (min_price) params.append('min_price', min_price);
if (max_price) params.append('max_price', max_price);
if (sorting) params.append('sorting', sorting);
return `/collections/${collectionId}/products?${params.toString()}`;
},

View File

@@ -304,11 +304,11 @@ const Checkout = ({ cartItems, shippingPrice, productIds, onBackToCart, onPlaceO
"checkout.Delivery_is_carried_out_in_the_cities_of_Ashgabat_Buzmein_and_Anau"
)}
</li>
<li>
{/* <li>
{t(
"checkout.The_minimum_order_amount_must_be_at_least_50_manat_for_orders_over_150_manat_delivery_is_free"
)}
</li>
</li> */}
<li>
{t(
"checkout.After_you_place_an_order_on_the_website_the_operator_will_call_you_to_confirm_the_order_for_regular_customers_confirmation_is_carried_out_automatically_at_their_request"

View File

@@ -8,7 +8,7 @@ const Layout = () => {
return (
<>
<Navbar />
<NavbarDown/>
{/* <NavbarDown/> */}
<main>
<Outlet />
</main>

View File

@@ -14,6 +14,9 @@
background-color: #fff;
margin-bottom: 1px;
border-bottom: 3px solid #f3f4f6;
position: sticky;
top: 0;
z-index: 100;
}
.btn{
@@ -38,7 +41,7 @@
background-color: #ffffff;
max-width: 1366px;
position: sticky;
top: 0;
top: 80px; // navbarUp yüksekliği kadar
padding-top: 12px;
padding-bottom: 12px;
padding-left: 1.375rem;
@@ -96,6 +99,9 @@
}
}
.navLinks {
width: 100%;
}
.navLinks ul {
list-style: none;
display: flex;

View File

@@ -135,7 +135,7 @@ const NavbarDown = () => {
];
return (
<header className={styles.navbar}>
<header className={styles.navbar} style={{ width: "100%" }}>
<div className={styles.navbarDown} style={{ position: "sticky" }}>
<nav className={styles.navLinks}>
<ul>

View File

@@ -9,7 +9,7 @@ import { useTranslation } from "react-i18next";
import tm from "../../assets/tm.png";
import ru from "../../assets/ru.png";
import en from "../../assets/en.png";
import NavbarDown from "./NavbarDown";
const Navbar = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const navigate = useNavigate();
@@ -92,6 +92,7 @@ const Navbar = () => {
</div>
</div>
</div>
<NavbarDown />
</header>
<Modal
open={isModalVisible}

View File

@@ -30,6 +30,7 @@
border-radius: 8px;
font-size: 0.875rem;
font-weight: 600;
z-index: 1;
@media screen and (max-width: 426px) {
font-size: 12px;
}

View File

@@ -225,6 +225,12 @@ const ProductCard = ({
const { name, price_amount, old_price_amount, media = [], reviews } = product;
// Hesaplanmış indirim oranı
let calculatedDiscount = null;
if (!product.discount && old_price_amount && price_amount && old_price_amount > price_amount) {
calculatedDiscount = Math.round(((old_price_amount - price_amount) / old_price_amount) * 100);
}
return (
<>
<div
@@ -234,8 +240,10 @@ const ProductCard = ({
onMouseLeave={() => setIsHovered(false)}
>
<div className={styles.imageContainer}>
{product.discount && (
<span className={styles.discountBadge}>-{product.discount}%</span>
{(product.discount || calculatedDiscount) && (
<span className={styles.discountBadge}>
-{product.discount ? product.discount : calculatedDiscount}%
</span>
)}
{product.stock === 0 && (
<span className={`${styles.discountBadge} ${styles.outOfStock}`}>

View File

@@ -1,3 +1,28 @@
.sortingContainer {
display: flex;
align-items: center;
gap: 8px;
margin-left: 16px;
}
.sortingLabel {
font-size: 14px;
color: #888;
}
.sortingSelect {
padding: 6px 12px;
border-radius: 6px;
border: 1px solid #d1d5db;
font-size: 15px;
background: #fff;
color: #222;
outline: none;
transition: border-color 0.2s;
}
.sortingSelect:focus {
border-color: #6c63ff;
}
.mobilePhoneGrid {
display: flex !important;

View File

@@ -18,6 +18,8 @@ const CategoryFilters = ({
onBrandSelect,
onBrandDeselect,
onBrandSearchChange,
sorting = "price_amount-descending",
onSortingChange = () => {},
className,
}) => {
const { t } = useTranslation();
@@ -123,6 +125,19 @@ const CategoryFilters = ({
/>
</div>
</div>
{/* Sıralama dropdown'u */}
<div className={styles.sortingContainer} style={{ marginTop: 12 }}>
<label htmlFor="sortingSidebar" className={styles.sortingLabel}>{t("category.sortBy")}: </label>
<select
id="sortingSidebar"
className={styles.sortingSelect}
value={sorting}
onChange={e => onSortingChange(e.target.value)}
>
<option value="price_amount-descending">{t("category.priceHighToLow")}</option>
<option value="price_amount-ascending">{t("category.priceLowToHigh")}</option>
</select>
</div>
</div>
</aside>
);

View File

@@ -17,6 +17,7 @@ const useCategoryProducts = ({
selectedFilterBrand,
minPrice,
maxPrice,
sorting,
searchQuery,
}) => {
const [products, setProducts] = useState([]);
@@ -35,6 +36,7 @@ const useCategoryProducts = ({
selectedFilterBrand && `fbrand-${selectedFilterBrand}`,
minPrice && `min-${minPrice}`,
maxPrice && `max-${maxPrice}`,
sorting && `sort-${sorting}`,
].filter(Boolean);
return parts.join("|") || "none";
}, [
@@ -45,6 +47,7 @@ const useCategoryProducts = ({
selectedFilterBrand,
minPrice,
maxPrice,
sorting,
]);
const fetchParams = useMemo(
@@ -54,8 +57,9 @@ const useCategoryProducts = ({
brands: selectedFilterBrand || undefined,
min_price: minPrice || undefined,
max_price: maxPrice || undefined,
sorting: sorting || undefined,
}),
[currentPage, selectedFilterBrand, minPrice, maxPrice],
[currentPage, selectedFilterBrand, minPrice, maxPrice, sorting],
);
const fetchKey = `${contextId}-p${currentPage}`;

View File

@@ -29,6 +29,7 @@ const CategoryPage = () => {
currentPage: 1,
minPrice: "",
maxPrice: "",
sorting: "price_amount-descending",
});
const [filterState, setFilterState] = useState({
@@ -94,6 +95,7 @@ const CategoryPage = () => {
selectedFilterBrand: filterState.selectedFilterBrand,
minPrice: pageState.minPrice,
maxPrice: pageState.maxPrice,
sorting: pageState.sorting,
searchQuery,
});
const isMobilePhoneView =
@@ -293,6 +295,22 @@ const CategoryPage = () => {
>
{t("category.filter")} <LuFilter />
</button>
<div className={styles.sortingContainer}>
<label htmlFor="sorting" className={styles.sortingLabel}>{t("category.sortBy")}: </label>
<select
id="sorting"
className={styles.sortingSelect}
value={pageState.sorting}
onChange={e => {
setPageState(prev => ({ ...prev, sorting: e.target.value, currentPage: 1 }));
setAllProducts([]);
setHasMore(true);
}}
>
<option value="price_amount-descending">{t("category.priceHighToLow")}</option>
<option value="price_amount-ascending">{t("category.priceLowToHigh")}</option>
</select>
</div>
</div>
<Drawer
@@ -335,6 +353,12 @@ const CategoryPage = () => {
onBrandSearchChange={(query) =>
setFilterState((prev) => ({ ...prev, brandSearchQuery: query }))
}
sorting={pageState.sorting}
onSortingChange={(value) => {
setPageState((prev) => ({ ...prev, sorting: value, currentPage: 1 }));
setAllProducts([]);
setHasMore(true);
}}
/>
</Drawer>
@@ -373,6 +397,12 @@ const CategoryPage = () => {
onBrandSearchChange={(query) =>
setFilterState((prev) => ({ ...prev, brandSearchQuery: query }))
}
sorting={pageState.sorting}
onSortingChange={(value) => {
setPageState((prev) => ({ ...prev, sorting: value, currentPage: 1 }));
setAllProducts([]);
setHasMore(true);
}}
/>
<main className={styles.productsContainer}>

View File

@@ -286,6 +286,8 @@
justify-content: space-between;
padding-bottom: 8px;
border-bottom: 1px solid #f1f1f1;
text-decoration: none;
color: inherit;
&:last-child {
border-bottom: none;
@@ -311,6 +313,27 @@
padding: 16px 20px;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
}
.descriptionCard::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 60px;
pointer-events: none;
background: linear-gradient(to top, #111 0%, #fff 100%);
opacity: 0.7;
z-index: 2;
}
.productDescriptionCollapsed + div {
/* Read more butonunu gradient üstünde göstermek için z-index */
position: relative;
z-index: 3;
}
.descriptionHeader {
@@ -358,18 +381,28 @@
overflow: hidden;
}
.productDescriptionWrapper {
display: flex;
flex-direction: column;
align-items: center;
}
.readMoreBtn {
background: none;
border: none;
color: #1890ff;
font-weight: 500;
color: #fff;
font-weight: bold;
cursor: pointer;
padding: 8px 0 0 0;
font-size: 14px;
font-size: 16px;
display: inline-block;
text-shadow: 0 1px 8px #000, 0 1px 1px #000;
letter-spacing: 0.5px;
margin-top: 8px;
&:hover {
text-decoration: underline;
opacity: 0.85;
}
}

View File

@@ -26,6 +26,7 @@ import {
import ImageCarousel from "../../components/ProductCard/imageCarousel/index";
import Loader from "../../components/Loader/index";
import { Result, Button } from "antd";
import { div } from "framer-motion/client";
const ProductPage = ({
productProp,
@@ -351,10 +352,14 @@ const ProductPage = ({
)} */}
{product.brand?.name && (
<div className={styles.metaItem}>
<a
href={`/brands/${product.brand.id}`}
target="_blank"
className={styles.metaItem}
>
<span className={styles.metaLabel}>{t("order.brand")}</span>
<span className={styles.metaValue}>{product.brand.name}</span>
</div>
</a>
)}
{product.channel?.[0]?.name && (
@@ -385,29 +390,31 @@ const ProductPage = ({
{t("product.description")}
</p>
</div>
<div
ref={descRef}
className={`${styles.productDescription} ${
!isDescExpanded ? styles.productDescriptionCollapsed : ""
}`}
dangerouslySetInnerHTML={{ __html: product.description }}
/>
{showReadMore && !isDescExpanded && (
<button
className={styles.readMoreBtn}
onClick={() => setIsDescExpanded(true)}
>
{t("product.readMore")}
</button>
)}
{showReadMore && isDescExpanded && (
<button
className={styles.readMoreBtn}
onClick={() => setIsDescExpanded(false)}
>
{t("product.readLess")}
</button>
)}
<div className={styles.productDescriptionWrapper}>
<div
ref={descRef}
className={`${styles.productDescription} ${
!isDescExpanded ? styles.productDescriptionCollapsed : ""
}`}
dangerouslySetInnerHTML={{ __html: product.description }}
/>
{showReadMore && !isDescExpanded && (
<button
className={styles.readMoreBtn}
onClick={() => setIsDescExpanded(true)}
>
{t("product.readMore")}
</button>
)}
{showReadMore && isDescExpanded && (
<button
className={styles.readMoreBtn}
onClick={() => setIsDescExpanded(false)}
>
{t("product.readLess")}
</button>
)}
</div>
</div>
)}
</div>