Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add task solution #551

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/arrow-left-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/arrow-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/arrow-right-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/arrow-top.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/img/icons/burger.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/img/icons/cart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/cross-x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/favourites-heart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions public/img/icons/footer-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/heart-filled.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/img/icons/home.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions public/img/icons/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/minus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/img/icons/plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/main-slider/smart-watches.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/main-slider/smartphones.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/main-slider/tablets.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Phone catalog</title>
<link rel="icon" href="favicon.svg" type="image/svg+xml">
</head>
<body>
<div id="root"></div>
</body>
</html>
1 change: 0 additions & 1 deletion src/App.scss

This file was deleted.

7 changes: 0 additions & 7 deletions src/App.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions src/api/products.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { client } from '../utils/fetchClient';

export const getAllProducts = () => {
return client.get('api/products.json');
};

export const getPhones = () => {
return client.get('api/phones.json');
};

export const getTablets = () => {
return client.get('api/tablets.json');
};

export const getAccessories = () => {
return client.get('api/accessories.json');
};
6 changes: 6 additions & 0 deletions src/app/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { useDispatch, useSelector } from 'react-redux';
import type { AppDispatch, RootState } from './store';

export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();
14 changes: 14 additions & 0 deletions src/app/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { combineSlices, configureStore } from '@reduxjs/toolkit';
import { productsSlice } from '../features/products';
import { cartSlice } from '../features/cart';
import { favouriteSlice } from '../features/favourite';

const rootReducer = combineSlices(productsSlice, cartSlice, favouriteSlice);

export const store = configureStore({
reducer: rootReducer,
});

export type RootState = ReturnType<typeof rootReducer>;
export type AppDispatch = typeof store.dispatch;
35 changes: 35 additions & 0 deletions src/components/BackButton/BackButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.back {
border: none;
background: transparent;
margin-top: 24px;
height: 16px;
display: flex;
gap: 4px;
cursor: pointer;
transition: color $hover-transition ease;
color: $white;
font-family: inherit;

&__text {
color: inherit;
font-weight: 700;
font-size: 12px;
line-height: 15px;
display: flex;
justify-content: center;
align-items: center;
}

&__arrow {
height: 16px;
width: 16px;
}

&:hover {
color: $accent;
}

@media (min-width: $tablet) {
margin-top: 40px;
}
}
14 changes: 14 additions & 0 deletions src/components/BackButton/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useNavigate } from 'react-router-dom';

export const BackButton = () => {
const navigate = useNavigate();

return (
<button className="back" onClick={() => navigate(-1)}>
<div className="back__arrow">
<img src="./img/icons/arrow-left-white.svg" alt="Arrow left" />
</div>
<span className="back__text">Back</span>
</button>
);
};
1 change: 1 addition & 0 deletions src/components/BackButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BackButton';
47 changes: 47 additions & 0 deletions src/components/Breadcrumbs/Breadcrumbs.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.breadcrumbs {
display: flex;
align-items: center;
gap: 8px;
margin: 24px 0;
height: 16px;

@media (min-width: $tablet) {
margin: 24px 0 40px;
}

&__item {
display: flex;
align-items: center;
gap: 8px;
height: 100%;
font-weight: 700;
font-size: 12px;
line-height: 15px;
color: $gray;
transition: color $hover-transition ease;

&__image {
transition: transform $hover-transition ease;

&:hover {
transform: scale(1.1);
}
}

&--link {
color: $white;
text-decoration: none;

&:hover {
color: $accent;
}
}

&--last {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
}
}
}
49 changes: 49 additions & 0 deletions src/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Link, useLocation } from 'react-router-dom';
import { useAppSelector } from '../../app/hooks';
import { Product } from '../../types/Product';
import React from 'react';

export const Breadcrumbs = () => {
const location = useLocation();
const breadcrumbs = location.pathname.split('/').filter(path => path);
const products = useAppSelector(state => state.products);
const currentProduct = products.find(
(product: Product) =>
product.itemId === breadcrumbs[breadcrumbs.length - 1],
) || { name: breadcrumbs[breadcrumbs.length - 1] };

breadcrumbs.pop();
breadcrumbs.push(currentProduct.name);

return (
<div className="breadcrumbs">
<Link to="/" className="breadcrumbs__item breadcrumbs__item--link">
<img
src="./img/icons/home.svg"
alt="Home"
className="breadcrumbs__item__image"
/>
</Link>
{breadcrumbs.map((crumb, index) => {
const routeTo = `/${breadcrumbs.slice(0, index + 1).join('/')}`;
const isLast = index === breadcrumbs.length - 1;
const crumbName = crumb.charAt(0).toUpperCase() + crumb.slice(1);

return (
<div key={index} className="breadcrumbs__item">
<img src="./img/icons/arrow-right.svg" alt="Arrow right" />
{!isLast ? (
<Link to={routeTo} className="breadcrumbs__item--link">
{crumbName}
</Link>
) : (
<span className="breadcrumbs__item breadcrumbs__item--last">
{crumbName}
</span>
)}
</div>
);
})}
</div>
);
};
1 change: 1 addition & 0 deletions src/components/Breadcrumbs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Breadcrumbs';
75 changes: 75 additions & 0 deletions src/components/Categories/Categories.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.categories {
margin-bottom: 56px;

&__group {
display: flex;
flex-direction: column;
gap: 32px;

@media (min-width: $tablet) {
flex-direction: row;
gap: 16px;
}
}

&__background {
overflow: hidden;
width: 100%;
aspect-ratio: 1 / 1;
position: relative;
transition: transform $hover-transition ease;
z-index: 1;

&:hover {
transform: scale(1.05);
z-index: 2;
}
}

&__item {
width: 100%;

@media (min-width: $tablet) {
width: calc((100% - 32px) / 3);
}

.categories__image {
height: 100%;
transform: translate(30%, 30%) scale(1.5);
}

&:nth-child(1) {
.categories__background {
background: #6D6474;
}
}

&:nth-child(2) {
.categories__background {
background: #8D8D92;
}
}

&:nth-child(3) {
.categories__background {
background: #D53C51;
}

.categories__image {
transform: translate(5%, 10%);
}
}
}

&__description {
color: $white;
margin-top: 20px;
}

&__count {
font-weight: 600;
font-size: 14px;
line-height: 21px;
color: $gray;
}
}
Loading
Loading