normalize mobile auth and profile ui to theme components

This commit is contained in:
dimitar committed 2026-03-29 20:07:33 +02:00
1 parent 7ada05da6a
commit ed14c57749
7 files changed
+557 -615

No files matched your search

+151 -127
View File
@@ -13,12 +13,17 @@ import { useUser, useAuth } from "@clerk/clerk-expo";
import { useRouter } from "expo-router";
import { fitnessProfileApi } from "@/api/fitnessProfile";
import { gymsApi, type Gym } from "@/api/gyms";
import { useTheme } from "../../contexts/ThemeContext";
import { Input } from "../../components/Input";
import { MinimalButton } from "../../components/MinimalButton";
import { MinimalCard } from "../../components/MinimalCard";
import log from "../../utils/logger";
export default function OnboardingScreen() {
const { user } = useUser();
const { getToken } = useAuth();
const router = useRouter();
const { colors, typography } = useTheme();
const [isSubmitting, setIsSubmitting] = useState(false);
const [gyms, setGyms] = useState<Gym[]>([]);
const [gymsLoading, setGymsLoading] = useState<boolean>(false);
@@ -134,24 +139,53 @@ export default function OnboardingScreen() {
const progress = calculateProgress();
return (
<ScrollView style={styles.container}>
<Text style={styles.title}>Set Up Your Fitness Profile</Text>
<Text style={styles.subtitle}>
<ScrollView
style={[styles.container, { backgroundColor: colors.background }]}
>
<Text
style={[typography.h2, { color: colors.textPrimary }, styles.title]}
>
Set Up Your Fitness Profile
</Text>
<Text
style={[
typography.body,
{ color: colors.textSecondary },
styles.subtitle,
]}
>
Help us personalize your fitness journey
</Text>
{/* Progress indicator */}
<View style={styles.progressContainer}>
<View style={styles.progressBarBackground}>
<View style={[styles.progressBarFill, { width: `${progress}%` }]} />
<View
style={[
styles.progressBarBackground,
{ backgroundColor: colors.borderLight },
]}
>
<View
style={[
styles.progressBarFill,
{ width: `${progress}%`, backgroundColor: colors.primary },
]}
/>
</View>
<Text style={styles.progressText}>{progress}% Complete</Text>
<Text
style={[
typography.caption,
{ color: colors.textTertiary },
styles.progressText,
]}
>
{progress}% Complete
</Text>
</View>
<View style={styles.form}>
<Text style={styles.label}>Height (cm)</Text>
<TextInput
style={styles.input}
<Input
label="Height (cm)"
value={fitnessProfile.height}
onChangeText={(value) =>
setFitnessProfile({ ...fitnessProfile, height: value })
@@ -160,9 +194,8 @@ export default function OnboardingScreen() {
placeholder="Enter height in cm"
/>
<Text style={styles.label}>Weight (kg)</Text>
<TextInput
style={styles.input}
<Input
label="Weight (kg)"
value={fitnessProfile.weight}
onChangeText={(value) =>
setFitnessProfile({ ...fitnessProfile, weight: value })
@@ -171,9 +204,8 @@ export default function OnboardingScreen() {
placeholder="Enter weight in kg"
/>
<Text style={styles.label}>Age</Text>
<TextInput
style={styles.input}
<Input
label="Age"
value={fitnessProfile.age}
onChangeText={(value) =>
setFitnessProfile({ ...fitnessProfile, age: value })
@@ -182,9 +214,9 @@ export default function OnboardingScreen() {
placeholder="Enter your age"
/>
<Text style={styles.label}>Fitness Goals</Text>
<TextInput
style={[styles.input, styles.textArea]}
<Input
label="Fitness Goals"
style={styles.textArea}
value={fitnessProfile.goals}
onChangeText={(value) =>
setFitnessProfile({ ...fitnessProfile, goals: value })
@@ -194,33 +226,48 @@ export default function OnboardingScreen() {
placeholder="What are your fitness goals?"
/>
<Text style={styles.label}>Fitness Level</Text>
<Text
style={[typography.h4, { color: colors.textPrimary }, styles.label]}
>
Fitness Level
</Text>
<View style={styles.buttonGroup}>
{["beginner", "intermediate", "advanced"].map((level) => (
<TouchableOpacity
key={level}
style={[
styles.levelButton,
fitnessProfile.fitnessLevel === level && styles.selectedButton,
styles.segmentButton,
{
backgroundColor:
fitnessProfile.fitnessLevel === level
? colors.primary
: colors.surface,
borderColor: colors.border,
},
]}
onPress={() => handleLevelSelect(level)}
>
<Text
style={[
styles.levelButtonText,
fitnessProfile.fitnessLevel === level &&
styles.selectedButtonText,
typography.caption,
{
color:
fitnessProfile.fitnessLevel === level
? colors.white
: colors.textSecondary,
textTransform: "capitalize",
},
]}
>
{level.charAt(0).toUpperCase() + level.slice(1)}
{level}
</Text>
</TouchableOpacity>
))}
</View>
<Text style={styles.label}>Medical Conditions</Text>
<TextInput
style={[styles.input, styles.textArea]}
<Input
label="Medical Conditions"
style={styles.textArea}
value={fitnessProfile.medicalConditions}
onChangeText={(value) =>
setFitnessProfile({ ...fitnessProfile, medicalConditions: value })
@@ -230,9 +277,9 @@ export default function OnboardingScreen() {
placeholder="Any medical conditions we should know about?"
/>
<Text style={styles.label}>Dietary Restrictions</Text>
<TextInput
style={[styles.input, styles.textArea]}
<Input
label="Dietary Restrictions"
style={styles.textArea}
value={fitnessProfile.dietaryRestrictions}
onChangeText={(value) =>
setFitnessProfile({
@@ -245,34 +292,47 @@ export default function OnboardingScreen() {
placeholder="Any dietary restrictions?"
/>
<Text style={styles.label}>Preferred Workout Time</Text>
<Text
style={[typography.h4, { color: colors.textPrimary }, styles.label]}
>
Preferred Workout Time
</Text>
<View style={styles.buttonGroup}>
{["morning", "afternoon", "evening"].map((time) => (
<TouchableOpacity
key={time}
style={[
styles.timeButton,
fitnessProfile.preferredWorkoutTime === time &&
styles.selectedButton,
styles.segmentButton,
{
backgroundColor:
fitnessProfile.preferredWorkoutTime === time
? colors.primary
: colors.surface,
borderColor: colors.border,
},
]}
onPress={() => handleTimeSelect(time)}
>
<Text
style={[
styles.timeButtonText,
fitnessProfile.preferredWorkoutTime === time &&
styles.selectedButtonText,
typography.caption,
{
color:
fitnessProfile.preferredWorkoutTime === time
? colors.white
: colors.textSecondary,
textTransform: "capitalize",
},
]}
>
{time.charAt(0).toUpperCase() + time.slice(1)}
{time}
</Text>
</TouchableOpacity>
))}
</View>
<Text style={styles.label}>Workouts per Week</Text>
<TextInput
style={styles.input}
<Input
label="Workouts per Week"
value={fitnessProfile.workoutFrequency}
onChangeText={(value) =>
setFitnessProfile({ ...fitnessProfile, workoutFrequency: value })
@@ -281,7 +341,11 @@ export default function OnboardingScreen() {
placeholder="Number of workouts per week"
/>
<Text style={styles.label}>Select a Gym</Text>
<Text
style={[typography.h4, { color: colors.textPrimary }, styles.label]}
>
Select a Gym
</Text>
{gymsLoading ? (
<ActivityIndicator />
) : (
@@ -293,15 +357,24 @@ export default function OnboardingScreen() {
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
style={[
styles.levelButton,
selectedGymId === null && styles.selectedButton,
styles.segmentButton,
{
backgroundColor:
selectedGymId === null ? colors.primary : colors.surface,
borderColor: colors.border,
},
]}
onPress={() => setSelectedGymId(null)}
>
<Text
style={[
styles.levelButtonText,
selectedGymId === null && styles.selectedButtonText,
typography.caption,
{
color:
selectedGymId === null
? colors.white
: colors.textSecondary,
},
]}
>
Proceed without gym
@@ -311,15 +384,26 @@ export default function OnboardingScreen() {
<TouchableOpacity
key={gym.id}
style={[
styles.levelButton,
selectedGymId === gym.id && styles.selectedButton,
styles.segmentButton,
{
backgroundColor:
selectedGymId === gym.id
? colors.primary
: colors.surface,
borderColor: colors.border,
},
]}
onPress={() => setSelectedGymId(gym.id)}
>
<Text
style={[
styles.levelButtonText,
selectedGymId === gym.id && styles.selectedButtonText,
typography.caption,
{
color:
selectedGymId === gym.id
? colors.white
: colors.textSecondary,
},
]}
>
{gym.name}
@@ -330,17 +414,14 @@ export default function OnboardingScreen() {
</ScrollView>
)}
<TouchableOpacity
style={styles.submitButton}
<MinimalButton
title="Complete Setup"
onPress={handleSubmit}
loading={isSubmitting}
disabled={isSubmitting}
>
{isSubmitting ? (
<ActivityIndicator color="white" />
) : (
<Text style={styles.submitButtonText}>Complete Setup</Text>
)}
</TouchableOpacity>
fullWidth
size="lg"
/>
</View>
</ScrollView>
);
@@ -349,18 +430,13 @@ export default function OnboardingScreen() {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f5f5f5",
},
title: {
fontSize: 24,
fontWeight: "bold",
textAlign: "center",
marginTop: 40,
marginBottom: 8,
},
subtitle: {
fontSize: 16,
color: "#666",
textAlign: "center",
marginBottom: 32,
},
@@ -368,91 +444,39 @@ const styles = StyleSheet.create({
padding: 20,
},
label: {
fontSize: 14,
fontWeight: "600",
color: "#374151",
marginBottom: 4,
},
input: {
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
padding: 12,
marginBottom: 16,
backgroundColor: "white",
marginBottom: 8,
},
textArea: {
height: 80,
minHeight: 80,
textAlignVertical: "top",
marginBottom: 16,
},
buttonGroup: {
flexDirection: "row",
justifyContent: "space-between",
flexWrap: "wrap",
gap: 8,
marginBottom: 16,
},
levelButton: {
flex: 1,
backgroundColor: "#f3f4f6",
segmentButton: {
minWidth: 100,
padding: 10,
borderRadius: 8,
marginHorizontal: 4,
borderRadius: 10,
borderWidth: 1,
alignItems: "center",
},
timeButton: {
flex: 1,
backgroundColor: "#f3f4f6",
padding: 10,
borderRadius: 8,
marginHorizontal: 4,
alignItems: "center",
},
selectedButton: {
backgroundColor: "#3b82f6",
},
levelButtonText: {
color: "#374151",
fontSize: 14,
fontWeight: "500",
},
timeButtonText: {
color: "#374151",
fontSize: 14,
fontWeight: "500",
},
selectedButtonText: {
color: "white",
},
submitButton: {
backgroundColor: "#3b82f6",
padding: 16,
borderRadius: 8,
alignItems: "center",
marginTop: 24,
},
submitButtonText: {
color: "white",
fontSize: 16,
fontWeight: "600",
},
progressContainer: {
paddingHorizontal: 20,
marginBottom: 16,
},
progressBarBackground: {
height: 8,
backgroundColor: "#e5e7eb",
borderRadius: 4,
overflow: "hidden",
marginBottom: 8,
},
progressBarFill: {
height: "100%",
backgroundColor: "#3b82f6",
borderRadius: 4,
},
progressText: {
fontSize: 12,
color: "#6b7280",
textAlign: "center",
},
progressText: { textAlign: "center" },
});
+54 -86
View File
@@ -4,7 +4,6 @@ import { useRouter } from "expo-router";
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
@@ -13,6 +12,9 @@ import {
ScrollView,
} from "react-native";
import { OAuthButtons } from "../../components/auth/OAuthButtons";
import { Input } from "../../components/Input";
import { MinimalButton } from "../../components/MinimalButton";
import { useTheme } from "../../contexts/ThemeContext";
import { getErrorMessage, getClerkErrorCode } from "../../utils/error-helpers";
import log from "../../utils/logger";
@@ -25,6 +27,7 @@ export default function SignInScreen() {
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const { colors, typography } = useTheme();
// Redirect if already signed in
useEffect(() => {
@@ -77,8 +80,15 @@ export default function SignInScreen() {
if (isSignedIn) {
return (
<View style={[styles.container, styles.centerContent]}>
<ActivityIndicator size="large" color="#2563eb" />
<Text style={styles.loadingText}>Redirecting...</Text>
<ActivityIndicator size="large" color={colors.primary} />
<Text
style={[
typography.body,
{ color: colors.textSecondary, marginTop: 12 },
]}
>
Redirecting...
</Text>
</View>
);
}
@@ -86,19 +96,33 @@ export default function SignInScreen() {
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.container}
style={[styles.container, { backgroundColor: colors.background }]}
>
<ScrollView
contentContainerStyle={styles.scrollContent}
keyboardShouldPersistTaps="handled"
>
<View style={styles.content}>
<Text style={styles.title}>Welcome Back</Text>
<Text style={styles.subtitle}>Sign in to continue to FitAI</Text>
<Text
style={[typography.h1, { color: colors.textPrimary }, styles.title]}
>
Welcome Back
</Text>
<Text
style={[
typography.body,
{ color: colors.textSecondary },
styles.subtitle,
]}
>
Sign in to continue to FitAI
</Text>
{error ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
<Text style={[typography.caption, { color: colors.danger }]}>
{error}
</Text>
</View>
) : null}
@@ -112,13 +136,11 @@ export default function SignInScreen() {
<View style={styles.form}>
<View style={styles.inputContainer}>
<Text style={styles.label}>Email</Text>
<TextInput
style={styles.input}
<Input
label="Email"
autoCapitalize="none"
value={emailAddress}
placeholder="Enter your email"
placeholderTextColor="#999"
onChangeText={setEmailAddress}
keyboardType="email-address"
autoComplete="email"
@@ -127,12 +149,10 @@ export default function SignInScreen() {
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>Password</Text>
<TextInput
style={styles.input}
<Input
label="Password"
value={password}
placeholder="Enter your password"
placeholderTextColor="#999"
secureTextEntry={true}
onChangeText={setPassword}
autoComplete="password"
@@ -140,26 +160,29 @@ export default function SignInScreen() {
/>
</View>
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
<MinimalButton
title="Sign In"
onPress={onSignInPress}
loading={loading}
disabled={loading || !emailAddress || !password}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Sign In</Text>
)}
</TouchableOpacity>
fullWidth
size="lg"
/>
</View>
<View style={styles.footer}>
<Text style={styles.footerText}>Don't have an account? </Text>
<Text style={[typography.caption, { color: colors.textSecondary }]}>
Don't have an account?{" "}
</Text>
<TouchableOpacity
onPress={() => router.push("/(auth)/sign-up")}
disabled={loading}
>
<Text style={styles.linkText}>Sign Up</Text>
<Text
style={[typography.bodyEmphasis, { color: colors.primary }]}
>
Sign Up
</Text>
</TouchableOpacity>
</View>
</View>
@@ -171,17 +194,11 @@ export default function SignInScreen() {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f5f5f5",
},
centerContent: {
justifyContent: "center",
alignItems: "center",
},
loadingText: {
marginTop: 12,
fontSize: 16,
color: "#666",
},
scrollContent: {
flexGrow: 1,
justifyContent: "center",
@@ -193,27 +210,18 @@ const styles = StyleSheet.create({
paddingVertical: 40,
},
title: {
fontSize: 32,
fontWeight: "bold",
color: "#1a1a1a",
marginBottom: 8,
},
subtitle: {
fontSize: 16,
color: "#666",
marginBottom: 32,
},
errorContainer: {
backgroundColor: "#fee",
backgroundColor: "rgba(255, 59, 59, 0.08)",
padding: 12,
borderRadius: 8,
borderRadius: 12,
marginBottom: 16,
borderLeftWidth: 4,
borderLeftColor: "#f44",
},
errorText: {
color: "#c00",
fontSize: 14,
borderLeftColor: "#FF3B3B",
},
form: {
marginBottom: 24,
@@ -221,51 +229,11 @@ const styles = StyleSheet.create({
inputContainer: {
marginBottom: 20,
},
label: {
fontSize: 14,
fontWeight: "600",
color: "#333",
marginBottom: 8,
},
input: {
backgroundColor: "#fff",
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
paddingHorizontal: 16,
paddingVertical: 12,
fontSize: 16,
color: "#1a1a1a",
},
button: {
backgroundColor: "#2563eb",
paddingVertical: 16,
borderRadius: 8,
alignItems: "center",
marginTop: 8,
},
buttonDisabled: {
backgroundColor: "#93c5fd",
},
buttonText: {
color: "#fff",
fontSize: 16,
fontWeight: "600",
},
footer: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
footerText: {
fontSize: 14,
color: "#666",
},
linkText: {
fontSize: 14,
color: "#2563eb",
fontWeight: "600",
},
dividerContainer: {
flexDirection: "row",
alignItems: "center",
@@ -274,11 +242,11 @@ const styles = StyleSheet.create({
dividerLine: {
flex: 1,
height: 1,
backgroundColor: "#ddd",
backgroundColor: "#E5E5EA",
},
dividerText: {
marginHorizontal: 10,
color: "#666",
color: "#8E8E93",
fontSize: 14,
},
});
+94 -113
View File
@@ -4,7 +4,6 @@ import { useRouter } from "expo-router";
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
@@ -13,6 +12,9 @@ import {
ScrollView,
} from "react-native";
import { OAuthButtons } from "../../components/auth/OAuthButtons";
import { Input } from "../../components/Input";
import { MinimalButton } from "../../components/MinimalButton";
import { useTheme } from "../../contexts/ThemeContext";
import { getErrorMessage, getClerkErrorCode } from "../../utils/error-helpers";
import log from "../../utils/logger";
@@ -29,6 +31,7 @@ export default function SignUpScreen() {
const [code, setCode] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const { colors, typography } = useTheme();
// Redirect if already signed in
useEffect(() => {
@@ -101,8 +104,15 @@ export default function SignUpScreen() {
if (isSignedIn) {
return (
<View style={[styles.container, styles.centerContent]}>
<ActivityIndicator size="large" color="#2563eb" />
<Text style={styles.loadingText}>Redirecting...</Text>
<ActivityIndicator size="large" color={colors.primary} />
<Text
style={[
typography.body,
{ color: colors.textSecondary, marginTop: 12 },
]}
>
Redirecting...
</Text>
</View>
);
}
@@ -118,42 +128,53 @@ export default function SignUpScreen() {
keyboardShouldPersistTaps="handled"
>
<View style={styles.content}>
<Text style={styles.title}>Verify Email</Text>
<Text style={styles.subtitle}>
<Text
style={[
typography.h1,
{ color: colors.textPrimary },
styles.title,
]}
>
Verify Email
</Text>
<Text
style={[
typography.body,
{ color: colors.textSecondary },
styles.subtitle,
]}
>
Enter the verification code sent to {emailAddress}
</Text>
{error ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
<Text style={[typography.caption, { color: colors.danger }]}>
{error}
</Text>
</View>
) : null}
<View style={styles.form}>
<View style={styles.inputContainer}>
<Text style={styles.label}>Verification Code</Text>
<TextInput
style={styles.input}
<Input
label="Verification Code"
value={code}
placeholder="Enter verification code"
placeholderTextColor="#999"
onChangeText={setCode}
keyboardType="number-pad"
editable={!loading}
/>
</View>
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
<MinimalButton
title="Verify Email"
onPress={onVerifyPress}
loading={loading}
disabled={loading || !code}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Verify Email</Text>
)}
</TouchableOpacity>
fullWidth
size="lg"
/>
</View>
</View>
</ScrollView>
@@ -164,19 +185,33 @@ export default function SignUpScreen() {
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.container}
style={[styles.container, { backgroundColor: colors.background }]}
>
<ScrollView
contentContainerStyle={styles.scrollContent}
keyboardShouldPersistTaps="handled"
>
<View style={styles.content}>
<Text style={styles.title}>Create Account</Text>
<Text style={styles.subtitle}>Sign up to get started with FitAI</Text>
<Text
style={[typography.h1, { color: colors.textPrimary }, styles.title]}
>
Create Account
</Text>
<Text
style={[
typography.body,
{ color: colors.textSecondary },
styles.subtitle,
]}
>
Sign up to get started with FitAI
</Text>
{error ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
<Text style={[typography.caption, { color: colors.danger }]}>
{error}
</Text>
</View>
) : null}
@@ -190,12 +225,10 @@ export default function SignUpScreen() {
<View style={styles.form}>
<View style={styles.inputContainer}>
<Text style={styles.label}>First Name</Text>
<TextInput
style={styles.input}
<Input
label="First Name"
value={firstName}
placeholder="Enter your first name"
placeholderTextColor="#999"
onChangeText={setFirstName}
autoComplete="given-name"
editable={!loading}
@@ -203,12 +236,10 @@ export default function SignUpScreen() {
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>Last Name</Text>
<TextInput
style={styles.input}
<Input
label="Last Name"
value={lastName}
placeholder="Enter your last name"
placeholderTextColor="#999"
onChangeText={setLastName}
autoComplete="family-name"
editable={!loading}
@@ -216,13 +247,11 @@ export default function SignUpScreen() {
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>Email</Text>
<TextInput
style={styles.input}
<Input
label="Email"
autoCapitalize="none"
value={emailAddress}
placeholder="Enter your email"
placeholderTextColor="#999"
onChangeText={setEmailAddress}
keyboardType="email-address"
autoComplete="email"
@@ -231,42 +260,51 @@ export default function SignUpScreen() {
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>Password</Text>
<TextInput
style={styles.input}
<Input
label="Password"
value={password}
placeholder="Create a password"
placeholderTextColor="#999"
secureTextEntry={true}
onChangeText={setPassword}
autoComplete="password-new"
editable={!loading}
/>
<Text style={styles.hint}>Must be at least 8 characters</Text>
<Text
style={[
typography.caption,
{ color: colors.textTertiary },
styles.hint,
]}
>
Must be at least 8 characters
</Text>
</View>
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
<MinimalButton
title="Sign Up"
onPress={onSignUpPress}
loading={loading}
disabled={
loading || !emailAddress || !password || !firstName || !lastName
}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Sign Up</Text>
)}
</TouchableOpacity>
fullWidth
size="lg"
/>
</View>
<View style={styles.footer}>
<Text style={styles.footerText}>Already have an account? </Text>
<Text style={[typography.caption, { color: colors.textSecondary }]}>
Already have an account?{" "}
</Text>
<TouchableOpacity
onPress={() => router.push("/(auth)/sign-in")}
disabled={loading}
>
<Text style={styles.linkText}>Sign In</Text>
<Text
style={[typography.bodyEmphasis, { color: colors.primary }]}
>
Sign In
</Text>
</TouchableOpacity>
</View>
</View>
@@ -278,17 +316,11 @@ export default function SignUpScreen() {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f5f5f5",
},
centerContent: {
justifyContent: "center",
alignItems: "center",
},
loadingText: {
marginTop: 12,
fontSize: 16,
color: "#666",
},
scrollContent: {
flexGrow: 1,
justifyContent: "center",
@@ -300,27 +332,18 @@ const styles = StyleSheet.create({
paddingVertical: 40,
},
title: {
fontSize: 32,
fontWeight: "bold",
color: "#1a1a1a",
marginBottom: 8,
},
subtitle: {
fontSize: 16,
color: "#666",
marginBottom: 32,
},
errorContainer: {
backgroundColor: "#fee",
backgroundColor: "rgba(255, 59, 59, 0.08)",
padding: 12,
borderRadius: 8,
borderRadius: 12,
marginBottom: 16,
borderLeftWidth: 4,
borderLeftColor: "#f44",
},
errorText: {
color: "#c00",
fontSize: 14,
borderLeftColor: "#FF3B3B",
},
form: {
marginBottom: 24,
@@ -328,56 +351,14 @@ const styles = StyleSheet.create({
inputContainer: {
marginBottom: 20,
},
label: {
fontSize: 14,
fontWeight: "600",
color: "#333",
marginBottom: 8,
},
input: {
backgroundColor: "#fff",
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
paddingHorizontal: 16,
paddingVertical: 12,
fontSize: 16,
color: "#1a1a1a",
},
hint: {
fontSize: 12,
color: "#999",
marginTop: 4,
},
button: {
backgroundColor: "#2563eb",
paddingVertical: 16,
borderRadius: 8,
alignItems: "center",
marginTop: 8,
},
buttonDisabled: {
backgroundColor: "#93c5fd",
},
buttonText: {
color: "#fff",
fontSize: 16,
fontWeight: "600",
},
footer: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
footerText: {
fontSize: 14,
color: "#666",
},
linkText: {
fontSize: 14,
color: "#2563eb",
fontWeight: "600",
},
dividerContainer: {
flexDirection: "row",
alignItems: "center",
@@ -386,11 +367,11 @@ const styles = StyleSheet.create({
dividerLine: {
flex: 1,
height: 1,
backgroundColor: "#ddd",
backgroundColor: "#E5E5EA",
},
dividerText: {
marginHorizontal: 10,
color: "#666",
color: "#8E8E93",
fontSize: 14,
},
});