Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/components/form/errorMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const ErrorMessage = ({message}) => {
return (
<div className="usermessage">
{message && <p>{message}</p>}
</div>
)

}

export default ErrorMessage

182 changes: 115 additions & 67 deletions src/context/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,85 +5,133 @@ import Modal from "../components/modal";
import Navigation from "../components/navigation";
import useAuth from "../hooks/useAuth";
import { createProfile, login, register } from "../service/apiClient";
import jwt_decode from "jwt-decode"

const AuthContext = createContext()
import jwt_decode from "jwt-decode";
import ERR from "../../src/utils/errors.js";
const AuthContext = createContext();

const AuthProvider = ({ children }) => {
const navigate = useNavigate()
const location = useLocation()
const [token, setToken] = useState(null)

useEffect(() => {
const storedToken = localStorage.getItem('token')

if (storedToken) {
setToken(storedToken)
navigate(location.state?.from?.pathname || "/")
}
}, [location.state?.from?.pathname, navigate])

const handleLogin = async (email, password) => {
const res = await login(email, password)

if (!res.data.token) {
return navigate("/login")
}

localStorage.setItem('token', res.data.token)

setToken(res.token)
navigate(location.state?.from?.pathname || "/")
};

const handleLogout = () => {
localStorage.removeItem('token')
setToken(null)
};
const navigate = useNavigate();
const location = useLocation();
const [token, setToken] = useState(null);

const handleRegister = async (email, password) => {
const res = await register(email, password)
setToken(res.data.token)
useEffect(() => {
const storedToken = localStorage.getItem("token");

navigate("/verification")
if (storedToken) {
setToken(storedToken);
navigate(location.state?.from?.pathname || "/");
}
}, [location.state?.from?.pathname, navigate]);

const handleLogin = async (email, password, setErrors) => {
try {
const validatedEmail = validationEmail(email);
if (!validatedEmail) {
throw new Error(ERR.EMAIL_ERROR_MESSAGE);
}

const validatedPassword = validationPassword(password);
if (!validatedPassword) {
throw new Error(ERR.PASSWORD_REQUIRMENTS);
}

const res = await login(email, password);
if (!res.status) {
throw new Error(res.error.message);
}
if (!res.data.token) {
return navigate("/login");
}

localStorage.setItem("token", res.data.token);

setToken(res.data.token);
navigate(location.state?.from?.pathname || "/");
} catch (error) {
setErrors(error.message);
}
};

const handleLogout = () => {
localStorage.removeItem("token");
setToken(null);
};

const handleRegister = async (email, password, setErrors) => {
try {
const validatedEmail = validationEmail(email);
if (!validatedEmail) {
throw new Error(ERR.EMAIL_ERROR_MESSAGE);
}
const validatedPassword = validationPassword(password);
if (!validatedPassword) {
throw new Error(ERR.PASSWORD_REQUIRMENTS);
}
const res = await register(email, password, setErrors);
if (!res.status) {
throw new Error(res.error.message);
}
setToken(res.data.token);
navigate("/verification");
} catch (error) {
setErrors(error.message);
}
};

const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => {
const { userId } = jwt_decode(token)
const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => {
const { userId } = jwt_decode(token);

await createProfile(userId, firstName, lastName, githubUrl, bio)
await createProfile(userId, firstName, lastName, githubUrl, bio);

localStorage.setItem('token', token)
navigate('/')
}
navigate("/");
};

const value = {
token,
onLogin: handleLogin,
onLogout: handleLogout,
onRegister: handleRegister,
onCreateProfile: handleCreateProfile
};
const value = {
token,
onLogin: handleLogin,
onLogout: handleLogout,
onRegister: handleRegister,
onCreateProfile: handleCreateProfile,
};

return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

const ProtectedRoute = ({ children }) => {
const { token } = useAuth()
const location = useLocation()

if (!token) {
return <Navigate to={"/login"} replace state={{ from: location }} />
}

return (
<div className="container">
<Header />
<Navigation />
<Modal />
{children}
</div>
)
const { token } = useAuth();
const location = useLocation();

if (!token) {
return <Navigate to={"/login"} replace state={{ from: location }} />;
}

return (
<div className="container">
<Header />
<Navigation />
<Modal />
{children}
</div>
);
};
function validationEmail(email) {
const emailPattern = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/;

return !email || !emailPattern.test(email) ? false : true;
}

function validationPassword(password) {
const minLength = 8;
const hasUppercase = /[A-Z]/.test(password);
const hasNumber = /\d/.test(password);
const hasSpecialCharacter = /[!@#$%^&*(),.?":{}|<>]/.test(password);

return password.length < minLength ||
!hasUppercase ||
!hasNumber ||
!hasSpecialCharacter
? false
: true;
}

export { AuthContext, AuthProvider, ProtectedRoute }
export { AuthContext, AuthProvider, ProtectedRoute };
87 changes: 46 additions & 41 deletions src/pages/login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,55 @@ import TextInput from "../../components/form/textInput";
import useAuth from "../../hooks/useAuth";
import CredentialsCard from "../../components/credentials";
import "./login.css";
import ErrorMessage from "../../components/form/errorMessage";

const Login = () => {
const { onLogin } = useAuth();
const [formData, setFormData] = useState({ email: "", password: "" });
const { onLogin } = useAuth();
const [formData, setFormData] = useState({ email: "", password: "" });
const [errors, setErrors] = useState(null);
const onChange = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
setErrors(null);
};

const onChange = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};

return (
<div className="bg-blue login credentialpage">
<CredentialsCard
title="Login"
socialLinksTitle="Or log in with"
altButtonTitle="Need an account?"
altButtonLink="/register"
altButtonText="Sign up"
>
<div className="login-form">
<form>
<TextInput
value={formData.email}
onChange={onChange}
name="email"
label={"Email *"}
/>
<TextInput
value={formData.password}
onChange={onChange}
name="password"
label={"Password *"}
type={"password"}
/>
</form>
<Button
text="Log in"
onClick={() => onLogin(formData.email, formData.password)}
classes="green width-full"
/>
</div>
</CredentialsCard>
</div>
);
return (
<div className="bg-blue login credentialpage">
<CredentialsCard
title="Login"
socialLinksTitle="Or log in with"
altButtonTitle="Need an account?"
altButtonLink="/register"
altButtonText="Sign up"
>
<div className="login-form">
<form>
<TextInput
value={formData.email}
onChange={onChange}
name="email"
label={"Email *"}
/>
<TextInput
value={formData.password}
onChange={onChange}
name="password"
label={"Password *"}
type={"password"}
/>
<ErrorMessage message={errors} />
</form>
<Button
text="Log in"
onClick={() =>
onLogin(formData.email, formData.password, setErrors)
}
classes="green width-full"
/>
</div>
</CredentialsCard>
</div>
);
};

export default Login;
Loading