♻️ Migrate account flows
💄 Optimize container width
			
			
This commit is contained in:
		| @@ -59,14 +59,14 @@ export function SnLoginCheckpoint({ | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       <Collapse in={!!error} sx={{ width: 320 }}> | ||||
|       <Collapse in={!!error} sx={{ width: '100%' }}> | ||||
|         <Alert sx={{ mb: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error"> | ||||
|           {error} | ||||
|         </Alert> | ||||
|       </Collapse> | ||||
|  | ||||
|       <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 | ||||
|             label={factor.type == 0 ? 'Password' : 'Verification code'} | ||||
|             type="password" | ||||
|   | ||||
| @@ -44,7 +44,7 @@ export function SnLoginRouter({ | ||||
|         </Alert> | ||||
|       </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"> | ||||
|           {factorList.map((factor) => ( | ||||
|             <Button | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import { ArrowForward } from '@mui/icons-material' | ||||
| import { Alert, Box, Button, Collapse, Link, TextField, Typography } from '@mui/material' | ||||
| import { SnAuthFactor, SnAuthResult, SnAuthTicket } from '@/services/auth' | ||||
| import { useForm } from 'react-hook-form' | ||||
| import NextLink from 'next/link' | ||||
|  | ||||
| import ErrorIcon from '@mui/icons-material/Error' | ||||
|  | ||||
| @@ -38,14 +39,14 @@ export function SnLoginStart({ onNext }: { onNext: (val: SnAuthTicket, fcs: SnAu | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       <Collapse in={!!error} sx={{ width: 320 }}> | ||||
|       <Collapse in={!!error} sx={{ width: '100%' }}> | ||||
|         <Alert sx={{ mb: 4 }} icon={<ErrorIcon fontSize="inherit" />} severity="error"> | ||||
|           {error} | ||||
|         </Alert> | ||||
|       </Collapse> | ||||
|  | ||||
|       <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 | ||||
|             label="Username" | ||||
|             helperText="You can also use email address and phone number" | ||||
| @@ -57,8 +58,14 @@ export function SnLoginStart({ onNext }: { onNext: (val: SnAuthTicket, fcs: SnAu | ||||
|           </Button> | ||||
|  | ||||
|           <Typography variant="caption" sx={{ opacity: 0.75, mx: 2 }}> | ||||
|             By continuing means you agree to our <Link href="#">Terms of Service</Link> and{' '} | ||||
|             <Link href="#">Privacy Policy</Link> | ||||
|             By continuing means you agree to our{' '} | ||||
|             <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> | ||||
|         </Box> | ||||
|       </form> | ||||
|   | ||||
| @@ -86,8 +86,9 @@ export default function Login() { | ||||
|         height: 'calc(100vh - 64px)', | ||||
|         textAlign: 'center', | ||||
|       }} | ||||
|       maxWidth="xs" | ||||
|     > | ||||
|       <Box> | ||||
|       <Box sx={{ width: '100%' }}> | ||||
|         <Typography variant="h5" component="h1"> | ||||
|           Login | ||||
|         </Typography> | ||||
|   | ||||
							
								
								
									
										71
									
								
								src/pages/flow/accounts/confirm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/pages/flow/accounts/confirm.tsx
									
									
									
									
									
										Normal 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> | ||||
|   ) | ||||
| } | ||||
							
								
								
									
										71
									
								
								src/pages/flow/accounts/deletion.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/pages/flow/accounts/deletion.tsx
									
									
									
									
									
										Normal 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> | ||||
|   ) | ||||
| } | ||||
							
								
								
									
										79
									
								
								src/pages/flow/accounts/password-reset.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/pages/flow/accounts/password-reset.tsx
									
									
									
									
									
										Normal 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> | ||||
|   ) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user