Skip to content

Commit

Permalink
Merge pull request #101 from MargoMarm/feature/scroll-again
Browse files Browse the repository at this point in the history
Feature/scroll again
  • Loading branch information
MargoMarm committed Sep 27, 2023
2 parents af2d833 + 0cef927 commit 89e0e6f
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 30 deletions.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"react-countdown-circle-timer": "^3.2.1",
"react-datepicker": "^4.18.0",
"react-dom": "^18.2.0",
"react-infinite-scroller": "^1.2.6",
"react-loader-spinner": "^5.4.5",
"react-redux": "^8.1.2",
"react-responsive": "^9.0.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import { useRef, useEffect } from 'react';
import { useSelector } from 'react-redux';

import { getSearchParams } from '../../redux/productsFilter/selectors';
import { Container } from './ProductOrExerciseContainer.styled';

export default function ProductsOrExercisesContainer({ children, ...props }) {
return <Container {...props}>{children}</Container>;
const containerRef = useRef();
const searchParams = useSelector(getSearchParams);

useEffect(() => {
console.log('scroll', containerRef.current.firstChild);
containerRef.current.firstChild?.scrollIntoView();
}, [searchParams]);

return (
<Container ref={containerRef} {...props}>
{children}
</Container>
);
}
2 changes: 2 additions & 0 deletions src/components/ProductsFilter/ProductsFilter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import debounce from 'lodash.debounce';

import { capitalizeWord } from '../../utils/capitalizeWord';
import { addSearchParams } from '../../redux/productsFilter/slice';

