Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 70 additions & 37 deletions crux-frontend/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@ export default function Login() {
const router = useRouter();
const {signin, loading, error} = useAuth();
const [identifier, setIdentifier] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [isVerificationStep, setIsVerificationStep] = useState(false);

const handleSignin = async () => {
const success = await signin(identifier);
if (success) {
router.push({
pathname: '/verify/[phone]',
params: {phone: identifier},
});
setIsVerificationStep(true);
}
};

const handleVerification = async () => {
// Add logic to verify the code
// If successful, navigate to the next screen
router.push({
pathname: '/verify/[phone]',
params: {phone: identifier},
});
};

return (
<View style={styles.container}>
<View style={styles.header}>
Expand All @@ -28,43 +36,68 @@ export default function Login() {
</Text>
</View>

<View style={styles.form}>
<TextInput
style={styles.input}
placeholder="Email or phone number"
placeholderTextColor="#666"
value={identifier}
onChangeText={setIdentifier}
/>
{isVerificationStep ? (
<>
<Text style={styles.title}>Verify your email</Text>
<Text style={styles.subtitle}>
We've sent a verification code to your email. Please enter it below.
</Text>
<TextInput
style={styles.input}
placeholder="Verification code"
placeholderTextColor="#666"
value={verificationCode}
onChangeText={setVerificationCode}
/>
<Pressable
style={styles.signInButton}
onPress={handleVerification}
disabled={loading}
>
<Text style={styles.signInButtonText}>Verify</Text>
</Pressable>
</>
) : (
<>
<View style={styles.form}>
<TextInput
style={styles.input}
placeholder="Email or phone number"
placeholderTextColor="#666"
value={identifier}
onChangeText={setIdentifier}
/>

{error && <Text style={styles.errorText}>{error}</Text>}
{error && <Text style={styles.errorText}>{error}</Text>}

<Pressable
style={styles.signInButton}
onPress={handleSignin}
disabled={loading}
>
<Text style={styles.signInButtonText}>Sign in</Text>
</Pressable>
<Pressable
style={styles.signInButton}
onPress={handleSignin}
disabled={loading}
>
<Text style={styles.signInButtonText}>Sign in</Text>
</Pressable>

<Link href="/signup" asChild>
<Pressable style={styles.signUpButton}>
<Text style={styles.signUpButtonText}>Sign up</Text>
</Pressable>
</Link>
<Link href="/signup" asChild>
<Pressable style={styles.signUpButton}>
<Text style={styles.signUpButtonText}>Sign up</Text>
</Pressable>
</Link>

<View style={styles.socialButtons}>
<Pressable style={styles.socialButton}>
<AntDesign name="linkedin-square" size={24} color="#0077B5" />
</Pressable>
<Pressable style={styles.socialButton}>
<AntDesign name="google" size={24} color="#DB4437" />
</Pressable>
<Pressable style={styles.socialButton}>
<AntDesign name="instagram" size={24} color="#E4405F" />
</Pressable>
</View>
</View>
<View style={styles.socialButtons}>
<Pressable style={styles.socialButton}>
<AntDesign name="linkedin-square" size={24} color="#0077B5" />
</Pressable>
<Pressable style={styles.socialButton}>
<AntDesign name="google" size={24} color="#DB4437" />
</Pressable>
<Pressable style={styles.socialButton}>
<AntDesign name="instagram" size={24} color="#E4405F" />
</Pressable>
</View>
</View>
</>
)}
</View>
);
}
Expand Down
143 changes: 90 additions & 53 deletions crux-frontend/app/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export default function SignUp() {
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [isVerificationStep, setIsVerificationStep] = useState(false);

const handleSignup = async () => {
const success = await signup({
Expand All @@ -20,77 +22,112 @@ export default function SignUp() {
phone,
});
if (success) {
router.push({pathname: '/verify/[phone]', params: {phone}});
setIsVerificationStep(true);
}
};

const handleVerification = async () => {
// Add logic to verify the code
// If successful, navigate to the next screen
router.push({pathname: '/verify/[phone]', params: {phone}});
};

return (
<View style={styles.container}>
<View style={styles.header}>
<Pressable onPress={() => router.canGoBack() && router.back()}>
<ArrowLeft size={24} color="#000" />
</Pressable>
<Text style={styles.progress}>1/3</Text>
<Text style={styles.progress}>{isVerificationStep ? '2/3' : '1/3'}</Text>
</View>

<Text style={styles.title}>Let's get to know you!</Text>
<Text style={styles.subtitle}>
Your journey starts here — just a few quick details.
</Text>

<View style={styles.form}>
<Text style={styles.label}>Your name</Text>
<View style={styles.nameInputs}>
<TextInput
style={[styles.input, styles.halfInput]}
placeholder="First name"
placeholderTextColor="#666"
value={firstName}
onChangeText={setFirstName}
/>
{isVerificationStep ? (
<>
<Text style={styles.title}>Verify your email</Text>
<Text style={styles.subtitle}>
We've sent a verification code to your email. Please enter it below.
</Text>
<TextInput
style={[styles.input, styles.halfInput]}
placeholder="Last name"
style={styles.input}
placeholder="Verification code"
placeholderTextColor="#666"
value={lastName}
onChangeText={setLastName}
value={verificationCode}
onChangeText={setVerificationCode}
/>
</View>
<Pressable
style={styles.nextButton}
onPress={handleVerification}
disabled={loading}
>
<ArrowLeft
size={24}
color="#fff"
style={{transform: [{rotate: '180deg'}]}}
/>
</Pressable>
</>
) : (
<>
<Text style={styles.title}>Let's get to know you!</Text>
<Text style={styles.subtitle}>
Your journey starts here — just a few quick details.
</Text>

<Text style={styles.label}>Email</Text>
<TextInput
style={styles.input}
placeholder="yourname@crux.com"
placeholderTextColor="#666"
inputMode="email"
value={email}
onChangeText={setEmail}
/>
<View style={styles.form}>
<Text style={styles.label}>Your name</Text>
<View style={styles.nameInputs}>
<TextInput
style={[styles.input, styles.halfInput]}
placeholder="First name"
placeholderTextColor="#666"
value={firstName}
onChangeText={setFirstName}
/>
<TextInput
style={[styles.input, styles.halfInput]}
placeholder="Last name"
placeholderTextColor="#666"
value={lastName}
onChangeText={setLastName}
/>
</View>

<Text style={styles.label}>Phone number</Text>
<TextInput
style={styles.input}
placeholder="+1 (333) 000-0000"
placeholderTextColor="#666"
inputMode="tel"
value={phone}
onChangeText={setPhone}
/>
<Text style={styles.label}>Email</Text>
<TextInput
style={styles.input}
placeholder="yourname@crux.com"
placeholderTextColor="#666"
inputMode="email"
value={email}
onChangeText={setEmail}
/>

{error && <Text style={styles.errorText}>{error}</Text>}
<Text style={styles.label}>Phone number</Text>
<TextInput
style={styles.input}
placeholder="+1 (333) 000-0000"
placeholderTextColor="#666"
inputMode="tel"
value={phone}
onChangeText={setPhone}
/>

<Pressable
style={styles.nextButton}
onPress={handleSignup}
disabled={loading}
>
<ArrowLeft
size={24}
color="#fff"
style={{transform: [{rotate: '180deg'}]}}
/>
</Pressable>
</View>
{error && <Text style={styles.errorText}>{error}</Text>}

<Pressable
style={styles.nextButton}
onPress={handleSignup}
disabled={loading}
>
<ArrowLeft
size={24}
color="#fff"
style={{transform: [{rotate: '180deg'}]}}
/>
</Pressable>
</View>
</>
)}
</View>
);
}
Expand Down
36 changes: 33 additions & 3 deletions crux-frontend/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,21 @@ const useAuth = () => {
resolve(false);
return;
}
resolve(true);
// Handle email verification
if (result?.userConfirmed === false) {
// Send verification code to user's email
result.user.getAttributeVerificationCode('email', {
onSuccess: () => {
resolve(true);
},
onFailure: (err) => {
setError(err.message || 'Failed to send verification code');
resolve(false);
},
});
} else {
resolve(true);
}
}
);
});
Expand All @@ -66,9 +80,25 @@ const useAuth = () => {

return new Promise<boolean>((resolve) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: () => {
onSuccess: (session) => {
setLoading(false);
resolve(true);
// Check if email is verified
cognitoUser.getUserAttributes((err, attributes) => {
if (err) {
setError(err.message || 'Failed to get user attributes');
resolve(false);
return;
}
const emailVerified = attributes?.find(
(attr) => attr.getName() === 'email_verified'
)?.getValue();
if (emailVerified === 'true') {
resolve(true);
} else {
setError('Email not verified');
resolve(false);
}
});
},
onFailure: (err) => {
setLoading(false);
Expand Down
7 changes: 4 additions & 3 deletions crux-frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion infra/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -420,4 +420,4 @@ resource "aws_security_group" "alb_sg" {
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
6 changes: 6 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}