first commit

This commit is contained in:
Liliia Hurko 2025-10-10 13:49:48 +02:00
parent 03df4465bb
commit 2d64c69ac5
8 changed files with 239 additions and 45 deletions

10
package-lock.json generated
View File

@ -14,6 +14,7 @@
"@testing-library/user-event": "^13.5.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-icons": "^5.5.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
@ -13902,6 +13903,15 @@
"integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==",
"license": "MIT"
},
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
"license": "MIT",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",

View File

@ -9,6 +9,7 @@
"@testing-library/user-event": "^13.5.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-icons": "^5.5.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},

View File

@ -1,38 +1,104 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400&display=swap');
body {
display: flex;
justify-content: center;
background-color: #2f4f4f;
font-family: 'Poppins', sans-serif;
}
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
background-color: white;
width: 350px;
padding: 20px 0;
margin: 20px 0;
border-radius: 6px;
}
.products {
width: 300px;
}
.product {
display: flex;
align-items: center;
background-color: #CEB5A7;
padding: 0 15px;
margin-bottom: 10px;
color: white;
border-radius: 6px;
}
.App-link {
color: #61dafb;
.product-info {
display: flex;
justify-content: space-between;
flex: 0.7;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
.checked {
text-decoration: line-through;
}
.product-info .input-name {
display: flex;
}
.product-info .input-name p {
margin-left: 10px;
}
.product-icons {
display: flex;
justify-content: flex-end;
align-self: center;
flex: 0.3;
}
.category {
margin-right: 10px;
font-size: 1.2em;
}
.add-list {
display: flex;
flex-direction: column;
width: 300px;
margin-bottom: 20px;
}
.input-div {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
max-height: 30px;
}
.input-div label {
margin-right: 10px;
}
.input-div select,
input {
padding: 5px;
background-color: white;
border: 1px solid gray;
border-radius: 6px;
}
.btn {
color: white;
background-color: #A17C6B;
border: transparent;
border-radius: 3px;
padding: 5px 0;
border-radius: 6px;
}
input[type=number] {
-moz-appearance: textfield;
}

View File

@ -1,25 +1,37 @@
import logo from './logo.svg';
import './App.css';
import { useState } from "react"
import Header from './components/Header'
import Products from './components/Products'
import AddProduct from './components/AddProduct'
import './App.css'
function App() {
const [products, setProducts] = useState([
{ id: 1, name: "mleko", category: "diary", quantity: 1 },
{ id: 2, name: "chleb", category: "bread", quantity: 1 },
{ id: 3, name: "jabłka", category: "fruit&vagetables", quantity: 2 }
])
const deleteProduct = (id) => {
setProducts(products.filter((product) => product.id !== id))
}
const addProduct = (product) => {
const id = products.length + 1
const newProduct = { id, ...product }
setProducts([...products, newProduct])
}
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<Header title="Lista zakupów" />
<AddProduct onAdd={addProduct} />
{products.length > 0 ? (
<Products products={products} onDelete={deleteProduct} />
) : (
<p>Brak produktów</p>
)}
</div>
);
)
}
export default App;
export default App

View File

@ -0,0 +1,51 @@
import { useState } from "react"
const AddProduct = ({ onAdd }) => {
const [name, setName] = useState('')
const [category, setCategory] = useState('fruit&vagetables')
const [quantity, setQuantity] = useState(1)
const add = (e) => {
e.preventDefault()
onAdd({ name, category, quantity })
setName('')
setCategory('fruit&vagetables')
setQuantity(1)
}
return (
<form className='add-list' onSubmit={add}>
<div className='input-div'>
<label>Produkt</label>
<input
type='text'
placeholder='Nazwa produktu'
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div className='input-div'>
<label>Kategoria</label>
<select value={category} onChange={(e) => setCategory(e.target.value)}>
<option value='fruit&vagetables'>Owoce i warzywa</option>
<option value='diary'>Nabiał</option>
<option value='bread'>Pieczywo</option>
</select>
</div>
<div className='input-div'>
<label>Ilość</label>
<input
type='number'
placeholder='0'
value={quantity}
min="0"
onChange={(e) => setQuantity(e.target.value)}
/>
</div>
<input type='submit' className='btn' value='Dodaj' />
</form>
)
}
export default AddProduct

9
src/components/Header.js Normal file
View File

@ -0,0 +1,9 @@
const Header = ({ title }) => {
return (
<div className='header'>
<h2>{title}</h2>
</div>
)
}
export default Header

32
src/components/Product.js Normal file
View File

@ -0,0 +1,32 @@
import { useState } from "react"
import { FiX } from "react-icons/fi"
import { GiMilkCarton, GiSlicedBread, GiShinyApple } from 'react-icons/gi'
const Product = ({ product, onDelete }) => {
const [isChecked, setIsChecked] = useState(false)
return (
<div className='product'>
<div className='product-info'>
<div className='input-name'>
<input
type='checkbox'
value={isChecked}
onChange={(e) => setIsChecked(!isChecked)}
required
/>
<p className={isChecked ? 'checked' : ''}>{product.name}</p>
</div>
<p>{product.quantity}</p>
</div>
<div className='product-icons'>
{product.category === "diary" && <GiMilkCarton className='category'></GiMilkCarton>}
{product.category === "bread" && <GiSlicedBread className='category'></GiSlicedBread>}
{product.category === "fruit&vagetables" && <GiShinyApple className='category'></GiShinyApple>}
<FiX onClick={() => onDelete(product.id)}></FiX>
</div>
</div>
)
}
export default Product

View File

@ -0,0 +1,13 @@
import Product from './Product'
const Products = ({ products, onDelete }) => {
return (
<div className='products'>
{products.map((product) => (
<Product key={product.id} product={product} onDelete={onDelete} />
))}
</div>
)
}
export default Products