diff --git a/src/App.tsx b/src/App.tsx index 010f3f0..038fc7d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,9 +1,11 @@ import { Outlet } from 'react-router'; import { Header } from './components/Header'; import { Footer } from './components/Footer'; +import { useInitFavourites } from './hooks/useInitFavourites'; import { useInitialCart } from './hooks/useInitialCart'; const App = () => { + useInitFavourites(); useInitialCart(); return ( diff --git a/src/Root.tsx b/src/Root.tsx index 782a511..2786007 100644 --- a/src/Root.tsx +++ b/src/Root.tsx @@ -3,6 +3,7 @@ import App from './App'; import CatalogPage from './pages/CatalogPage'; import NotFound from './pages/NotFound'; import ScrollToTop from './components/ScrollToTop'; +import { FavouritesPage } from './pages/FavouritesPage'; import { CartPage } from './pages/CartPage'; export const Root = () => ( @@ -21,6 +22,7 @@ export const Root = () => ( Accessories Page} /> + } /> } /> } /> diff --git a/src/components/Card.tsx b/src/components/Card.tsx index ca66ea5..f1c88cd 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -1,7 +1,12 @@ import classNames from 'classnames'; import { useState } from 'react'; import { FiHeart } from 'react-icons/fi'; -import { addItemToCart, useAppDispatch } from '../redux'; +import { + addItemToCart, + useAppDispatch, + toggleFavourite, + useAppSelector, +} from '../redux'; import { Button } from './Button'; import { ProductProperties } from './ProductProperties'; import { IProduct } from '../types/Product'; @@ -11,8 +16,13 @@ type Props = { }; export const Card = ({ product }: Props) => { - const [favorite, setFavorite] = useState(false); + const { favouriteItems } = useAppSelector((state) => state.favourites); const dispatch = useAppDispatch(); + const [favorite, setFavorite] = useState(false); + + const isFavourite = (id: string) => + favouriteItems.some((item) => item._id === id); + const productProps = [ { name: 'Screen', @@ -28,7 +38,8 @@ export const Card = ({ product }: Props) => { }, ]; - const handleAddToFav = () => { + const handleToggleFav = (currentProduct: IProduct) => { + dispatch(toggleFavourite(currentProduct)); setFavorite(!favorite); }; @@ -68,11 +79,11 @@ export const Card = ({ product }: Props) => { 'active:scale-95', 'flex justify-center items-center shrink-0 duration-300', ])} - onClick={handleAddToFav} + onClick={() => handleToggleFav(product)} > diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 98f2f6d..95a7c87 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -50,12 +50,12 @@ export const Header: React.FC = () => {
- - +
{ + const dispatch = useAppDispatch(); + + useEffect(() => { + dispatch(getInitialFavourites()); + }, []); +}; diff --git a/src/pages/FavouritesPage.tsx b/src/pages/FavouritesPage.tsx index 51c1a9d..c11cc21 100644 --- a/src/pages/FavouritesPage.tsx +++ b/src/pages/FavouritesPage.tsx @@ -1,27 +1,9 @@ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import { Card } from '../components/Card'; -import axios from 'axios'; -import { IProduct } from '../types/Product'; +import { useAppSelector } from '../redux'; export const FavouritesPage: React.FC = () => { - // #region rewrite to Redux - const [products, setProducts] = useState([]); - // #endregion - - // #region rewrite to RTQ Query - useEffect(() => { - axios - .get('https://dreamteam.onrender.com/products', { - params: { page: 1, perPage: 8 }, - }) - .then((res) => { - setProducts(res.data.data); - }) - .catch((e) => { - throw new Error(e); - }); - }, []); - // #endregion + const favouriteItems = useAppSelector(state => state.favourites.favouriteItems); return (
@@ -30,11 +12,11 @@ export const FavouritesPage: React.FC = () => { FavouritesPage

- 5 items + {`${favouriteItems.length} items`}

- {products.map((pr) => ( + {favouriteItems.map((pr) => ( ))}
diff --git a/src/redux/index.ts b/src/redux/index.ts index ec8673f..fff499e 100644 --- a/src/redux/index.ts +++ b/src/redux/index.ts @@ -1,9 +1,11 @@ import { configureStore } from '@reduxjs/toolkit'; import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; +import { favouritesSlice } from './slices/favouritesSlice'; import { cartSlice } from './slices/cartSlice'; const store = configureStore({ reducer: { + [favouritesSlice.name]: favouritesSlice.reducer, [cartSlice.name]: cartSlice.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(), @@ -11,6 +13,7 @@ const store = configureStore({ export { store }; +export * from './slices/favouritesSlice'; export * from './slices/cartSlice'; export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch; diff --git a/src/redux/slices/favouritesSlice.tsx b/src/redux/slices/favouritesSlice.tsx new file mode 100644 index 0000000..a8815bf --- /dev/null +++ b/src/redux/slices/favouritesSlice.tsx @@ -0,0 +1,39 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { IProduct } from '../../types/Product'; + +type InitialState = { + favouriteItems: IProduct[]; +}; + +const initialState: InitialState = { + favouriteItems: [], +}; + +export const favouritesSlice = createSlice({ + name: 'favourites', + initialState, + reducers: { + getInitialFavourites: (state) => { + state.favouriteItems = JSON.parse( + localStorage.getItem('favourite-items') || '[]', + ) as IProduct[]; + }, + toggleFavourite: (state, action) => { + const hasProductId = state.favouriteItems.some( + (favouriteItem) => favouriteItem._id === action.payload._id, + ); + + if (hasProductId) { + state.favouriteItems = state.favouriteItems.filter( + (favouriteItem) => favouriteItem._id !== action.payload._id, + ); + localStorage.setItem('favourite-items', JSON.stringify(state.favouriteItems)); + } else { + state.favouriteItems.push(action.payload); + localStorage.setItem('favourite-items', JSON.stringify(state.favouriteItems)); + } + }, + }, +}); + +export const { toggleFavourite, getInitialFavourites } = favouritesSlice.actions;