277 lines
8.5 KiB
JavaScript
277 lines
8.5 KiB
JavaScript
import { useState } from "react";
|
|
import {
|
|
Box,
|
|
Typography,
|
|
Button,
|
|
TextField,
|
|
useTheme,
|
|
useMediaQuery,
|
|
} from "@mui/material";
|
|
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
|
import { Formik } from "formik";
|
|
import * as yup from "yup";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { useDispatch } from "react-redux";
|
|
import { setLogin } from "state";
|
|
import Dropzone from "react-dropzone";
|
|
import FlexBetween from "components/FlexBetween";
|
|
|
|
const registerSchema = yup.object().shape({
|
|
firstName: yup.string().required("First name is required"),
|
|
lastName: yup.string().required("Last name is required"),
|
|
email: yup.string().email("Invalid email").required("Email is required"),
|
|
password: yup.string().required("Password is required"),
|
|
location: yup.string(),
|
|
description: yup.string(),
|
|
profilePicture: yup.string(),
|
|
});
|
|
|
|
const loginSchema = yup.object().shape({
|
|
email: yup.string().email("Invalid email").required("Email is required"),
|
|
password: yup.string().required("Password is required"),
|
|
});
|
|
|
|
const initialRegisterValues = {
|
|
firstName: "",
|
|
lastName: "",
|
|
email: "",
|
|
password: "",
|
|
location: "",
|
|
description: "",
|
|
profilePicture: "",
|
|
};
|
|
|
|
const initialLoginValues = {
|
|
email: "",
|
|
password: "",
|
|
};
|
|
|
|
const Form = () => {
|
|
const [pageType, setPageType] = useState("login");
|
|
const { palette } = useTheme();
|
|
const dispatch = useDispatch();
|
|
const navigate = useNavigate();
|
|
const isNotMobile = useMediaQuery("(min-width: 600px)");
|
|
const isLogin = pageType === "login";
|
|
const isRegister = pageType === "register";
|
|
|
|
const register = async (values, onSubmitProps) => {
|
|
const formData = new FormData();
|
|
for (const key in values) {
|
|
formData.append(key, values[key]);
|
|
}
|
|
formData.append("profilePicturePath", values.profilePicture.name);
|
|
|
|
const savedUserResponse = await fetch(
|
|
"http://localhost:3001/auth/register",
|
|
{
|
|
method: "POST",
|
|
body: formData,
|
|
}
|
|
);
|
|
|
|
const savedUser = await savedUserResponse.json();
|
|
onSubmitProps.resetForm();
|
|
|
|
if (savedUser) {
|
|
setPageType("login");
|
|
}
|
|
};
|
|
|
|
const login = async (values, onSubmitProps) => {
|
|
const loggedInUserResponse = await fetch(
|
|
"http://localhost:3001/auth/login",
|
|
{
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(values),
|
|
}
|
|
);
|
|
|
|
const loggedInUser = await loggedInUserResponse.json();
|
|
onSubmitProps.resetForm();
|
|
|
|
if (loggedInUser) {
|
|
dispatch(setLogin({ user: loggedInUser, token: loggedInUser.token }));
|
|
navigate("/home");
|
|
}
|
|
};
|
|
|
|
const handleFormSubmit = async (values, onSubmitProps) => {
|
|
if (isLogin) {
|
|
await login(values, onSubmitProps);
|
|
}
|
|
if (isRegister) {
|
|
await register(values, onSubmitProps);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Formik
|
|
onSubmit={handleFormSubmit}
|
|
initialValues={isLogin ? initialLoginValues : initialRegisterValues}
|
|
validationSchema={isLogin ? loginSchema : registerSchema}
|
|
>
|
|
{({
|
|
values,
|
|
errors,
|
|
touched,
|
|
handleChange,
|
|
handleBlur,
|
|
handleSubmit,
|
|
setFieldValue,
|
|
resetForm,
|
|
}) => (
|
|
<form onSubmit={handleSubmit}>
|
|
<Box
|
|
display="grid"
|
|
gap="30px"
|
|
gridTemplateColumns="repeat(4,minmax(0, 1fr))"
|
|
sx={{
|
|
"& > div": { gridColumn: isNotMobile ? undefined : "span 4" },
|
|
}}
|
|
>
|
|
{isRegister && (
|
|
<>
|
|
<TextField
|
|
label="First name"
|
|
onBlur={handleBlur}
|
|
onChange={handleChange}
|
|
value={values.firstName}
|
|
name="firstName"
|
|
error={
|
|
Boolean(touched.firstName) && Boolean(errors.firstName)
|
|
}
|
|
helperText={touched.firstName && errors.firstName}
|
|
sx={{ gridColumn: "span 2" }}
|
|
/>
|
|
<TextField
|
|
label="Last name"
|
|
onBlur={handleBlur}
|
|
onChange={handleChange}
|
|
value={values.lastName}
|
|
name="lastName"
|
|
error={Boolean(touched.lastName) && Boolean(errors.lastName)}
|
|
helperText={touched.lastName && errors.lastName}
|
|
sx={{ gridColumn: "span 2" }}
|
|
/>
|
|
<TextField
|
|
label="Location"
|
|
onBlur={handleBlur}
|
|
onChange={handleChange}
|
|
value={values.location}
|
|
name="location"
|
|
error={Boolean(touched.location) && Boolean(errors.location)}
|
|
helperText={touched.location && errors.location}
|
|
sx={{ gridColumn: "span 4" }}
|
|
/>
|
|
<TextField
|
|
label="Description"
|
|
onBlur={handleBlur}
|
|
onChange={handleChange}
|
|
value={values.description}
|
|
name="description"
|
|
error={
|
|
Boolean(touched.description) && Boolean(errors.description)
|
|
}
|
|
helperText={touched.description && errors.description}
|
|
sx={{ gridColumn: "span 4" }}
|
|
/>
|
|
<Box
|
|
gridColumn="span 4"
|
|
border={`1px solid ${palette.neutral.medium}`}
|
|
borderRadius="5px"
|
|
p="1rem"
|
|
>
|
|
<Dropzone
|
|
acceptedFiles=".jpg,.jpeg,.png"
|
|
multiple={false}
|
|
onDrop={(acceptedFiles) => {
|
|
setFieldValue("profilePicture", acceptedFiles[0]);
|
|
}}
|
|
>
|
|
{({ getRootProps, getInputProps }) => (
|
|
<Box
|
|
{...getRootProps()}
|
|
border={`2px dashed ${palette.primary.main}`}
|
|
p="1rem"
|
|
sx={{ "&:hover": { cursor: "pointer" } }}
|
|
>
|
|
<input {...getInputProps()} />
|
|
{!values.profilePicture ? (
|
|
<p>Add your profile photo here</p>
|
|
) : (
|
|
<FlexBetween>
|
|
<Typography>
|
|
{values.profilePicture.name}
|
|
</Typography>
|
|
<EditOutlinedIcon />
|
|
</FlexBetween>
|
|
)}
|
|
</Box>
|
|
)}
|
|
</Dropzone>
|
|
</Box>
|
|
</>
|
|
)}
|
|
<TextField
|
|
label="Email"
|
|
onBlur={handleBlur}
|
|
onChange={handleChange}
|
|
value={values.email}
|
|
name="email"
|
|
error={Boolean(touched.email) && Boolean(errors.email)}
|
|
helperText={touched.email && errors.email}
|
|
sx={{ gridColumn: "span 4" }}
|
|
/>
|
|
<TextField
|
|
label="Password"
|
|
type="password"
|
|
onBlur={handleBlur}
|
|
onChange={handleChange}
|
|
value={values.password}
|
|
name="password"
|
|
error={Boolean(touched.password) && Boolean(errors.password)}
|
|
helperText={touched.password && errors.password}
|
|
sx={{ gridColumn: "span 4" }}
|
|
/>
|
|
</Box>
|
|
{/* Buttons */}
|
|
<Box>
|
|
<Button
|
|
fullWidth
|
|
type="submit"
|
|
sx={{
|
|
m: "2rem 0",
|
|
p: "1rem",
|
|
backgroundColor: palette.primary.main,
|
|
color: palette.background.alt,
|
|
"&:hover": { color: palette.primary.main },
|
|
}}
|
|
>
|
|
{isLogin ? "LOGIN" : "REGISTER"}
|
|
</Button>
|
|
<Typography
|
|
onClick={() => {
|
|
setPageType(isLogin ? "register" : "login");
|
|
resetForm();
|
|
}}
|
|
sx={{
|
|
textDecoration: "underline",
|
|
color: palette.primary.main,
|
|
"&:hover": { cursor: "pointer", color: palette.primary.light },
|
|
}}
|
|
>
|
|
{isLogin
|
|
? "Don't have an account? Register here"
|
|
: "Already have an account? Login here"}
|
|
</Typography>
|
|
</Box>
|
|
</form>
|
|
)}
|
|
</Formik>
|
|
);
|
|
};
|
|
|
|
export default Form;
|