diff --git a/frontend/src/components/auth/Login.vue b/frontend/src/components/auth/Login.vue index 1c4f77ed6350ccddba5bac961e848a15a30d30a8..9615eac1ca11418878e966d40c7b21133d817605 100644 --- a/frontend/src/components/auth/Login.vue +++ b/frontend/src/components/auth/Login.vue @@ -1,5 +1,5 @@ <template> - <div class="login-container"> + <div class="global-container"> <h1 class="title">Bejelentkezés</h1> <div v-if="registrationSuccess" class="alert alert-success"> Regisztráció sikeres! Most már bejelentkezhetsz. @@ -19,7 +19,7 @@ <button type="submit">Bejelentkezés</button> </form> <p>Még nem vagy regisztrálva?</p> - <router-link to="/register" tag="button" class="register-button">Regisztrálás</router-link> + <router-link to="/register" tag="button" class="button">Regisztrálás</router-link> </div> </template> @@ -42,7 +42,13 @@ export default { if (response.status === 200) { this.$store.commit('setToken', response.data.token); - this.$router.push('/'); + + const redirect = this.$route.query.redirect; + if (redirect) { + this.$router.push(redirect); + } else { + this.$router.push('/'); + } } } catch (error) { this.error = 'Helytelen felhasználónév vagy jelszó'; @@ -58,46 +64,4 @@ export default { }; }, }; -</script> - -<style lang="postcss"> -.login-container { - @apply flex flex-col items-center justify-center min-h-screen bg-blue-200; -} - -.input-group { - @apply mb-4; -} - -label { - @apply block mb-2 text-sm font-bold text-gray-700; -} - -input { - @apply w-full px-3 py-2 text-sm leading-tight text-gray-700 border rounded shadow appearance-none; -} - -button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none; -} - -p { - @apply mt-10; -} - -.register-button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none mb-8; -} - -.alert-success { - @apply bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4; -} - -.alert-error { - @apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4; -} - -.title { - @apply text-4xl font-bold mb-8 text-center p-4; -} -</style> \ No newline at end of file +</script> \ No newline at end of file diff --git a/frontend/src/components/auth/Register.vue b/frontend/src/components/auth/Register.vue index 1ba6333fda16b15c374752466479cce39c740e34..f203a741485b658ea69cfb0aa5fc6b9b69d82bb4 100644 --- a/frontend/src/components/auth/Register.vue +++ b/frontend/src/components/auth/Register.vue @@ -1,5 +1,5 @@ <template> - <div class="login-container"> + <div class="global-container"> <h1 class="title">Regisztráció</h1> <div v-if="errorMessage" class="alert alert-error"> {{ errorMessage }} @@ -40,21 +40,16 @@ export default { }; const validateForm = () => { - const usernameRegex = /^[a-zA-Z0-9]+$/; - const minLength = 5; + const usernameRegex = /^\w{5,20}$/; // username can contain numbers, upper and lowercase characters + const passwordRegex = /^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,20}$/; // password must contain at least one uppercase letter and one digit if (!username.value) { errorMessage.value = 'Felhasználónév megadása kötelező'; return false; } - if (username.value.length < minLength) { - errorMessage.value = 'A felhasználónév legalább 5 karakter hosszú kell legyen'; - return false; - } - if (!username.value.match(usernameRegex)) { - errorMessage.value = 'Felhasználónév csak betűket és számokat tartalmazhat'; + errorMessage.value = 'Érvénytelen felhasználónév. A felhasználónévnek legalább 5 és legfeljebb 20 karakter hosszúnak kell lennie.'; return false; } @@ -63,12 +58,12 @@ export default { return false; } - if (password.value.length < minLength) { - errorMessage.value = 'A jelszó legalább 5 karakter hosszú kell legyen'; + if (!password.value.match(passwordRegex)) { + errorMessage.value = 'Érvénytelen jelszó. A jelszónak legalább 8 és legfeljebb 20 karakter hosszúnak kell lennie, és tartalmaznia kell legalább egy nagybetűt és egy számot.'; return false; } - errorMessage.value = ''; // Clear the error message if all fields are valid + errorMessage.value = ''; return true; }; @@ -90,9 +85,9 @@ export default { // Display error message if (error.response && error.response.data) { - errorMessage.value = 'Registration failed: ' + error.response.data; + errorMessage.value = 'Regisztráció sikertelen: ' + error.response.data; } else { - errorMessage.value = 'Registration failed: ' + error.message; + errorMessage.value = 'Regisztráció sikertelen: ' + error.message; } } }; @@ -105,34 +100,4 @@ export default { }; }, }; -</script> - -<style lang="postcss"> -.login-container { - @apply flex flex-col items-center justify-center min-h-screen bg-blue-200; -} - -.input-group { - @apply mb-4; -} - -label { - @apply block mb-2 text-sm font-bold text-gray-700; -} - -input { - @apply w-full px-3 py-2 text-sm leading-tight text-gray-700 border rounded shadow appearance-none; -} - -button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none mb-8; -} - -.title { - @apply text-4xl font-bold mb-8 text-center p-4; -} - -.alert-error { - @apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4; -} -</style> \ No newline at end of file +</script> \ No newline at end of file diff --git a/frontend/src/components/common/Footer.vue b/frontend/src/components/common/Footer.vue index 73e15f916d4cd2f492851ffe108704271f679d61..8f6c1a9aeadbc165465e8e457565b152b43d84c3 100644 --- a/frontend/src/components/common/Footer.vue +++ b/frontend/src/components/common/Footer.vue @@ -8,8 +8,4 @@ export default { name: 'Footer' } -</script> - -<style scoped lang="postcss"> -/* Add your styles here */ -</style> \ No newline at end of file +</script> \ No newline at end of file diff --git a/frontend/src/components/common/Header.vue b/frontend/src/components/common/Header.vue index 869c0e94361b2572a7d074a466211d7c89913f84..de22f73e58385bab6fe03c204470ded30255483d 100644 --- a/frontend/src/components/common/Header.vue +++ b/frontend/src/components/common/Header.vue @@ -1,6 +1,6 @@ <template> <nav> - <h1 class="title">Vau-Vau Alapítvány</h1> + <router-link to="/" class="title">Vau-Vau Alapítvány</router-link> <ul> <li><router-link to="/" class="nav-link" active-class="active-link">Főoldal</router-link></li> <li><router-link to="/dogs" class="nav-link" active-class="active-link">Kutyák</router-link></li> diff --git a/frontend/src/components/dogs/AddDog.vue b/frontend/src/components/dogs/AddDog.vue index ec553fbea7442716a9c6db715dde4c3f82f740cc..fb0e9720e171f214e66a18a8d3ac1e1a8dd7c206 100644 --- a/frontend/src/components/dogs/AddDog.vue +++ b/frontend/src/components/dogs/AddDog.vue @@ -1,5 +1,5 @@ <template> - <div class="edit-dog-container"> + <div class="global-container"> <h1>Kutya hozzáadása</h1> <div v-if="errorMessage" class="alert alert-error"> {{ errorMessage }} @@ -75,26 +75,4 @@ export default { }, }, }; -</script> - -<style lang="postcss"> -.edit-dog-container { - @apply flex flex-col items-center justify-center min-h-screen bg-blue-200; -} - -.input-group { - @apply mb-4; -} - -label { - @apply block mb-2 text-sm font-bold text-gray-700; -} - -input { - @apply w-full px-3 py-2 text-sm leading-tight text-gray-700 border rounded shadow appearance-none; -} - -button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none; -} -</style> \ No newline at end of file +</script> \ No newline at end of file diff --git a/frontend/src/components/dogs/AllDogs.vue b/frontend/src/components/dogs/AllDogs.vue index 149f325629698fab816494e7679419cceb214969..a4e258b31c13f7c9bce143ed1597ec49cede1a2b 100644 --- a/frontend/src/components/dogs/AllDogs.vue +++ b/frontend/src/components/dogs/AllDogs.vue @@ -1,6 +1,6 @@ <template> - <div class="dog-list-container"> - <router-link to="/add-dog" class="add-button">Új kutya hozzáadása</router-link> + <div class="global-container"> + <router-link to="/add-dog" class="button">Új kutya hozzáadása</router-link> <div v-if="!loaded"> Betöltés... </div> @@ -71,31 +71,21 @@ export default { </script> <style scoped lang="postcss"> -.dog-list-container { - @apply flex flex-col justify-center items-center flex-grow bg-blue-200; -} .dog-item-container { @apply flex flex-wrap justify-around p-4 rounded; } .dog-item { - @apply flex flex-col items-center bg-white m-4 p-4 rounded shadow w-1/4; + @apply flex flex-col items-center bg-white m-4 p-4 rounded shadow w-1/4 min-w-64 min-h-64; } .dog-image { - @apply w-full h-64 object-cover mb-4 rounded; + @apply w-full h-64 object-cover mb-4 rounded min-w-64 min-h-64; } .dog-name { @apply text-lg font-bold; } -.alert-error { - @apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4; -} - -.add-button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none mb-8; -} </style> \ No newline at end of file diff --git a/frontend/src/components/dogs/EditDog.vue b/frontend/src/components/dogs/EditDog.vue index 2a907e51e5a4baf16e8c4b2ad16b7f6a9a80a592..7d6f757806430712bde53ebaf1bed07e48b24bc4 100644 --- a/frontend/src/components/dogs/EditDog.vue +++ b/frontend/src/components/dogs/EditDog.vue @@ -1,5 +1,5 @@ <template> - <div class="edit-dog-container"> + <div class="global-container"> <h1>Kutya szerkesztése</h1> <div v-if="errorMessage" class="alert alert-error"> {{ errorMessage }} diff --git a/frontend/src/components/dogs/SingleDog.vue b/frontend/src/components/dogs/SingleDog.vue index a4508b008eba95953bd63835d9bbbf85da65a0a1..002250a876463667adb37acca823628394ff29f7 100644 --- a/frontend/src/components/dogs/SingleDog.vue +++ b/frontend/src/components/dogs/SingleDog.vue @@ -1,11 +1,11 @@ <template> - <div v-if="dog" class="single-dog flex flex-col items-center bg-gray-100 p-4 rounded shadow"> + <div v-if="dog" class="global-container"> <h1 class="text-2xl font-bold mb-4">{{ dog.name }}</h1> <img :src="dog.picture" :alt="`${dog.name} képe`" class="w-64 h-64 object-cover mb-4 rounded shadow"/> <p class="text-lg mb-2"><strong>Kor:</strong> {{ dog.age }}</p> <p class="text-lg"><strong>Faj:</strong> {{ dog.breed }}</p> - <router-link :to="`/edit-dog/${dog.id}`" tag="button" class="edit-button">Szerkesztés</router-link> - <button @click="deleteDog" class="delete-button">Törlés</button> + <router-link :to="`/edit-dog/${dog.id}`" tag="button" class="button">Szerkesztés</router-link> + <button @click="deleteDog" class="button delete-button ">Törlés</button> </div> <div v-else>Betöltés...</div> </template> @@ -36,8 +36,17 @@ export default { const config = { headers: { Authorization: `Bearer ${this.token}` }, }; - await axios.delete(apiURL + `/dogs/${this.$route.params.id}`, config); - this.$router.push(`/dogs`); + try { + await axios.delete(apiURL + `/dogs/${this.$route.params.id}`, config); + this.$router.push(`/dogs`); + } catch (error) { + if (error.response && error.response.status === 401) { + this.$router.push('/login'); + } else { + console.error(error); + // Handle other types of errors + } + } } }, }, @@ -45,27 +54,11 @@ export default { </script> <style scoped lang="postcss"> -.single-dog { - @apply flex flex-col items-center bg-blue-200 p-4 rounded shadow; -} - -h1 { - @apply text-2xl font-bold mb-4; -} - img { @apply w-64 h-64 object-cover mb-4 rounded shadow bg-white; } -p { - @apply text-lg mb-2; -} - -.edit-button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none; -} - .delete-button { - @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-red-500 rounded hover:bg-red-700 focus:outline-none; + @apply bg-red-500 hover:bg-red-700; } </style> \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css index ff55ea7e29918104668c52eedbbba3f62f8d86d7..4a6b44dafe5000dda50f5a109be69293c7424e9f 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -50,123 +50,156 @@ p { @apply mb-4; } -@media (max-width: 600px) { - nav ul { - @apply flex flex-col space-y-4 items-center; - } - - nav ul li { - @apply block; - } +.global-container { + @apply flex flex-col items-center justify-center min-h-screen bg-blue-200; +} - nav ul li a { - @apply text-lg; - } +.input-group { + @apply mb-4; +} - nav h1 { - @apply text-2xl; - } +.label { + @apply block mb-2 text-sm font-bold text-gray-700; +} - .hero { - @apply py-12; - } +.input { + @apply w-full px-3 py-2 text-sm leading-tight text-gray-700 border rounded shadow appearance-none; +} - .features { - @apply py-12; - } +.button { + @apply px-4 py-2 mt-4 text-sm font-medium text-white bg-blue-500 rounded hover:bg-blue-700 focus:outline-none mb-8; +} - .cta { - @apply py-12; - } +.title { + @apply text-4xl font-bold mb-8 text-center p-4; +} - footer { - @apply py-4; - } +.alert-error { + @apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4; +} - footer p { - @apply text-sm; - } +.global-container label, +.global-container input, +.global-container button { + @apply text-lg; +} - h2 { - @apply text-xl; - } +button { + @apply text-lg px-2 py-1 mt-4 mb-4 rounded transition-colors duration-150 ease-in-out; +} - p { - @apply text-sm; - } +.button { + @apply text-lg px-2 py-1 mt-4 mb-4 bg-blue-500 text-white rounded transition-colors duration-150 ease-in-out; +} - .login-container { - @apply p-4; - } +.button:hover { + @apply bg-blue-700; +} - .login-container label, - .login-container input, - .login-container button { - @apply text-xs; - } +.alert-success { + @apply bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4; } -/* Styles for extra small devices (phones, 600px and below) */ -@media (max-width: 600px) { - body { - @apply text-sm; - } +.alert-error { + @apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4; +} - .login-container label, - .login-container input, - .login-container button { - @apply text-sm; - } +.title { + @apply text-lg font-bold mb-4; } -/* Styles for small devices (portrait tablets and large phones, 600px and up) */ @media (min-width: 600px) { - body { + body { @apply text-base; } - .login-container label, - .login-container input, - .login-container button { + .global-container { + @apply p-6; + } + + .global-container label, + .global-container input, + .global-container button { @apply text-base; } + + button { + @apply text-base px-3 py-2 mt-6 mb-6; + } + + .title { + @apply text-xl font-bold mb-6; + } } -/* Styles for medium devices (landscape tablets, 768px and up) */ @media (min-width: 768px) { - body { + body { @apply text-lg; } - .login-container label, - .login-container input, - .login-container button { + .global-container { + @apply p-8; + } + + .global-container label, + .global-container input, + .global-container button { @apply text-lg; } + + button { + @apply text-lg px-4 py-2 mt-8 mb-8; + } + + .title { + @apply text-2xl font-bold mb-8; + } } -/* Styles for large devices (laptops/desktops, 992px and up) */ @media (min-width: 992px) { - body { + body { @apply text-xl; } - .login-container label, - .login-container input, - .login-container button { + .global-container { + @apply p-10; + } + + .global-container label, + .global-container input, + .global-container button { @apply text-xl; } + + button { + @apply text-xl px-5 py-3 mt-10 mb-10; + } + + .title { + @apply text-3xl font-bold mb-10; + } } -/* Styles for extra large devices (large laptops and desktops, 1200px and up) */ @media (min-width: 1200px) { - body { + body { @apply text-2xl; } - .login-container label, - .login-container input, - .login-container button { + .global-container { + @apply p-12; + } + + .global-container label, + .global-container input, + .global-container button { @apply text-2xl; } -} \ No newline at end of file + + button { + @apply text-2xl px-6 py-4 mt-12 mb-12; + } + + .title { + @apply text-4xl font-bold mb-12; + } +} diff --git a/frontend/src/main.js b/frontend/src/main.js index 62597161e4b9434938c5f5fdb061a3f9e272a405..d057994cdc9839305099e87e0f5d4a47c404cfa0 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -21,7 +21,7 @@ const routes = [ {path: '/faq', component: FAQ}, {path: '/dog/:id', name: 'SingleDog', component: SingleDog}, {path: '/edit-dog/:id', name: 'EditDog', component: EditDog, meta: {requiresAuth: true}}, - {path: '/login', component: Login}, + {path: '/login', component: Login, name: 'Login'}, {path: '/register', component: Register}, {path: '/add-dog', name: 'AddDog', component: AddDog, meta: {requiresAuth: true}}, {path: '/:pathMatch(.*)*', redirect: '/'} @@ -33,11 +33,18 @@ const router = createRouter({ }) router.beforeEach((to, from, next) => { - if (to.name === 'edit' && !store.state.token) { - next({ name: 'login' }) + if (to.meta.requiresAuth) { + store.dispatch('checkAuthenticationStatus') + .then(isAuthenticated => { + if (!isAuthenticated) { + next({ name: 'Login', query: { redirect: to.fullPath } }); + } else { + next(); + } + }); } else { - next() + next(); } -}) +}); createApp(App).use(router).use(store).mount('#app'); \ No newline at end of file diff --git a/frontend/src/store.js b/frontend/src/store.js index 239cfb918224b3d956ee87b01fcf92fb435fa9d8..547800a5913636fbab4eb9ef36db989a5c91197e 100644 --- a/frontend/src/store.js +++ b/frontend/src/store.js @@ -23,4 +23,12 @@ export default createStore({ state.registrationSuccess = success; } }, + getters: { + isAuthenticated: state => !!state.token, + }, + actions: { + checkAuthenticationStatus: ({ getters }) => { + return Promise.resolve(getters.isAuthenticated); + }, + }, }); \ No newline at end of file