Archived
135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
import { useState, type ReactNode } from "react";
|
|
import {
|
|
Text,
|
|
TextInput,
|
|
TouchableOpacity,
|
|
Alert,
|
|
ActivityIndicator,
|
|
KeyboardAvoidingView,
|
|
Platform,
|
|
ScrollView,
|
|
} from "react-native";
|
|
import { useAuth } from "../context/AuthContext";
|
|
import { isStrongPassword } from "@cloud-reader/shared";
|
|
import { authStyles } from "./authStyles";
|
|
import { AuthFormError } from "./AuthFormError";
|
|
import { requireValidEmail } from "./authValidation";
|
|
|
|
export default function RegisterScreen({
|
|
navigation,
|
|
}: {
|
|
navigation: any;
|
|
}): ReactNode {
|
|
const { register } = useAuth();
|
|
const [username, setUsername] = useState("");
|
|
const [email, setEmail] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [confirmPassword, setConfirmPassword] = useState("");
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [submitting, setSubmitting] = useState(false);
|
|
|
|
const handleRegister = async () => {
|
|
setError(null);
|
|
|
|
if (!username.trim()) {
|
|
Alert.alert("Validation Error", "Please enter a username.");
|
|
return;
|
|
}
|
|
if (!requireValidEmail(email)) {
|
|
return;
|
|
}
|
|
if (!isStrongPassword(password)) {
|
|
Alert.alert(
|
|
"Validation Error",
|
|
"Password must be at least 8 characters and include uppercase, lowercase, and a number.",
|
|
);
|
|
return;
|
|
}
|
|
if (password !== confirmPassword) {
|
|
Alert.alert("Validation Error", "Passwords do not match.");
|
|
return;
|
|
}
|
|
|
|
setSubmitting(true);
|
|
try {
|
|
await register(email.trim(), username.trim(), password);
|
|
} catch {
|
|
setError("Could not create the account. Try a different email.");
|
|
} finally {
|
|
setSubmitting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<KeyboardAvoidingView
|
|
style={authStyles.container}
|
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
>
|
|
<ScrollView contentContainerStyle={authStyles.innerScroll}>
|
|
<Text style={authStyles.titleCompact}>Create Account</Text>
|
|
<Text style={authStyles.subtitle}>Join Cloud Reader</Text>
|
|
|
|
{error ? <AuthFormError message={error} /> : null}
|
|
|
|
<TextInput
|
|
style={authStyles.input}
|
|
placeholder="Username"
|
|
placeholderTextColor="#666"
|
|
value={username}
|
|
onChangeText={setUsername}
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
/>
|
|
|
|
<TextInput
|
|
style={authStyles.input}
|
|
placeholder="Email"
|
|
placeholderTextColor="#666"
|
|
value={email}
|
|
onChangeText={setEmail}
|
|
keyboardType="email-address"
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
/>
|
|
|
|
<TextInput
|
|
style={authStyles.input}
|
|
placeholder="Password"
|
|
placeholderTextColor="#666"
|
|
value={password}
|
|
onChangeText={setPassword}
|
|
secureTextEntry
|
|
/>
|
|
|
|
<TextInput
|
|
style={authStyles.input}
|
|
placeholder="Confirm Password"
|
|
placeholderTextColor="#666"
|
|
value={confirmPassword}
|
|
onChangeText={setConfirmPassword}
|
|
secureTextEntry
|
|
/>
|
|
|
|
<TouchableOpacity
|
|
style={[authStyles.button, submitting && authStyles.buttonDisabled]}
|
|
onPress={handleRegister}
|
|
disabled={submitting}
|
|
>
|
|
{submitting ? (
|
|
<ActivityIndicator color="#fff" />
|
|
) : (
|
|
<Text style={authStyles.buttonText}>Create Account</Text>
|
|
)}
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity onPress={() => navigation.goBack()}>
|
|
<Text style={authStyles.linkText}>
|
|
Already have an account?{" "}
|
|
<Text style={authStyles.linkBold}>Sign In</Text>
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
);
|
|
}
|