poprawa edycji transakcji, dodanie harmonogramu

This commit is contained in:
Wiktor Szynaka 2024-11-28 21:30:29 +01:00
parent 03bf26a8a1
commit c4cd38ecac
7 changed files with 542 additions and 258 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import axios from 'axios'; import axios from 'axios';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -13,6 +13,15 @@ const DodawanieProduktu = () => {
}); });
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => {
if (newProduct.type === '0') {
setNewProduct(prevState => ({
...prevState,
availability: '',
}));
}
}, [newProduct.type]);
const handleInputChange = (event) => { const handleInputChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setNewProduct({ ...newProduct, [name]: value }); setNewProduct({ ...newProduct, [name]: value });

View File

@ -11,7 +11,7 @@ const EdycjaProduktu = () => {
type: '1', type: '1',
availability: '', availability: '',
}); });
const [error, setError] = useState(null); const [errors, setErrors] = useState({});
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
@ -19,7 +19,7 @@ const EdycjaProduktu = () => {
try { try {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
if (!token) { if (!token) {
setError('Brak tokena. Użytkownik musi być zalogowany.'); setErrors({ general: 'Brak tokena. Użytkownik musi być zalogowany.' });
return; return;
} }
@ -28,10 +28,18 @@ const EdycjaProduktu = () => {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
}); });
setProduct(response.data);
const productData = response.data;
setProduct({
name: productData.name,
description: productData.description,
price: productData.price,
type: productData.type.toString(),
availability: productData.availability || '',
});
} catch (error) { } catch (error) {
console.error('Błąd podczas pobierania produktu:', error); console.error('Błąd podczas pobierania produktu:', error);
setError('Wystąpił błąd podczas pobierania danych produktu.'); setErrors({ general: 'Wystąpił błąd podczas pobierania danych produktu.' });
} }
}; };
@ -40,14 +48,42 @@ const EdycjaProduktu = () => {
const handleInputChange = (event) => { const handleInputChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setProduct({ ...product, [name]: value });
if (name === 'type') {
if (value === '0') {
setProduct({
...product,
[name]: value,
availability: '',
});
} else {
setProduct({
...product,
[name]: value,
});
}
} else {
setProduct({ ...product, [name]: value });
}
setErrors((prevErrors) => ({
...prevErrors,
[name]: null,
}));
}; };
const handleSaveChanges = async () => { const handleSaveChanges = async () => {
const { name, description, price, type, availability } = product; const { name, description, price, type, availability } = product;
let validationErrors = {};
if (!name || !description || !price || type === '') { if (!name) validationErrors.name = 'Nazwa produktu jest wymagana.';
setError('Proszę uzupełnić wszystkie wymagane pola.'); if (!description) validationErrors.description = 'Opis produktu jest wymagany.';
if (!price) validationErrors.price = 'Cena produktu jest wymagana.';
if (type === '') validationErrors.type = 'Typ produktu jest wymagany.';
if (price < 0) validationErrors.price = 'Cena nie może być ujemna.';
if (type === '1' && !availability) validationErrors.availability = 'Dostępność jest wymagana dla produktu.';
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
return; return;
} }
@ -63,7 +99,7 @@ const EdycjaProduktu = () => {
try { try {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
if (!token) { if (!token) {
setError('Brak tokena. Użytkownik musi być zalogowany.'); setErrors({ general: 'Brak tokena. Użytkownik musi być zalogowany.' });
return; return;
} }
@ -74,74 +110,91 @@ const EdycjaProduktu = () => {
}, },
}; };
const response = await axios.put(`https://localhost:7039/api/Products/${id}`, payload, config); await axios.put(`https://localhost:7039/api/Products/${id}`, payload, config);
setErrors({});
console.log('Produkt zapisany:', response.data);
setError(null);
navigate('/produkty'); navigate('/produkty');
} catch (error) { } catch (error) {
console.error('Błąd podczas zapisywania zmian:', error); console.error('Błąd podczas zapisywania zmian:', error);
if (error.response && error.response.status === 400) { if (error.response && error.response.status === 400) {
setError('ID produktu nie zgadza się.'); setErrors({ general: error.response.data });
} else { } else {
setError('Wystąpił błąd podczas zapisywania zmian. Spróbuj ponownie.'); setErrors({ general: 'Wystąpił błąd podczas zapisywania zmian. Spróbuj ponownie.' });
} }
} }
}; };
return ( return (
<div className="p-8 bg-gray-100 rounded-lg shadow-md"> <div className="p-8 bg-gray-100 rounded-lg shadow-md">
<h2 className="text-2xl font-bold mb-4">Edycja produktu</h2> <h2 className="text-2xl font-bold mb-4">Edycja produktu</h2>
{error && <p className="text-red-500 mb-4">{error}</p>} {errors.general && <p className="text-red-500 mb-4">{errors.general}</p>}
<div className="grid grid-cols-2 gap-4">
<input <div className="grid grid-cols-2 gap-8">
type="text" <div className="relative">
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 <input
type="number" type="text"
name="availability" name="name"
value={product.availability} value={product.name}
onChange={handleInputChange} onChange={handleInputChange}
placeholder="Dostępność (ilość)" placeholder="Nazwa produktu lub usługi"
className="block w-full px-4 py-2 border border-gray-300 rounded-lg" className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
/> />
{errors.name && <span className="absolute text-red-500 text-sm">{errors.name}</span>}
</div>
<div className="relative">
<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"
/>
{errors.description && <span className="absolute text-red-500 text-sm">{errors.description}</span>}
</div>
<div className="relative">
<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"
/>
{errors.price && <span className="absolute text-red-500 text-sm">{errors.price}</span>}
</div>
<div className="relative">
<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>
{errors.type && <span className="absolute text-red-500 text-sm">{errors.type}</span>}
</div>
{product.type === '1' && (
<div className="relative">
<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"
/>
{errors.availability && <span className="absolute text-red-500 text-sm">{errors.availability}</span>}
</div>
)} )}
</div> </div>
<div className="mt-4"> <div className="mt-4">
<button <button
onClick={handleSaveChanges} onClick={handleSaveChanges}

