377 lines
10 KiB
TypeScript
377 lines
10 KiB
TypeScript
import Stepper from '@mui/material/Stepper';
|
||
import Step from '@mui/material/Step';
|
||
import StepLabel from '@mui/material/StepLabel';
|
||
import { useEffect, useRef, useState } from 'react';
|
||
import {
|
||
StepConnector,
|
||
stepConnectorClasses,
|
||
StepIconProps,
|
||
styled,
|
||
Typography,
|
||
Box,
|
||
TextField,
|
||
Button,
|
||
Snackbar,
|
||
CircularProgress,
|
||
} from '@mui/material';
|
||
import LoginRoundedIcon from '@mui/icons-material/LoginRounded';
|
||
import VerifiedRoundedIcon from '@mui/icons-material/VerifiedRounded';
|
||
import AssignmentIndRoundedIcon from '@mui/icons-material/AssignmentIndRounded';
|
||
import {
|
||
generateVerificationCode,
|
||
registerUser,
|
||
getVerificationStatus,
|
||
} from '../api';
|
||
import QRCodeStyling from 'qr-code-styling';
|
||
import popalogo from '../../../assets/icons/popa-popa.svg';
|
||
|
||
const ColorlibConnector = styled(StepConnector)(({ theme }) => ({
|
||
[`&.${stepConnectorClasses.alternativeLabel}`]: {
|
||
top: 22,
|
||
},
|
||
[`&.${stepConnectorClasses.active}`]: {
|
||
[`& .${stepConnectorClasses.line}`]: {
|
||
backgroundImage:
|
||
'linear-gradient( 95deg,rgb(242,113,33) 0%,rgb(233,64,87) 50%,rgb(138,35,135) 100%)',
|
||
},
|
||
},
|
||
[`&.${stepConnectorClasses.completed}`]: {
|
||
[`& .${stepConnectorClasses.line}`]: {
|
||
backgroundImage:
|
||
'linear-gradient( 95deg,rgb(242,113,33) 0%,rgb(233,64,87) 50%,rgb(138,35,135) 100%)',
|
||
},
|
||
},
|
||
[`& .${stepConnectorClasses.line}`]: {
|
||
height: 3,
|
||
border: 0,
|
||
backgroundColor: '#eaeaf0',
|
||
borderRadius: 1,
|
||
...theme.applyStyles('dark', {
|
||
backgroundColor: theme.palette.grey[800],
|
||
}),
|
||
},
|
||
}));
|
||
|
||
const ColorlibStepIconRoot = styled('div')<{
|
||
ownerState: { completed?: boolean; active?: boolean };
|
||
}>(({ theme }) => ({
|
||
backgroundColor: '#ccc',
|
||
zIndex: 1,
|
||
color: '#fff',
|
||
width: 50,
|
||
height: 50,
|
||
display: 'flex',
|
||
borderRadius: '50%',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
...theme.applyStyles('dark', {
|
||
backgroundColor: theme.palette.grey[700],
|
||
}),
|
||
variants: [
|
||
{
|
||
props: ({ ownerState }) => ownerState.active,
|
||
style: {
|
||
backgroundImage:
|
||
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
|
||
boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
|
||
},
|
||
},
|
||
{
|
||
props: ({ ownerState }) => ownerState.completed,
|
||
style: {
|
||
backgroundImage:
|
||
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
|
||
},
|
||
},
|
||
],
|
||
}));
|
||
|
||
function ColorlibStepIcon(props: StepIconProps) {
|
||
const { active, completed, className } = props;
|
||
|
||
const icons: { [index: string]: React.ReactElement<unknown> } = {
|
||
1: <AssignmentIndRoundedIcon />,
|
||
2: <VerifiedRoundedIcon />,
|
||
3: <LoginRoundedIcon />,
|
||
};
|
||
|
||
return (
|
||
<ColorlibStepIconRoot
|
||
ownerState={{ completed, active }}
|
||
className={className}
|
||
>
|
||
{icons[String(props.icon)]}
|
||
</ColorlibStepIconRoot>
|
||
);
|
||
}
|
||
|
||
const qrCode = new QRCodeStyling({
|
||
width: 300,
|
||
height: 300,
|
||
// image: popalogo,
|
||
shape: 'square',
|
||
margin: 10,
|
||
dotsOptions: {
|
||
gradient: {
|
||
type: 'linear',
|
||
colorStops: [
|
||
{
|
||
offset: 0,
|
||
color: 'rgb(242,113,33)',
|
||
},
|
||
{
|
||
offset: 1,
|
||
color: 'rgb(233,64,87)',
|
||
},
|
||
],
|
||
},
|
||
type: 'rounded',
|
||
},
|
||
imageOptions: {
|
||
crossOrigin: 'anonymous',
|
||
margin: 20,
|
||
imageSize: 0.5,
|
||
},
|
||
backgroundOptions: {
|
||
color: 'transparent',
|
||
},
|
||
});
|
||
|
||
export const Registration = () => {
|
||
const [activeStep, setActiveStep] = useState(0);
|
||
const [username, setUsername] = useState('');
|
||
const [password, setPassword] = useState('');
|
||
const [open, setOpen] = useState(false);
|
||
const [message, setMessage] = useState('');
|
||
const [verificationCode, setVerificationCode] = useState<string | null>(null);
|
||
const ref = useRef(null);
|
||
const [url, setUrl] = useState('');
|
||
const steps = ['Создание аккаунта', 'Верификация аккаунта в телеграмме'];
|
||
|
||
useEffect(() => {
|
||
if (ref.current) {
|
||
qrCode.append(ref.current);
|
||
}
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
qrCode.update({
|
||
data: url,
|
||
});
|
||
}, [url]);
|
||
|
||
const handleCreateAccount = async () => {
|
||
const response = await registerUser(username, password);
|
||
if (response.status === 'success') {
|
||
setActiveStep(1);
|
||
} else {
|
||
setOpen(true);
|
||
setMessage(response.status);
|
||
}
|
||
};
|
||
|
||
const handleClose = () => {
|
||
setOpen(false);
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (activeStep === 1) {
|
||
handleGenerateVerificationCode(username);
|
||
setUrl(`https://t.me/popa_popa_popa_bot?start=${username}`);
|
||
|
||
const intervalId = setInterval(() => {
|
||
handleVerifyCode();
|
||
}, 5000);
|
||
|
||
return () => {
|
||
clearInterval(intervalId);
|
||
};
|
||
}
|
||
}, [activeStep]);
|
||
|
||
const handleGenerateVerificationCode = async (username: string) => {
|
||
console.log(username);
|
||
const response = await generateVerificationCode(username);
|
||
setVerificationCode(response.code);
|
||
};
|
||
|
||
const handleVerifyCode = async () => {
|
||
const response = await getVerificationStatus(username);
|
||
if (response.is_verified) {
|
||
window.location.href = '/login';
|
||
}
|
||
};
|
||
|
||
const handleOpenBot = () => {
|
||
window.open(`https://t.me/popa_popa_popa_bot?start=${username}`, '_blank');
|
||
};
|
||
|
||
return (
|
||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||
<Stepper
|
||
activeStep={activeStep}
|
||
alternativeLabel
|
||
connector={<ColorlibConnector />}
|
||
>
|
||
{steps.map((label) => (
|
||
<Step key={label}>
|
||
<StepLabel
|
||
sx={{
|
||
'& .MuiStepLabel-label': {
|
||
color: 'white',
|
||
},
|
||
'& .Mui-completed': {
|
||
color: 'white !important',
|
||
},
|
||
'& .Mui-active': {
|
||
backgroundImage:
|
||
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
|
||
WebkitBackgroundClip: 'text',
|
||
WebkitTextFillColor: 'transparent',
|
||
},
|
||
}}
|
||
StepIconComponent={ColorlibStepIcon}
|
||
>
|
||
{label}
|
||
</StepLabel>
|
||
</Step>
|
||
))}
|
||
</Stepper>
|
||
{activeStep === 0 && (
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 2,
|
||
alignItems: 'center',
|
||
}}
|
||
>
|
||
<Typography variant="h6">Создание аккаунта</Typography>
|
||
<Typography variant="body1">Введите ваш никнейм</Typography>
|
||
<TextField
|
||
required
|
||
name="username"
|
||
variant="outlined"
|
||
value={username}
|
||
onChange={(e) => setUsername(e.target.value)}
|
||
sx={{
|
||
width: '100%',
|
||
// '& .MuiFormLabel-root': {
|
||
// color: 'white',
|
||
// },
|
||
'& .MuiInputBase-input': {
|
||
color: 'white',
|
||
},
|
||
'& .MuiInput-underline:after': {
|
||
borderBottomColor: '#B2BAC2',
|
||
},
|
||
'& .MuiOutlinedInput-root': {
|
||
'& fieldset': {
|
||
borderColor: '#E0E3E7',
|
||
color: 'white',
|
||
},
|
||
'&:hover fieldset': {
|
||
borderColor: '#B2BAC2',
|
||
},
|
||
'&.Mui-focused fieldset': {
|
||
borderColor: '#6F7E8C',
|
||
},
|
||
},
|
||
}}
|
||
/>
|
||
<Typography variant="body1">Введите ваш пароль</Typography>
|
||
<TextField
|
||
required
|
||
name="password"
|
||
type="password"
|
||
variant="outlined"
|
||
value={password}
|
||
onChange={(e) => setPassword(e.target.value)}
|
||
sx={{
|
||
width: '100%',
|
||
// '& .MuiFormLabel-root': {
|
||
// color: 'white',
|
||
// },
|
||
'& .MuiInputBase-input': {
|
||
color: 'white',
|
||
},
|
||
'& .MuiInput-underline:after': {
|
||
borderBottomColor: '#B2BAC2',
|
||
},
|
||
'& .MuiOutlinedInput-root': {
|
||
'& fieldset': {
|
||
borderColor: '#E0E3E7',
|
||
color: 'white',
|
||
},
|
||
'&:hover fieldset': {
|
||
borderColor: '#B2BAC2',
|
||
},
|
||
'&.Mui-focused fieldset': {
|
||
borderColor: '#6F7E8C',
|
||
},
|
||
},
|
||
}}
|
||
/>
|
||
<Button
|
||
variant="contained"
|
||
color="primary"
|
||
sx={{ width: '100%', mt: 2 }}
|
||
onClick={handleCreateAccount}
|
||
>
|
||
Создать
|
||
</Button>
|
||
</Box>
|
||
)}
|
||
{activeStep === 1 && (
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 2,
|
||
alignItems: 'center',
|
||
}}
|
||
>
|
||
<Typography variant="h6">Откройте бота в телеграмме</Typography>
|
||
<Button
|
||
variant="contained"
|
||
color="primary"
|
||
sx={{ width: '100%', mt: 2 }}
|
||
onClick={handleOpenBot}
|
||
>
|
||
Открыть бота
|
||
</Button>
|
||
<div ref={ref} />
|
||
<Typography variant="body1">
|
||
Введите код верификации в боте
|
||
</Typography>
|
||
{verificationCode ? (
|
||
<>
|
||
<Typography
|
||
variant="h2"
|
||
sx={{
|
||
backgroundImage:
|
||
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
|
||
WebkitBackgroundClip: 'text',
|
||
WebkitTextFillColor: 'transparent',
|
||
}}
|
||
>
|
||
{verificationCode}
|
||
</Typography>
|
||
<Typography variant="body1">Ждем ответа от бота</Typography>
|
||
<CircularProgress />
|
||
</>
|
||
) : (
|
||
<CircularProgress />
|
||
)}
|
||
</Box>
|
||
)}
|
||
<Snackbar
|
||
open={open}
|
||
autoHideDuration={6000}
|
||
onClose={handleClose}
|
||
message={message}
|
||
/>
|
||
</Box>
|
||
);
|
||
};
|