feat: initial commit and template import

This commit is contained in:
Amadeu Jose Andrade Junior
2025-02-05 16:40:00 -03:00
commit 8123a94fcf
37 changed files with 12414 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
/* eslint-disable import/prefer-default-export */
export const FormSX = {
p: 3,
zIndex: 1,
top: '50%',
left: '50%',
boxShadow: 6,
userSelect: 'none',
overflow: 'hidden',
position: 'absolute',
borderRadius: '10px',
transition: 'transform 0.3s',
width: { xs: '90%', sm: 400 },
transform: 'translate(-50%, -50%)',
img: {
p: '16px 32px',
},
button: {
height: '3rem',
color: 'white',
textShadow: '1px 1px 1px rgba(0, 0, 0, 0.6)',
},
a: {
fontWeight: '500',
lineHeight: '19px',
color: 'primary.main',
transition: 'color 0.3s',
textShadow: '1px 1px 1px rgba(0, 0, 0, 0.6)',
},
'@keyframes wawes': {
from: {
transform: 'rotate(0deg)',
},
to: {
transform: 'rotate(360deg)',
},
},
'&::before, &::after': {
content: '""',
zIndex: -1,
width: '600px',
height: '800px',
position: 'absolute',
borderRadius: '40% 45% 35% 40%',
},
'&::before': {
top: '-35%',
left: '75%',
animation: 'wawes 6s linear infinite',
background:
'linear-gradient(90deg, rgba(0, 101, 243, 0.2) 0%, rgba(0, 120, 255, 0.4) 100%)',
},
'&::after': {
top: '-30%',
left: '70%',
animation: 'wawes 8s linear infinite',
background:
'linear-gradient(90deg, rgba(0, 110, 255, 0.5) 0%, rgba(0, 120, 255, 0.3) 100%)',
},
'& span': {
fontSize: '0.75rem',
},
'& input': {
fontSize: '16px',
borderRadius: '5px',
},
'& label.Mui-focused ': {
pt: 0.2,
},
'& .MuiFormLabel-root': {
fontSize: '16px',
},
'& .MuiOutlinedInput-root': {
'&:hover fieldset': {
borderColor: 'primary.main',
},
},
};

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Stack, useTheme, Typography } from '@mui/material';
import { FormSX } from './Auth.styles';
function AuthOutlet({ children, header }) {
const theme = useTheme();
return (
<form>
<Stack
gap={3}
sx={{
...FormSX,
border: `1px solid ${theme.palette.grey.border}`,
background: theme.palette.grey[50],
}}
>
{header ? (
<Typography textAlign="center" variant="h2">
{header}
</Typography>
) : (
<img
src={
theme.palette.mode === 'dark'
? 'https://picsum.photos/100/50'
: 'https://picsum.photos/200/300'
}
alt="logo"
/>
)}
{children}
</Stack>
</form>
);
}
export default AuthOutlet;

105
src/pages/Auth/Login.jsx Normal file
View File

@@ -0,0 +1,105 @@
import {
Box,
Stack,
Typography,
TextField,
InputAdornment,
Button,
Link,
IconButton,
} from '@mui/material';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import VisibilityIcon from '@mui/icons-material/Visibility';
import { useNavigate } from 'react-router-dom';
import React from 'react';
import AuthOutlet from './AuthOutlet';
function Login() {
const email = React.useRef(null);
const password = React.useRef(null);
const navigate = useNavigate();
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => setShowPassword(!showPassword);
const handleMouseDownPassword = () => setShowPassword(!showPassword);
const loginHandler = async (e) => {
e.preventDefault();
const user = email.current.value.replace(/\s+/g, '');
const pwd = password.current.value.replace(/\s+/g, '');
if (user === '') {
// Please enter your email.
email.current.focus();
} else if (pwd === '') {
// 'Please enter your password.'
password.current.focus();
} else {
// do login stuff
}
};
/** Focus email input when component mounted. */
React.useEffect(() => {
email.current.focus();
}, []);
return (
<AuthOutlet>
<TextField
inputRef={email}
type="email"
label="E-mail"
variant="outlined"
autoComplete="off"
/>
<Stack gap={1}>
<TextField
inputRef={password}
type={showPassword ? 'text' : 'password'}
label="Password"
variant="outlined"
sx={{ '& .MuiInputBase-root ': { pr: '4px' } }}
autoComplete="new-password"
InputProps={{
// <-- This is where the toggle button sis added.
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
>
{showPassword ? <VisibilityIcon /> : <VisibilityOffIcon />}
</IconButton>
</InputAdornment>
),
}}
/>
<Link
variant="body2"
textAlign="right"
onClick={() => navigate('/forgot-password')}
>
Forgot password?
</Link>
<Button variant="contained" onClick={loginHandler}>
Sign in
</Button>
</Stack>
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
<Typography variant="body2" component="p">
Dont you have an account?
</Typography>
<Link
variant="body2"
sx={{ display: 'inline', ml: 1 }}
onClick={() => navigate('/register')}
>
Register
</Link>
</Box>
</AuthOutlet>
);
}
export default Login;