View File

@ -1,238 +1,292 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from "react";
import axios from 'axios'; import axios from "axios";
import { useParams, useNavigate } from 'react-router-dom'; import { useParams, useNavigate } from "react-router-dom";
import Select from 'react-select'; import Select from "react-select";
const EdycjaTransakcji = () => { const EdycjaTransakcji = () => {
const { id } = useParams(); const { id } = useParams();
const [transaction, setTransaction] = useState({ const [transaction, setTransaction] = useState({
date: '', id: 2,
employeeId: '', date: "",
paymentType: '', employeeId: "",
discount: '', transactionProducts: [],
description: '', paymentType: "",
transactionProducts: [{ productID: '', productName: '', quantity: '' }], discount: "",
description: "",
totalPrice: 0,
}); });
const [products, setProducts] = useState([]); const [products, setProducts] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [errors, setErrors] = useState({});
const navigate = useNavigate(); const navigate = useNavigate();
const getToken = () => { const getToken = () => {
const token = localStorage.getItem('token'); const token = localStorage.getItem("token");
if (!token) { if (!token) {
setError('Brak tokena. Użytkownik musi być zalogowany.'); setError("Brak tokena. Użytkownik musi być zalogowany.");
return null;
} }
return token; return token;
}; };
useEffect(() => { useEffect(() => {
const fetchTransaction = async () => { const fetchTransactionData = async () => {
try { const token = getToken();
const token = getToken(); if (!token) return;
if (!token) return;
const transactionResponse = await axios.get(`https://localhost:7039/api/transaction/${id}`, { try {
headers: { const [transactionRes, productsRes] = await Promise.all([
Authorization: `Bearer ${token}`, axios.get(`https://localhost:7039/api/transaction/${id}`, {
}, headers: { Authorization: `Bearer ${token}` },
}); }),
console.log('Dane transakcji:', transactionResponse.data); axios.get("https://localhost:7039/api/Products", {
headers: { Authorization: `Bearer ${token}` },
}),
]);
const updatedTransaction = { const updatedTransaction = {
...transactionResponse.data, ...transactionRes.data,
transactionProducts: transactionResponse.data.transactionProducts.map((transactionProduct) => ({ transactionProducts: transactionRes.data.transactionProducts.map((tp) => ({
productID: transactionProduct.product.id, id: tp.id,
productName: transactionProduct.product.name, transactionId: transactionRes.data.id,
quantity: transactionProduct.quantity, productID: tp.product.id,
productName: tp.product.name,
quantity: tp.quantity,
})), })),
}; };
setTransaction(updatedTransaction); setTransaction(updatedTransaction);
const productResponse = await axios.get('https://localhost:7039/api/Products', { const productOptions = productsRes.data.map((product) => ({
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log('Produkty:', productResponse.data);
const productOptions = productResponse.data.map((product) => ({
value: product.id, value: product.id,
label: product.name, label: product.name,
})); }));
setProducts(productOptions); setProducts(productOptions);
} catch (error) { } catch (err) {
console.error('Błąd podczas pobierania transakcji lub produktów:', error); console.error(err);
setError('Wystąpił błąd podczas ładowania danych.'); setError("Wystąpił błąd podczas ładowania danych.");
} finally {
setIsLoading(false);
} }
}; };
fetchTransaction(); fetchTransactionData();
}, [id]); }, [id]);
const validateForm = () => {
const validationErrors = {};
if (!transaction.date) validationErrors.date = "Data transakcji jest wymagana.";
if (!transaction.employeeId || transaction.employeeId <= 0) validationErrors.employeeId = "Numer pracownika jest błędny.";
if (transaction.transactionProducts.length === 0)
validationErrors.transactionProducts = "Transakcja musi zawierać co najmniej jeden produkt.";
else {
transaction.transactionProducts.forEach((product, index) => {
if (!product.productID) validationErrors[`productID_${index}`] = "Produkt jest wymagany.";
if (!product.quantity || product.quantity <= 0)
validationErrors[`quantity_${index}`] = "Ilość musi być większa niż 0.";
});
}
if (!transaction.paymentType) validationErrors.paymentType = "Sposób płatności jest wymagany.";
if (transaction.discount < 0) validationErrors.discount = "Rabat nie może być ujemny.";
setErrors(validationErrors);
return Object.keys(validationErrors).length === 0;
};
const handleInputChange = (event) => { const handleInputChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setTransaction({ ...transaction, [name]: value }); setTransaction((prev) => ({ ...prev, [name]: value }));
setErrors((prevErrors) => ({ ...prevErrors, [name]: null }));
};
const handleAddProduct = () => {
setTransaction((prev) => ({
...prev,
transactionProducts: [
...prev.transactionProducts,
{ id: null, transactionId: prev.id, productID: 0, productName: "", quantity: "" },
],
}));
}; };
const handleProductChange = (index, selectedOption) => { const handleProductChange = (index, selectedOption) => {
const updatedTransactionProducts = [...transaction.transactionProducts]; setTransaction((prev) => {
updatedTransactionProducts[index].productID = selectedOption.value; const updatedProducts = prev.transactionProducts.map((product, i) =>
updatedTransactionProducts[index].productName = selectedOption.label; i === index
setTransaction({ ? { ...product, productID: selectedOption.value, productName: selectedOption.label }
...transaction, : product
transactionProducts: updatedTransactionProducts, );
return { ...prev, transactionProducts: updatedProducts };
}); });
setErrors((prevErrors) => ({ ...prevErrors, [`productID_${index}`]: null }));
}; };
const handleQuantityChange = (index, quantity) => {
const handleAddProduct = () => { setTransaction((prev) => {
setTransaction({ const updatedProducts = prev.transactionProducts.map((product, i) =>
...transaction, i === index ? { ...product, quantity } : product
transactionProducts: [ );
...transaction.transactionProducts, return { ...prev, transactionProducts: updatedProducts };
{ productID: 0, productName: '', quantity: '' },
],
}); });
setErrors((prevErrors) => ({ ...prevErrors, [`quantity_${index}`]: null }));
}; };
const handleRemoveProduct = (index) => { const handleRemoveProduct = async (index) => {
const updatedTransactionProducts = [...transaction.transactionProducts]; const token = getToken();
updatedTransactionProducts.splice(index, 1); if (!token) {
setTransaction({ console.error("Brak tokena, nie można usunąć produktu.");
...transaction, setError("Użytkownik musi być zalogowany.");
transactionProducts: updatedTransactionProducts, return;
}); }
};
const handleSaveChanges = async () => { const productToRemove = transaction.transactionProducts[index];
if (!transaction.date || !transaction.employeeId || transaction.transactionProducts.some(product => !product.productName || !product.quantity)) { console.log(productToRemove);
setError('Proszę uzupełnić wszystkie pola.');
if (!productToRemove || !productToRemove.id) {
console.error("Nie znaleziono ID transakcyjnego produktu. Usuwanie lokalne.");
setTransaction((prev) => ({
...prev,
transactionProducts: prev.transactionProducts.filter((_, i) => i !== index),
}));
return; return;
} }
try { try {
const token = getToken(); await axios.delete(
if (!token) { `https://localhost:7039/api/Transaction/${transaction.id}/product/${productToRemove.productID}`,
setError('Brak tokena. Użytkownik musi być zalogowany.'); { headers: { Authorization: `Bearer ${token}` } }
return; );
} console.log(`Produkt o ID transakcji ${productToRemove.id} został usunięty.`);
const response = await axios.put(`https://localhost:7039/api/transaction/${id}`, transaction, { setTransaction((prev) => ({
headers: { ...prev,
Authorization: `Bearer ${token}`, transactionProducts: prev.transactionProducts.filter((_, i) => i !== index),
}, }));
}); } catch (err) {
console.log('Zaktualizowana transakcja:', response.data); console.error("Błąd podczas usuwania produktu:", err.response?.data || err.message);
navigate('/transakcje'); setError(err.response?.data?.message || "Nie udało się usunąć produktu. Spróbuj ponownie.");
} catch (error) { }
console.error('Błąd podczas zapisywania zmian:', error); };
setError('Wystąpił błąd podczas zapisywania zmian.');
const handleSaveChanges = async () => {
if (!validateForm()) return;
const token = getToken();
if (!token) return;
const updatedTransaction = {
...transaction,
transactionProducts: transaction.transactionProducts.map((tp) => ({
id: tp.id || 0,
transactionId: transaction.id,
productID: tp.productID,
productName: tp.productName,
quantity: Number(tp.quantity),
})),
};
try {
await axios.put(
`https://localhost:7039/api/transaction/${transaction.id}`,
updatedTransaction,
{ headers: { Authorization: `Bearer ${token}` } }
);
navigate("/transakcje");
} catch (err) {
console.error(err);
setError(err.response.data);
} }
}; };
return ( return (
<div className="bg-white p-8 rounded-lg"> <div className="bg-white p-8 rounded-lg">
<h2 className="text-2xl font-bold mb-4">Edycja Transakcji</h2> <h2 className="text-2xl font-bold mb-4">Edycja Transakcji</h2>
{error && <p className="text-red-500 mb-4">{error}</p>} {error && <p className="text-red-500 mb-4">{error}</p>}
<div className="mb-4">
<input <input
type="datetime-local" type="datetime-local"
name="date" name="date"
value={transaction.date} value={transaction.date}
onChange={handleInputChange} onChange={handleInputChange}
placeholder="Data" placeholder="Data"
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg" className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
/> />
{errors.date && <span className="text-red-500 text-sm">{errors.date}</span>}
<input </div>
type="number" <div className="mb-4">
name="employeeId" <input
value={transaction.employeeId} type="number"
onChange={handleInputChange} name="employeeId"
placeholder="Nr. Pracownika" value={transaction.employeeId}
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg" onChange={handleInputChange}
/> placeholder="Nr. Pracownika"
className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
{isLoading ? ( />
<div className="text-center">Ładowanie produktów...</div> {errors.employeeId && <span className="text-red-500 text-sm">{errors.employeeId}</span>}
) : ( </div>
<> {transaction.transactionProducts.map((product, index) => (
{transaction.transactionProducts.map((product, index) => ( <div key={index} className="mb-4">
<div key={index} className="mb-4"> <Select
<Select value={products.find((p) => p.value === product.productID) || null}
name={`productName-${index}`} onChange={(option) => handleProductChange(index, option)}
value={products.find(option => option.value === product.productID) || null} options={products}
onChange={(selectedOption) => handleProductChange(index, selectedOption)} className="mb-2"
options={products} placeholder="Wybierz produkt"
className="block w-full mb-2" />
placeholder="Wybierz produkt..." {errors[`productID_${index}`] && (
/> <span className="text-red-500 text-sm">{errors[`productID_${index}`]}</span>
<input )}
type="number" <input
name={`quantity-${index}`} type="number"
value={product.quantity} value={product.quantity}
onChange={(e) => { onChange={(e) => handleQuantityChange(index, e.target.value)}
const updatedTransactionProducts = [...transaction.transactionProducts]; placeholder="Ilość"
updatedTransactionProducts[index].quantity = e.target.value; className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
setTransaction({ ...transaction, transactionProducts: updatedTransactionProducts }); />
}} {errors[`quantity_${index}`] && (
placeholder="Ilość" <span className="text-red-500 text-sm">{errors[`quantity_${index}`]}</span>
className="block w-full mb-2 px-4 py-2 border border-gray-300 rounded-lg" )}
/> <button
<button onClick={() => handleRemoveProduct(index)}
onClick={() => handleRemoveProduct(index)} className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded" >
> Usuń
Usuń </button>
</button> </div>
</div> ))}
))}
</>
)}
<button <button
onClick={handleAddProduct} onClick={handleAddProduct}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
> >
Dodaj produkt Dodaj produkt
</button> </button>
<div className="mb-4">
<input <input
type="text" type="text"
name="paymentType" name="paymentType"
value={transaction.paymentType} value={transaction.paymentType}
onChange={handleInputChange} onChange={handleInputChange}
placeholder="Sposób płatności" placeholder="Sposób płatności"
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg" className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
/> />
{errors.paymentType && (
<input <span className="text-red-500 text-sm">{errors.paymentType}</span>
type="number" )}
name="discount" </div>
value={transaction.discount} <div className="mb-4">
onChange={handleInputChange} <input
placeholder="Rabat" type="number"
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg" name="discount"
/> value={transaction.discount}
onChange={handleInputChange}
<input placeholder="Rabat"
type="text" className="block w-full px-4 py-2 border border-gray-300 rounded-lg"
name="description" />
value={transaction.description} {errors.discount && <span className="text-red-500 text-sm">{errors.discount}</span>}
onChange={handleInputChange} </div>
placeholder="Opis"
className="block w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg"
/>
<button <button
onClick={handleSaveChanges} onClick={handleSaveChanges}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 my-3 rounded" className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
> >
Zapisz zmiany Zapisz zmiany
</button> </button>

View File

@ -1,10 +1,177 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { jwtDecode } from 'jwt-decode';
const Harmonogram = () => { const Harmonogram = () => {
const [workdays, setWorkdays] = useState([]);
const [email, setEmail] = useState(null);
const [currentDate, setCurrentDate] = useState(new Date());
const [displayDate, setDisplayDate] = useState(new Date());
const [daysInMonth, setDaysInMonth] = useState([]);
const [manualDateChange, setManualDateChange] = useState(false);
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
const decodedToken = jwtDecode(token);
setEmail(decodedToken.email);
fetchWorkdays(decodedToken.email);
}
const interval = setInterval(() => {
if (!manualDateChange) {
setCurrentDate(new Date());
}
}, 1000);
return () => clearInterval(interval);
}, [manualDateChange]);
const fetchWorkdays = async (email) => {
try {
const response = await axios.get(`https://localhost:7039/api/Workday/user/${email}/workdays`, {
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
});
setWorkdays(response.data);
} catch (error) {
console.error('Błąd podczas pobierania dni roboczych:', error);
}
};
const handleStartWorkday = async (date) => {
const token = localStorage.getItem('token');
if (!token) {
alert('Brak tokena. Użytkownik musi być zalogowany.');
return;
}
try {
await axios.post(
'https://localhost:7039/api/workday/start',
{ date },
{
headers: { Authorization: `Bearer ${token}` },
}
);
alert('Dzień roboczy rozpoczęty!');
fetchWorkdays(email);
} catch (error) {
console.error(error);
}
};
const isWorkday = (date) => {
return workdays.includes(date);
};
const formatTime = (date) => {
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
const seconds = date.getSeconds().toString().padStart(2, '0');
return `${hours}:${minutes}:${seconds}`;
};
const formatDayOfWeek = (date) => {
const daysOfWeek = ['Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela'];
return daysOfWeek[date.getDay() === 0 ? 6 : date.getDay() - 1];
};
const formatDate = (date) => {
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear();
return `${day}-${month}-${year}`;
};
const generateDaysInMonth = () => {
const firstDayOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
const lastDayOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth() + 1, 0);
const firstDayWeekday = (firstDayOfMonth.getDay() === 0 ? 6 : firstDayOfMonth.getDay() - 1);
const numberOfDaysInMonth = lastDayOfMonth.getDate();
const days = [];
for (let i = 0; i < firstDayWeekday; i++) {
days.push(null);
}
for (let i = 1; i <= numberOfDaysInMonth; i++) {
days.push(i);
}
setDaysInMonth(days);
};
useEffect(() => {
generateDaysInMonth();
}, [displayDate]);
const changeMonth = (direction) => {
setManualDateChange(true);
const newDate = new Date(displayDate);
if (direction === 'previous') {
newDate.setMonth(displayDate.getMonth() - 1);
} else if (direction === 'next') {
newDate.setMonth(displayDate.getMonth() + 1);
}
setDisplayDate(newDate);
setTimeout(() => setManualDateChange(false), 1000);
};
const formatMonth = (monthIndex) => {
const months = [
'Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec',
'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień',
];
return months[monthIndex];
};
return ( return (
<div> <div className="container mx-auto px-4 py-6">
<h1>Harmonogram</h1> <div className="flex justify-between items-center mb-6">
<div className="text-lg font-semibold">
<p>{formatDate(currentDate)} - {formatDayOfWeek(currentDate)}</p>
<p>{formatTime(currentDate)}</p>
</div>
</div> </div>
<div className="flex justify-between items-center mb-4">
<button
className="bg-blue-500 text-white py-2 px-4 rounded"
onClick={() => changeMonth('previous')}
>
Poprzedni miesiąc
</button>
<h2 className="text-2xl font-bold">{formatMonth(displayDate.getMonth())} {displayDate.getFullYear()}</h2>
<button
className="bg-blue-500 text-white py-2 px-4 rounded"
onClick={() => changeMonth('next')}
>
Następny miesiąc
</button>
</div>
<div className="grid grid-cols-7 gap-4">
{['P', 'W', 'Ś', 'C', 'P', 'S', 'N'].map((day, index) => (
<div key={index} className="text-center font-semibold">{day}</div>
))}
{daysInMonth.map((day, index) => (
<div
key={index}
className={`text-center py-5 rounded-lg ${day ? 'cursor-pointer' : 'text-transparent'}
${day && 'bg-gray-200 hover:bg-gray-300 transition duration-150 ease-in-out'}
${isWorkday(formatDate(new Date(displayDate.getFullYear(), displayDate.getMonth(), day))) && 'bg-green-200'}`}
style={{
boxShadow: day ? '0 4px 6px rgba(0, 0, 0, 0.1)' : 'none',
}}
onClick={() => day && handleStartWorkday(new Date(displayDate.getFullYear(), displayDate.getMonth(), day))}
>
{day}
</div>
))}
</div>
</div>
); );
}; };

View File

@ -81,7 +81,7 @@ const ListaProduktow = ({ onAdd }) => {
<td className="p-2 border">{product.name}</td> <td className="p-2 border">{product.name}</td>
<td className="p-2 border">{product.description}</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">{parseFloat(product.price).toFixed(2)}</td>
<td className="p-2 border">{product.availability}</td> <td className="p-2 border">{product.type === 0 ? "" : product.availability}</td>
<td className="p-2 border"> <td className="p-2 border">
<button <button
onClick={() => handleEditProduct(product.id)} onClick={() => handleEditProduct(product.id)}

View File

@ -16,7 +16,7 @@ const Navbar = ({ setToken }) => {
}; };
return ( return (
<div className="flex items-center justify-between bg-gray-300 p-7 h-16"> <div className="flex items-center justify-between bg-gray-300 p-7 h-16 top-0">
<div className="flex items-center flex-shrink-0 text-black mr-6"> <div className="flex items-center flex-shrink-0 text-black mr-6">
<Link to="/" className="text-2xl font-customFont font-bold tracking-wide">FIRMTRACKER</Link> <Link to="/" className="text-2xl font-customFont font-bold tracking-wide">FIRMTRACKER</Link>
</div> </div>

View File

@ -9,16 +9,16 @@ import raportyIcon from "../icons/raport.png";
const Sidebar = ({ userRole }) => { const Sidebar = ({ userRole }) => {
return ( return (
<div className="bg-gray-200 h-screen flex justify-center marign-0 w-max"> <div className="bg-gray-200 h-screen flex-grow justify-center w-max sticky top-0 z-0">
<ul className=""> <ul>
{userRole !== 'User' && ( {userRole !== 'User' && (
<> <>
<Link to="/panel" className="text-black px-10 py-2 block font-customFont text-center w-max"> <Link to="/panel" className="text-black px-10 py-2 block font-customFont text-center w-max">
<li className='flex items-center'> <li className='flex items-center'>
<img src={adminIcon} alt="Obrazek 1" className="w-7 h-7 mr-2" /> <img src={adminIcon} alt="Obrazek 1" className="w-7 h-7 mr-2" />
Panel Administratora Panel Administratora
</li></Link> </li></Link>
</> </>
)} )}
<Link to="/produkty" className="text-black px-10 py-2 block font-customFont text-center w-max"> <Link to="/produkty" className="text-black px-10 py-2 block font-customFont text-center w-max">
<li className='flex items-center'> <li className='flex items-center'>
@ -51,6 +51,7 @@ const Sidebar = ({ userRole }) => {
)} )}
</ul> </ul>
</div> </div>
); );
} }
export default Sidebar; export default Sidebar;