329 lines
10 KiB
JavaScript
329 lines
10 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { useRouter } from "next/router";
|
|
import { setCookie } from "cookies-next";
|
|
import { useSnackbar } from "notistack";
|
|
import Grid from "@mui/material/Grid";
|
|
import LoadingButton from "@mui/lab/LoadingButton";
|
|
import IconButton from "@mui/material/IconButton";
|
|
import { Typography } from "@mui/material";
|
|
import { Box } from "@mui/system";
|
|
import TextField from "@mui/material/TextField";
|
|
import InputAdornment from "@mui/material/InputAdornment";
|
|
import Button from "@mui/material/Button";
|
|
import Visibility from "@mui/icons-material/Visibility";
|
|
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
|
import styles from "./signinform.module.css";
|
|
import Fetcher from "services/Fetcher";
|
|
import { useUserProfile } from "contexts/userProfileContext";
|
|
|
|
const SignInForm = () => {
|
|
const { state, dispatch } = useUserProfile();
|
|
|
|
// Define and initialize state variables
|
|
const [formValues, setFormValues] = useState({
|
|
email: "",
|
|
password: "",
|
|
});
|
|
const [errorHandlers, setErrorHandlers] = useState({
|
|
email: false,
|
|
password: false,
|
|
});
|
|
const [loading, setLoading] = useState(false);
|
|
const [errMsg, setErrMsg] = useState("");
|
|
|
|
// Create instances of external services
|
|
const api = new Fetcher();
|
|
const router = useRouter();
|
|
|
|
// Access the Snackbar notification function
|
|
const { enqueueSnackbar } = useSnackbar();
|
|
|
|
// Handle changes in the input fields
|
|
const handleChange = (event) => {
|
|
setFormValues({ ...formValues, [event.target.name]: event.target.value });
|
|
};
|
|
|
|
// Handle form submission
|
|
const handleSubmit = async (event) => {
|
|
event.preventDefault();
|
|
|
|
const { email, password } = formValues;
|
|
|
|
// Validate the form fields
|
|
if (email === "" && password === "") {
|
|
setErrorHandlers({ ...errorHandlers, email: true, password: true });
|
|
setErrMsg("all fields are required");
|
|
setTimeout(() => {
|
|
setErrorHandlers({ ...errorHandlers, email: false, password: false });
|
|
setErrMsg("");
|
|
}, 2000);
|
|
return;
|
|
} else if (email === "") {
|
|
setErrorHandlers({ ...errorHandlers, email: true });
|
|
setErrMsg("email field is required");
|
|
setTimeout(() => {
|
|
setErrorHandlers({ ...errorHandlers, email: false });
|
|
setErrMsg("");
|
|
}, 2000);
|
|
return;
|
|
} else if (password === "") {
|
|
setErrorHandlers({ ...errorHandlers, password: true });
|
|
setErrMsg("password field is required");
|
|
setTimeout(() => {
|
|
setErrorHandlers({ ...errorHandlers, password: false });
|
|
setErrMsg("");
|
|
}, 2000);
|
|
return;
|
|
}
|
|
|
|
// Initiate the login process
|
|
setLoading(true);
|
|
try {
|
|
// Prepare the login request data
|
|
const data = {
|
|
username: email,
|
|
password,
|
|
};
|
|
|
|
// Send the login request to the server
|
|
const res = await api.login(data);
|
|
|
|
if (res.status === 204 || res.length === 0) {
|
|
// Handle login failure
|
|
enqueueSnackbar("Wrong Credentials", {
|
|
variant: "error",
|
|
});
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
// Store the token in cookies
|
|
// Calculate the expiration time in 24 hours
|
|
const expirationDate = new Date();
|
|
expirationDate.setTime(expirationDate.getTime() + 24 * 60 * 60 * 1000); // 24 hours in milliseconds
|
|
|
|
const cookieOptions = {
|
|
expires: expirationDate,
|
|
httpOnly: true, // Make the cookie accessible only via HTTP (recommended for security)
|
|
};
|
|
|
|
// Set the login token in a cookie
|
|
await setCookie("cmc-token", res.token);
|
|
|
|
const userProfileData = res.profile;
|
|
localStorage.setItem("cmc-profile", JSON.stringify(userProfileData));
|
|
|
|
dispatch({ type: "SET_USER_PROFILE", payload: userProfileData });
|
|
|
|
enqueueSnackbar("Login Successful", {
|
|
variant: "success",
|
|
autoHideDuration: 4000,
|
|
});
|
|
|
|
// Redirect the user to a new page after successful login
|
|
router.push("/");
|
|
|
|
console.log(res);
|
|
} catch (error) {
|
|
// Handle any errors that occur during login
|
|
setLoading(false);
|
|
console.log(error);
|
|
} finally {
|
|
// Ensure that the loading indicator is cleared after a short delay
|
|
setTimeout(() => {
|
|
setLoading(false);
|
|
}, 5000);
|
|
}
|
|
};
|
|
|
|
// Define and initialize the state variable for toggling password visibility
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
|
|
// Toggle password visibility
|
|
const handleTogglePassword = () => {
|
|
setShowPassword(!showPassword);
|
|
};
|
|
|
|
useEffect(() => {
|
|
// Prefetch the dashboard page to optimize navigation
|
|
router.prefetch("/");
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<div className={styles.authenticationBox}>
|
|
<Box
|
|
component="main"
|
|
sx={{
|
|
maxWidth: "510px",
|
|
ml: "auto",
|
|
mr: "auto",
|
|
padding: "50px 0 100px",
|
|
paddingInline: { sm: "10px", lg: "0" },
|
|
zIndex: "999",
|
|
position: "relative",
|
|
}}
|
|
>
|
|
<Grid item xs={12} md={12} lg={12} xl={12}>
|
|
<Box>
|
|
<Box
|
|
display="flex"
|
|
alignItems="center"
|
|
justifyContent="center"
|
|
mb="70px"
|
|
>
|
|
<img
|
|
src="/images/logos/android-chrome-512x512.png"
|
|
alt="logo"
|
|
className={styles.favicon}
|
|
/>
|
|
</Box>
|
|
|
|
<Box component="form" noValidate onSubmit={handleSubmit}>
|
|
<Box
|
|
sx={{
|
|
background: "#fff",
|
|
padding: "30px 20px",
|
|
borderRadius: "10px",
|
|
mb: "20px",
|
|
}}
|
|
className="bg-black"
|
|
>
|
|
<Grid container alignItems="center" spacing={2}>
|
|
<Grid item xs={12}>
|
|
<TextField
|
|
required
|
|
fullWidth
|
|
id="email"
|
|
label={
|
|
errorHandlers.email && errMsg !== ""
|
|
? errMsg
|
|
: "Email Address"
|
|
}
|
|
value={formValues.email}
|
|
onChange={handleChange}
|
|
name="email"
|
|
autoComplete="email"
|
|
InputProps={{
|
|
style: { borderRadius: 8 },
|
|
}}
|
|
sx={textFieldStyles}
|
|
error={errorHandlers.email}
|
|
/>
|
|
</Grid>
|
|
|
|
<Grid item xs={12}>
|
|
<TextField
|
|
required
|
|
fullWidth
|
|
name="password"
|
|
label={
|
|
errorHandlers.password && errMsg !== ""
|
|
? errMsg
|
|
: "Password"
|
|
}
|
|
value={formValues.password}
|
|
type={showPassword ? "text" : "password"}
|
|
id="password"
|
|
autoComplete="new-password"
|
|
onChange={handleChange}
|
|
error={errorHandlers.password}
|
|
InputProps={{
|
|
style: { borderRadius: 8 },
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton
|
|
onClick={handleTogglePassword}
|
|
sx={{
|
|
color: "#4687BA",
|
|
"&:hover": {
|
|
color: "#4687BA",
|
|
},
|
|
}}
|
|
>
|
|
{showPassword ? (
|
|
<VisibilityOff />
|
|
) : (
|
|
<Visibility />
|
|
)}
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
}}
|
|
sx={textFieldStyles}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</Box>
|
|
|
|
<Box sx={{ backgroundColor: "#4687BA" }}>
|
|
<LoadingButton
|
|
type="submit"
|
|
fullWidth
|
|
variant="contained"
|
|
loading={loading}
|
|
disabled={loading}
|
|
loadingIndicator="Signing in…"
|
|
sx={{
|
|
backgroundColor: "#4687BA",
|
|
textTransform: "capitalize",
|
|
borderRadius: "8px",
|
|
fontWeight: "500",
|
|
fontSize: "16px",
|
|
padding: "12px 10px",
|
|
color: "#fff !important",
|
|
"&:hover": {
|
|
backgroundColor: "rgba(70, 135, 186, 0.8)",
|
|
},
|
|
}}
|
|
>
|
|
<span>{loading ? "Signing in…" : "Sign In"}</span>
|
|
</LoadingButton>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
</Grid>
|
|
</Box>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default SignInForm;
|
|
|
|
// Custom styles for text fields in sign up
|
|
const textFieldStyles = {
|
|
"& .MuiOutlinedInput-root": {
|
|
"& fieldset": {
|
|
borderColor: "#4687BA",
|
|
"&:hover": {
|
|
borderColor: "#4687BA",
|
|
},
|
|
},
|
|
"&.Mui-focused fieldset": {
|
|
borderColor: "#4687BA",
|
|
},
|
|
},
|
|
"& .MuiInputAdornment-positionEnd": {
|
|
cursor: "pointer",
|
|
},
|
|
"& .MuiFormLabel-root": {
|
|
color: "#4687BA",
|
|
},
|
|
"&:hover .MuiFormLabel-root": {
|
|
color: "#4687BA",
|
|
},
|
|
"&.Mui-focused .MuiFormLabel-root": {
|
|
color: "#4687BA",
|
|
},
|
|
"& .MuiInputBase-input": {
|
|
color: "#4687BA",
|
|
},
|
|
"&:hover .MuiInputBase-input": {
|
|
color: "#4687BA",
|
|
},
|
|
"&.Mui-focused .MuiInputBase-input": {
|
|
color: "#4687BA",
|
|
},
|
|
};
|