Skip to content
Open
Show file tree
Hide file tree
Changes from 126 commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
2ab2ae0
Add solution
Yar14k Mar 21, 2026
fbfaf83
Add solution
Yar14k Mar 21, 2026
bb3cb62
Add solution
Yar14k Mar 21, 2026
6ec9f0c
Add solution
Yar14k Mar 21, 2026
f090cae
Add solution
Yar14k Mar 21, 2026
85e1662
Add solution
Yar14k Mar 21, 2026
631a071
Add solution
Yar14k Mar 21, 2026
b3a78f2
Add solution
Yar14k Mar 21, 2026
136131a
Add solution
Yar14k Mar 22, 2026
f599edc
Add solution
Yar14k Mar 22, 2026
b67c275
Add solution
Yar14k Mar 23, 2026
e3d3c80
Add solution
Yar14k Mar 23, 2026
cda0827
Add solution
Yar14k Mar 23, 2026
9e51103
Add solution
Yar14k Mar 23, 2026
2c685d3
Add solution
Yar14k Mar 23, 2026
31d1661
Add solution
Yar14k Mar 24, 2026
a92bbc7
Add solution
Yar14k Mar 24, 2026
2d5ab04
Add solution-
Yar14k Mar 24, 2026
d6e3c4e
Add solution
Yar14k Mar 24, 2026
88ebdb3
Add solution
Yar14k Mar 25, 2026
9f83604
Add solution
Yar14k Mar 26, 2026
43acba6
Add solution
Yar14k Mar 26, 2026
e1630b6
Add solution
Yar14k Mar 27, 2026
6b039c3
Add solution
Yar14k Mar 27, 2026
0144ad7
Add solution
Yar14k Mar 27, 2026
e3bbea7
Add solution
Yar14k Mar 27, 2026
25a7377
Add solution
Yar14k Mar 28, 2026
0b67e15
Add solution
Yar14k Mar 28, 2026
c1eb87d
Add solution
Yar14k Mar 28, 2026
b3664c8
Add solution
Yar14k Mar 29, 2026
f4672d4
Add solution
Yar14k Mar 29, 2026
a62218a
Add solution
Yar14k Mar 29, 2026
d630c8f
Add solution
Yar14k Mar 29, 2026
82992b4
Add solution
Yar14k Mar 29, 2026
5b47c94
Add solution
Yar14k Mar 29, 2026
4b9bbcf
Add solution
Yar14k Mar 30, 2026
4d2e8f7
Add solution
Yar14k Apr 2, 2026
28432f9
Add solution
Yar14k Apr 3, 2026
2152ea5
Add solution
Yar14k Apr 3, 2026
348ddb4
Add solution
Yar14k Apr 4, 2026
4174b1f
Add solution
Yar14k Apr 4, 2026
7f15948
Add solution
Yar14k Apr 4, 2026
8d6787f
Add solution
Yar14k Apr 5, 2026
f1a01a9
Add solution
Yar14k Apr 5, 2026
a5bd840
Add solution
Yar14k Apr 5, 2026
8f3144b
Add solution
Yar14k Apr 5, 2026
a508218
Add solution
Yar14k Apr 5, 2026
912675f
Add solution
Yar14k Apr 5, 2026
ff1e3d1
Add solution
Yar14k Apr 5, 2026
1acc1e8
Add solution
Yar14k Apr 5, 2026
07e6cb8
Add solution
Yar14k Apr 5, 2026
a213eb5
Add solution
Yar14k Apr 6, 2026
b0be4e6
Add solution
Yar14k Apr 6, 2026
ba4cd59
Add solution
Yar14k Apr 6, 2026
0d1ff08
Add solution
Yar14k Apr 7, 2026
c46fb3d
Add solution
Yar14k Apr 9, 2026
89cef16
Add solution
Yar14k Apr 12, 2026
d72eae7
Add solution
Yar14k Apr 13, 2026
93f42ae
Add solution
Yar14k Apr 13, 2026
cd95021
Add solution
Yar14k Apr 13, 2026
571dd08
Add solution
Yar14k Apr 14, 2026
275ed9b
Add solution
Yar14k Apr 14, 2026
8354eed
Add solution
Yar14k Apr 15, 2026
a26d8b1
Add solution
Yar14k Apr 15, 2026
4e161b0
Add solution
Yar14k Apr 18, 2026
3515955
Add solution
Yar14k Apr 20, 2026
ef90e24
Add solution
Yar14k Apr 20, 2026
8d8b097
Add solution
Yar14k Apr 20, 2026
86ff9fe
Add solution
Yar14k Apr 20, 2026
346bf17
Add solution
Yar14k Apr 20, 2026
ed261f4
Add solution
Yar14k Apr 20, 2026
87afd1d
Add solution
Yar14k Apr 21, 2026
908138f
Add solution
Yar14k Apr 21, 2026
0c95ba2
Add solutio
Yar14k Apr 21, 2026
ddd32ee
Add solution
Yar14k Apr 21, 2026
d6ba001
Add solution
Yar14k Apr 21, 2026
d7cd36c
Add solution
Yar14k Apr 22, 2026
8a236cc
Add solution
Yar14k Apr 22, 2026
66e1645
Add solution
Yar14k Apr 22, 2026
ba2b0bf
Add solution
Yar14k Apr 24, 2026
4693de6
Add solution
Yar14k Apr 25, 2026
0ef4acd
Add solution
Yar14k Apr 26, 2026
fb2b837
Add solution
Yar14k Apr 26, 2026
cd4ec9a
Add solution
Yar14k Apr 27, 2026
e1f23a8
Add solution
Yar14k Apr 27, 2026
4a21e94
Add solution
Yar14k Apr 27, 2026
4dbeed7
Add solution
Yar14k Apr 27, 2026
53f73eb
Add solution
Yar14k Apr 27, 2026
9ad6e72
Add solution
Yar14k Apr 27, 2026
067b90f
Add solution
Yar14k Apr 27, 2026
d2c5535
Add solution
Yar14k Apr 27, 2026
d8448e0
Add solution
Yar14k Apr 27, 2026
2197486
Add solution
Yar14k Apr 27, 2026
e34b2c6
Add solution
Yar14k Apr 27, 2026
bf2771b
Add solution
Yar14k Apr 27, 2026
7409837
Add solution
Yar14k Apr 27, 2026
a0c616e
Add solution
Yar14k Apr 27, 2026
525ba6c
Add solution
Yar14k Apr 27, 2026
a1d24a4
Add solution
Yar14k Apr 28, 2026
59a2fc2
Add solution
Yar14k Apr 28, 2026
b60af87
Add solution
Yar14k Apr 28, 2026
d8bf932
Add solution
Yar14k Apr 28, 2026
5b68cda
Add solution
Yar14k Apr 28, 2026
8b08734
Add solution
Yar14k Apr 29, 2026
a2fa20d
Add solution
Yar14k Apr 29, 2026
70b157d
Add solution
Yar14k Apr 29, 2026
413c8bb
Add solution
Yar14k Apr 29, 2026
ab4ec1d
Add solution
Yar14k Apr 30, 2026
58e0775
Add solution
Yar14k Apr 30, 2026
0a08a7c
Add solution
Yar14k May 1, 2026
183760a
Add solution
Yar14k May 1, 2026
0c09fdd
Add solution
Yar14k May 1, 2026
4f4a70c
Add solution
Yar14k May 2, 2026
69c7a19
Add solution
Yar14k May 2, 2026
7256191
Add solution
Yar14k May 2, 2026
f56fb48
Add solution
Yar14k May 2, 2026
b20c11b
Add solution
Yar14k May 2, 2026
9329e42
Add solution
Yar14k May 2, 2026
83a3263
Add solution
Yar14k May 2, 2026
2f14b17
Add solution
Yar14k May 2, 2026
e9cda60
Add solution
Yar14k May 2, 2026
1eab48d
Add solution
Yar14k May 2, 2026
853cfe1
Add solution
Yar14k May 2, 2026
f7b562b
Add solution
Yar14k May 2, 2026
54de231
Add solution
Yar14k May 2, 2026
4c6510c
Add solution
Yar14k May 3, 2026
0292fe3
Add solution
Yar14k May 3, 2026
f2cf0f7
Add solution
Yar14k May 3, 2026
ac0ae48
Add solution
Yar14k May 4, 2026
2168121
Add solution
Yar14k May 4, 2026
d741422
Add solution
Yar14k May 5, 2026
4f65691
Add solution
Yar14k May 5, 2026
c9fa782
Add solution
Yar14k May 5, 2026
a5df6fc
Add solution
Yar14k May 5, 2026
811f859
Add solution
Yar14k May 5, 2026
30c01fb
Add solution
Yar14k May 5, 2026
e69826b
Add solution
Yar14k May 5, 2026
db6305c
Add solutio
Yar14k May 5, 2026
c30b53d
Add solution
Yar14k May 5, 2026
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
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<link rel="icon" href="./public/img/icons/icon--fingers.png"/>
<title>Nice Gadgets</title>
</head>
<body>
<div id="root"></div>
Expand Down
7,589 changes: 4,240 additions & 3,349 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
"license": "GPL-3.0",
"dependencies": {
"@fortawesome/fontawesome-free": "^6.5.2",
"bootstrap": "^5.3.8",
"bulma": "^1.0.1",
"classnames": "^2.5.1",
"normalize.css": "^8.0.1",
"react": "^18.3.1",
"react-bootstrap": "^2.10.10",
"react-dom": "^18.3.1",
"react-router-dom": "^6.25.1",
"react-transition-group": "^4.4.5"
"react-transition-group": "^4.4.5",
"swiper": "^12.1.3"
},
"devDependencies": {
"@cypress/react18": "^2.0.1",
"@mate-academy/scripts": "^1.8.5",
"@mate-academy/scripts": "^2.1.3",
"@mate-academy/students-ts-config": "*",
"@mate-academy/stylelint-config": "*",
"@types/node": "^20.14.10",
Expand All @@ -35,7 +39,7 @@
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.4",
"eslint-plugin-react-hooks": "^4.6.2",
"gh-pages": "^6.1.1",
"gh-pages": "^5.0.0",
"mochawesome": "^7.1.3",
"mochawesome-merge": "^4.3.0",
"mochawesome-report-generator": "^6.2.0",
Expand Down
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/Logo/Logo.png
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/Logo/logo--tablet.png
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/category-phones--gold.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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/category-phones--purple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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/icon--basket.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/icon--close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions public/img/icons/icon--fingers.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/icon--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.
3 changes: 3 additions & 0 deletions public/img/icons/icon--heart.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/icon--home.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/icon--menu.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/icon--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/icon--plus.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/icon--slider--down--gray.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/icon--slider--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/icon--slider--right--gray.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/icon--slider--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/icon--slider--top--gray.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/icon--slider--top.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-category--accessory.png
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-category--phone.png
Binary file added public/img/main-category--tablet.png
35 changes: 34 additions & 1 deletion src/App.scss
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
// not empty
@use 'swiper/css' as *;
@use 'swiper/css/navigation' as *;
@use 'swiper/css/pagination' as *;

body {
margin: 0;
};

.App {
min-height:calc(100vh - 160px);
}

/* fonts.scss */

@font-face {
font-family: 'Mont';
src: url('/public/fonts/Mont-Regular.otf') format('opentype');
font-weight: 400;
font-style: normal;
}

@font-face {
font-family: 'Mont';
src: url('/public/fonts/Mont-SemiBold.otf') format('opentype');
font-weight: 600;
font-style: normal;
}

@font-face {
font-family: 'Mont';
src: url('/public/fonts/Mont-Bold.otf') format('opentype');
font-weight: 700;
font-style: normal;
}
97 changes: 92 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,94 @@
import './App.scss';
import Home from './pages/homePage/Home';
import Phones from './pages/phonesPage/Phones';
import Accessories from './pages/accessoriesPage/Accessories';
import Tablets from './pages/tabletsPage/Tablets';
import Heart from './pages/heartPage/Heart';
import ProductPage from './pages/productPage/ProductPage';
import { HashRouter, Routes, Route } from 'react-router-dom';
import Basket from './pages/basketPage/Basket';
import { useLocalStorage } from './api';
import { FavoriteProduct } from './types/FavoriteProduct';
import { BasketProduct } from './types/BasketProduct';
import Footer from './components/Footer/Footer';
import Header from './components/Header/Header';
import BurgerMenu from './pages/BurgerMenu/BurgerMenu';
import { AppContext } from './AppContext';
import { useState } from 'react';
import TermsPage from './pages/termsPage/TermsPage';

export const App = () => (
<div className="App">
<h1>Product Catalog</h1>
</div>
);
export const App = () => {
const [favorites, setFavorites] = useLocalStorage<FavoriteProduct[]>(
'favorites',
[],
);
const [baskets, setBaskets] = useLocalStorage<BasketProduct[]>('baskets', []);
const [showMessage, setShowMessage] = useState(false);
const removeBaskets = (itemId: string) => {
const updatedBaskets = baskets.filter(basket => basket.itemId !== itemId);

setBaskets(updatedBaskets);
};

const handleIncrease = (itemId: string) => {
setBaskets(prev => {
return prev.map(item =>
item.itemId === itemId
? { ...item, quantity: item.quantity + 1 }
: item,
);
});
};

const handleDecrease = (itemId: string) => {
setBaskets(prev =>
prev.map(item =>
item.itemId === itemId
? { ...item, quantity: Math.max(1, item.quantity - 1) }
: item,
),
);
};

const handleCheckout = () => {
setBaskets([]);
setShowMessage(true);

setTimeout(() => setShowMessage(false), 3000);
};

return (
<HashRouter>
<AppContext.Provider
value={{
favorites,
setFavorites,
baskets,
setBaskets,
removeBaskets,
handleIncrease,
handleDecrease,
handleCheckout,
showMessage,
}}
>
<Header />
<div className="App">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/phones" element={<Phones />} />
<Route path="/tablets" element={<Tablets />} />
<Route path="/accessories" element={<Accessories />} />
<Route path="/heart" element={<Heart />} />
<Route path="/basket" element={<Basket />} />
<Route path="/:category/:id" element={<ProductPage />} />

<Route path="/burgermenu" element={<BurgerMenu />} />
<Route path="/terms" element={<TermsPage />} />
</Routes>
</div>
<Footer />
</AppContext.Provider>
</HashRouter>
);
};
17 changes: 17 additions & 0 deletions src/AppContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createContext } from 'react';
import { BasketProduct } from './types/BasketProduct';
import { FavoriteProduct } from './types/FavoriteProduct';

