← back to Costa Rica App

app/login.tsx

82 lines

import { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet, Alert, Platform } from 'react-native';
import * as AppleAuthentication from 'expo-apple-authentication';
import { router } from 'expo-router';
import { api, setToken } from '../src/api';

export default function Login() {
  const [mode, setMode] = useState<'login' | 'register'>('login');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [name, setName] = useState('');
  const [phone, setPhone] = useState('');
  const [busy, setBusy] = useState(false);

  async function submit() {
    setBusy(true);
    try {
      const r = mode === 'login'
        ? await api.login(email, password)
        : await api.register({ email, password, full_name: name, phone });
      await setToken(r.token);
      router.back();
    } catch (e: any) { Alert.alert('Error', e.message); } finally { setBusy(false); }
  }
  async function appleSignIn() {
    try {
      const cred = await AppleAuthentication.signInAsync({
        requestedScopes: [
          AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
          AppleAuthentication.AppleAuthenticationScope.EMAIL,
        ],
      });
      const fullName = [cred.fullName?.givenName, cred.fullName?.familyName].filter(Boolean).join(' ');
      const r = await api.apple(cred.identityToken!, fullName || undefined);
      await setToken(r.token);
      router.back();
    } catch (e: any) {
      if (e.code === 'ERR_REQUEST_CANCELED') return;
      Alert.alert('Apple sign-in failed', e.message);
    }
  }

  return (
    <View style={s.wrap}>
      <Text style={s.h}>{mode === 'login' ? 'Welcome back' : 'Create account'}</Text>
      {Platform.OS === 'ios' && (
        <>
          <AppleAuthentication.AppleAuthenticationButton
            buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
            buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}
            cornerRadius={10}
            style={{ height: 48, marginBottom: 14 }}
            onPress={appleSignIn}
          />
          <View style={s.orRow}><View style={s.line} /><Text style={s.or}>or</Text><View style={s.line} /></View>
        </>
      )}
      {mode === 'register' && <TextInput style={s.i} placeholder="Full name" value={name} onChangeText={setName} />}
      <TextInput style={s.i} placeholder="Email" autoCapitalize="none" keyboardType="email-address" value={email} onChangeText={setEmail} />
      {mode === 'register' && <TextInput style={s.i} placeholder="Phone (+506…)" keyboardType="phone-pad" value={phone} onChangeText={setPhone} />}
      <TextInput style={s.i} placeholder="Password" secureTextEntry value={password} onChangeText={setPassword} />
      <TouchableOpacity style={s.cta} onPress={submit} disabled={busy}>
        <Text style={s.ctaTxt}>{busy ? '…' : mode === 'login' ? 'Sign in' : 'Sign up'}</Text>
      </TouchableOpacity>
      <TouchableOpacity onPress={() => setMode(mode === 'login' ? 'register' : 'login')}>
        <Text style={s.switch}>{mode === 'login' ? 'New here? Create an account' : 'Have an account? Sign in'}</Text>
      </TouchableOpacity>
    </View>
  );
}
const s = StyleSheet.create({
  wrap: { flex: 1, padding: 20, backgroundColor: '#f6f7f5' },
  h: { fontSize: 24, fontWeight: '800', color: '#1a2b22', marginBottom: 16 },
  i: { backgroundColor: '#fff', borderRadius: 10, height: 48, paddingHorizontal: 14, marginBottom: 12, borderWidth: 1, borderColor: '#e2e5e0' },
  cta: { backgroundColor: '#0a7d55', height: 52, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginTop: 6 },
  ctaTxt: { color: '#fff', fontSize: 16, fontWeight: '700' },
  switch: { color: '#0a7d55', textAlign: 'center', marginTop: 18 },
  orRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 14 },
  line: { flex: 1, height: 1, backgroundColor: '#d8ddd6' },
  or: { color: '#6b756e', marginHorizontal: 10, fontSize: 13 },
});