export default function ProductsFilter() {
const makeReqObj = (input, category, recommended) => {
Expand Down Expand Up @@ -52,6 +53,7 @@ export default function ProductsFilter() {
useEffect(() => {
const reqObj = makeReqObj(query, currentCategory, isRecommended);
const urlParams = new URLSearchParams(reqObj).toString();
dispatch(addSearchParams(urlParams));
dispatch(fetchProducts(urlParams));
}, [query, currentCategory, isRecommended, dispatch]);

Expand Down
6 changes: 3 additions & 3 deletions src/components/Scrollbar/Scrollbar.syled.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { mq } from '../../utils';

export const ScrollContainer = styled.div`
width: ${({ width }) => width?.mob + 'px' || '100%'};
${mq.tablet} {
width: ${({ width }) => width?.nab + 'px' || '100%'};
height: 660px;
}
${mq.desktop} {
width: ${({ width }) => width?.dt + 'px' || '100%'};
height: 487px;
height: calc(100vh - 220px);
}
`;
4 changes: 2 additions & 2 deletions src/pages/Exercises/Exercises.styled.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ export const ExercisesListContainer = styled.div`
${mq.tablet} {
padding: 72px 32px 48px 32px;
padding: 32px 32px 48px 32px;
}
${mq.desktop} {
padding: 68px 81px 81px 96px;
padding: 0px 81px 81px 96px;
}
`;

Expand Down
75 changes: 57 additions & 18 deletions src/pages/Products/Products.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,82 @@ import { FlexWrapper, ProductPageContainer } from './Products.styled';
import Scrollbar from '../../components/Scrollbar';
import ProductsOrExercisesItem from '../../components/ProductsOrExercisesItem/ProductsOrExercisesItem';
import { useDispatch, useSelector } from 'react-redux';
import { getProducts } from '../../redux/productsFilter/selectors';

import { getAddProductIsLoading } from '../../redux/products/selectors';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { fetchProducts } from '../../redux/productsFilter/operations';
import EmptyProductList from '../../components/EmptyProductList/EmptyProductList';
import Loader from '../../components/Lodaer/Loader';
import { fetchMoreProducts } from '../../redux/productsFilter/operations';
import {
getIsLoading,
getSearchParams,
getProducts,
getHasMore,
} from '../../redux/productsFilter/selectors';
import InfiniteScroll from 'react-infinite-scroller';

const Products = () => {
const [page, setPage] = useState(1);

const hasMore = useSelector(getHasMore);

const isLoadingMoreProducts = useSelector(getIsLoading);

const dispatch = useDispatch();
const products = useSelector(getProducts);
const isLoading = useSelector(getAddProductIsLoading);

const searchParams = useSelector(getSearchParams);

useEffect(() => {
dispatch(fetchProducts());
}, [dispatch]);
setPage(1);
}, [searchParams]);

return (
<ProductPageContainer>
<FlexWrapper>
<Title text="Products" />
<ProductsFilter />
</FlexWrapper>
{isLoading ? (
<Loader />
) : products.length !== 0 ? (
{products.length !== 0 ? (
<Scrollbar width={{ dt: '868' }}>
<ProductsOrExercisesContainer>
{products.map(product => {
return (
<ProductsOrExercisesItem
key={product.id}
page="product"
data={product}
/>
<InfiniteScroll
pageStart={1}
loadMore={() => {
if (page === 1) {
setPage(prevPage => prevPage + 1);
return;
}

const urlParams = { page, limit: 20 };
const paginationParams = new URLSearchParams(
urlParams,
).toString();
dispatch(
fetchMoreProducts(`${searchParams}&${paginationParams}`),
);
})}
</ProductsOrExercisesContainer>
setPage(prevPage => prevPage + 1);
}}
hasMore={hasMore && !isLoadingMoreProducts}
loader={
<div className="loader" key={0}>
Loading ...
</div>
}
useWindow={false}
>
<ProductsOrExercisesContainer>
{products.map(product => {
return (
<ProductsOrExercisesItem
key={product.id}
page="product"
data={product}
/>
);
})}
</ProductsOrExercisesContainer>
</InfiniteScroll>
</Scrollbar>
) : (
<EmptyProductList />
Expand Down
12 changes: 12 additions & 0 deletions src/redux/productsFilter/operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ export const getCategories = createAsyncThunk(
},
},
);

export const fetchMoreProducts = createAsyncThunk(
`fetchMoreProducts`,
async (params, thunkAPI) => {
try {
const { data } = await axios.get(`api/products?${params}`);
return data;
} catch (error) {
return thunkAPI.rejectWithValue(error.message);
}
},
);
3 changes: 3 additions & 0 deletions src/redux/productsFilter/selectors.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export const getProducts = state => state.products.products;
export const getProductsCategories = state => state.products.categories;
export const getIsLoading = state => state.products.isLoading;
export const getSearchParams = state => state.products.searchParams;
export const getHasMore = state => state.products.hasMore;
35 changes: 29 additions & 6 deletions src/redux/productsFilter/slice.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { createSlice } from '@reduxjs/toolkit';
import { fetchProducts, getCategories } from './operations';


import { fetchProducts, getCategories, fetchMoreProducts } from './operations';

export const productsSlice = createSlice({
name: 'products',
initialState : {
initialState: {
products: [],
categories: [],
error: null,
isLoading: false,
searchParams: '',
hasMore: false,
},
reducers: {
addSearchParams: {
reducer(state, action) {
state.searchParams = action.payload;
},
},
},
reducers: {},
extraReducers: builder => {
builder.addCase(fetchProducts.fulfilled, (state, action) => {
state.products = action.payload;
state.error = null;
state.isLoading = false;
state.hasMore = action.payload.length < 20 ? false : true;
});
builder.addCase(fetchProducts.pending, (state, action) => {
state.isLoading = true;
Expand All @@ -37,6 +44,22 @@ export const productsSlice = createSlice({
state.error = action.payload;
state.isLoading = false;
});
builder.addCase(fetchMoreProducts.fulfilled, (state, action) => {
state.products = [...state.products, ...action.payload];
state.error = null;
state.isLoading = false;
state.hasMore = action.payload.length < 20 ? false : true;
});
builder.addCase(fetchMoreProducts.pending, (state, action) => {
state.isLoading = true;
});
builder.addCase(fetchMoreProducts.rejected, (state, action) => {
state.error = action.payload;
state.isLoading = false;
});
},
});
export default productsSlice.reducer;

export default productsSlice.reducer;

export const { addSearchParams } = productsSlice.actions;

0 comments on commit 89e0e6f

Please sign in to comment.