type AppContextType = {
showMessage: boolean;
favorites: FavoriteProduct[];
setFavorites: React.Dispatch<React.SetStateAction<FavoriteProduct[]>>;
baskets: BasketProduct[];
setBaskets: React.Dispatch<React.SetStateAction<BasketProduct[]>>;
removeBaskets: (itemId: string) => void;
handleIncrease: (itemId: string) => void;
handleDecrease: (itemId: string) => void;
handleCheckout: () => void;
};

export const AppContext = createContext<AppContextType | null>(null);
101 changes: 101 additions & 0 deletions src/Pages/BurgerMenu/BurgerFooter/BurgerFooter.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
.burger-footer {
display: flex;
flex-direction: row;
justify-content: center;

width: 100%;
margin-top: auto;
padding: 0;
border-top: 1px solid #e2e6e9;
}

.burger-footer--heart {
border-right: 1px solid #e2e6e9;
}

.burger-footer--basket,
.burger-footer--heart {
position: relative;

display: flex;
align-items: center;
justify-content: center;

width: 50%;
height: 64px;
}

.burger-footer--heart::after,
.burger-footer--basket::after {
position: absolute;
bottom: 0;
left: 0;

width: 100%;
height: 2px;

opacity: 0;
background-color: black;

transition: opacity 0.2s ease;
}

