♻️ Migrate account flows

💄 Optimize container width
This commit is contained in:
LittleSheep 2025-01-04 17:36:12 +08:00
parent f5ca0c192f
commit d92ffbae5d
7 changed files with 237 additions and 8 deletions

View File

@ -59,14 +59,14 @@ export function SnLoginCheckpoint({
return ( return (
<> <>
<Collapse in={!!error} sx={{ width: 320 }}> <Collapse in={!!error} sx={{ width: '100%' }}>
<Alert sx={{ mb: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error"> <Alert sx={{ mb: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error">
{error} {error}
</Alert> </Alert>
</Collapse> </Collapse>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Box sx={{ display: 'flex', flexDirection: 'column', width: 320, gap: 2, textAlign: 'center' }}> <Box sx={{ display: 'flex', flexDirection: 'column', width: '100%', gap: 2, textAlign: 'center' }}>
<TextField <TextField
label={factor.type == 0 ? 'Password' : 'Verification code'} label={factor.type == 0 ? 'Password' : 'Verification code'}
type="password" type="password"

View File

@ -44,7 +44,7 @@ export function SnLoginRouter({
</Alert> </Alert>
</Collapse> </Collapse>
<Box sx={{ display: 'flex', flexDirection: 'column', width: 320, gap: 2, textAlign: 'center' }}> <Box sx={{ display: 'flex', flexDirection: 'column', width: '100%', gap: 2, textAlign: 'center' }}>
<ButtonGroup orientation="vertical" aria-label="Vertical button group"> <ButtonGroup orientation="vertical" aria-label="Vertical button group">
{factorList.map((factor) => ( {factorList.map((factor) => (
<Button <Button

View File

@ -6,6 +6,7 @@ import { ArrowForward } from '@mui/icons-material'
import { Alert, Box, Button, Collapse, Link, TextField, Typography } from '@mui/material' import { Alert, Box, Button, Collapse, Link, TextField, Typography } from '@mui/material'
import { SnAuthFactor, SnAuthResult, SnAuthTicket } from '@/services/auth' import { SnAuthFactor, SnAuthResult, SnAuthTicket } from '@/services/auth'
import { useForm } from 'react-hook-form' import { useForm } from 'react-hook-form'
import NextLink from 'next/link'
import ErrorIcon from '@mui/icons-material/Error' import ErrorIcon from '@mui/icons-material/Error'
@ -38,14 +39,14 @@ export function SnLoginStart({ onNext }: { onNext: (val: SnAuthTicket, fcs: SnAu
return ( return (
<> <>
<Collapse in={!!error} sx={{ width: 320 }}> <Collapse in={!!error} sx={{ width: '100%' }}>
<Alert sx={{ mb: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error"> <Alert sx={{ mb: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error">
{error} {error}
</Alert> </Alert>
</Collapse> </Collapse>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Box sx={{ display: 'flex', flexDirection: 'column', width: 320, gap: 2, textAlign: 'center' }}> <Box sx={{ display: 'flex', flexDirection: 'column', width: '100%', gap: 2, textAlign: 'center' }}>
<TextField <TextField
label="Username" label="Username"
helperText="You can also use email address and phone number" helperText="You can also use email address and phone number"
@ -57,8 +58,14 @@ export function SnLoginStart({ onNext }: { onNext: (val: SnAuthTicket, fcs: SnAu
</Button> </Button>
<Typography variant="caption" sx={{ opacity: 0.75, mx: 2 }}> <Typography variant="caption" sx={{ opacity: 0.75, mx: 2 }}>
By continuing means you agree to our <Link href="#">Terms of Service</Link> and{' '} By continuing means you agree to our{' '}
<Link href="#">Privacy Policy</Link> <NextLink href="/terms/privacy-policy" passHref>
<Link component="span">Privacy Policy</Link>
</NextLink>{' '}
and{' '}
<NextLink href="/terms/user-agreements" passHref>
<Link component="span">User Agreements</Link>
</NextLink>
</Typography> </Typography>
</Box> </Box>
</form> </form>

View File

@ -86,8 +86,9 @@ export default function Login() {
height: 'calc(100vh - 64px)', height: 'calc(100vh - 64px)',
textAlign: 'center', textAlign: 'center',
}} }}
maxWidth="xs"
> >
<Box> <Box sx={{ width: '100%' }}>
<Typography variant="h5" component="h1"> <Typography variant="h5" component="h1">
Login Login
</Typography> </Typography>

View File

@ -0,0 +1,71 @@
import { sni } from '@/services/network'
import { Container, Box, Typography, CircularProgress, Alert, Collapse } from '@mui/material'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import ErrorIcon from '@mui/icons-material/Error'
import 'animate.css'
export default function AccountConfirm() {
const router = useRouter()
const [error, setError] = useState<string | null>(null)
async function confirm() {
try {
await sni.post('/cgi/id/users/me/confirm', {
code: router.query['code'] as string,
})
router.push('/')
} catch (err: any) {
setError(err.toString())
}
}
useEffect(() => {
confirm()
}, [])
return (
<Container
sx={{
display: 'grid',
placeItems: 'center',
height: 'calc(100vh - 64px)',
textAlign: 'center',
}}
maxWidth="xs"
>
<Box sx={{ width: '100%' }}>
<Typography variant="h5" component="h1">
Confirm Account
</Typography>
<Typography variant="subtitle2" component="h2">
Confirm your registeration on Solar Network
</Typography>
<Collapse in={!!error} sx={{ width: '100%' }}>
<Alert sx={{ mt: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error">
{error}
</Alert>
</Collapse>
{!error && (
<Box sx={{ mt: 3 }}>
<CircularProgress />
<Typography
variant="body2"
sx={{ mt: 3 }}
className="animate__animated animate__flash animate__infinite"
style={{ '--animate-duration': '3s' } as any}
>
Hold on a moment, we're working on it...
</Typography>
</Box>
)}
</Box>
</Container>
)
}

View File

@ -0,0 +1,71 @@
import { sni } from '@/services/network'
import { Container, Box, Typography, Alert, Collapse, Button } from '@mui/material'
import { useRouter } from 'next/router'
import { useState } from 'react'
import ErrorIcon from '@mui/icons-material/Error'
import 'animate.css'
export default function AccountConfirm() {
const router = useRouter()
const [error, setError] = useState<string | null>(null)
const [busy, setBusy] = useState(false)
async function confirm() {
try {
setBusy(true)
await sni.patch('/cgi/id/users/me/deletion', {
code: router.query['code'] as string,
})
router.push('/')
} catch (err: any) {
setError(err.toString())
} finally {
setBusy(false)
}
}
return (
<Container
sx={{
display: 'grid',
placeItems: 'center',
height: 'calc(100vh - 64px)',
textAlign: 'center',
}}
maxWidth="xs"
>
<Box sx={{ width: '100%' }}>
<Typography variant="h5" component="h1">
Delete Account
</Typography>
<Typography variant="subtitle2" component="h2">
Confirm delete your account from Solar Network
</Typography>
<Collapse in={!!error} sx={{ width: '100%' }}>
<Alert sx={{ mt: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error">
{error}
</Alert>
</Collapse>
<Box sx={{ mt: 3 }}>
<Typography variant="body2" gutterBottom>
Are you sure you want to delete your account? This action is irreversible. All the resources created by you
or related to your account will be deleted.
</Typography>
<Typography variant="body2">
If you have changed your mind, you can close this tab at any time, nothing will be affected.
</Typography>
<Button sx={{ mt: 3 }} onClick={() => confirm()} disabled={busy}>
Confirm
</Button>
</Box>
</Box>
</Container>
)
}

View File

@ -0,0 +1,79 @@
import { sni } from '@/services/network'
import { Container, Box, Typography, Alert, Collapse, Button, TextField } from '@mui/material'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import ErrorIcon from '@mui/icons-material/Error'
import 'animate.css'
export type SnResetPasswordForm = {
password: string
}
export default function AccountConfirm() {
const router = useRouter()
const { handleSubmit, register } = useForm<SnResetPasswordForm>()
const [error, setError] = useState<string | null>(null)
const [busy, setBusy] = useState(false)
async function confirm(data: any) {
try {
setBusy(true)
await sni.patch('/cgi/id/users/me/password-reset', {
code: router.query['code'] as string,
new_password: data.password,
})
router.push('/')
} catch (err: any) {
setError(err.toString())
} finally {
setBusy(false)
}
}
return (
<Container
sx={{
display: 'grid',
placeItems: 'center',
height: 'calc(100vh - 64px)',
textAlign: 'center',
}}
maxWidth="xs"
>
<Box sx={{ width: '100%' }}>
<Typography variant="h5" component="h1">
Reset Password
</Typography>
<Typography variant="subtitle2" component="h2">
Reset your password on Solar Network
</Typography>
<Collapse in={!!error} sx={{ width: '100%' }}>
<Alert sx={{ mt: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error">
{error}
</Alert>
</Collapse>
<form onSubmit={handleSubmit(confirm)}>
<Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', width: '100%', gap: 2, textAlign: 'center' }}>
<TextField
label="New Password"
type="password"
autoComplete="new-password"
{...register('password', { required: true })}
/>
<Button type="submit" disabled={busy}>
Next
</Button>
</Box>
</form>
</Box>
</Container>
)
}