Skip to content

Commit

Permalink
Merge pull request #39 from fe-may23-dreamTeam/carousel-with-data-fro…
Browse files Browse the repository at this point in the history
…m-api

Carousel with data from api
  • Loading branch information
MaxSchmide authored Sep 7, 2023
2 parents a63661d + 2274f23 commit 2f89966
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 53 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"react-redux": "^8.1.2",
"react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
"react-slick": "^0.29.0",
"slick-carousel": "^1.8.1",
"swiper": "^9.4.1",
"typescript": "^4.9.5",
"use-react-router-breadcrumbs": "^4.0.1",
Expand Down Expand Up @@ -55,6 +57,7 @@
},
"devDependencies": {
"@mate-academy/eslint-config": "^0.0.25",
"@types/react-slick": "^0.23.10",
"@types/swiper": "^6.0.0",
"husky": "^8.0.3",
"lint-staged": "^14.0.1",
Expand Down
22 changes: 22 additions & 0 deletions public/assets/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@800&display=swap"
rel="stylesheet"
/>
<link
rel="shortcut icon"
href="public/assets/favicon.svg"
type="image/x-icon"
/>
</head>
<body>
<div id="root"></div>
Expand Down
10 changes: 5 additions & 5 deletions src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {
} from 'react-router-dom';
import App from './App';
import CatalogPage from './pages/CatalogPage';
import NotFound from './pages/NotFound';
import { ProductPage } from './pages/ProductPage';
import NotFoundPage from './pages/NotFoundPage';
import ProductPage from './pages/ProductPage';
import ScrollToTop from './components/ScrollToTop';
import { FavouritesPage } from './pages/FavouritesPage';
import { CartPage } from './pages/CartPage';
import FavouritesPage from './pages/FavouritesPage';
import CartPage from './pages/CartPage';
import HomePage from './pages/HomePage';
import { Toaster } from 'react-hot-toast';

Expand All @@ -37,7 +37,7 @@ export const Root = () => (
</Route>
<Route path="favourites" element={<FavouritesPage />} />
<Route path="cart" element={<CartPage />} />
<Route path="*" element={<NotFound />} />
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
11 changes: 7 additions & 4 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const Card = ({ product, isFetching }: Props) => {

const handleAddToCart = () => {
if (items.some(({ id }) => id === product._id)) {
toast.error('This product already in cart');
toast.error('This product is already in your cart');

return;
}
Expand All @@ -69,7 +69,7 @@ export const Card = ({ product, isFetching }: Props) => {
};

dispatch(addItemToCart(itemData));
toast.success('Successfully added to cart!');
toast.success('Successfully added to your cart!');
};

return (
Expand All @@ -88,9 +88,12 @@ export const Card = ({ product, isFetching }: Props) => {
})}
/>
<div className="grid auto-rows-auto gap-y-2 object-cover">
<NavLink to={`/${product.category.name}/${product._id}`}>
<NavLink
to={`/${product.category.name}/${product._id}`}
className="max-h-[130px] tablet:max-h-[200px]"
>
<img
className="mx-auto max-h-[130px] tablet:max-h-[200px]"
className="mx-auto object-contain h-full tablet:aspect-square"
src={product.images[0]}
alt={product.namespaceId}
/>
Expand Down
86 changes: 86 additions & 0 deletions src/components/Carousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import Slider from 'react-slick';
import { FiChevronLeft, FiChevronRight } from 'react-icons/fi';
import { Card } from './Card';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import { IProduct } from '../types/Product';
import { useParams } from 'react-router-dom';
import { useGetProductByTypeQuery } from '../redux/api/productApi';
import { ErrorMessage } from './ErrorMessage';
import { Loader } from './Loader';

const settings = {
className: 'mx-auto overflow-hidden !static',
slidesToScroll: 1,
initialSlide: 0,
infinite: true,
variableWidth: true,
nextArrow: <SampleNextArrow />,
prevArrow: <SamplePrevArrow />,
swipeToSlide: false,
};

function SampleNextArrow(props: any) {
const { onClick } = props;

return (
<button
onClick={onClick}
className="absolute top-0 right-0 cursor-pointer border rounded-full border-icons border-solid hover:border-primary active:text-primary focus:text-primary h-8 w-8 flex items-center justify-center"
>
<FiChevronRight className="w-4 h-4" />
</button>
);
}

function SamplePrevArrow(props: any) {
const { onClick } = props;

return (
<button
onClick={onClick}
className="absolute top-0 right-12 cursor-pointer border rounded-full border-icons border-solid hover:border-primary active:text-primary focus:text-primary h-8 w-8 flex items-center justify-center"
>
<FiChevronLeft className="w-4 h-4" />
</button>
);
}

type Props = {
title: string;
type: 'discount' | 'new' | 'recommended';
};

export const Carousel: React.FC<Props> = ({ title, type }) => {
const { phoneId } = useParams();
const {
data: products,
isError,
isFetching,
} = useGetProductByTypeQuery({ type, phoneId });

return (
<div className="Carousel relative mx-auto desktop:max-w-[1152px] pt-16 mt-[150px] desktop:pb-20 tablet:pb-16">
<ErrorMessage isError={isError}>
<Loader isLoading={isFetching}>
<h2 className="font-extrabold text-2xl desktop:text-4xl text-primary absolute left-0 top-0">
{title}
</h2>
<Slider {...settings} className="space-x-4">
{products &&
products.map((product: IProduct) => (
<div key={product._id} className="max-w-[272px]">
<Card
isFetching={isFetching}
product={product}
key={product._id}
/>
</div>
))}
</Slider>
</Loader>
</ErrorMessage>
</div>
);
};
2 changes: 1 addition & 1 deletion src/components/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Props = {
export const Loader = ({ isLoading, children }: Props) => {
if (isLoading) {
return (
<div className="absolute left-1/2 -translate-x-1/2 flex place-content-center ">
<div className="top-0 absolute left-1/2 -translate-x-1/2 flex place-content-center ">
<FiSmartphone className="w-20 h-40 rounded-full animate-bounce text-accent" />
</div>
);
Expand Down
8 changes: 8 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,11 @@
height: 432px !important;
}
}

.Carousel .slick-track {
@apply space-x-4;
}

.slick-slider {
position: static !important;
}
4 changes: 3 additions & 1 deletion src/pages/CartPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { clearCart, useAppDispatch, useAppSelector } from '../redux';
import { getTotalProductsCost } from '../utils/getTotalCost';
import { getTotalItemsCount } from '../utils/getTotalItemsCount';

export const CartPage: React.FC = () => {
const CartPage = () => {
const navigate = useNavigate();

const { items: cartItems } = useAppSelector((state) => state.cart);
Expand Down Expand Up @@ -85,3 +85,5 @@ export const CartPage: React.FC = () => {
</>
);
};

export default CartPage;
24 changes: 15 additions & 9 deletions src/pages/CatalogPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const CatalogPage: React.FC = () => {
};

return (
<main className="relative container mx-auto flex flex-col items-center tablet:items-start px-4 tablet:px-6 desktop:w-[1200px]">
<main className="relative container mx-auto flex flex-col items-center tablet:items-start p-4 tablet:px-6 desktop:w-[1200px]">
<ErrorMessage isError={isError}>
<Loader isLoading={isFetching}>
<BreadCrumb />
Expand Down Expand Up @@ -100,15 +100,21 @@ const CatalogPage: React.FC = () => {
)}

<div className="mb-10 relative grid grid-cols-1 gap-4 tablet:grid-cols-2 desktop:grid-cols-4">
{products?.data.map((product: IProduct) => (
<Card
isFetching={isFetching}
product={product}
key={product._id}
/>
))}
{products?.data.length > 0 ? (
products?.data.map((product: IProduct) => (
<Card
isFetching={isFetching}
product={product}
key={product._id}
/>
))
) : (
<p className="col-span-4 tablet:col-span-12 desktop:col-span-24">
Sorry, we ran out of these products
</p>
)}
</div>
{products?.data.length > perPage && (
{products?.totalProducts > perPage && (
<Pagination
className="mb-20"
total={total}
Expand Down
6 changes: 4 additions & 2 deletions src/pages/FavouritesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Card } from '../components/Card';
import { useAppSelector } from '../redux';
import BreadCrumb from '../components/BreadCrumb';

export const FavouritesPage: React.FC = () => {
const FavouritesPage = () => {
const { favouriteItems } = useAppSelector((state) => state.favourites);

return (
<main className="container mx-auto flex flex-col items-center tablet:items-start px-4 pb-6 tablet:px-6 desktop:w-[1200px]">
<main className="container mx-auto flex flex-col items-center tablet:items-start p-4 pb-6 tablet:px-6 desktop:w-[1200px]">
<BreadCrumb />

<header>
Expand All @@ -32,3 +32,5 @@ export const FavouritesPage: React.FC = () => {
</main>
);
};

export default FavouritesPage;
6 changes: 5 additions & 1 deletion src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Carousel } from '../components/Carousel';
import CategoryCard from '../components/CategoryCard';

const HomePage = () => {
Expand All @@ -19,7 +20,7 @@ const HomePage = () => {
>
Welcome to Nice Gadgets store!
</h1>
<div className="w-full tablet:w-4/5 mx-auto">
<div className="select-none w-full tablet:w-4/5 mx-auto">
<Swiper
modules={[Pagination, Navigation]}
pagination={true}
Expand Down Expand Up @@ -58,6 +59,8 @@ const HomePage = () => {
</Swiper>
</div>

<Carousel title={'Brand new models'} type={'new'} />

<section className="mt-[57px] tablet:mt-[64px] desktop:mt-[80px] desktop:max-w-[1136px] desktop:mx-auto">
<h2 className="font-mont font-extrabold text-[22px] tablet:text-[32px] text-primary mx-[16px] tablet:mx-[24px] desktop:mx-[32px]">
Shop by category
Expand All @@ -68,6 +71,7 @@ const HomePage = () => {
<CategoryCard type={'Accessories'} image={accessoriesoneImage} />
</div>
</section>
<Carousel title={'Hot prices'} type={'discount'} />
</main>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/pages/NotFound.tsx → src/pages/NotFoundPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const NotFound = () => {
const NotFoundPage = () => {
return (
<main className="grid min-h-full place-items-center bg-white px-6 py-24 tablet:py-32 desktop:px-8">
<div className="text-center">
Expand Down Expand Up @@ -31,4 +31,4 @@ const NotFound = () => {
);
};

export default NotFound;
export default NotFoundPage;
Loading

0 comments on commit 2f89966

Please sign in to comment.