Compare commits
2 Commits
fe76deb2d9
...
03bf26a8a1
Author | SHA1 | Date | |
---|---|---|---|
|
03bf26a8a1 | ||
|
d656e183b6 |
@ -3,7 +3,11 @@ import React, { useState, useEffect } from 'react';
|
||||
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
|
||||
import PanelAdministratora from './components/PanelAdministratora';
|
||||
import ZarzadzanieProduktami from './components/ZarzadzanieProduktami';
|
||||
import Transakcje from './components/Transakcje';
|
||||
import DodawanieProduktu from './components/DodawanieProduktów';
|
||||
import EdycjaProduktu from './components/EdycjaProduktu';
|
||||
import ZarzadzanieTransakcjami from './components/ZarzadzanieTransakcjami';
|
||||
import DodawanieTransakcji from './components/DodawanieTransakcji';
|
||||
import EdycjaTransakcji from './components/EdycjaTransakcji';
|
||||
import NavBar from './components/NavBar';
|
||||
import Sidebar from './components/Sidebar';
|
||||
import Wydatki from './components/Wydatki';
|
||||
@ -43,22 +47,18 @@ const App = () => {
|
||||
)}
|
||||
<div className="w-3/4">
|
||||
<Routes>
|
||||
{/* Przekierowanie na stronę logowania, jeśli token jest pusty */}
|
||||
<Route path="/" element={token ? <Navigate to="/transakcje" /> : <Navigate to="/login" />} />
|
||||
|
||||
{/* Strona logowania */}
|
||||
<Route path="/login" element={token ? <Navigate to="/transakcje" /> : <Login setToken={setToken} />} />
|
||||
|
||||
{/* Chronione ścieżki */}
|
||||
<Route path="/transakcje" element={token ? <Transakcje /> : <Navigate to="/login" />} />
|
||||
<Route path="/transakcje" element={token ? <ZarzadzanieTransakcjami /> : <Navigate to="/login" />} />
|
||||
<Route path="/transakcje/dodaj" element={token ? <DodawanieTransakcji /> : <Navigate to="/login" />} />
|
||||
<Route path="/transakcje/edytuj/:id" element={token ? <EdycjaTransakcji /> : <Navigate to="/login" />} />
|
||||
<Route path="/panel" element={token ? <PanelAdministratora /> : <Navigate to="/login" />} />
|
||||
<Route path="/produkty" element={token ? <ZarzadzanieProduktami /> : <Navigate to="/login" />} />
|
||||
<Route path="/produkty/dodaj" element={token ? <DodawanieProduktu /> : <Navigate to="/login" />} />
|
||||
<Route path="/produkty/edytuj/:id" element={token ? <EdycjaProduktu /> : <Navigate to="/login" />} />
|
||||
<Route path="/wydatki" element={token ? <Wydatki /> : <Navigate to="/login" />} />
|
||||
<Route path="/raporty" element={token ? <Raporty /> : <Navigate to="/login" />} />
|
||||
<Route path="/harmonogram" element={token ? <Harmonogram /> : <Navigate to="/login" />} />
|
||||
|
||||
{/* Przekierowanie dla nieznanych ścieżek */}
|
||||
<Route path="*" element={<Navigate to="/login" />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
|
130
firm/src/components/DodawanieProduktów.js
Normal file
130
firm/src/components/DodawanieProduktów.js
Normal file
@ -0,0 +1,130 @@
|
||||
import React, { useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const DodawanieProduktu = () => {
|
||||
const [error, setError] = useState(null);
|
||||
const [newProduct, setNewProduct] = useState({
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
type: '1',
|
||||
availability: '',
|
||||
});
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setNewProduct({ ...newProduct, [name]: value });
|
||||
};
|
||||
|
||||
const handleAddProduct = async () => {
|
||||
const { name, description, price, type, availability } = newProduct;
|
||||
|
||||
if (!name || !description || !price || type === '') {
|
||||
setError('Proszę uzupełnić wszystkie wymagane pola.');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
name,
|
||||
description,
|
||||
price,
|
||||
type: parseInt(type, 10),
|
||||
...(type === '1' && { availability: availability || 0 }),
|
||||
};
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
};
|
||||
|
||||
await axios.post('https://localhost:7039/api/Products', payload, config);
|
||||
|
||||
setNewProduct({
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
type: '1',
|
||||
availability: '',
|
||||
});
|
||||
setError(null);
|
||||
navigate('/produkty');
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas dodawania produktu:', error);
|
||||
setError('Wystąpił błąd podczas dodawania produktu. Spróbuj ponownie.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-8 bg-gray-100 rounded-lg shadow-md">
|
||||
<h2 className="text-2xl font-bold mb-4">Dodaj nowy produkt lub usługę</h2>
|
||||
{error && <p className="text-red-500 mb-4">{error}</p>}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={newProduct.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Nazwa produktu lub usługi"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={newProduct.description}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Opis"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
name="price"
|
||||
value={newProduct.price}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Cena"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<select
|
||||
name="type"
|
||||
value={newProduct.type}
|
||||
onChange={handleInputChange}
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
>
|
||||
<option value="1">Produkt</option>
|
||||
<option value="0">Usługa</option>
|
||||
</select>
|
||||
{newProduct.type === '1' && (
|
||||
<input
|
||||
type="number"
|
||||
name="availability"
|
||||
value={newProduct.availability}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Dostępność (ilość)"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<button
|
||||
onClick={handleAddProduct}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Dodaj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DodawanieProduktu;
|
260
firm/src/components/DodawanieTransakcji.js
Normal file
260
firm/src/components/DodawanieTransakcji.js
Normal file
@ -0,0 +1,260 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Select from 'react-select';
|
||||
|
||||
const DodawanieTransakcji = () => {
|
||||
const [error, setError] = useState(null);
|
||||
const [newTransaction, setNewTransaction] = useState({
|
||||
id: 2,
|
||||
date: '',
|
||||
employeeId: '',
|
||||
paymentType: '',
|
||||
discount: '',
|
||||
description: '',
|
||||
transactionProducts: [
|
||||
{
|
||||
id: 2,
|
||||
transactionId: 0,
|
||||
productID: 0,
|
||||
productName: '',
|
||||
quantity: ''
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
const [products, setProducts] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await axios.get('https://localhost:7039/api/Products', config);
|
||||
const productOptions = response.data.map(product => ({
|
||||
value: product.id,
|
||||
label: product.name,
|
||||
}));
|
||||
setProducts(productOptions);
|
||||
} catch (error) {
|
||||
setError('Wystąpił błąd podczas ładowania produktów.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProducts();
|
||||
}, []);
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setNewTransaction({ ...newTransaction, [name]: value });
|
||||
};
|
||||
|
||||
const handleProductChange = (index, selectedOption) => {
|
||||
const updatedTransactionProducts = [...newTransaction.transactionProducts];
|
||||
updatedTransactionProducts[index].productID = selectedOption.value;
|
||||
updatedTransactionProducts[index].productName = selectedOption.label;
|
||||
setNewTransaction({
|
||||
...newTransaction,
|
||||
transactionProducts: updatedTransactionProducts,
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddProduct = () => {
|
||||
setNewTransaction({
|
||||
...newTransaction,
|
||||
transactionProducts: [
|
||||
...newTransaction.transactionProducts,
|
||||
{
|
||||
id: 2,
|
||||
transactionId: 0,
|
||||
productID: 0,
|
||||
productName: '',
|
||||
quantity: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveProduct = (index) => {
|
||||
const updatedTransactionProducts = [...newTransaction.transactionProducts];
|
||||
updatedTransactionProducts.splice(index, 1);
|
||||
setNewTransaction({
|
||||
...newTransaction,
|
||||
transactionProducts: updatedTransactionProducts,
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddTransaction = async () => {
|
||||
if (!newTransaction.date || !newTransaction.employeeId || newTransaction.transactionProducts.some(product => !product.productName || !product.quantity)) {
|
||||
setError('Proszę uzupełnić wszystkie pola.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('Nowa transakcja:', newTransaction);
|
||||
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
};
|
||||
|
||||
await axios.post('https://localhost:7039/api/Transaction', newTransaction, config);
|
||||
|
||||
setNewTransaction({
|
||||
id: 0,
|
||||
date: '',
|
||||
employeeId: '',
|
||||
transactionProducts: [
|
||||
{
|
||||
id: 0,
|
||||
transactionId: 0,
|
||||
productID: 0,
|
||||
productName: '',
|
||||
quantity: ''
|
||||
}
|
||||
],
|
||||
paymentType: '',
|
||||
discount: '',
|
||||
description: '',
|
||||
totalPrice: 0,
|
||||
});
|
||||
navigate('/transakcje');
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas dodawania transakcji:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white p-8 rounded-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Dodaj nową transakcję</h2>
|
||||
|
||||
{error && <p className="text-red-500 mb-4">{error}</p>}
|
||||
|
||||
<input
|
||||
type="datetime-local"
|
||||
name="date"
|
||||
value={newTransaction.date}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Data"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
name="employeeId"
|
||||
value={newTransaction.employeeId}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Nr. Pracownika"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="text-center">Ładowanie produktów...</div>
|
||||
) : (
|
||||
<>
|
||||
{newTransaction.transactionProducts.map((product, index) => (
|
||||
<div key={index} className="mb-4">
|
||||
<Select
|
||||
name={`productName-${index}`}
|
||||
value={products.find(option => option.value === product.productID)}
|
||||
onChange={(selectedOption) => handleProductChange(index, selectedOption)}
|
||||
options={products}
|
||||
className="block w-full mb-2"
|
||||
placeholder="Wybierz produkt..."
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
name={`quantity-${index}`}
|
||||
value={product.quantity}
|
||||
onChange={(e) => {
|
||||
const updatedTransactionProducts = [...newTransaction.transactionProducts];
|
||||
updatedTransactionProducts[index].quantity = e.target.value;
|
||||
setNewTransaction({ ...newTransaction, transactionProducts: updatedTransactionProducts });
|
||||
}}
|
||||
placeholder="Ilość"
|
||||
className="block w-full mb-2 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button
|
||||
onClick={() => handleRemoveProduct(index)}
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Usuń
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={handleAddProduct}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded"
|
||||
>
|
||||
Dodaj produkt
|
||||
</button>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="paymentType"
|
||||
value={newTransaction.paymentType}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Sposób płatności"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
name="discount"
|
||||
value={newTransaction.discount}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Rabat"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={newTransaction.description}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Opis"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={handleAddTransaction}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded"
|
||||
>
|
||||
Dodaj transakcję
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DodawanieTransakcji;
|
157
firm/src/components/EdycjaProduktu.js
Normal file
157
firm/src/components/EdycjaProduktu.js
Normal file
@ -0,0 +1,157 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
|
||||
const EdycjaProduktu = () => {
|
||||
const { id } = useParams();
|
||||
const [product, setProduct] = useState({
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
type: '1',
|
||||
availability: '',
|
||||
});
|
||||
const [error, setError] = useState(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchProduct = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await axios.get(`https://localhost:7039/api/Products/${id}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
setProduct(response.data);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania produktu:', error);
|
||||
setError('Wystąpił błąd podczas pobierania danych produktu.');
|
||||
}
|
||||
};
|
||||
|
||||
fetchProduct();
|
||||
}, [id]);
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setProduct({ ...product, [name]: value });
|
||||
};
|
||||
|
||||
const handleSaveChanges = async () => {
|
||||
const { name, description, price, type, availability } = product;
|
||||
|
||||
if (!name || !description || !price || type === '') {
|
||||
setError('Proszę uzupełnić wszystkie wymagane pola.');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
price,
|
||||
type: parseInt(type, 10),
|
||||
...(type === '1' && { availability: availability || 0 }),
|
||||
};
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await axios.put(`https://localhost:7039/api/Products/${id}`, payload, config);
|
||||
|
||||
console.log('Produkt zapisany:', response.data);
|
||||
|
||||
setError(null);
|
||||
navigate('/produkty');
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas zapisywania zmian:', error);
|
||||
|
||||
if (error.response && error.response.status === 400) {
|
||||
setError('ID produktu nie zgadza się.');
|
||||
} else {
|
||||
setError('Wystąpił błąd podczas zapisywania zmian. Spróbuj ponownie.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="p-8 bg-gray-100 rounded-lg shadow-md">
|
||||
<h2 className="text-2xl font-bold mb-4">Edycja produktu</h2>
|
||||
{error && <p className="text-red-500 mb-4">{error}</p>}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={product.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Nazwa produktu lub usługi"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={product.description}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Opis"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
name="price"
|
||||
value={product.price}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Cena"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<select
|
||||
name="type"
|
||||
value={product.type}
|
||||
onChange={handleInputChange}
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
>
|
||||
<option value="1">Produkt</option>
|
||||
<option value="0">Usługa</option>
|
||||
</select>
|
||||
{product.type === '1' && (
|
||||
<input
|
||||
type="number"
|
||||
name="availability"
|
||||
value={product.availability}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Dostępność (ilość)"
|
||||
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<button
|
||||
onClick={handleSaveChanges}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Zapisz zmiany
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EdycjaProduktu;
|
243
firm/src/components/EdycjaTransakcji.js
Normal file
243
firm/src/components/EdycjaTransakcji.js
Normal file
@ -0,0 +1,243 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import Select from 'react-select';
|
||||
|
||||
const EdycjaTransakcji = () => {
|
||||
const { id } = useParams();
|
||||
const [transaction, setTransaction] = useState({
|
||||
date: '',
|
||||
employeeId: '',
|
||||
paymentType: '',
|
||||
discount: '',
|
||||
description: '',
|
||||
transactionProducts: [{ productID: '', productName: '', quantity: '' }],
|
||||
});
|
||||
const [products, setProducts] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const getToken = () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTransaction = async () => {
|
||||
try {
|
||||
const token = getToken();
|
||||
if (!token) return;
|
||||
|
||||
const transactionResponse = await axios.get(`https://localhost:7039/api/transaction/${id}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
console.log('Dane transakcji:', transactionResponse.data);
|
||||
|
||||
const updatedTransaction = {
|
||||
...transactionResponse.data,
|
||||
transactionProducts: transactionResponse.data.transactionProducts.map((transactionProduct) => ({
|
||||
productID: transactionProduct.product.id,
|
||||
productName: transactionProduct.product.name,
|
||||
quantity: transactionProduct.quantity,
|
||||
})),
|
||||
};
|
||||
setTransaction(updatedTransaction);
|
||||
|
||||
const productResponse = await axios.get('https://localhost:7039/api/Products', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
console.log('Produkty:', productResponse.data);
|
||||
|
||||
const productOptions = productResponse.data.map((product) => ({
|
||||
value: product.id,
|
||||
label: product.name,
|
||||
}));
|
||||
setProducts(productOptions);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania transakcji lub produktów:', error);
|
||||
setError('Wystąpił błąd podczas ładowania danych.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTransaction();
|
||||
}, [id]);
|
||||
|
||||
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setTransaction({ ...transaction, [name]: value });
|
||||
};
|
||||
|
||||
const handleProductChange = (index, selectedOption) => {
|
||||
const updatedTransactionProducts = [...transaction.transactionProducts];
|
||||
updatedTransactionProducts[index].productID = selectedOption.value;
|
||||
updatedTransactionProducts[index].productName = selectedOption.label;
|
||||
setTransaction({
|
||||
...transaction,
|
||||
transactionProducts: updatedTransactionProducts,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const handleAddProduct = () => {
|
||||
setTransaction({
|
||||
...transaction,
|
||||
transactionProducts: [
|
||||
...transaction.transactionProducts,
|
||||
{ productID: 0, productName: '', quantity: '' },
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveProduct = (index) => {
|
||||
const updatedTransactionProducts = [...transaction.transactionProducts];
|
||||
updatedTransactionProducts.splice(index, 1);
|
||||
setTransaction({
|
||||
...transaction,
|
||||
transactionProducts: updatedTransactionProducts,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSaveChanges = async () => {
|
||||
if (!transaction.date || !transaction.employeeId || transaction.transactionProducts.some(product => !product.productName || !product.quantity)) {
|
||||
setError('Proszę uzupełnić wszystkie pola.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
setError('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await axios.put(`https://localhost:7039/api/transaction/${id}`, transaction, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
console.log('Zaktualizowana transakcja:', response.data);
|
||||
navigate('/transakcje');
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas zapisywania zmian:', error);
|
||||
setError('Wystąpił błąd podczas zapisywania zmian.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white p-8 rounded-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Edycja Transakcji</h2>
|
||||
|
||||
{error && <p className="text-red-500 mb-4">{error}</p>}
|
||||
|
||||
<input
|
||||
type="datetime-local"
|
||||
name="date"
|
||||
value={transaction.date}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Data"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
name="employeeId"
|
||||
value={transaction.employeeId}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Nr. Pracownika"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="text-center">Ładowanie produktów...</div>
|
||||
) : (
|
||||
<>
|
||||
{transaction.transactionProducts.map((product, index) => (
|
||||
<div key={index} className="mb-4">
|
||||
<Select
|
||||
name={`productName-${index}`}
|
||||
value={products.find(option => option.value === product.productID) || null}
|
||||
onChange={(selectedOption) => handleProductChange(index, selectedOption)}
|
||||
options={products}
|
||||
className="block w-full mb-2"
|
||||
placeholder="Wybierz produkt..."
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
name={`quantity-${index}`}
|
||||
value={product.quantity}
|
||||
onChange={(e) => {
|
||||
const updatedTransactionProducts = [...transaction.transactionProducts];
|
||||
updatedTransactionProducts[index].quantity = e.target.value;
|
||||
setTransaction({ ...transaction, transactionProducts: updatedTransactionProducts });
|
||||
}}
|
||||
placeholder="Ilość"
|
||||
className="block w-full mb-2 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button
|
||||
onClick={() => handleRemoveProduct(index)}
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Usuń
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={handleAddProduct}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded"
|
||||
>
|
||||
Dodaj produkt
|
||||
</button>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="paymentType"
|
||||
value={transaction.paymentType}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Sposób płatności"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
name="discount"
|
||||
value={transaction.discount}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Rabat"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={transaction.description}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Opis"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={handleSaveChanges}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded"
|
||||
>
|
||||
Zapisz zmiany
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EdycjaTransakcji;
|
135
firm/src/components/ListaProduktów.js
Normal file
135
firm/src/components/ListaProduktów.js
Normal file
@ -0,0 +1,135 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import editIcon from '../icons/edit.png';
|
||||
import koszIcon from '../icons/kosz.png';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const ListaProduktow = ({ onAdd }) => {
|
||||
const [products, setProducts] = useState([]);
|
||||
const [deleteProductId, setDeleteProductId] = useState(null);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const fetchProducts = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
try {
|
||||
const response = await axios.get('https://localhost:7039/api/products', {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
setProducts(response.data);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania produktów:', error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchProducts();
|
||||
}, []);
|
||||
|
||||
const handleDeleteProduct = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
alert('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!deleteProductId) {
|
||||
console.error('Brak ID produktu do usunięcia!');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await axios.delete(`https://localhost:7039/api/Products/${deleteProductId}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
fetchProducts();
|
||||
setShowModal(false);
|
||||
setDeleteProductId(null);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas usuwania produktu:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditProduct = (productId) => {
|
||||
navigate(`/produkty/edytuj/${productId}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-5xl">Katalog Produktów</h1>
|
||||
<button onClick={onAdd} className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
|
||||
Dodaj Produkt
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<table className="w-full border border-gray-300">
|
||||
<thead className="bg-gray-200">
|
||||
<tr>
|
||||
<th className="p-2 border">ID</th>
|
||||
<th className="p-2 border">Produkt</th>
|
||||
<th className="p-2 border">Opis</th>
|
||||
<th className="p-2 border">Cena</th>
|
||||
<th className="p-2 border">Dostępność</th>
|
||||
<th className="p-2 border"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{products.map((product) => (
|
||||
<tr key={product.id}>
|
||||
<td className="p-2 border">{product.id}</td>
|
||||
<td className="p-2 border">{product.name}</td>
|
||||
<td className="p-2 border">{product.description}</td>
|
||||
<td className="p-2 border">{parseFloat(product.price).toFixed(2)}</td>
|
||||
<td className="p-2 border">{product.availability}</td>
|
||||
<td className="p-2 border">
|
||||
<button
|
||||
onClick={() => handleEditProduct(product.id)}
|
||||
className="mr-2 bg-blue-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
<img src={editIcon} alt="Edytuj" className="inline w-5 mr-2" />
|
||||
Edytuj
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setDeleteProductId(product.id);
|
||||
setShowModal(true);
|
||||
}}
|
||||
className="bg-red-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
<img src={koszIcon} alt="Usuń" className="inline w-5 mr-2" />
|
||||
Usuń
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{showModal && (
|
||||
<div className="fixed inset-0 bg-gray-500 bg-opacity-50 flex justify-center items-center z-50">
|
||||
<div className="bg-white p-6 rounded-md shadow-lg w-96">
|
||||
<h2 className="text-lg font-bold mb-4">Czy na pewno chcesz usunąć ten produkt?</h2>
|
||||
<div className="flex justify-between">
|
||||
<button
|
||||
onClick={handleDeleteProduct}
|
||||
className="bg-red-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
Tak
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowModal(false)}
|
||||
className="bg-gray-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
Anuluj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListaProduktow;
|
177
firm/src/components/ListaTransakcji.js
Normal file
177
firm/src/components/ListaTransakcji.js
Normal file
@ -0,0 +1,177 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import editIcon from '../icons/edit.png';
|
||||
import koszIcon from '../icons/kosz.png';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const ListaTransakcji = ({ onAdd}) => {
|
||||
const [transactions, setTransactions] = useState([]);
|
||||
const [deleteTransactionId, setDeleteTransactionId] = useState(null);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const fetchTransactions = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
console.error('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get('https://localhost:7039/api/Transaction', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
setTransactions(response.data);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania transakcji:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchProducts = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
console.error('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get('https://localhost:7039/api/Products', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
response.data.map(product => ({ value: product.id, label: product.name }));
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania produktów:', error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTransactions();
|
||||
fetchProducts();
|
||||
}, []);
|
||||
|
||||
const formatDate = (date) => {
|
||||
const newDate = new Date(date);
|
||||
return newDate.toLocaleDateString();
|
||||
};
|
||||
|
||||
const formatPrice = (price) => {
|
||||
return price.toFixed(2).replace('.', ',');
|
||||
};
|
||||
|
||||
const handleDeleteTransaction = async () => {
|
||||
try {
|
||||
await axios.delete(`https://localhost:7039/api/transaction/${deleteTransactionId}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
||||
},
|
||||
});
|
||||
setTransactions(transactions.filter(transaction => transaction.id !== deleteTransactionId));
|
||||
setShowModal(false);
|
||||
setDeleteTransactionId(null);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas usuwania transakcji:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const openDeleteConfirmation = (transactionId) => {
|
||||
setDeleteTransactionId(transactionId);
|
||||
setShowModal(true);
|
||||
};
|
||||
|
||||
const handleEditTransaction = (transactionId) => {
|
||||
navigate(`/transakcje/edytuj/${transactionId}`);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-5xl">Lista Transakcji</h1>
|
||||
<button onClick={onAdd} className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
|
||||
Dodaj Transakcję
|
||||
</button>
|
||||
</div>
|
||||
<div className="w-8/10 mx-auto mt-2">
|
||||
<div className="h-screen overflow-y-auto">
|
||||
<table className="w-full border-collapse border border-gray-300">
|
||||
<thead className="bg-gray-200">
|
||||
<tr>
|
||||
<th className="border border-gray-300 p-2">ID</th>
|
||||
<th className="border border-gray-300 p-2">Data</th>
|
||||
<th className="border border-gray-300 p-2">Produkt</th>
|
||||
<th className="border border-gray-300 p-2">Ilość</th>
|
||||
<th className="border border-gray-300 p-2">Kwota</th>
|
||||
<th className="border border-gray-300 p-2">Sposób płatności</th>
|
||||
<th className="border border-gray-300 p-2">Nr. Pracownika</th>
|
||||
<th className="border border-gray-300 p-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{transactions.map(transaction => (
|
||||
<tr key={transaction.id}>
|
||||
<td className="border border-gray-300 p-2">{transaction.id}</td>
|
||||
<td className="border border-gray-300 p-2">{formatDate(transaction.date)}</td>
|
||||
<td className="border border-gray-300 p-2">
|
||||
{transaction.transactionProducts.map(product => (
|
||||
<div key={product.id}>{product.product.name}</div>
|
||||
))}
|
||||
</td>
|
||||
<td className="border border-gray-300 p-2">
|
||||
{transaction.transactionProducts.map(product => (
|
||||
<div key={product.id}>{product.quantity}</div>
|
||||
))}
|
||||
</td>
|
||||
<td className="border border-gray-300 p-2">{formatPrice(transaction.totalPrice)}</td>
|
||||
<td className="border border-gray-300 p-2">{transaction.paymentType}</td>
|
||||
<td className="border border-gray-300 p-2">{transaction.employeeId}</td>
|
||||
<td className="p-2 border">
|
||||
<button
|
||||
onClick={() => handleEditTransaction(transaction.id)}
|
||||
className="mr-2 bg-blue-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
<img src={editIcon} alt="Edytuj" className="inline w-5 mr-2" />
|
||||
Edytuj
|
||||
</button>
|
||||
<button
|
||||
onClick={() => openDeleteConfirmation(transaction.id)}
|
||||
className="bg-red-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
<img src={koszIcon} alt="Usuń" className="inline w-5 mr-2" />
|
||||
Usuń
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showModal && (
|
||||
<div className="fixed inset-0 bg-gray-500 bg-opacity-50 flex justify-center items-center z-50">
|
||||
<div className="bg-white p-6 rounded-md shadow-lg w-96">
|
||||
<h2 className="text-lg font-bold mb-4">Czy na pewno chcesz usunąć tę transakcję?</h2>
|
||||
<div className="flex justify-between">
|
||||
<button
|
||||
onClick={handleDeleteTransaction}
|
||||
className="bg-red-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
Tak
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowModal(false)}
|
||||
className="bg-gray-500 text-white py-2 px-4 rounded"
|
||||
>
|
||||
Anuluj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListaTransakcji;
|
@ -1,488 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import Select from 'react-select';
|
||||
import editIcon from "../icons/edit.png";
|
||||
import koszIcon from "../icons/kosz.png";
|
||||
import plusIcon from "../icons/plus.png";
|
||||
import ConfirmationModal from './ConfirmationModal';
|
||||
|
||||
const Transakcje = () => {
|
||||
const [transactions, setTransactions] = useState([]);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
const [editTransaction, setEditTransaction] = useState(null);
|
||||
const [error, setError] = useState(null);
|
||||
const [products, setProducts] = useState([]);
|
||||
const [deleteTransactionId, setDeleteTransactionId] = useState(null);
|
||||
const [newTransaction, setNewTransaction] = useState({
|
||||
id: 2,
|
||||
date: "",
|
||||
employeeId: "",
|
||||
transactionProducts: [
|
||||
{
|
||||
id: 0,
|
||||
transactionId: 2,
|
||||
productID: 0,
|
||||
productName: "",
|
||||
quantity: ""
|
||||
}
|
||||
],
|
||||
paymentType: "",
|
||||
discount: "",
|
||||
description: "",
|
||||
totalPrice: 0
|
||||
});
|
||||
|
||||
const fetchTransactions = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
console.error('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get('https://localhost:7039/api/Transaction', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
setTransactions(response.data);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas dodawania transakcji:', error);
|
||||
}
|
||||
};
|
||||
const fetchProducts = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
console.error('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get('https://localhost:7039/api/Products', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
setProducts(response.data.map(product => ({ value: product.id, label: product.name })));
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania produktów:', error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTransactions();
|
||||
fetchProducts();
|
||||
console.log();
|
||||
}, []);
|
||||
|
||||
const handleAddTransaction = async () => {
|
||||
if (!newTransaction.date || !newTransaction.employeeId || newTransaction.transactionProducts.some(product => !product.productName || !product.quantity)) {
|
||||
setError('Proszę uzupełnić wszystkie pola.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
console.log('Nowa transakcja:', newTransaction);
|
||||
await axios.post('https://localhost:7039/api/Transaction', newTransaction);
|
||||
|
||||
fetchTransactions();
|
||||
setIsModalOpen(false);
|
||||
setNewTransaction({
|
||||
id: 2,
|
||||
date: "",
|
||||
employeeId: "",
|
||||
transactionProducts: [
|
||||
{
|
||||
id: 2,
|
||||
transactionId: 0,
|
||||
productID: 0,
|
||||
productName: "",
|
||||
quantity: ""
|
||||
}
|
||||
],
|
||||
paymentType: "",
|
||||
discount: "",
|
||||
description: "",
|
||||
totalPrice: 0
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas dodawania transakcji:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (dateString) => {
|
||||
const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' };
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('pl-PL', options).replace(",", "");
|
||||
};
|
||||
const formatPrice = (price) => {
|
||||
return parseFloat(price).toFixed(2);
|
||||
};
|
||||
|
||||
const handleAddProduct = () => {
|
||||
setNewTransaction({
|
||||
...newTransaction,
|
||||
transactionProducts: [
|
||||
...newTransaction.transactionProducts,
|
||||
{
|
||||
id: 2,
|
||||
transactionId: 0,
|
||||
productID: 0,
|
||||
productName: "",
|
||||
quantity: ""
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveProduct = (index) => {
|
||||
const updatedTransactionProducts = [...newTransaction.transactionProducts];
|
||||
updatedTransactionProducts.splice(index, 1);
|
||||
setNewTransaction({
|
||||
...newTransaction,
|
||||
transactionProducts: updatedTransactionProducts
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteTransaction = async (transactionId) => {
|
||||
try {
|
||||
await axios.delete(`https://localhost:7039/api/Transaction/${transactionId}`);
|
||||
fetchTransactions();
|
||||
setDeleteTransactionId(null);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas usuwania transakcji:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleEditTransaction = async (transaction) => {
|
||||
try {
|
||||
if (!editTransaction) {
|
||||
setEditTransaction(transaction);
|
||||
setIsEditModalOpen(true);
|
||||
return;
|
||||
}
|
||||
if (!editTransaction.date || !editTransaction.employeeId || editTransaction.transactionProducts.some(product => !product.productName || !product.quantity) || !editTransaction.paymentType){
|
||||
setError('Proszę uzupełnić wszystkie pola.');
|
||||
return;}
|
||||
await axios.put(`https://localhost:7039/api/Transaction/${editTransaction.id}`, editTransaction);
|
||||
fetchTransactions();
|
||||
setIsEditModalOpen(false);
|
||||
setEditTransaction(null);
|
||||
setError(null);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas edycji transakcji:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleProductChange = (index, selectedOption) => {
|
||||
const updatedTransactionProducts = [...newTransaction.transactionProducts];
|
||||
updatedTransactionProducts[index].productID = selectedOption.value;
|
||||
updatedTransactionProducts[index].productName = selectedOption.label;
|
||||
setNewTransaction({
|
||||
...newTransaction,
|
||||
transactionProducts: updatedTransactionProducts
|
||||
});
|
||||
};
|
||||
const handleEditProductChange = (index, selectedOption) => {
|
||||
const updatedTransactionProducts = [...editTransaction.transactionProducts];
|
||||
updatedTransactionProducts[index].productID = selectedOption.value;
|
||||
updatedTransactionProducts[index].productName = selectedOption.label;
|
||||
setEditTransaction({
|
||||
...editTransaction,
|
||||
transactionProducts: updatedTransactionProducts
|
||||
});
|
||||
};
|
||||
const openDeleteConfirmation = (transactionId) => {
|
||||
setDeleteTransactionId(transactionId);
|
||||
};
|
||||
|
||||
const closeDeleteConfirmation = () => {
|
||||
setDeleteTransactionId(null);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className='p-10 ml-11'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='h-20 text-5xl ml-1'>
|
||||
Lista Transakcji
|
||||
</div>
|
||||
<button onClick={() => setIsModalOpen(true)} className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded flex">
|
||||
<img src={plusIcon} alt="" className="w-8 h-8 mr-2" />Dodaj
|
||||
</button>
|
||||
</div>
|
||||
{error && (
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Błąd</h2>
|
||||
<p>{error}</p>
|
||||
<button onClick={() => window.location.reload()} className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
|
||||
Zamknij
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isEditModalOpen && editTransaction && (
|
||||
<div className="absolute top-0 left-0 w-full h-screen bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Edytuj transakcję</h2>
|
||||
<input
|
||||
type="datetime-local"
|
||||
name="date"
|
||||
value={editTransaction.date}
|
||||
onChange={(e) => setEditTransaction({ ...editTransaction, date: e.target.value })}
|
||||
placeholder="Data"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
Numer Pracownika
|
||||
<input
|
||||
type="number"
|
||||
name="employeeId"
|
||||
value={editTransaction.employeeId}
|
||||
onChange={(e) => setEditTransaction({ ...editTransaction, employeeId: e.target.value })}
|
||||
placeholder="Nr. Pracownika"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
{editTransaction.transactionProducts.map((product, index) => (
|
||||
<div key={index}>
|
||||
<Select
|
||||
name={`productName-${index}`}
|
||||
value={products.find(option => option.value === product.productName)}
|
||||
onChange={(selectedOption) => handleEditProductChange(index, selectedOption)}
|
||||
options={products}
|
||||
className="block w-full mb-4"
|
||||
placeholder="Wybierz produkt..."
|
||||
/>
|
||||
Ilość
|
||||
<input
|
||||
type="number"
|
||||
name={`quantity-${index}`}
|
||||
value={product.quantity}
|
||||
onChange={(e) => {
|
||||
const newTransactionProducts = [...editTransaction.transactionProducts];
|
||||
newTransactionProducts[index].quantity = e.target.value;
|
||||
setEditTransaction({ ...editTransaction, transactionProducts: newTransactionProducts });
|
||||
}}
|
||||
placeholder="Ilość"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<input
|
||||
type="text"
|
||||
name="paymentType"
|
||||
value={editTransaction.paymentType}
|
||||
onChange={(e) => setEditTransaction({ ...editTransaction, paymentType: e.target.value })}
|
||||
placeholder="Sposób płatności"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
Zniżka
|
||||
<input
|
||||
type="number"
|
||||
name="discount"
|
||||
value={editTransaction.discount}
|
||||
onChange={(e) => setEditTransaction({ ...editTransaction, discount: e.target.value })}
|
||||
placeholder="Rabat"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={editTransaction.description}
|
||||
onChange={(e) => setEditTransaction({ ...editTransaction, description: e.target.value })}
|
||||
placeholder="Opis"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleEditTransaction();
|
||||
setIsEditModalOpen(false);
|
||||
}}
|
||||
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Zapisz zmiany
|
||||
</button>
|
||||
<button
|
||||
onClick={() => window.location.reload()}
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Anuluj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isModalOpen && (
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Dodaj nową transakcję</h2>
|
||||
<input
|
||||
type="datetime-local"
|
||||
name="date"
|
||||
value={newTransaction.date}
|
||||
onChange={(e) => setNewTransaction({ ...newTransaction, date: e.target.value })}
|
||||
placeholder="Data"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
name="employeeId"
|
||||
value={newTransaction.employeeId}
|
||||
onChange={(e) => setNewTransaction({ ...newTransaction, employeeId: e.target.value })}
|
||||
placeholder="Nr. Pracownika"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
{newTransaction.transactionProducts.map((product, index) => (
|
||||
<div key={index}>
|
||||
<Select
|
||||
name={`productName-${index}`}
|
||||
value={products.find(option => option.value === product.productName)}
|
||||
onChange={(selectedOption) => handleProductChange(index, selectedOption)}
|
||||
options={products}
|
||||
className="block w-full mb-4"
|
||||
placeholder="Wybierz produkt..."
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
name={`quantity-${index}`}
|
||||
value={product.quantity}
|
||||
onChange={(e) => {
|
||||
const newTransactionProducts = [...newTransaction.transactionProducts];
|
||||
newTransactionProducts[index].quantity = e.target.value;
|
||||
setNewTransaction({ ...newTransaction, transactionProducts: newTransactionProducts });
|
||||
}}
|
||||
placeholder="Ilość" className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button onClick={() => handleRemoveProduct(index)} className="bg-red-500 hover:bg-red-700 text-white font-bold my-2 py-2 px-4 rounded">
|
||||
Usuń
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
<button onClick={handleAddProduct} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded">
|
||||
Dodaj
|
||||
</button>
|
||||
<input
|
||||
type="text"
|
||||
name="paymentType"
|
||||
value={newTransaction.paymentType}
|
||||
onChange={(e) => setNewTransaction({ ...newTransaction, paymentType: e.target.value })}
|
||||
placeholder="Sposób płatności"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
name="discount"
|
||||
value={newTransaction.discount}
|
||||
onChange={(e) => setNewTransaction({ ...newTransaction, discount: e.target.value })}
|
||||
placeholder="Rabat"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={newTransaction.description}
|
||||
onChange={(e) => setNewTransaction({ ...newTransaction, description: e.target.value })}
|
||||
placeholder="Opis"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleAddTransaction();
|
||||
setIsModalOpen(false);
|
||||
|
||||
}}
|
||||
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Dodaj transakcję
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 mx-1 rounded"
|
||||
>
|
||||
Anuluj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-8/10 mx-auto mt-2">
|
||||
<div className="h-screen overflow-y-auto">
|
||||
<table className="w-full border-collapse border border-gray-300">
|
||||
<thead className="bg-gray-200">
|
||||
<tr>
|
||||
<th className="border border-gray-300 p-2">ID</th>
|
||||
<th className="border border-gray-300 p-2">Data</th>
|
||||
<th className="border border-gray-300 p-2">Produkt</th>
|
||||
<th className="border border-gray-300 p-2">Ilość</th>
|
||||
<th className="border border-gray-300 p-2">Kwota</th>
|
||||
<th className="border border-gray-300 p-2">Sposób płatności</th>
|
||||
<th className="border border-gray-300 p-2">Nr. Pracownika</th>
|
||||
<th className="border border-gray-300 p-2"></th>
|
||||
<th className="border border-gray-300 p-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{transactions.map(transaction => (
|
||||
<tr key={transaction.id}>
|
||||
<td className="border border-gray-300 p-2">{transaction.id}</td>
|
||||
<td className="border border-gray-300 p-2">{formatDate(transaction.date)}</td>
|
||||
<td className="border border-gray-300 p-2">
|
||||
{transaction.transactionProducts.map(product => (
|
||||
<div key={product.id}>{product.product.name}</div>
|
||||
))}
|
||||
</td>
|
||||
<td className="border border-gray-300 p-2">
|
||||
{transaction.transactionProducts.map(product => (
|
||||
<div key={product.id}>{product.quantity}</div>
|
||||
))}
|
||||
</td>
|
||||
<td className="border border-gray-300 p-2">{formatPrice(transaction.totalPrice)}</td>
|
||||
<td className="border border-gray-300 p-2">{transaction.paymentType}</td>
|
||||
<td className="border border-gray-300 p-2">{transaction.employeeId}</td>
|
||||
<td className="border border-gray-300 p-2"><button onClick={() =>{handleEditTransaction(transaction);
|
||||
console.log(transaction);
|
||||
}
|
||||
}
|
||||
className="mr-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded flex">
|
||||
<img src={editIcon} alt="" className="w-8 h-8 mr-2" />Edytuj
|
||||
</button></td>
|
||||
<td className="border border-gray-300 p-2"><button onClick={() => openDeleteConfirmation(transaction.id)}
|
||||
className="mr-2 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded flex">
|
||||
<img src={koszIcon} alt="" className="w-8 h-8 mr-2" />Usuń
|
||||
</button></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="flex justify-start mt-4">
|
||||
</div>
|
||||
</div>
|
||||
{deleteTransactionId && (
|
||||
<ConfirmationModal
|
||||
message="Czy na pewno chcesz usunąć tę transakcję?"
|
||||
onCancel={closeDeleteConfirmation}
|
||||
onConfirm={() => {handleDeleteTransaction(deleteTransactionId); setDeleteTransactionId(false);}}
|
||||
/>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Transakcje
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,325 +1,22 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import editIcon from "../icons/edit.png";
|
||||
import koszIcon from "../icons/kosz.png";
|
||||
import plusIcon from "../icons/plus.png";
|
||||
import ConfirmationModal from './ConfirmationModal';
|
||||
import React from 'react';
|
||||
import { Routes, Route, useNavigate } from 'react-router-dom';
|
||||
import ListaProduktow from './ListaProduktów';
|
||||
import DodawanieProduktu from './DodawanieProduktów';
|
||||
import EdycjaProduktu from './EdycjaProduktu';
|
||||
|
||||
const ZarzadzanieProduktami = () => {
|
||||
const [products, setProducts] = useState([]);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [deleteProductId, setDeleteProductId] = useState(null);
|
||||
const [newProduct, setNewProduct] = useState({
|
||||
name: "",
|
||||
description: "",
|
||||
price: "",
|
||||
type: "",
|
||||
availability: ""
|
||||
});
|
||||
const [editProduct, setEditProduct] = useState(null);
|
||||
|
||||
const fetchProducts = async () => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
console.error('Brak tokena. Użytkownik musi być zalogowany.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.get('https://localhost:7039/api/products', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
setProducts(response.data);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas pobierania produktów:', error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchProducts();
|
||||
}, []);
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setNewProduct({ ...newProduct, [name]: value });
|
||||
};
|
||||
|
||||
const handleAddProduct = async () => {
|
||||
if (!newProduct.name || !newProduct.description || !newProduct.price || !newProduct.type || !newProduct.availability) {
|
||||
setError('Proszę uzupełnić wszystkie pola.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const config = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
await axios.post('https://localhost:7039/api/Products', newProduct, config);
|
||||
fetchProducts();
|
||||
setIsModalOpen(false);
|
||||
setNewProduct({
|
||||
name: "",
|
||||
availability: "",
|
||||
price: "",
|
||||
type: "",
|
||||
description: ""
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas dodawania:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditProduct = (product) => {
|
||||
setEditProduct(product);
|
||||
setIsEditModalOpen(true);
|
||||
};
|
||||
|
||||
const handleSaveEditedProduct = async () => {
|
||||
if (!editProduct.name || !editProduct.description || !editProduct.price || !editProduct.type || !editProduct.availability) {
|
||||
setError('Proszę uzupełnić wszystkie pola.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await axios.put(`https://localhost:7039/api/Products/${editProduct.id}`, editProduct);
|
||||
fetchProducts();
|
||||
setIsEditModalOpen(false);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas edycji:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteProduct = async () => {
|
||||
try {
|
||||
await axios.delete(`https://localhost:7039/api/Products/${deleteProductId}`);
|
||||
fetchProducts();
|
||||
setDeleteProductId(null);
|
||||
} catch (error) {
|
||||
console.error('Błąd podczas usuwania produktu:', error);
|
||||
if (error.response && error.response.data) {
|
||||
setError(error.response.data);
|
||||
} else {
|
||||
setError('Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const openDeleteConfirmation = (productId) => {
|
||||
setDeleteProductId(productId);
|
||||
};
|
||||
|
||||
const closeDeleteConfirmation = () => {
|
||||
setDeleteProductId(null);
|
||||
};
|
||||
const formatPrice = (price) => {
|
||||
return parseFloat(price).toFixed(2);
|
||||
};
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className='p-10 ml-11'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='h-20 text-5xl ml-1'>
|
||||
Katalog Produktów
|
||||
</div>
|
||||
<button onClick={() => setIsModalOpen(true)} className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded flex">
|
||||
<img src={plusIcon} alt="" className="w-8 h-8 mr-2" />Dodaj
|
||||
</button>
|
||||
</div>
|
||||
{error && (
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Błąd</h2>
|
||||
<p>{error}</p>
|
||||
<button onClick={() => window.location.reload()} className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
|
||||
Zamknij
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isEditModalOpen && editProduct && (
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white p-8 rounded-lg shadow-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Edytuj produkt</h2>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={editProduct.name}
|
||||
onChange={(e) => setEditProduct({ ...editProduct, name: e.target.value })}
|
||||
placeholder="Nazwa produktu"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
<div className="p-10 ml-11">
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={<ListaProduktow onAdd={() => navigate('/produkty/dodaj')} onEdit={(id) => navigate(`/produkty/edytuj/${id}`)} />}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={editProduct.description}
|
||||
onChange={(e) => setEditProduct({ ...editProduct, description: e.target.value })}
|
||||
placeholder="Opis"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="price"
|
||||
value={editProduct.price}
|
||||
onChange={(e) => setEditProduct({ ...editProduct, price: e.target.value })}
|
||||
placeholder="Cena"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="type"
|
||||
value={editProduct.type}
|
||||
onChange={(e) => setEditProduct({ ...editProduct, type: e.target.value })}
|
||||
placeholder="Typ"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="availability"
|
||||
value={editProduct.availability}
|
||||
onChange={(e) => setEditProduct({ ...editProduct, availability: e.target.value })}
|
||||
placeholder="Dostępność"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleSaveEditedProduct();
|
||||
setIsEditModalOpen(false);
|
||||
}}
|
||||
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Zapisz zmiany
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsEditModalOpen(false)}
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Anuluj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isModalOpen && (
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-70">
|
||||
<div className="bg-white p-8 rounded-lg shadow-lg">
|
||||
<h2 className="text-2xl font-bold mb-4">Dodaj nowy produkt</h2>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={newProduct.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Nazwa produktu"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
value={newProduct.description}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Opis"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="price"
|
||||
value={newProduct.price}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Cena"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="type"
|
||||
value={newProduct.type}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Kategoria"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="availability"
|
||||
value={newProduct.availability}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Dostępność"
|
||||
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleAddProduct();
|
||||
setIsModalOpen(false)
|
||||
}}
|
||||
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Dodaj produkt
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Anuluj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-8/10 mx-auto mt-2">
|
||||
<div className="h-screen overflow-y-auto">
|
||||
<table className="w-full border-collapse border border-gray-300">
|
||||
<thead className="bg-gray-200 top-0 z-10 sticky">
|
||||
<tr>
|
||||
<th className="border border-gray-300 p-2">ID</th>
|
||||
<th className="border border-gray-300 p-2">Produkt</th>
|
||||
<th className="border border-gray-300 p-2">Opis</th>
|
||||
<th className="border border-gray-300 p-2">Cena</th>
|
||||
<th className="border border-gray-300 p-2">Kategoria</th>
|
||||
<th className="border border-gray-300 p-2">Dostępność</th>
|
||||
<th className="border border-gray-300 p-2"></th>
|
||||
<th className="border border-gray-300 p-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{products.map(product => (
|
||||
<tr key={product.id}>
|
||||
<td className="border border-gray-300 p-2">{product.id}</td>
|
||||
<td className="border border-gray-300 p-2">{product.name}</td>
|
||||
<td className="border border-gray-300 p-2">{product.description}</td>
|
||||
<td className="border border-gray-300 p-2">{formatPrice(product.price)}</td>
|
||||
<td className="border border-gray-300 p-2">{product.type}</td>
|
||||
<td className="border border-gray-300 p-2">{product.availability}</td>
|
||||
<td className="border border-gray-300 p-2"><button onClick={() => handleEditProduct(product)}
|
||||
className="mr-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded flex">
|
||||
<img src={editIcon} alt="" className="w-8 h-8 mr-2" />Edytuj
|
||||
</button></td>
|
||||
<td className="border border-gray-300 p-2">
|
||||
<button onClick={() => openDeleteConfirmation(product.id)}
|
||||
className="mr-2 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded flex">
|
||||
<img src={koszIcon} alt="" className="w-8 h-8 mr-2" />Usuń
|
||||
</button></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{deleteProductId && (
|
||||
<ConfirmationModal
|
||||
message="Czy na pewno chcesz usunąć ten produkt?"
|
||||
onCancel={closeDeleteConfirmation}
|
||||
onConfirm={ () => {handleDeleteProduct(); setDeleteProductId(false);}}
|
||||
/>
|
||||
)}
|
||||
<Route path="/dodaj" element={<DodawanieProduktu />} />
|
||||
<Route path="/edytuj/:id" element={<EdycjaProduktu />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
24
firm/src/components/ZarzadzanieTransakcjami.js
Normal file
24
firm/src/components/ZarzadzanieTransakcjami.js
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import { Routes, Route, useNavigate } from 'react-router-dom';
|
||||
import ListaTransakcji from './ListaTransakcji';
|
||||
import DodawanieTransakcji from './DodawanieTransakcji';
|
||||
import EdycjaTransakcji from './EdycjaTransakcji';
|
||||
|
||||
const ZarzadzanieTransakcjami = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="p-10 ml-11">
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={<ListaTransakcji onAdd={() => navigate('/transakcje/dodaj')} onEdit={(id) => navigate(`/transakcje/edytuj/${id}`)} />}
|
||||
/>
|
||||
<Route path="/dodaj" element={<DodawanieTransakcji />} />
|
||||
<Route path="/edytuj/:id" element={<EdycjaTransakcji />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ZarzadzanieTransakcjami;
|
Loading…
Reference in New Issue
Block a user