diff --git a/backend/src/main/java/org/maires/employee/controller/dto/EmployeeCreationDto.java b/backend/src/main/java/org/maires/employee/controller/dto/EmployeeCreationDto.java index 4bf5538..1ebb3e8 100644 --- a/backend/src/main/java/org/maires/employee/controller/dto/EmployeeCreationDto.java +++ b/backend/src/main/java/org/maires/employee/controller/dto/EmployeeCreationDto.java @@ -23,7 +23,7 @@ public record EmployeeCreationDto( @Size(min = 4, message = "Full name must be >= 4 characters!") @Pattern( regexp = "\\D+", - message = "FullName must not contain digit!" + message = "Full name must not contain digit!" ) String fullName, diff --git a/frontend/public/forgotPassword.svg b/frontend/public/forgotPassword.svg new file mode 100644 index 0000000..6458514 --- /dev/null +++ b/frontend/public/forgotPassword.svg @@ -0,0 +1,1680 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/forgotPasswordAvatar.svg b/frontend/public/forgotPasswordAvatar.svg new file mode 100644 index 0000000..1cf0d8e --- /dev/null +++ b/frontend/public/forgotPasswordAvatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/login.svg b/frontend/public/login.svg new file mode 100644 index 0000000..c771b1d --- /dev/null +++ b/frontend/public/login.svg @@ -0,0 +1,3028 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/loginAvatar.svg b/frontend/public/loginAvatar.svg new file mode 100644 index 0000000..b6ef5dd --- /dev/null +++ b/frontend/public/loginAvatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/logo.svg b/frontend/public/logo.svg new file mode 100644 index 0000000..41c2c67 --- /dev/null +++ b/frontend/public/logo.svg @@ -0,0 +1 @@ + employee_group_solid \ No newline at end of file diff --git a/frontend/public/register.svg b/frontend/public/register.svg new file mode 100644 index 0000000..c464b02 --- /dev/null +++ b/frontend/public/register.svg @@ -0,0 +1,4792 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/registerAvatar.svg b/frontend/public/registerAvatar.svg new file mode 100644 index 0000000..0b00552 --- /dev/null +++ b/frontend/public/registerAvatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/app/dashboard-employees/page.tsx b/frontend/src/app/dashboard-employees/page.tsx index 91fe327..49548ea 100644 --- a/frontend/src/app/dashboard-employees/page.tsx +++ b/frontend/src/app/dashboard-employees/page.tsx @@ -22,7 +22,7 @@ function DashboardEmployees() { return ( -
+
{isModalCreateEmployeeOpen && } diff --git a/frontend/src/app/dashboard-users/page.tsx b/frontend/src/app/dashboard-users/page.tsx index 16deb7b..0e8b86d 100644 --- a/frontend/src/app/dashboard-users/page.tsx +++ b/frontend/src/app/dashboard-users/page.tsx @@ -21,7 +21,7 @@ function DashboardUsers() { if (isAuthenticated === null || !isAuthenticated) return null; return ( -
+
{isModalCreateUserOpen && } diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 2aa1c1c..a649690 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -8,6 +8,10 @@ @apply font-roboto; } +body { + @apply bg-light-neutral-150 +} + td, th { @apply p-spacing-little-08 } diff --git a/frontend/src/app/reset-password/page.tsx b/frontend/src/app/reset-password/page.tsx index 84b1957..1226a69 100644 --- a/frontend/src/app/reset-password/page.tsx +++ b/frontend/src/app/reset-password/page.tsx @@ -3,12 +3,16 @@ 'use client'; import React, { useState } from 'react'; -import { useSearchParams } from 'next/navigation'; +import { useRouter, useSearchParams } from 'next/navigation'; +import Swal from 'sweetalert2'; +import Button from '../../components/buttons/Button'; function PasswordResetPage() { const [newPassword, setNewPassword] = useState(''); + const [loading, setLoading] = useState(false); const searchParams = useSearchParams(); const token = searchParams.get('token'); + const router = useRouter(); const handlePasswordChange = (e: React.ChangeEvent) => { setNewPassword(e.target.value); @@ -16,60 +20,77 @@ function PasswordResetPage() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); + setLoading(true); - const response = await fetch(`http://localhost:8080/password/reset?token=${token}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ newPassword }), - }); - - if (response.ok) { - alert('Password has been changed!'); - } else { - const errorData = await response.json(); - alert(`Failed to reset password: ${errorData.message}`); + try { + const response = await fetch(`http://localhost:8080/password/reset?token=${token}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ newPassword }), + }); + + if (response.ok) { + const Toast = Swal.mixin({ + toast: true, + position: 'top-end', + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + didOpen: (toast) => { + toast.onmouseenter = Swal.stopTimer; + toast.onmouseleave = Swal.resumeTimer; + }, + }); + + Toast.fire({ + icon: 'success', + title: 'Changed successfully', + }).then(() => router.replace('/')); + } + } catch (error) { + console.error('Error fetching:', error); + return null; + } finally { + setLoading(false); } }; return (
+
+

Reset Password

- + +
+
); } diff --git a/frontend/src/components/FormLogin.tsx b/frontend/src/components/FormLogin.tsx index 9e0ed36..357c47f 100644 --- a/frontend/src/components/FormLogin.tsx +++ b/frontend/src/components/FormLogin.tsx @@ -6,6 +6,7 @@ import React, { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useDispatch, useSelector } from 'react-redux'; import Swal from 'sweetalert2'; +import Image from 'next/image'; import AuthFooter from './AuthFooter'; import Button from './buttons/Button'; import Divider from './Divider'; @@ -15,6 +16,8 @@ import ModalChangePassword from './modal/ModalChangePassword'; import { AppDispatch, RootState } from '../store'; import auth from '../services/auth'; import { clearError } from '../store/authSlice'; +import login from '../../public/login.svg'; +import loginAvatar from '../../public/loginAvatar.svg'; function FormLogin() { const dispatch = useDispatch(); @@ -78,7 +81,15 @@ function FormLogin() { return ( - <> +
+ +
+ Logo +
{isModalPasswordChangeOpen && } @@ -87,11 +98,21 @@ function FormLogin() { onSubmit={ handleSubmit } > -

- Welcome back -

+
+

+ Welcome back +

+ + Login avatar + +
- +
); } diff --git a/frontend/src/components/FormRegister.tsx b/frontend/src/components/FormRegister.tsx index f9df308..546a088 100644 --- a/frontend/src/components/FormRegister.tsx +++ b/frontend/src/components/FormRegister.tsx @@ -5,6 +5,8 @@ import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useDispatch, useSelector } from 'react-redux'; +import Swal from 'sweetalert2'; +import Image from 'next/image'; import Input from './Input'; import Button from './buttons/Button'; import Divider from './Divider'; @@ -12,10 +14,12 @@ import AuthFooter from './AuthFooter'; import { AppDispatch, RootState } from '../store'; import register from '../services/register'; import { clearError } from '../store/registerSlice'; +import registerIcon from '../../public/register.svg'; +import registerAvatar from '../../public/registerAvatar.svg'; function FormRegister() { const dispatch = useDispatch(); - const { loading, user, error } = useSelector((state: RootState) => state.register); + const { loading, error } = useSelector((state: RootState) => state.register); const [formData, setFormaData] = useState({ photo: '', fullName: '', username: '', email: '', password: '', role: 'user' }); const [confirmPassword, setConfirmPassword] = useState(''); const router = useRouter(); @@ -24,10 +28,6 @@ function FormRegister() { dispatch(clearError()); }, [dispatch, router]); - useEffect(() => { - if (user.id) { router.push('/'); } - }, [user, router]); - const handleInputChange = (event: React.ChangeEvent) => { const { name, value } = event.target; setFormaData((prevData) => ({ ...prevData, [name]: value })); @@ -42,98 +42,145 @@ function FormRegister() { const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); if (isFormValid) { - dispatch(register(formData)); + const resultAction = await dispatch(register(formData)); + + if (register.fulfilled.match(resultAction)) { + const Toast = Swal.mixin({ + toast: true, + position: 'top-end', + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + didOpen: (toast) => { + toast.onmouseenter = Swal.stopTimer; + toast.onmouseleave = Swal.resumeTimer; + }, + }); + + Toast.fire({ + icon: 'success', + title: 'Registered successfully', + }).then(() => { + router.replace('/'); + }); + } } }; return ( -
-

+ +
+ Logo Register +
+ + - Register -

- - - - - - - - - - - - - -
+ ); } diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index e23eb40..0723b3d 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -5,12 +5,14 @@ import { useRouter } from 'next/navigation'; import { useDispatch, useSelector } from 'react-redux'; import { useEffect, useState } from 'react'; +import Image from 'next/image'; import { logout } from '../store/authSlice'; import { AppDispatch, RootState } from '../store'; import useToken from '../hooks/useToken'; import getTokenSubject from '../utils/getTokenSubject'; import findLoggedUser from '../services/findLoggedUser'; import Loading from './Loading'; +import logo from '../../public/logo.svg'; function Header() { const dispatch = useDispatch(); @@ -41,9 +43,13 @@ function Header() { if (!token) return null; return ( -
+
-

ES.

+
+ + Logo + +
+ + {handleErrosInputFields(error, id, placeholder)} +
+ ); } diff --git a/frontend/src/components/RowDetail.tsx b/frontend/src/components/RowDetail.tsx index bffb28b..30fcb38 100644 --- a/frontend/src/components/RowDetail.tsx +++ b/frontend/src/components/RowDetail.tsx @@ -7,22 +7,24 @@ type RowDetailProps = { employeeData: string, header: string, breakpoint: string, - showDetails: string - handleSort: () => void + showDetails: string, + handleSort: () => void, + index: number }; -function RowDetail({ employeeData, header, breakpoint, showDetails, handleSort }:RowDetailProps) { +function RowDetail({ employeeData, header, breakpoint, showDetails, handleSort, index }:RowDetailProps) { const windowWidth = useWindowWidth(); + const isOdd = index % 2 === 0; return ( - + -
+

@@ -36,7 +38,7 @@ function RowDetail({ employeeData, header, breakpoint, showDetails, handleSort }

-

+

{employeeData} diff --git a/frontend/src/components/modal/ModalChangePassword.tsx b/frontend/src/components/modal/ModalChangePassword.tsx index 0485153..3053d17 100644 --- a/frontend/src/components/modal/ModalChangePassword.tsx +++ b/frontend/src/components/modal/ModalChangePassword.tsx @@ -5,12 +5,15 @@ import { useEffect, useState } from 'react'; import { FaTimes } from 'react-icons/fa'; import { useDispatch, useSelector } from 'react-redux'; +import Image from 'next/image'; +import Swal from 'sweetalert2'; import Input from '../Input'; import Button from '../buttons/Button'; import { AppDispatch, RootState } from '../../store'; import passwordChange from '../../services/passwordChange'; import { clearError } from '../../store/passwordChangeSlice'; import { closeModalPasswordChange } from '../../store/modalPasswordChangeSlice'; +import forgetPasswordAvatar from '../../../public/forgotPasswordAvatar.svg'; function ModalChangePassword() { const dispatch = useDispatch(); @@ -50,8 +53,30 @@ function ModalChangePassword() { const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); - dispatch(clearError()); - dispatch(passwordChange(formData.email)); + + const resultAction = await dispatch(passwordChange(formData.email)); + + if (passwordChange.fulfilled.match(resultAction)) { + const Toast = Swal.mixin({ + toast: true, + position: 'top-end', + showConfirmButton: false, + timer: 3000, + timerProgressBar: true, + didOpen: (toast) => { + toast.onmouseenter = Swal.stopTimer; + toast.onmouseleave = Swal.resumeTimer; + }, + }); + + Toast.fire({ + icon: 'success', + title: 'Email sent successfully', + }).then(() => { + dispatch(closeModalPasswordChange()); + dispatch(clearError()); + }); + } }; const handleClickInside = (event: React.MouseEvent) => { @@ -87,10 +112,18 @@ function ModalChangePassword() { className="font-bold text-center text-2xl text-light-neutral-900" > - Please enter your email + Forgot password?

+ Forgot password avatar +