first commit
This commit is contained in:
parent
03df4465bb
commit
2d64c69ac5
10
package-lock.json
generated
10
package-lock.json
generated
@ -14,6 +14,7 @@
|
|||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
}
|
}
|
||||||
@ -13902,6 +13903,15 @@
|
|||||||
"integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==",
|
"integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
|
120
src/App.css
120
src/App.css
@ -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 {
|
.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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: 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;
|
color: white;
|
||||||
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-link {
|
.product-info {
|
||||||
color: #61dafb;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
.checked {
|
||||||
from {
|
text-decoration: line-through;
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
48
src/App.js
48
src/App.js
@ -1,25 +1,37 @@
|
|||||||
import logo from './logo.svg';
|
import { useState } from "react"
|
||||||
import './App.css';
|
import Header from './components/Header'
|
||||||
|
import Products from './components/Products'
|
||||||
|
import AddProduct from './components/AddProduct'
|
||||||
|
import './App.css'
|
||||||
|
|
||||||
function App() {
|
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 (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
<Header title="Lista zakupów" />
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
<AddProduct onAdd={addProduct} />
|
||||||
<p>
|
{products.length > 0 ? (
|
||||||
Edit <code>src/App.js</code> and save to reload.
|
<Products products={products} onDelete={deleteProduct} />
|
||||||
</p>
|
) : (
|
||||||
<a
|
<p>Brak produktów</p>
|
||||||
className="App-link"
|
)}
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Learn React
|
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App
|
51
src/components/AddProduct.js
Normal file
51
src/components/AddProduct.js
Normal 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
9
src/components/Header.js
Normal 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
32
src/components/Product.js
Normal 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
|
13
src/components/Products.js
Normal file
13
src/components/Products.js
Normal 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
|
Loading…
Reference in New Issue
Block a user