TinySkin/frontend/src/views/SendEmail.tsx
2023-11-25 17:37:07 +08:00

181 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import TextField from '@mui/material/TextField';
import { useRequest, useTitle } from 'ahooks';
import { getConfig } from '@/apis/apis';
import { useEffect, useRef, useState } from 'react';
import Snackbar from '@mui/material/Snackbar';
import Alert from '@mui/material/Alert';
import CaptchaWidget from '@/components/CaptchaWidget';
import type { refType as CaptchaWidgetRef } from '@/components/CaptchaWidget'
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import { useNavigate } from "react-router-dom";
import { ApiErr } from '@/apis/error';
import Loading from '@/components/Loading';
export default function SendEmail({ title, anyEmail = false, sendService }: { title: string, anyEmail?: boolean, sendService: (email: string, captchaToken: string) => Promise<unknown> }) {
const [err, setErr] = useState("");
const [domain, setDomain] = useState("");
const [email, setEmail] = useState("")
const captchaRef = useRef<CaptchaWidgetRef>(null)
const [captchaToken, setCaptchaToken] = useState("");
const [open, setOpen] = useState(false);
useTitle(title)
const navigate = useNavigate();
const [helperText, setHelperText] = useState("")
const [loading, setLoading] = useState(false);
const server = useRequest(getConfig, {
cacheKey: "/api/v1/config",
staleTime: 60000,
onError: e => {
console.warn(e)
setErr(String(e))
}
})
useEffect(() => {
if (server.data?.AllowDomain.length != 0) {
setDomain(server.data?.AllowDomain[0] ?? "")
}
}, [server.data?.AllowDomain])
const emailonChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setEmail(e.target.value)
if (e.target.value == "") {
setHelperText("邮箱不得为空")
}
setHelperText("")
}
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (email == "") {
setHelperText("邮箱不得为空")
}
const sendEmail = (() => {
if (!anyEmail && domain != "") {
return `${email}@${domain}`
}
return email
})()
if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(sendEmail)) {
setHelperText("邮箱格式错误")
return
}
if (!anyEmail && server.data?.EmailReg && server.data?.EmailReg != ""
&& !new RegExp(server.data?.EmailReg).test(sendEmail)) {
setHelperText(server.data?.EmailRegMsg ?? "邮箱不满足正则要求")
return
}
if (server.data?.captcha.type != "" && captchaToken == "") {
return
}
setLoading(true)
sendService(sendEmail, captchaToken).then(() => setOpen(true)).catch(e => {
captchaRef.current?.reload()
console.warn(e)
if (e instanceof ApiErr) {
switch (e.code) {
case 10:
setErr("验证码错误")
return
case 11:
setErr("暂时无法对此邮箱发送邮件")
return
}
}
setErr(String(e))
}).finally(() => setLoading(false))
}
const handleClose = () => {
navigate("/")
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
{title}
</Typography>
<Box component="form" noValidate onSubmit={onSubmit} sx={{ mt: 3 }}>
<Grid container spacing={2}>
<Grid item xs={12} sx={{ display: 'grid', columnGap: '3px', gridTemplateColumns: "1fr auto" }}>
<TextField fullWidth
required
name="email"
label="邮箱"
value={email}
helperText={helperText}
error={helperText != ""}
onChange={emailonChange}
/>
{
server.data?.AllowDomain.length != 0 && !anyEmail &&
<FormControl>
<InputLabel></InputLabel>
<Select label="域名" value={domain} onChange={v => setDomain(v.target.value)}>
{server.data?.AllowDomain.map(v => <MenuItem value={v}>@{v}</MenuItem>)}
</Select>
</FormControl>
}
</Grid>
<Grid item xs={12}>
<CaptchaWidget ref={captchaRef} onSuccess={setCaptchaToken} />
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
</Button>
</Box>
</Box>
<Snackbar anchorOrigin={{ vertical: 'top', horizontal: 'center' }} open={err !== ""}>
<Alert onClose={() => setErr("")} severity="error">{err}</Alert>
</Snackbar>
<Dialog open={open}>
<DialogTitle></DialogTitle>
<DialogContent>
<Typography></Typography>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}></Button>
</DialogActions>
</Dialog>
{loading && <Loading />}
</Container>
)
}