.burger-footer--heart:hover::after,
.burger-footer--basket:hover::after {
opacity: 1;
}

.burger-footer__icon--heart {
display: flex;
align-items: center;
justify-content: center;

width: 32px;
height: 32px;
border-radius: 0;

background-color: white;
background-image: url('../../../../public/img/icons/icon--heart.svg');
background-repeat: no-repeat;
background-position: center;
background-size: 16px 16px;
}

.burger-footer__icon--basket {
display: flex;
align-items: center;
justify-content: center;

width: 32px;
height: 32px;
border-radius: 0;

background-color: white;
background-image: url('../../../../public/img/icons/icon--basket.svg');
background-repeat: no-repeat;
background-position: center;
background-size: 16px 16px;
}

.burger-footer__icon--badge {
position: absolute;
top: 24%;
right: 40%;

width: auto;
height: 12px;
padding: 2px 6px;
border-radius: 50%;

font-size: 8px;
font-weight: bold;
line-height: 13px;
color: white;
text-align: center;

background-color: #f08080;

@media (min-width: 640px) {
right: 46%;
}
}
34 changes: 34 additions & 0 deletions src/Pages/BurgerMenu/BurgerFooter/BurgerFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { BasketProduct } from '../../../types/BasketProduct';
import { FavoriteProduct } from '../../../types/FavoriteProduct';
import './BurgerFooter.scss';
import { Link } from 'react-router-dom';

type BurgerFooterProps = {
favorites: FavoriteProduct[];
baskets: BasketProduct[];
};

const BurgerFooter = ({ favorites, baskets }: BurgerFooterProps) => {
return (
<footer className="burger-footer">
<div className="burger-footer--heart">
<Link to="/heart" className="burger-footer__icon--heart">
{favorites.length > 0 && (
<span className="burger-footer__icon--badge">
{favorites.length}
</span>
)}
</Link>
</div>
<div className="burger-footer--basket">
<Link to="/basket" className="burger-footer__icon--basket">
{baskets.length > 0 && (
<span className="burger-footer__icon--badge">{baskets.length}</span>
)}
</Link>
</div>
</footer>
);
};

export default BurgerFooter;
Loading
Loading