import { Box, Link, Typography } from '@mui/joy' import { useQueryClient } from '@tanstack/react-query' import React from 'react' import { useNavigate } from 'react-router-dom' import { useNotification } from '../../service/NotificationProvider' import { login, signUp } from '../../utils/Fetcher' import { AuthPasswordField, AuthSubmitButton, AuthTextField, LegalLinks, } from './AuthFields' import AuthShell from './AuthShell' const SignupView = () => { const [username, setUsername] = React.useState('') const [password, setPassword] = React.useState('') const Navigate = useNavigate() const queryClient = useQueryClient() const [displayName, setDisplayName] = React.useState('') const [email, setEmail] = React.useState('') const [usernameError, setUsernameError] = React.useState('') const [passwordError, setPasswordError] = React.useState('') const [emailError, setEmailError] = React.useState('') const [displayNameError, setDisplayNameError] = React.useState('') const [isSubmitting, setIsSubmitting] = React.useState(false) const { showError } = useNotification() const handleLogin = (username, password) => { login(username, password).then(response => { if (response.status === 200) { response.json().then(res => { localStorage.setItem('token', res.token) localStorage.setItem('token_expiry', res.expire) // Invalidate user profile queries to ensure fresh data queryClient.invalidateQueries(['userProfile']) // The "how did you hear about us" step (/heard-about) is // temporarily skipped; new accounts go straight to circle setup. // Re-enable by navigating to '/heard-about' again — that view // already forwards to '/circle-setup' when done. Navigate('/circle-setup', { replace: true }) }) } else { console.log('Login failed', response) // Navigate('/login') } }) } const handleSignUpValidation = () => { // Reset errors before validation setUsernameError(null) setPasswordError(null) setDisplayNameError(null) setEmailError(null) let isValid = true if (!username.trim()) { setUsernameError('Username is required') isValid = false } if (username.length < 4) { setUsernameError('Username must be at least 4 characters') isValid = false } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { setEmailError('Invalid email address') isValid = false } if (password.length < 8) { setPasswordError('Password must be between 8 and 64 characters') isValid = false } if (password.length > 64) { setPasswordError('Password must be between 8 and 64 characters') isValid = false } if (!displayName.trim()) { setDisplayNameError('Display name is required') isValid = false } // display name should only contain letters and spaces and numbers: if (!/^[a-zA-Z0-9 ]+$/.test(displayName)) { setDisplayNameError('Display name can only contain letters and numbers') isValid = false } // username should only contain lowercase letters, numbers, dot and dash: if (!/^[a-z0-9.-]+$/.test(username)) { setUsernameError( 'Username can only contain lowercase letters, numbers, dot and dash', ) isValid = false } return isValid } const handleSubmit = async e => { e.preventDefault() if (!handleSignUpValidation()) { return } setIsSubmitting(true) signUp(username, password, displayName, email) .then(response => { if (response.status === 201) { handleLogin(username, password) } else if (response.status === 403) { showError({ title: 'Signup Failed', message: 'Signup disabled, please contact admin', }) } else { console.log('Signup failed') response.json().then(res => { showError({ title: 'Signup Failed', message: res.error || 'An error occurred during signup', }) }) } }) .finally(() => setIsSubmitting(false)) } return ( } logoSize={0} > { setDisplayNameError(null) setDisplayName(e.target.value) }} /> { setUsernameError(null) setUsername(e.target.value.trim()) }} /> { setEmailError(null) setEmail(e.target.value.trim()) }} /> { setPasswordError(null) setPassword(e.target.value) }} /> Create account By creating an account you agree to our Terms of Service and Privacy Policy. Already have an account?{' '} Navigate('/login')} > Sign in ) } export default SignupView