Majdnem kész

This commit is contained in:
Sándor Máté Magony
2025-04-24 15:38:31 +02:00
parent db245545eb
commit 2d71603962
121 changed files with 3870 additions and 2601 deletions

View File

@@ -6,21 +6,24 @@ import Kezdolap from './WC_Komponens/Kezdolap/Kezdolap';
import LegkozelebbiMosdo from './WC_Komponens/Kereso/Legkozelebbi';
import HozzaadForm from './WC_Komponens/Hozzadas/HozzaadForm';
import Lablec from './WC_Komponens/Lablec/Lablec';
import { AuthProvider } from './WC_Komponens/Bejel_Regisz/AuthContext';
export default function App() {
return (
<>
<Menusor />
<div className=''>
<Routes>
<Route index element={<Kezdolap />}/>
<Route path="/kereso" element={<LegkozelebbiMosdo />}/>
<Route path="/bejelentkezes" element={<Bejelentkezes />}/>
<Route path="/regisztracio" element={<Regisztracio />} />
<Route path="/hozzaadas" element={<HozzaadForm />}/>
</Routes>
</div>
<Lablec />
<AuthProvider>
<Menusor />
<div className=''>
<Routes>
<Route index element={<Kezdolap />}/>
<Route path="/kereso" element={<LegkozelebbiMosdo />}/>
<Route path="/bejelentkezes" element={<Bejelentkezes />}/>
<Route path="/regisztracio" element={<Regisztracio />} />
<Route path="/hozzaadas" element={<HozzaadForm />}/>
</Routes>
</div>
<Lablec />
</AuthProvider>
</>
);
}

View File

@@ -0,0 +1,143 @@
import React, { createContext, useState, useEffect, useContext } from 'react';
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const API_URL = 'http://localhost:8000/api';
useEffect(() => {
// Check if user is logged in on page load
const token = localStorage.getItem('token');
if (token) {
fetchUserData(token);
} else {
setLoading(false);
}
}, []);
const fetchUserData = async (token) => {
try {
const response = await fetch(`${API_URL}/auth/me`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const userData = await response.json();
setUser(userData);
} else {
localStorage.removeItem('token');
}
} catch (error) {
setError('Felhasználói adatok lekérdezése sikertelen');
} finally {
setLoading(false);
}
};
const login = async (felhNev, jelszo) => {
setLoading(true);
setError(null);
try {
const response = await fetch(`${API_URL}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
felh_nev: felhNev,
jelszo: jelszo
}),
});
const data = await response.json();
if (response.ok) {
localStorage.setItem('token', data.access_token);
setUser(data.user);
return true;
} else {
setError(data.error || 'Bejelentkezés sikertelen');
return false;
}
} catch (error) {
setError('Hálózati vagy szerver hiba');
return false;
} finally {
setLoading(false);
}
};
const register = async (userData) => {
setLoading(true);
setError(null);
try {
const response = await fetch(`${API_URL}/auth/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
const data = await response.json();
if (response.ok) {
return { success: true, data };
} else {
setError(data.error || 'Regisztráció sikertelen');
return { success: false, errors: data };
}
} catch (error) {
setError('Hálózati vagy szerver hiba');
return { success: false, errors: { message: 'Hálózati vagy szerver hiba' } };
} finally {
setLoading(false);
}
};
const logout = async () => {
const token = localStorage.getItem('token');
if (token) {
try {
await fetch(`${API_URL}/auth/logout`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
}
});
} catch (error) {
console.error('Kijelentkezés sikertelen', error);
}
}
localStorage.removeItem('token');
setUser(null);
};
const value = {
user,
loading,
error,
login,
register,
logout,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}

View File

@@ -1,29 +1,67 @@
import { useState } from 'react';
import { useAuth } from './AuthContext'; // Update this path
import { useNavigate } from 'react-router-dom';
export default function Bejelentkezes() {
return (
<div className="flex justify-center items-center min-h-screen bg-yellow-100">
<form className="bg-white p-6 rounded-lg shadow-lg w-80 space-y-4">
<h2 className="text-2xl font-bold text-center">Bejelentkezés</h2>
<input
type="text"
placeholder="Felhasználónév"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<input
type="password"
placeholder="Jelszó"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
type="submit"
className="w-full bg-yellow-600 text-white py-2 rounded-lg hover:bg-yellow-700 transition"
>
Bejelentkezés
</button>
</form>
</div>
);
}
const [felhNev, setFelhNev] = useState('');
const [jelszo, setJelszo] = useState('');
const [error, setError] = useState('');
const { login, loading } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
if (!felhNev || !jelszo) {
setError('Minden mező kitöltése kötelező');
return;
}
const success = await login(felhNev, jelszo);
if (success) {
navigate('/');
}
};
return (
<div className="flex justify-center items-center min-h-screen bg-yellow-100">
<form
className="bg-white p-6 rounded-lg shadow-lg w-80 space-y-4"
onSubmit={handleSubmit}
>
<h2 className="text-2xl font-bold text-center">Bejelentkezés</h2>
{error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-2 rounded">
{error}
</div>
)}
<input
type="text"
placeholder="Felhasználónév"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
value={felhNev}
onChange={(e) => setFelhNev(e.target.value)}
/>
<input
type="password"
placeholder="Jelszó"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
value={jelszo}
onChange={(e) => setJelszo(e.target.value)}
/>
<button
type="submit"
className="w-full bg-yellow-600 text-white py-2 rounded-lg hover:bg-yellow-700 transition"
disabled={loading}
>
{loading ? 'Betöltés...' : 'Bejelentkezés'}
</button>
</form>
</div>
);
}