121
src/pages/Auth/Register.jsx Normal file
View File

@@ -0,0 +1,121 @@
import React from 'react';
import { Box, Stack, Typography, TextField, Button, Link } from '@mui/material';
import { useNavigate } from 'react-router-dom';
import AuthOutlet from './AuthOutlet';
function Register() {
const ad = React.useRef(null);
const soyad = React.useRef(null);
const email = React.useRef(null);
const password = React.useRef(null);
const passwordConf = React.useRef(null);
const navigate = useNavigate();
const registerHandler = async (e) => {
e.preventDefault();
const FirstName = ad.current.value.replace(/\s+/g, '');
const LastName = soyad.current.value.replace(/\s+/g, '');
const Email = email.current.value.replace(/\s+/g, '');
const Password = password.current.value.replace(/\s+/g, '');
const pwdConf = passwordConf.current.value.replace(/\s+/g, '');
if (FirstName === '') {
// 'Please enter name.'
ad.current.focus();
} else if (LastName === '') {
// 'Please enter surname.'
soyad.current.focus();
} else if (Email === '') {
// 'Please enter email.'
email.current.focus();
} else if (!/^[\w-.]+@([\w-]+\.)+[\w-]{1,20}$/.test(Email)) {
// 'Please enter real email.'
email.current.focus();
} else if (Password === '') {
// 'Please enter password.'
password.current.focus();
} else if (pwdConf === '') {
// 'Please enter password again.'
passwordConf.current.focus();
} else if (Password !== pwdConf) {
// 'Passwords do not match.'
password.current.focus();
} else if (Password.length < 6) {
// 'Password must be at least 6 characters.'
password.current.focus();
} else if (
!/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{6,}$/.test(Password)
) {
// 'Password must contain at least one uppercase letter, one lowercase letter and one number.',
password.current.focus();
} else {
// do register stuff
}
};
/** Focus name input when component mounted. */
React.useEffect(() => {
ad.current.focus();
}, []);
return (
<AuthOutlet>
<Stack direction="row" gap={3} sx={{ alignItems: 'center' }}>
<TextField
inputRef={ad}
label="Name"
type="text"
variant="outlined"
autoComplete="off"
/>
<TextField
inputRef={soyad}
label="Surname"
type="text"
variant="outlined"
autoComplete="off"
/>
</Stack>
<TextField
inputRef={email}
type="email"
label="E-mail"
variant="outlined"
autoComplete="off"
/>
<TextField
inputRef={password}
type="password"
autoComplete="new-password"
label="Password"
variant="outlined"
/>
<TextField
inputRef={passwordConf}
hidden
type="password"
autoComplete="new-password"
label="Password (again)"
variant="outlined"
/>
<Button variant="contained" onClick={registerHandler}>
Sign Up
</Button>
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
<Typography variant="body2" component="p">
Alredy have an account?
</Typography>
<Link
variant="body2"
sx={{ display: 'inline', ml: 1 }}
onClick={() => navigate('/login')}
>
Sign In
</Link>
</Box>
</AuthOutlet>
);
}
export default Register;