202 lines
6.8 KiB
TypeScript
202 lines
6.8 KiB
TypeScript
import { isClerkAPIResponseError, useSignUp } from '@clerk/clerk-expo'
|
|
import { ClerkAPIError } from '@clerk/types'
|
|
import { router } from 'expo-router'
|
|
import { useState } from 'react'
|
|
import { StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
|
|
|
|
export default function SignUpScreen() {
|
|
const { signUp, setActive, isLoaded } = useSignUp()
|
|
const [pendingVerification, setPendingVerification] = useState(false)
|
|
const [code, setCode] = useState('')
|
|
const [errors, setErrors] = useState<ClerkAPIError[]>([])
|
|
const [fname, setFname] = useState('')
|
|
const [lname, setLname] = useState('')
|
|
const [email, setUsername] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
|
|
async function onSignUpPress() {
|
|
if (!isLoaded) return
|
|
setErrors([])
|
|
|
|
try {
|
|
// Start Auth
|
|
await signUp.create({
|
|
firstName: fname,
|
|
lastName: lname,
|
|
emailAddress: email,
|
|
password
|
|
})
|
|
|
|
// Set confirmation
|
|
await signUp.prepareEmailAddressVerification()
|
|
setPendingVerification(true)
|
|
} catch (e) {
|
|
if (isClerkAPIResponseError(e)) setErrors(e.errors)
|
|
console.log(JSON.stringify(e))
|
|
}
|
|
}
|
|
|
|
async function onVerifyPress() {
|
|
if (!isLoaded) return
|
|
setErrors([])
|
|
|
|
try {
|
|
// Use the code the user provided to attempt verification
|
|
const signUpAttempt = await signUp.attemptEmailAddressVerification({
|
|
code
|
|
})
|
|
|
|
// If verification was completed, set the session to active
|
|
// and redirect the user
|
|
if (signUpAttempt.status === 'complete') {
|
|
await createUser(signUpAttempt.createdUserId)
|
|
await setActive({ session: signUpAttempt.createdSessionId })
|
|
} else {
|
|
// If the status is not complete, check why. User may need to
|
|
// complete further steps.
|
|
console.error(JSON.stringify(signUpAttempt, null, 2))
|
|
}
|
|
} catch (e: any) {
|
|
// See https://clerk.com/docs/custom-flows/error-handling
|
|
// for more info on error handling
|
|
console.error(JSON.stringify(e, null, 2))
|
|
setErrors(e.errors)
|
|
}
|
|
}
|
|
|
|
async function createUser(clerkUserID: string | null) {
|
|
fetch('http://localhost:3000/api/v1/users', {
|
|
method: 'POST',
|
|
headers: {
|
|
Accept: 'application/json, text/plain, */*',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
name: `${fname} ${lname}`,
|
|
email,
|
|
clerkUserID
|
|
})
|
|
})
|
|
}
|
|
|
|
if (pendingVerification) {
|
|
return (
|
|
<View style={styles.container}>
|
|
<Text style={styles.textCenter}>Enter the verification code we sent to {email}</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={code}
|
|
placeholder='Enter your verification code'
|
|
onChangeText={(code) => setCode(code)}
|
|
/>
|
|
<TouchableOpacity onPress={onVerifyPress} style={styles.button}>
|
|
<Text>Verify</Text>
|
|
</TouchableOpacity>
|
|
{errors.map((error) => (
|
|
<Text key={error.longMessage} style={{ color: 'red' }}>
|
|
{error.longMessage}
|
|
</Text>
|
|
))}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<>
|
|
<Text style={styles.text}>Create an account</Text>
|
|
<View style={{ width: '80%', marginTop: 20 }}>
|
|
<Text style={styles.textlabel}>First name</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={fname}
|
|
placeholder='Enter first name'
|
|
onChangeText={setFname}
|
|
/>
|
|
<Text style={styles.textlabel}>Last name</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={lname}
|
|
placeholder='Enter last name'
|
|
onChangeText={setLname}
|
|
/>
|
|
<Text style={styles.textlabel}>Email</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={email}
|
|
placeholder='Enter email'
|
|
onChangeText={setUsername}
|
|
/>
|
|
<Text style={styles.textlabel}>Password</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={password}
|
|
placeholder='Enter password'
|
|
secureTextEntry
|
|
onChangeText={setPassword}
|
|
/>
|
|
<TouchableOpacity
|
|
style={styles.button}
|
|
onPress={() => {
|
|
onSignUpPress()
|
|
}}
|
|
>
|
|
<Text style={{ color: '#fff', fontWeight: 'bold' }}>Sign Up</Text>
|
|
</TouchableOpacity>
|
|
<Text style={styles.textCenter}>Already have an account?</Text>
|
|
<TouchableOpacity
|
|
style={styles.signIn}
|
|
onPress={() => {
|
|
router.navigate('/sign-in')
|
|
}}
|
|
>
|
|
<Text style={{ color: '#fff' }}>Sign In</Text>
|
|
</TouchableOpacity>{' '}
|
|
</View>
|
|
{errors.map((error) => (
|
|
<Text key={error.longMessage} style={{ color: 'red' }}>
|
|
{error.longMessage}
|
|
</Text>
|
|
))}
|
|
</>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: '#25292e',
|
|
justifyContent: 'center',
|
|
alignItems: 'center'
|
|
},
|
|
text: {
|
|
color: '#fff'
|
|
},
|
|
textCenter: {
|
|
color: '#ffffff',
|
|
alignSelf: 'center',
|
|
marginBottom: 12
|
|
},
|
|
textlabel: {
|
|
color: '#fff',
|
|
marginBottom: 3
|
|
},
|
|
input: {
|
|
backgroundColor: '#fff',
|
|
borderRadius: 5,
|
|
padding: 10,
|
|
marginBottom: 15
|
|
},
|
|
button: {
|
|
backgroundColor: '#1e90ff',
|
|
padding: 12,
|
|
borderRadius: 5,
|
|
alignItems: 'center',
|
|
marginBottom: 15
|
|
},
|
|
signIn: {
|
|
alignItems: 'center'
|
|
}
|
|
})
|