fixed some bugs
This commit is contained in:
@@ -7,7 +7,7 @@ export const brandsApi = baseApi.injectEndpoints({
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params.type) queryParams.append("type", params.type);
|
||||
if (params.page) queryParams.append("page", params.page);
|
||||
if (params.limit) queryParams.append("limit", params.limit);
|
||||
if (params.perPage) queryParams.append("perPage", params.perPage);
|
||||
const queryString = queryParams.toString();
|
||||
return `/brands${queryString ? `?${queryString}` : ""}`;
|
||||
},
|
||||
@@ -25,10 +25,10 @@ export const brandsApi = baseApi.injectEndpoints({
|
||||
return `/brands/${params}/products`;
|
||||
}
|
||||
|
||||
const { id, page = 1, limit = 24, sorting, min_price, max_price } = params;
|
||||
const { id, page = 1, perPage = 12, sorting, min_price, max_price } = params;
|
||||
const urlParams = new URLSearchParams();
|
||||
urlParams.append("page", page);
|
||||
urlParams.append("limit", limit);
|
||||
urlParams.append("perPage", perPage);
|
||||
if (sorting) urlParams.append("sorting", sorting);
|
||||
if (min_price) urlParams.append("min_price", min_price);
|
||||
if (max_price) urlParams.append("max_price", max_price);
|
||||
|
||||
@@ -7,10 +7,10 @@ export const categoriesApi = baseApi.injectEndpoints({
|
||||
}),
|
||||
|
||||
getCategoryProducts: builder.query({
|
||||
query: ({ categoryId, page = 1, limit = 24, brands, min_price, max_price, sorting }) => {
|
||||
query: ({ categoryId, page = 1, perPage = 12, brands, min_price, max_price, sorting }) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append("page", page);
|
||||
params.append("limit", limit);
|
||||
params.append("perPage", perPage);
|
||||
if (brands) params.append("brands", brands);
|
||||
if (min_price) params.append("min_price", min_price);
|
||||
if (max_price) params.append("max_price", max_price);
|
||||
@@ -41,7 +41,7 @@ export const categoriesApi = baseApi.injectEndpoints({
|
||||
|
||||
getAllCategoryProductsPaginated: builder.query({
|
||||
async queryFn(
|
||||
{ category, page = 1, limit = 24, brands, min_price, max_price, sorting },
|
||||
{ category, page = 1, perPage = 12, brands, min_price, max_price, sorting },
|
||||
_queryApi,
|
||||
_extraOptions,
|
||||
baseQuery
|
||||
@@ -58,7 +58,7 @@ export const categoriesApi = baseApi.injectEndpoints({
|
||||
if (categoryIds.length === 1) {
|
||||
const params = new URLSearchParams();
|
||||
params.append("page", page);
|
||||
params.append("limit", limit);
|
||||
params.append("perPage", perPage);
|
||||
if (brands) params.append("brands", brands);
|
||||
if (min_price) params.append("min_price", min_price);
|
||||
if (max_price) params.append("max_price", max_price);
|
||||
@@ -86,7 +86,7 @@ export const categoriesApi = baseApi.injectEndpoints({
|
||||
const requests = categoryIds.map((categoryId) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append("page", page);
|
||||
params.append("limit", limit);
|
||||
params.append("perPage", perPage);
|
||||
if (brands) params.append("brands", brands);
|
||||
if (min_price) params.append("min_price", min_price);
|
||||
if (max_price) params.append("max_price", max_price);
|
||||
|
||||
@@ -8,14 +8,14 @@ export const channelsApi = baseApi.injectEndpoints({
|
||||
const {
|
||||
channelId,
|
||||
page = 1,
|
||||
limit = 24,
|
||||
perPage = 24,
|
||||
min_price,
|
||||
max_price,
|
||||
sorting,
|
||||
} = params;
|
||||
const urlParams = new URLSearchParams();
|
||||
urlParams.append("page", page);
|
||||
urlParams.append("limit", limit);
|
||||
urlParams.append("perPage", perPage);
|
||||
if (min_price) urlParams.append("min_price", min_price);
|
||||
if (max_price) urlParams.append("max_price", max_price);
|
||||
if (sorting) urlParams.append("sorting", sorting);
|
||||
@@ -31,7 +31,7 @@ export const channelsApi = baseApi.injectEndpoints({
|
||||
query: (params = {}) => {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params.page) queryParams.append("page", params.page);
|
||||
if (params.limit) queryParams.append("limit", params.limit);
|
||||
if (params.perPage) queryParams.append("perPage", params.perPage);
|
||||
if (params.search) queryParams.append("search", params.search);
|
||||
const queryString = queryParams.toString();
|
||||
return `/channels${queryString ? `?${queryString}` : ""}`;
|
||||
|
||||
@@ -19,17 +19,17 @@ export const collectionsApi = baseApi.injectEndpoints({
|
||||
}),
|
||||
|
||||
checkCollectionHasProducts: builder.query({
|
||||
query: (collectionId) => `/collections/${collectionId}/products?limit=1`,
|
||||
query: (collectionId) => `/collections/${collectionId}/products`,
|
||||
transformResponse: (response) => ({
|
||||
hasProducts: response.data && response.data.length > 0,
|
||||
}),
|
||||
}),
|
||||
|
||||
getCollectionProductsPaginated: builder.query({
|
||||
query: ({ collectionId, page = 1, limit = 24, brands, min_price, max_price, sorting }) => {
|
||||
query: ({ collectionId, page = 1, perPage = 24, brands, min_price, max_price, sorting }) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append("page", page);
|
||||
params.append("limit", limit);
|
||||
params.append("perPage", perPage);
|
||||
if (brands) params.append("brands", brands);
|
||||
if (min_price) params.append("min_price", min_price);
|
||||
if (max_price) params.append("max_price", max_price);
|
||||
|
||||
@@ -174,11 +174,11 @@ const Checkout = ({
|
||||
}
|
||||
>
|
||||
<span className={styles.optionTitle}>{payment.name}</span>
|
||||
<span className={styles.optionDesc}>
|
||||
{/* <span className={styles.optionDesc}>
|
||||
{payment.name === "Nagt"
|
||||
? t("checkout.payment_in_cash_upon_delivery_of_the_order")
|
||||
: t("checkout.payment_by_card")}
|
||||
</span>
|
||||
</span> */}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -94,7 +94,6 @@ const Footer = () => {
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<img src={apk} alt="Download APK" className={styles.appLogo} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,23 +7,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.brandsScroll {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
overflow-x: auto;
|
||||
.brandsSwiper {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Webkit */
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
/* Hide scrollbar for Firefox, IE, Edge */
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
.brandSlide {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.brandCard {
|
||||
flex: 0 0 auto;
|
||||
width: 122px;
|
||||
height: 50px;
|
||||
background: #ffffff;
|
||||
@@ -56,37 +48,8 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.allButton {
|
||||
flex: 0 0 auto;
|
||||
width: 122px;
|
||||
height: 67.6px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
gap: 4px;
|
||||
color: #111827;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-1px);
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.brandCard, .allButton {
|
||||
.brandCard {
|
||||
width: 100px;
|
||||
// height: 79.2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +1,67 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useGetBrandsQuery } from '../../app/api/brandsApi';
|
||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||
import { Autoplay } from 'swiper/modules';
|
||||
import 'swiper/css';
|
||||
import styles from './HomeBrands.module.scss';
|
||||
import { Logo } from '../Icons';
|
||||
import { IoIosArrowForward } from 'react-icons/io';
|
||||
|
||||
const HomeBrands = () => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
// We fetch a larger amount so we have enough to shuffle.
|
||||
const { data: brandsData, isLoading } = useGetBrandsQuery({ limit: 50 });
|
||||
|
||||
const randomBrands = useMemo(() => {
|
||||
if (!brandsData) return [];
|
||||
// Create a shallow copy and shuffle it
|
||||
const shuffled = [...brandsData].sort(() => 0.5 - Math.random());
|
||||
// Pick the first 9 brands
|
||||
return shuffled.slice(0, 8);
|
||||
}, [brandsData]);
|
||||
// Fetch brands.
|
||||
const { data: brandsData, isLoading } = useGetBrandsQuery({ limit: 100 });
|
||||
|
||||
if (isLoading || !brandsData || brandsData.length === 0) return null;
|
||||
|
||||
// "Еще" in ru, "Hemmesi" in tm, "More" in en
|
||||
const getMoreText = () => {
|
||||
const lang = i18n.language;
|
||||
if (lang === 'ru') return 'Еще';
|
||||
if (lang === 'en') return 'More';
|
||||
return 'Hemmesi';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.brandsScroll}>
|
||||
{randomBrands.map((brand) => (
|
||||
<div
|
||||
key={brand.id}
|
||||
className={styles.brandCard}
|
||||
onClick={() => navigate(`/brands/${brand.id}`)}
|
||||
>
|
||||
{brand.media?.[0]?.thumbnail || brand.media?.[0]?.images_800x800 || brand.logo ? (
|
||||
<img
|
||||
src={
|
||||
brand.media?.[0]?.thumbnail ||
|
||||
brand.media?.[0]?.images_800x800 ||
|
||||
brand.logo
|
||||
}
|
||||
alt={brand.name}
|
||||
onError={(e) => {
|
||||
e.target.style.display = "none";
|
||||
e.target.nextSibling.style.display = "flex";
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.logoFallback}>
|
||||
<Swiper
|
||||
modules={[Autoplay]}
|
||||
spaceBetween={12}
|
||||
slidesPerView={'auto'}
|
||||
slidesPerGroup={2}
|
||||
loop={true}
|
||||
autoplay={{
|
||||
delay: 3000,
|
||||
disableOnInteraction: false,
|
||||
}}
|
||||
className={styles.brandsSwiper}
|
||||
>
|
||||
{brandsData.map((brand) => (
|
||||
<SwiperSlide key={brand.id} className={styles.brandSlide}>
|
||||
<div
|
||||
className={styles.brandCard}
|
||||
onClick={() => navigate(`/brands/${brand.id}`)}
|
||||
>
|
||||
{brand.media?.[0]?.thumbnail || brand.media?.[0]?.images_800x800 || brand.logo ? (
|
||||
<img
|
||||
src={
|
||||
brand.media?.[0]?.thumbnail ||
|
||||
brand.media?.[0]?.images_800x800 ||
|
||||
brand.logo
|
||||
}
|
||||
alt={brand.name}
|
||||
onError={(e) => {
|
||||
e.target.style.display = "none";
|
||||
e.target.nextSibling.style.display = "flex";
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.logoFallback}>
|
||||
<Logo width={40} height={40} />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.logoFallback} style={{ display: "none" }}>
|
||||
<Logo width={40} height={40} />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.logoFallback} style={{ display: "none" }}>
|
||||
<Logo width={40} height={40} />
|
||||
</div>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
<div
|
||||
className={styles.allButton}
|
||||
onClick={() => navigate('/brands')}
|
||||
>
|
||||
<span>{getMoreText()}</span>
|
||||
<IoIosArrowForward />
|
||||
</div>
|
||||
</div>
|
||||
</Swiper>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomeBrands;
|
||||
|
||||
|
||||
@@ -72,8 +72,16 @@
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
height: 2.4em;
|
||||
line-height: 1.2;
|
||||
|
||||
@media screen and (max-width: 426px) {
|
||||
font-size: 14px;
|
||||
height: 2.8em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +90,15 @@
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
height: 2.8em;
|
||||
|
||||
@media screen and (max-width: 1023px) {
|
||||
font-size: 12px;
|
||||
height: 2.8em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +106,8 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
margin: 0;
|
||||
margin-top: auto;
|
||||
margin-bottom: 0;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ const ProductCard = ({
|
||||
onAddToCart,
|
||||
onToggleFavorite,
|
||||
isFavorite = false,
|
||||
descriptionMaxLength = 85,
|
||||
descriptionMaxLength = 120,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -499,3 +499,45 @@ width: 85%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.channelHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
margin-bottom: 20px;
|
||||
|
||||
.channelLogo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
.channelInfo {
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
padding: 15px;
|
||||
gap: 15px;
|
||||
|
||||
.channelLogo {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.channelInfo h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import {
|
||||
useGetFiltersQuery,
|
||||
useLazyGetFiltersQuery,
|
||||
} from "../../../app/api/filtersApi";
|
||||
import { useGetChannelsQuery } from "../../../app/api/channelsApi";
|
||||
|
||||
const useCategoryData = ({
|
||||
categoryId,
|
||||
collectionId,
|
||||
brandId,
|
||||
channelId, // EKLE
|
||||
channelId,
|
||||
selectedFilterCategory,
|
||||
searchQuery,
|
||||
}) => {
|
||||
@@ -46,6 +47,19 @@ const useCategoryData = ({
|
||||
skip: !collectionId,
|
||||
});
|
||||
|
||||
const {
|
||||
data: channelsListData,
|
||||
isLoading: channelsLoading,
|
||||
error: channelsError,
|
||||
} = useGetChannelsQuery({ perPage: 100 }, {
|
||||
skip: !channelId,
|
||||
});
|
||||
|
||||
const channelData = useMemo(() => {
|
||||
if (!channelId || !channelsListData?.data) return null;
|
||||
return channelsListData.data.find(c => String(c.id) === String(channelId));
|
||||
}, [channelId, channelsListData]);
|
||||
|
||||
const isSubCategory = useMemo(() => {
|
||||
if (!categoriesData?.data || !categoryId) return false;
|
||||
|
||||
@@ -94,8 +108,8 @@ const useCategoryData = ({
|
||||
setSelectedCategory(category);
|
||||
}, [categoryId, categoriesData]);
|
||||
|
||||
const isLoading = filtersLoading || collectionLoading;
|
||||
const hasError = filtersError || collectionError;
|
||||
const isLoading = filtersLoading || collectionLoading || channelsLoading;
|
||||
const hasError = filtersError || collectionError || channelsError;
|
||||
|
||||
return {
|
||||
categoriesData,
|
||||
@@ -103,6 +117,7 @@ const useCategoryData = ({
|
||||
isSubCategory,
|
||||
filtersData: activeFilters,
|
||||
collectionData,
|
||||
channelData,
|
||||
isLoading,
|
||||
hasError,
|
||||
fetchFilters,
|
||||
|
||||
@@ -124,7 +124,7 @@ const useCategoryProducts = ({
|
||||
|
||||
const params = {
|
||||
page: snapshot.currentPage,
|
||||
limit: 24,
|
||||
perPage: 12,
|
||||
brands: snapshot.selectedFilterBrand || undefined,
|
||||
min_price: snapshot.minPrice || undefined,
|
||||
max_price: snapshot.maxPrice || undefined,
|
||||
|
||||
@@ -88,6 +88,7 @@ const CategoryPage = () => {
|
||||
isSubCategory,
|
||||
filtersData,
|
||||
collectionData,
|
||||
channelData,
|
||||
isLoading: dataLoading,
|
||||
hasError: dataError,
|
||||
fetchFilters,
|
||||
@@ -373,18 +374,35 @@ const CategoryPage = () => {
|
||||
|
||||
return (
|
||||
<div className={styles.categoryPage}>
|
||||
{(categoryId || filterState.selectedFilterCategory) && (
|
||||
<CategoryBreadcrumbs
|
||||
categoriesData={categoriesData}
|
||||
categoryId={filterState.selectedFilterCategory || categoryId}
|
||||
onCategoryClick={handleCategoryClick}
|
||||
/>
|
||||
)}
|
||||
{channelId && channelData ? (
|
||||
<div className={styles.channelHeader}>
|
||||
{channelData.media?.[0]?.thumbnail && (
|
||||
<img
|
||||
src={channelData.media[0].thumbnail}
|
||||
alt={channelData.name}
|
||||
className={styles.channelLogo}
|
||||
/>
|
||||
)}
|
||||
<div className={styles.channelInfo}>
|
||||
<h1>{channelData.name}</h1>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{(categoryId || filterState.selectedFilterCategory) && (
|
||||
<CategoryBreadcrumbs
|
||||
categoriesData={categoriesData}
|
||||
categoryId={filterState.selectedFilterCategory || categoryId}
|
||||
onCategoryClick={handleCategoryClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
<h2>{pageTitle}</h2>
|
||||
<p className={styles.sum}>
|
||||
{t("category.total")}: {totalItems} {t("category.items")}
|
||||
</p>
|
||||
<h2>{pageTitle}</h2>
|
||||
<p className={styles.sum}>
|
||||
{t("category.total")}: {totalItems} {t("category.items")}
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className={styles.bars}>
|
||||
<button
|
||||
|
||||
@@ -329,8 +329,8 @@
|
||||
to top,
|
||||
rgba(0, 0, 0, 0.95) 0%,
|
||||
rgba(0, 0, 0, 0.7) 0%,
|
||||
rgba(0, 0, 0, 0.3) 70%,
|
||||
rgba(255, 255, 255, 0) 100%
|
||||
rgba(0, 0, 0, 0.3) 35%,
|
||||
rgba(255, 255, 255, 0) 35%
|
||||
);
|
||||
z-index: 2;
|
||||
opacity: 0;
|
||||
@@ -386,9 +386,6 @@
|
||||
}
|
||||
|
||||
.productDescriptionCollapsed {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 10;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,14 +69,78 @@ const ProductPage = ({
|
||||
|
||||
const [isDescExpanded, setIsDescExpanded] = useState(false);
|
||||
const [showReadMore, setShowReadMore] = useState(false);
|
||||
const [collapsedMaxHeight, setCollapsedMaxHeight] = useState(null);
|
||||
const descRef = React.useRef(null);
|
||||
const productInfoRef = React.useRef(null);
|
||||
const imageColRef = React.useRef(null);
|
||||
|
||||
// Ürün değişince desc'i kapat
|
||||
useEffect(() => {
|
||||
setIsDescExpanded(false);
|
||||
}, [productId]);
|
||||
|
||||
// Resim kolonu yüksekliği ile desc kolonu yüksekliğini karşılaştır
|
||||
useEffect(() => {
|
||||
if (!product?.description) return;
|
||||
|
||||
const plainText = product.description.replace(/<[^>]*>/g, "").trim();
|
||||
setShowReadMore(plainText.length > 300);
|
||||
const imageEl = imageColRef.current;
|
||||
const infoEl = productInfoRef.current;
|
||||
if (!imageEl || !infoEl) return;
|
||||
|
||||
const checkHeights = () => {
|
||||
const descEl = descRef.current;
|
||||
if (!descEl) return;
|
||||
|
||||
const descTrueH = descEl.scrollHeight;
|
||||
const descVisibleH = descEl.getBoundingClientRect().height;
|
||||
|
||||
// ── Mobil: tek kolon layout, sabit eşik kullan ──────────────────
|
||||
if (window.innerWidth <= 639) {
|
||||
const MOBILE_THRESHOLD = 220;
|
||||
if (descTrueH > MOBILE_THRESHOLD) {
|
||||
setShowReadMore(true);
|
||||
setCollapsedMaxHeight(MOBILE_THRESHOLD);
|
||||
} else {
|
||||
setShowReadMore(false);
|
||||
setCollapsedMaxHeight(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Desktop/tablet: resim kolonu yüksekliğiyle karşılaştır ──────
|
||||
const imageH = imageEl.getBoundingClientRect().height;
|
||||
if (imageH === 0) return;
|
||||
|
||||
const infoCurrentH = infoEl.getBoundingClientRect().height;
|
||||
// Info kolonunun gerçek (kısıtsız) yüksekliği:
|
||||
const infoTrueH = infoCurrentH + (descTrueH - descVisibleH);
|
||||
|
||||
if (infoTrueH > imageH) {
|
||||
const overflow = infoTrueH - imageH;
|
||||
const newDescMaxH = Math.max(descTrueH - overflow, 60);
|
||||
setShowReadMore(true);
|
||||
setCollapsedMaxHeight(newDescMaxH);
|
||||
} else {
|
||||
setShowReadMore(false);
|
||||
setCollapsedMaxHeight(null);
|
||||
}
|
||||
};
|
||||
|
||||
// İlk kontrol (DOM yerleştikten sonra)
|
||||
const raf = requestAnimationFrame(checkHeights);
|
||||
|
||||
const ro = new ResizeObserver(checkHeights);
|
||||
ro.observe(imageEl);
|
||||
ro.observe(infoEl);
|
||||
|
||||
// Mobil↔desktop geçişi için window resize de dinlenir
|
||||
window.addEventListener("resize", checkHeights);
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(raf);
|
||||
ro.disconnect();
|
||||
window.removeEventListener("resize", checkHeights);
|
||||
};
|
||||
}, [product?.description]);
|
||||
|
||||
const { getCartItem } = useCart();
|
||||
@@ -325,7 +389,7 @@ const ProductPage = ({
|
||||
{/* ── 3 kolon ana section ── */}
|
||||
<div className={styles.productSection}>
|
||||
{/* KOLON 1: Resim */}
|
||||
<div className={styles.productImage}>
|
||||
<div className={styles.productImage} ref={imageColRef}>
|
||||
<ImageCarousel
|
||||
images={product.media}
|
||||
altText={product.name}
|
||||
@@ -410,6 +474,11 @@ const ProductPage = ({
|
||||
className={`${styles.productDescription} ${
|
||||
!isDescExpanded && showReadMore ? styles.productDescriptionCollapsed : ""
|
||||
}`}
|
||||
style={
|
||||
!isDescExpanded && showReadMore && collapsedMaxHeight
|
||||
? { maxHeight: `${collapsedMaxHeight}px` }
|
||||
: undefined
|
||||
}
|
||||
dangerouslySetInnerHTML={{ __html: product.description }}
|
||||
/>
|
||||
{showReadMore && !isDescExpanded && (
|
||||
@@ -442,7 +511,7 @@ const ProductPage = ({
|
||||
<div className={styles.priceRight}>
|
||||
{isPriceZero(product.price_amount) ? (
|
||||
<span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontWeight: 600 }}>
|
||||
{t("cart.pendingPriceTitle")} <PendingPriceBadge />
|
||||
<PendingPriceBadge />
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -27,7 +27,7 @@ const StoresPage = () => {
|
||||
|
||||
// Initial fetch on component mount
|
||||
useEffect(() => {
|
||||
getChannels({ page: 1, limit: itemsPerPage });
|
||||
getChannels({ page: 1, perPage: itemsPerPage });
|
||||
}, [getChannels]);
|
||||
|
||||
// Process stores data when it arrives
|
||||
@@ -93,9 +93,9 @@ const StoresPage = () => {
|
||||
}, [allStores, searchTerm, t]);
|
||||
|
||||
const loadMoreStores = () => {
|
||||
if (!searchTerm && !isFetching && hasMore) {
|
||||
if (!searchTerm && !isFetching && hasMore && allStores.length > 0) {
|
||||
const nextPage = page + 1;
|
||||
getChannels({ page: nextPage, limit: itemsPerPage });
|
||||
getChannels({ page: nextPage, perPage: itemsPerPage });
|
||||
setPage(nextPage);
|
||||
}
|
||||
};
|
||||
@@ -106,7 +106,7 @@ const StoresPage = () => {
|
||||
setPage(1);
|
||||
setAllStores([]);
|
||||
setHasMore(true);
|
||||
getChannels({ page: 1, limit: itemsPerPage, search: value });
|
||||
getChannels({ page: 1, perPage: itemsPerPage, search: value });
|
||||
};
|
||||
|
||||
const handleStoreClick = (storeId) => {
|
||||
|
||||
Reference in New Issue
Block a user