diff --git a/src/app/api/categories.js b/src/app/api/categories.js index 1594e93..c13401c 100644 --- a/src/app/api/categories.js +++ b/src/app/api/categories.js @@ -44,7 +44,7 @@ export const categoriesApi = baseApi.injectEndpoints({ getAllCategoryProductsPaginated: builder.query({ async queryFn( - { category, page = 1, limit = 6, brands, min_price, max_price }, + { category, page = 1, limit = 6, brands, min_price, max_price, sorting }, queryApi, extraOptions, baseQuery @@ -65,11 +65,12 @@ export const categoriesApi = baseApi.injectEndpoints({ 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); + const result = await baseQuery( `categories/${categoryId}/products?${params.toString()}` ); - + if (result.data && result.data.data) { allPageProducts = [...allPageProducts, ...result.data.data]; hasMoreByCategory[categoryId] = !!result.data.pagination.next_page_url; diff --git a/src/app/api/collectionsApi.js b/src/app/api/collectionsApi.js index e493ccf..7de32b2 100644 --- a/src/app/api/collectionsApi.js +++ b/src/app/api/collectionsApi.js @@ -30,14 +30,14 @@ export const collectionsApi = baseApi.injectEndpoints({ }), getCollectionProductsPaginated: builder.query({ - query: ({ collectionId, page = 1, limit = 6, brands, min_price, max_price, sorting }) => { + query: ({ collectionId, page = 1, limit = 6, brands, min_price, max_price, sorting = "price_amount-ascending" }) => { 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); + params.append('sorting', sorting); return `/collections/${collectionId}/products?${params.toString()}`; }, diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index c8bb4af..30c02b7 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -172,7 +172,17 @@ export default { price: "Price", minPrice: "Min Price", maxPrice: "Max Price", - }, + priceHighToLow: "From expensive to cheap", + priceLowToHigh: "From cheap to expensive", + priceRange: "Price Range", + under50: "Under 50m", + under100: "Under 100m", + from50to200: "50 - 200", + from200to500: "200 - 500", + from500to1000: "500 - 1000", + over1000: "Over 1000m", + sortBy: "Sort By", + }, product: { productCode: "Product code", barCode: "Barcode", diff --git a/src/i18n/locales/ru.js b/src/i18n/locales/ru.js index 091d30c..8abc871 100644 --- a/src/i18n/locales/ru.js +++ b/src/i18n/locales/ru.js @@ -167,9 +167,19 @@ export default { From_expensive_to_cheap: "От дорогих к дешевым", From_cheap_to_expensive: "От дешевых к дорогим", price: "Цена", - minPrice: "Минимальная цена", - maxPrice: "Максимальная цена", - }, + minPrice: "Мин цена", + maxPrice: "Макс цена", + priceHighToLow: "От дорогих к дешевым", + priceLowToHigh: "От дешевых к дорогим", + priceRange: "Диапазон цен", + under50: "До 50m", + under100: "До 100m", + from50to200: "50 - 200", + from200to500: "200 - 500", + from500to1000: "500 - 1000", + over1000: "Более 1000m", + sortBy: "Сортировать по", + }, product: { productCode: "Код товара", barCode: "Штрих-код", diff --git a/src/i18n/locales/tm.js b/src/i18n/locales/tm.js index f12379e..3cc4f3c 100644 --- a/src/i18n/locales/tm.js +++ b/src/i18n/locales/tm.js @@ -170,9 +170,19 @@ export default { From_expensive_to_cheap: "Gymmatdan arzana", From_cheap_to_expensive: "Arzandan gymmada", price: "Bahasy", - maxPrice: "Maksimum baha", - minPrice: "Minimum baha", - }, + maxPrice: "Maks baha", + minPrice: "Min baha", + priceHighToLow: "Gymmatdan arzana", + priceLowToHigh: "Arzandan gymmada", + priceRange: "Baha diapazony", + under50: "50m aşagynda", + under100: "100m aşagynda", + from50to200: "50 - 200", + from200to500: "200 - 500", + from500to1000: "500 - 1000", + over1000: "1000m dan ýokary", + sortBy: "Tertiplemek", + }, product: { productCode: "Haryt kody", barCode: "Çyzgyç kod", diff --git a/src/pages/Category/CategoryPage.module.scss b/src/pages/Category/CategoryPage.module.scss index b15a351..020d91a 100644 --- a/src/pages/Category/CategoryPage.module.scss +++ b/src/pages/Category/CategoryPage.module.scss @@ -1,28 +1,96 @@ +.sortingSection { + display: flex; + flex-direction: column; + gap: 8px; + + .sortingTitle { + font-size: 14px; + color: #333; + font-weight: 600; + margin: 0 0 8px 0; + } + + .sortingButtonsContainer { + display: flex; + flex-direction: column; + gap: 6px; + + .sortingBtn { + padding: 8px 12px; + border: 1px solid #d1d5db; + border-radius: 5px; + background: #fff; + color: #333; + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease-in-out; + text-align: center; + + &:hover { + border-color: #d32824; + background-color: #fff5f5; + } + + &.activeSorting { + background-color: #d32824; + color: #fff; + border-color: #d32824; + font-weight: 600; + } + } + } +} + .sortingContainer { display: flex; align-items: center; gap: 8px; margin-left: 16px; + + .sortingLabel { + font-size: 14px; + color: #888; + } } -.sortingLabel { - font-size: 14px; - color: #888; + + +.pricePresetsContainer { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; + margin-bottom: 12px; + + .pricePresetBtn { + padding: 7px 10px; + border: 1px solid #d1d5db; + border-radius: 5px; + background: #fff; + color: #333; + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease-in-out; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:hover { + border-color: #d32824; + background-color: #fff5f5; + } + + &.activePreset { + background-color: #d32824; + color: #fff; + border-color: #d32824; + font-weight: 600; + } + } } -.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; @@ -32,41 +100,64 @@ // Price Filter Styles .priceFilterContainer { display: flex; - align-items: center; - gap: 8px; + flex-direction: column; + gap: 12px; border-radius: 8px; margin-bottom: 16px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); + padding: 12px; + background-color: #f9f9f9; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06); + animation: slideDown 0.2s ease-in-out; } + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + .priceInputGroup { display: flex; flex-direction: column; align-items: flex-start; - gap: 4px; + gap: 6px; + flex: 1; + min-width: 0; } + .priceLabel { - font-size: 13px; - color: #888; - margin-bottom: 2px; + font-size: 12px; + color: #666; + font-weight: 600; + letter-spacing: 0.3px; } + .priceInput { - width: 90px; - padding: 6px 10px; + padding: 8px 10px; border: 1px solid #d1d5db; border-radius: 6px; - font-size: 15px; + font-size: 14px; background: #fff; - transition: border-color 0.2s; + transition: all 0.2s ease; + + &::placeholder { + color: #bbb; + } } + .priceInput:focus { - border-color: #6c63ff; + border-color: #d32824; + box-shadow: 0 0 0 3px rgba(211, 40, 36, 0.1); outline: none; } + .priceDivider { - font-size: 18px; - color: #aaa; - font-weight: bold; - margin: 0 6px; + display: none; } .filtersContainer{ diff --git a/src/pages/Category/components/CategoryFilters.jsx b/src/pages/Category/components/CategoryFilters.jsx index 65eaa0d..d90ae22 100644 --- a/src/pages/Category/components/CategoryFilters.jsx +++ b/src/pages/Category/components/CategoryFilters.jsx @@ -1,6 +1,7 @@ -import React from "react"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { TiTick } from "react-icons/ti"; +import { Divider } from "antd"; import styles from "../CategoryPage.module.scss"; const CategoryFilters = ({ @@ -24,6 +25,25 @@ const CategoryFilters = ({ }) => { const { t } = useTranslation(); + const pricePresets = [ + { label: t("category.under50"), min: 0, max: 50 }, + { label: t("category.under100"), min: 0, max: 100 }, + { label: t("category.from50to200"), min: 50, max: 200 }, + { label: t("category.from200to500"), min: 200, max: 500 }, + { label: t("category.from500to1000"), min: 500, max: 1000 }, + { label: t("category.over1000"), min: 1000, max: 999999 }, + ]; + + const handlePricePreset = (preset) => { + onMinPriceChange(preset.min.toString()); + onMaxPriceChange(preset.max.toString()); + }; + + const sortOptions = [ + { value: "price_amount-ascending", label: t("category.priceLowToHigh") }, + { value: "price_amount-descending", label: t("category.priceHighToLow") }, + ]; + if (searchQuery) return null; return ( @@ -100,6 +120,23 @@ const CategoryFilters = ({ )}