View File

@@ -1,52 +1,144 @@
import { useState } from 'react';
import { useAuth } from './AuthContext'; // Update this path
import { useNavigate } from 'react-router-dom';
export default function Regisztracio() {
return (
<div className="flex justify-center items-center min-h-screen bg-yellow-100">
<form className="bg-white p-6 rounded-lg shadow-lg w-96 space-y-4">
<h2 className="text-2xl font-bold text-center">Regisztráció</h2>
const [formData, setFormData] = useState({
nev: '',
email: '',
felh_nev: '',
jelszo: '',
jelszo_confirmation: ''
});
const [errors, setErrors] = useState({});
const { register, loading } = useAuth();
const navigate = useNavigate();
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
setErrors({});
// Basic validation
const newErrors = {};
if (!formData.nev) newErrors.nev = 'A név megadása kötelező';
if (!formData.email) newErrors.email = 'Az email megadása kötelező';
if (!formData.felh_nev) newErrors.felh_nev = 'A felhasználónév megadása kötelező';
if (!formData.jelszo) newErrors.jelszo = 'A jelszó megadása kötelező';
if (formData.jelszo !== formData.jelszo_confirmation) {
newErrors.jelszo_confirmation = 'A jelszavak nem egyeznek';
}
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}
const result = await register(formData);
if (result.success) {
navigate('/bejelentkezes'); // Navigate to login page after successful registration
} else if (result.errors) {
// Format Laravel validation errors
const serverErrors = {};
for (const key in result.errors) {
if (Array.isArray(result.errors[key])) {
serverErrors[key] = result.errors[key][0];
} else {
serverErrors[key] = result.errors[key];
}
}
setErrors(serverErrors);
}
};
return (
<div className="flex justify-center items-center min-h-screen bg-yellow-100">
<form
className="bg-white p-6 rounded-lg shadow-lg w-96 space-y-4"
onSubmit={handleSubmit}
>
<h2 className="text-2xl font-bold text-center">Regisztráció</h2>
<div>
<label className="block text-gray-700">Név:</label>
<input
type="text"
name="nev"
placeholder="Név"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.nev ? 'border-red-500' : ''}`}
value={formData.nev}
onChange={handleChange}
/>
{errors.nev && <p className="text-red-500 text-sm mt-1">{errors.nev}</p>}
</div>
<div>
<label className="block text-gray-700">E-mail cím:</label>
<input
type="email"
name="email"
placeholder="E-mail cím"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.email ? 'border-red-500' : ''}`}
value={formData.email}
onChange={handleChange}
/>
{errors.email && <p className="text-red-500 text-sm mt-1">{errors.email}</p>}
</div>
<div>
<label className="block text-gray-700">Felhasználónév:</label>
<input
type="text"
name="felh_nev"
placeholder="Felhasználónév"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.felh_nev ? 'border-red-500' : ''}`}
value={formData.felh_nev}
onChange={handleChange}
/>
{errors.felh_nev && <p className="text-red-500 text-sm mt-1">{errors.felh_nev}</p>}
</div>
<div>
<label className="block text-gray-700">Jelszó:</label>
<input
type="password"
name="jelszo"
placeholder="Jelszó"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.jelszo ? 'border-red-500' : ''}`}
value={formData.jelszo}
onChange={handleChange}
/>
{errors.jelszo && <p className="text-red-500 text-sm mt-1">{errors.jelszo}</p>}
</div>
<div>
<label className="block text-gray-700">Jelszó újra:</label>
<input
type="password"
name="jelszo_confirmation"
placeholder="Jelszó újra"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.jelszo_confirmation ? 'border-red-500' : ''}`}
value={formData.jelszo_confirmation}
onChange={handleChange}
/>
<button
type="submit"
className="w-full bg-yellow-600 text-white py-2 rounded-lg hover:bg-yellow-700 transition"
>
Regisztráció
</button>
</form>
</div>
);
}
{errors.jelszo_confirmation && <p className="text-red-500 text-sm mt-1">{errors.jelszo_confirmation}</p>}
</div>
<button
type="submit"
className="w-full bg-yellow-600 text-white py-2 rounded-lg hover:bg-yellow-700 transition"
disabled={loading}
>
{loading ? 'Betöltés...' : 'Regisztráció'}
</button>
</form>
</div>
);
}

View File

@@ -1,11 +1,13 @@
import React, { useState, useEffect } from "react";
import { TfiWheelchair } from "react-icons/tfi";
import { mosdokFetch } from "../../apiFetch";
import { useAuth } from "../Bejel_Regisz/AuthContext";
export default function Csempe() {
const [mosdok, setMosdok] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const { user } = useAuth();
useEffect(() => {
const getData = async () => {
@@ -22,6 +24,27 @@ export default function Csempe() {
getData();
}, []);
function mosdoTorles(mosdoId){
fetch("http://localhost:8000/api/mosdotorles/" + mosdoId, {
method: "DELETE",
header: {
"Accept" : "application/json",
"Content-Type" : "application/json"
}
})
.then(response => {
if (response.ok) {
// Sikeres törlés után szűrd ki az adott elemet a state-ből
setMosdok(prev => prev.filter(m => m.id !== mosdoId));
} else {
console.error("Törlés sikertelen");
}
})
.catch(error => {
console.error("Hiba a törlés során:", error);
});
}
if (loading) {
return(
<div className="flex justify-center items-center h-32">
@@ -34,29 +57,62 @@ export default function Csempe() {
return <div className="text-center text-red-600 p-4">{error}</div>;
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-4">
{mosdok.map((mosdo, index) => (
<div key={index} className="bg-white shadow-lg rounded-xl p-6 border border-gray-200 relative">
<h1 className="text-xl font-semibold text-gray-800 mb-3">{mosdo.nev}</h1>
<div className="text-gray-600 space-y-1">
<p><span className="font-medium text-gray-800">Kerület:</span> {mosdo.kerulet?.kerulet_nev}</p>
<p><span className="font-medium text-gray-800">Legközelebbi megálló:</span> {mosdo.kozeli_megall}</p>
<p><span className="font-medium text-gray-800">Ár:</span> {mosdo.ar} Ft</p>
<p><span className="font-medium text-gray-800">Nyitvatartás:</span> {mosdo.nyitva}</p>
if(user && user.is_admin){
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-4">
{mosdok.map((mosdo, index) => (
<div key={index} className="bg-white shadow-lg rounded-xl p-6 border border-gray-200 relative">
<h1 className="text-xl font-semibold text-gray-800 mb-3">{mosdo.nev}</h1>
<div className="text-gray-600 space-y-1">
<p><span className="font-medium text-gray-800">Kerület:</span> {mosdo.kerulet?.kerulet_nev}</p>
<p><span className="font-medium text-gray-800">Legközelebbi megálló:</span> {mosdo.kozeli_megall}</p>
<p><span className="font-medium text-gray-800">Ár:</span> {mosdo.ar} Ft</p>
<p><span className="font-medium text-gray-800">Nyitvatartás:</span> {mosdo.nyitva}</p>
</div>
{mosdo.akadalym === 1 ? <TfiWheelchair className="absolute bottom-10 right-10 w-8 h-8"/> : ""}
<a
href={mosdo.utvonal}
target="_blank"
rel="noopener noreferrer"
className="font-bold mt-4 inline-block bg-yellow-500 text-white py-2 px-4 rounded-lg shadow-md hover:bg-yellow-600 transition"
>
Útvonalterv
</a>
<button
onClick={() => mosdoTorles(mosdo.id)}
className="font-bold mt-4 inline-block bg-red-500 text-white py-2 px-4 rounded-lg shadow-md hover:bg-red-600 transition"
>
Törlés
</button>
</div>
{mosdo.akadalym === 1 ? <TfiWheelchair className="absolute bottom-10 right-10 w-8 h-8"/> : ""}
<a
href={mosdo.utvonal}
target="_blank"
rel="noopener noreferrer"
className="font-bold mt-4 inline-block bg-yellow-500 text-white py-2 px-4 rounded-lg shadow-md hover:bg-yellow-600 transition"
>
Útvonalterv
</a>
</div>
))}
</div>
);
))}
</div>
);
} else {
return(
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-4">
{mosdok.map((mosdo, index) => (
<div key={index} className="bg-white shadow-lg rounded-xl p-6 border border-gray-200 relative">
<h1 className="text-xl font-semibold text-gray-800 mb-3">{mosdo.nev}</h1>
<div className="text-gray-600 space-y-1">
<p><span className="font-medium text-gray-800">Kerület:</span> {mosdo.kerulet?.kerulet_nev}</p>
<p><span className="font-medium text-gray-800">Legközelebbi megálló:</span> {mosdo.kozeli_megall}</p>
<p><span className="font-medium text-gray-800">Ár:</span> {mosdo.ar} Ft</p>
<p><span className="font-medium text-gray-800">Nyitvatartás:</span> {mosdo.nyitva}</p>
</div>
{mosdo.akadalym === 1 ? <TfiWheelchair className="absolute bottom-10 right-10 w-8 h-8"/> : ""}
<a
href={mosdo.utvonal}
target="_blank"
rel="noopener noreferrer"
className="font-bold mt-4 inline-block bg-yellow-500 text-white py-2 px-4 rounded-lg shadow-md hover:bg-yellow-600 transition"
>
Útvonalterv
</a>
</div>
))}
</div>
)
}
}

View File

@@ -1,58 +1,92 @@
import { useState } from "react";
import { Link } from "react-router-dom";
import { Menu, X } from "lucide-react";
import { useAuth } from "../Bejel_Regisz/AuthContext";
export default function Menusor() {
const [menuOpen, setMenuOpen] = useState(false);
const { user, logout } = useAuth();
return (
<nav className="bg-yellow-200 text-amber-900 py-4 px-6 flex justify-between items-center shadow-md sticky top-0 w-full z-50">
<Link to="/" className="text-2xl font-bold flex items-center">
<img src="/Logo.png" alt="PeePal Logo" className="h-14 ml-2 hover:h-15" />
</Link>
if (!user) {
return (
<nav className="bg-yellow-200 text-amber-900 py-4 px-6 flex justify-between items-center shadow-md sticky top-0 w-full z-50">
<Link to="/" className="text-2xl font-bold flex items-center">
<img src="/Logo.png" alt="PeePal Logo" className="h-14 ml-2 hover:h-15" />
</Link>
{/* Hamburger ikon */}
<button
className="md:hidden text-amber-900"
onClick={() => setMenuOpen(!menuOpen)}
>
{menuOpen ? <X size={32} /> : <Menu size={32} />}
</button>
<button
className="md:hidden text-amber-900"
onClick={() => setMenuOpen(!menuOpen)}
>
{menuOpen ? <X size={32} /> : <Menu size={32} />}
</button>
{/* Menü */}
<ul
className={`md:flex md:space-x-6 md:items-center text-lg ${
menuOpen
? "absolute top-16 left-0 w-full bg-yellow-200 flex flex-col items-center space-y-4 py-4 shadow-lg"
: "hidden md:flex"
}`}
>
<li>
<Link
to="/kereso"
className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition"
>
Legközelebbi mosdó
</Link>
</li>
<li className="hidden md:block border-l-2 border-amber-800 h-10"></li>
<li>
<Link
to="/bejelentkezes"
className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition"
>
Bejelentkezés
</Link>
</li>
<li>
<Link
to="/regisztracio"
className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition"
>
Regisztráció
</Link>
</li>
</ul>
</nav>
);
<ul
className={`md:flex md:space-x-6 md:items-center text-lg ${
menuOpen
? "absolute top-16 left-0 w-full bg-yellow-200 flex flex-col items-center space-y-4 py-4 shadow-lg"
: "hidden md:flex"
}`}
>
<li>
<Link to="/kereso" className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition">
Legközelebbi mosdó
</Link>
</li>
<li className="hidden md:block border-l-2 border-amber-800 h-10"></li>
<li>
<Link to="/bejelentkezes" className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition">
Bejelentkezés
</Link>
</li>
<li>
<Link to="/regisztracio" className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition">
Regisztráció
</Link>
</li>
</ul>
</nav>
);
} else {
return (
<nav className="bg-yellow-200 text-amber-900 py-4 px-6 flex justify-between items-center shadow-md sticky top-0 w-full z-50">
<Link to="/" className="text-2xl font-bold flex items-center">
<img src="/Logo.png" alt="PeePal Logo" className="h-14 ml-2 hover:h-15" />
</Link>
<button
className="md:hidden text-amber-900"
onClick={() => setMenuOpen(!menuOpen)}
>
{menuOpen ? <X size={32} /> : <Menu size={32} />}
</button>
<ul
className={`md:flex md:space-x-6 md:items-center text-lg ${
menuOpen
? "absolute top-16 left-0 w-full bg-yellow-200 flex flex-col items-center space-y-4 py-4 shadow-lg"
: "hidden md:flex"
}`}
>
<li>
<Link to="/kereso" className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition">
Legközelebbi mosdó
</Link>
</li>
<li className="hidden md:block border-l-2 border-amber-800 h-10"></li>
<li>
<button
onClick={() => {
logout();
setMenuOpen(false);
}}
className="hover:bg-yellow-500 px-4 py-2 rounded-lg transition"
>
Kijelentkezés
</button>
</li>
</ul>
</nav>
);
}
}