first commit
parent
55bd58a761
commit
3390923c66
|
|
@ -1,35 +0,0 @@
|
|||
import { Tabs } from 'expo-router';
|
||||
import React from 'react';
|
||||
|
||||
import { HapticTab } from '@/components/haptic-tab';
|
||||
import { IconSymbol } from '@/components/ui/icon-symbol';
|
||||
import { Colors } from '@/constants/theme';
|
||||
import { useColorScheme } from '@/hooks/use-color-scheme';
|
||||
|
||||
export default function TabLayout() {
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
|
||||
headerShown: false,
|
||||
tabBarButton: HapticTab,
|
||||
}}>
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
title: 'Home',
|
||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="explore"
|
||||
options={{
|
||||
title: 'Explore',
|
||||
tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
import { Image } from 'expo-image';
|
||||
import { Platform, StyleSheet } from 'react-native';
|
||||
|
||||
import { Collapsible } from '@/components/ui/collapsible';
|
||||
import { ExternalLink } from '@/components/external-link';
|
||||
import ParallaxScrollView from '@/components/parallax-scroll-view';
|
||||
import { ThemedText } from '@/components/themed-text';
|
||||
import { ThemedView } from '@/components/themed-view';
|
||||
import { IconSymbol } from '@/components/ui/icon-symbol';
|
||||
import { Fonts } from '@/constants/theme';
|
||||
|
||||
export default function TabTwoScreen() {
|
||||
return (
|
||||
<ParallaxScrollView
|
||||
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
|
||||
headerImage={
|
||||
<IconSymbol
|
||||
size={310}
|
||||
color="#808080"
|
||||
name="chevron.left.forwardslash.chevron.right"
|
||||
style={styles.headerImage}
|
||||
/>
|
||||
}>
|
||||
<ThemedView style={styles.titleContainer}>
|
||||
<ThemedText
|
||||
type="title"
|
||||
style={{
|
||||
fontFamily: Fonts.rounded,
|
||||
}}>
|
||||
Explore
|
||||
</ThemedText>
|
||||
</ThemedView>
|
||||
<ThemedText>This app includes example code to help you get started.</ThemedText>
|
||||
<Collapsible title="File-based routing">
|
||||
<ThemedText>
|
||||
This app has two screens:{' '}
|
||||
<ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '}
|
||||
<ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText>
|
||||
</ThemedText>
|
||||
<ThemedText>
|
||||
The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '}
|
||||
sets up the tab navigator.
|
||||
</ThemedText>
|
||||
<ExternalLink href="https://docs.expo.dev/router/introduction">
|
||||
<ThemedText type="link">Learn more</ThemedText>
|
||||
</ExternalLink>
|
||||
</Collapsible>
|
||||
<Collapsible title="Android, iOS, and web support">
|
||||
<ThemedText>
|
||||
You can open this project on Android, iOS, and the web. To open the web version, press{' '}
|
||||
<ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project.
|
||||
</ThemedText>
|
||||
</Collapsible>
|
||||
<Collapsible title="Images">
|
||||
<ThemedText>
|
||||
For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '}
|
||||
<ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
|
||||
different screen densities
|
||||
</ThemedText>
|
||||
<Image
|
||||
source={require('@/assets/images/react-logo.png')}
|
||||
style={{ width: 100, height: 100, alignSelf: 'center' }}
|
||||
/>
|
||||
<ExternalLink href="https://reactnative.dev/docs/images">
|
||||
<ThemedText type="link">Learn more</ThemedText>
|
||||
</ExternalLink>
|
||||
</Collapsible>
|
||||
<Collapsible title="Light and dark mode components">
|
||||
<ThemedText>
|
||||
This template has light and dark mode support. The{' '}
|
||||
<ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect
|
||||
what the user's current color scheme is, and so you can adjust UI colors accordingly.
|
||||
</ThemedText>
|
||||
<ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/">
|
||||
<ThemedText type="link">Learn more</ThemedText>
|
||||
</ExternalLink>
|
||||
</Collapsible>
|
||||
<Collapsible title="Animations">
|
||||
<ThemedText>
|
||||
This template includes an example of an animated component. The{' '}
|
||||
<ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
|
||||
the powerful{' '}
|
||||
<ThemedText type="defaultSemiBold" style={{ fontFamily: Fonts.mono }}>
|
||||
react-native-reanimated
|
||||
</ThemedText>{' '}
|
||||
library to create a waving hand animation.
|
||||
</ThemedText>
|
||||
{Platform.select({
|
||||
ios: (
|
||||
<ThemedText>
|
||||
The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '}
|
||||
component provides a parallax effect for the header image.
|
||||
</ThemedText>
|
||||
),
|
||||
})}
|
||||
</Collapsible>
|
||||
</ParallaxScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerImage: {
|
||||
color: '#808080',
|
||||
bottom: -90,
|
||||
left: -35,
|
||||
position: 'absolute',
|
||||
},
|
||||
titleContainer: {
|
||||
flexDirection: 'row',
|
||||
gap: 8,
|
||||
},
|
||||
});
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
import { Image } from 'expo-image';
|
||||
import { Platform, StyleSheet } from 'react-native';
|
||||
|
||||
import { HelloWave } from '@/components/hello-wave';
|
||||
import ParallaxScrollView from '@/components/parallax-scroll-view';
|
||||
import { ThemedText } from '@/components/themed-text';
|
||||
import { ThemedView } from '@/components/themed-view';
|
||||
import { Link } from 'expo-router';
|
||||
|
||||
export default function HomeScreen() {
|
||||
return (
|
||||
<ParallaxScrollView
|
||||
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
|
||||
headerImage={
|
||||
<Image
|
||||
source={require('@/assets/images/partial-react-logo.png')}
|
||||
style={styles.reactLogo}
|
||||
/>
|
||||
}>
|
||||
<ThemedView style={styles.titleContainer}>
|
||||
<ThemedText type="title">Welcome!</ThemedText>
|
||||
<HelloWave />
|
||||
</ThemedView>
|
||||
<ThemedView style={styles.stepContainer}>
|
||||
<ThemedText type="subtitle">Step 1: Try it</ThemedText>
|
||||
<ThemedText>
|
||||
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
|
||||
Press{' '}
|
||||
<ThemedText type="defaultSemiBold">
|
||||
{Platform.select({
|
||||
ios: 'cmd + d',
|
||||
android: 'cmd + m',
|
||||
web: 'F12',
|
||||
})}
|
||||
</ThemedText>{' '}
|
||||
to open developer tools.
|
||||
</ThemedText>
|
||||
</ThemedView>
|
||||
<ThemedView style={styles.stepContainer}>
|
||||
<Link href="/modal">
|
||||
<Link.Trigger>
|
||||
<ThemedText type="subtitle">Step 2: Explore</ThemedText>
|
||||
</Link.Trigger>
|
||||
<Link.Preview />
|
||||
<Link.Menu>
|
||||
<Link.MenuAction title="Action" icon="cube" onPress={() => alert('Action pressed')} />
|
||||
<Link.MenuAction
|
||||
title="Share"
|
||||
icon="square.and.arrow.up"
|
||||
onPress={() => alert('Share pressed')}
|
||||
/>
|
||||
<Link.Menu title="More" icon="ellipsis">
|
||||
<Link.MenuAction
|
||||
title="Delete"
|
||||
icon="trash"
|
||||
destructive
|
||||
onPress={() => alert('Delete pressed')}
|
||||
/>
|
||||
</Link.Menu>
|
||||
</Link.Menu>
|
||||
</Link>
|
||||
|
||||
<ThemedText>
|
||||
{`Tap the Explore tab to learn more about what's included in this starter app.`}
|
||||
</ThemedText>
|
||||
</ThemedView>
|
||||
<ThemedView style={styles.stepContainer}>
|
||||
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
|
||||
<ThemedText>
|
||||
{`When you're ready, run `}
|
||||
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
|
||||
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
|
||||
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
|
||||
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
|
||||
</ThemedText>
|
||||
</ThemedView>
|
||||
</ParallaxScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
titleContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
stepContainer: {
|
||||
gap: 8,
|
||||
marginBottom: 8,
|
||||
},
|
||||
reactLogo: {
|
||||
height: 178,
|
||||
width: 290,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
|
|
@ -1,24 +1,14 @@
|
|||
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
|
||||
// app/_layout.tsx
|
||||
import { Stack } from 'expo-router';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import 'react-native-reanimated';
|
||||
|
||||
import { useColorScheme } from '@/hooks/use-color-scheme';
|
||||
|
||||
export const unstable_settings = {
|
||||
anchor: '(tabs)',
|
||||
};
|
||||
|
||||
export default function RootLayout() {
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
return (
|
||||
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||
<Stack>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="modal" options={{ presentation: 'modal', title: 'Modal' }} />
|
||||
<>
|
||||
<StatusBar style="dark" />
|
||||
<Stack screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="index" />
|
||||
</Stack>
|
||||
<StatusBar style="auto" />
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,215 @@
|
|||
// app/index.tsx - SUA TELA DE LOGIN
|
||||
// Adicione esta linha com os outros imports:
|
||||
import { Link } from 'expo-router';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
StyleSheet,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
Alert,
|
||||
Image,
|
||||
ActivityIndicator
|
||||
} from 'react-native';
|
||||
|
||||
export default function LoginScreen() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleLogin = () => {
|
||||
if (!email || !password) {
|
||||
Alert.alert('Atenção', 'Por favor, preencha todos os campos');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!email.includes('@')) {
|
||||
Alert.alert('Email inválido', 'Por favor, insira um email válido');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
// SIMULAÇÃO DE LOGIN (depois troca por API real)
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
Alert.alert(
|
||||
'Login realizado!',
|
||||
`Bem-vindo(a), ${email.split('@')[0]}!`,
|
||||
[{ text: 'OK', onPress: () => console.log('Login OK') }]
|
||||
);
|
||||
// Aqui você navegaria para o app principal: router.replace('/(tabs)');
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.container}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
|
||||
{/* LOGO/TÍTULO */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>📱 Estágios+</Text>
|
||||
<Text style={styles.subtitle}>Escola Profissional de Vila do Conde</Text>
|
||||
</View>
|
||||
|
||||
{/* FORMULÁRIO */}
|
||||
<View style={styles.form}>
|
||||
<Text style={styles.label}>Email</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Insira o seu email"
|
||||
placeholderTextColor="#999"
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
editable={!loading}
|
||||
/>
|
||||
|
||||
<Text style={styles.label}>Palavra-passe</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Insira a sua palavra-passe"
|
||||
placeholderTextColor="#999"
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
secureTextEntry
|
||||
editable={!loading}
|
||||
/>
|
||||
|
||||
{/* BOTÃO ENTRAR */}
|
||||
<TouchableOpacity
|
||||
style={[styles.button, loading && styles.buttonDisabled]}
|
||||
onPress={handleLogin}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#fff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>ENTRAR</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* LINK ESQUECI SENHA */}
|
||||
<TouchableOpacity style={styles.forgotLink}>
|
||||
<Text style={styles.forgotText}>Esqueceu-se da palavra-passe?</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* CADASTRO */}
|
||||
<View style={styles.footer}>
|
||||
<Text style={styles.footerText}>Não tem uma conta?</Text>
|
||||
<Link href="/register" asChild>
|
||||
<TouchableOpacity>
|
||||
<Text style={styles.registerText}> Crie uma conta agora</Text>
|
||||
</TouchableOpacity>
|
||||
</Link>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
|
||||
// ESTILOS
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#f8f9fa',
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginBottom: 48,
|
||||
},
|
||||
title: {
|
||||
fontSize: 32,
|
||||
fontWeight: '800',
|
||||
color: '#2d3436',
|
||||
marginBottom: 8,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
color: '#636e72',
|
||||
textAlign: 'center',
|
||||
},
|
||||
form: {
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 20,
|
||||
padding: 24,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 12,
|
||||
elevation: 5,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: '#2d3436',
|
||||
marginBottom: 8,
|
||||
marginLeft: 4,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 14,
|
||||
fontSize: 16,
|
||||
marginBottom: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: '#dfe6e9',
|
||||
color: '#2d3436',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: '#0984e3',
|
||||
borderRadius: 12,
|
||||
paddingVertical: 16,
|
||||
alignItems: 'center',
|
||||
marginTop: 8,
|
||||
marginBottom: 24,
|
||||
},
|
||||
buttonDisabled: {
|
||||
backgroundColor: '#74b9ff',
|
||||
},
|
||||
buttonText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
},
|
||||
forgotLink: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
forgotText: {
|
||||
color: '#0984e3',
|
||||
fontSize: 15,
|
||||
fontWeight: '500',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
marginTop: 40,
|
||||
paddingTop: 24,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: '#dfe6e9',
|
||||
},
|
||||
footerText: {
|
||||
color: '#636e72',
|
||||
fontSize: 15,
|
||||
},
|
||||
registerText: {
|
||||
color: '#0984e3',
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import { Link } from 'expo-router';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import { ThemedText } from '@/components/themed-text';
|
||||
import { ThemedView } from '@/components/themed-view';
|
||||
|
||||
export default function ModalScreen() {
|
||||
return (
|
||||
<ThemedView style={styles.container}>
|
||||
<ThemedText type="title">This is a modal</ThemedText>
|
||||
<Link href="/" dismissTo style={styles.link}>
|
||||
<ThemedText type="link">Go to home screen</ThemedText>
|
||||
</Link>
|
||||
</ThemedView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 20,
|
||||
},
|
||||
link: {
|
||||
marginTop: 15,
|
||||
paddingVertical: 15,
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
// app/register.tsx - TELA DE CRIAR CONTA (CORRIGIDA)
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
KeyboardAvoidingView,
|
||||
Platform
|
||||
} from 'react-native';
|
||||
import { Link } from 'expo-router';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
export default function RegisterScreen() {
|
||||
const [form, setForm] = useState({
|
||||
nome: '',
|
||||
email: '',
|
||||
telefone: '',
|
||||
password: '',
|
||||
confirmarPassword: ''
|
||||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleChange = (field: string, value: string) => {
|
||||
setForm(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const handleRegister = () => {
|
||||
if (!form.nome.trim()) {
|
||||
Alert.alert('Erro', 'Por favor, insira seu nome');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!form.email.includes('@')) {
|
||||
Alert.alert('Erro', 'Por favor, insira um email válido');
|
||||
return;
|
||||
}
|
||||
|
||||
if (form.password.length < 6) {
|
||||
Alert.alert('Erro', 'A senha deve ter pelo menos 6 caracteres');
|
||||
return;
|
||||
}
|
||||
|
||||
if (form.password !== form.confirmarPassword) {
|
||||
Alert.alert('Erro', 'As senhas não coincidem');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
Alert.alert(
|
||||
'Sucesso!',
|
||||
`Conta criada para ${form.nome}`,
|
||||
[{ text: 'OK' }]
|
||||
);
|
||||
|
||||
setForm({
|
||||
nome: '',
|
||||
email: '',
|
||||
telefone: '',
|
||||
password: '',
|
||||
confirmarPassword: ''
|
||||
});
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<StatusBar style="dark" />
|
||||
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.container}
|
||||
>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContainer}
|
||||
showsVerticalScrollIndicator={false}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
>
|
||||
{/* BOTÃO VOLTAR NO TOPO (AGORA SEM BUG DO NOTCH) */}
|
||||
<Link href="/" asChild>
|
||||
<TouchableOpacity style={styles.backHeaderButton} disabled={loading}>
|
||||
<Text style={styles.backHeaderText}>←</Text>
|
||||
</TouchableOpacity>
|
||||
</Link>
|
||||
|
||||
{/* CABEÇALHO */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Criar Nova Conta</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Preencha os dados abaixo para se registar
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* FORMULÁRIO */}
|
||||
<View style={styles.formCard}>
|
||||
{/* NOME */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Nome Completo</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Digite seu nome completo"
|
||||
value={form.nome}
|
||||
onChangeText={(text) => handleChange('nome', text)}
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* EMAIL */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Email</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="exemplo@email.com"
|
||||
value={form.email}
|
||||
onChangeText={(text) => handleChange('email', text)}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* TELEFONE */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Telefone</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="912 345 678"
|
||||
value={form.telefone}
|
||||
onChangeText={(text) => handleChange('telefone', text)}
|
||||
keyboardType="phone-pad"
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* SENHA */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Senha</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Mínimo 6 caracteres"
|
||||
value={form.password}
|
||||
onChangeText={(text) => handleChange('password', text)}
|
||||
secureTextEntry
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* CONFIRMAR SENHA */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Confirmar Senha</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Digite novamente a senha"
|
||||
value={form.confirmarPassword}
|
||||
onChangeText={(text) => handleChange('confirmarPassword', text)}
|
||||
secureTextEntry
|
||||
editable={!loading}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* BOTÃO REGISTRAR */}
|
||||
<TouchableOpacity
|
||||
style={[styles.registerButton, loading && styles.buttonDisabled]}
|
||||
onPress={handleRegister}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#FFFFFF" />
|
||||
) : (
|
||||
<Text style={styles.registerButtonText}>CRIAR CONTA</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* AVISO */}
|
||||
<View style={styles.termsContainer}>
|
||||
<Text style={styles.termsText}>
|
||||
Ao criar uma conta, concorda com os nossos Termos de Serviço e Política de Privacidade.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// ESTILOS
|
||||
const styles = StyleSheet.create({
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContainer: {
|
||||
flexGrow: 1,
|
||||
padding: 20,
|
||||
paddingTop: 20, // SafeArea já resolve o notch
|
||||
},
|
||||
backHeaderButton: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 10,
|
||||
zIndex: 50,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: '#f0f0f0',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
backHeaderText: {
|
||||
fontSize: 24,
|
||||
color: '#007AFF',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginTop: 50,
|
||||
marginBottom: 40,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#1a1a1a',
|
||||
marginBottom: 8,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
color: '#666',
|
||||
textAlign: 'center',
|
||||
},
|
||||
formCard: {
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: 16,
|
||||
padding: 24,
|
||||
marginBottom: 24,
|
||||
borderWidth: 1,
|
||||
borderColor: '#e9ecef',
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
marginBottom: 6,
|
||||
marginLeft: 4,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 14,
|
||||
fontSize: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: '#ddd',
|
||||
color: '#333',
|
||||
},
|
||||
registerButton: {
|
||||
backgroundColor: '#007AFF',
|
||||
borderRadius: 12,
|
||||
paddingVertical: 16,
|
||||
alignItems: 'center',
|
||||
marginTop: 10,
|
||||
marginBottom: 20,
|
||||
},
|
||||
buttonDisabled: {
|
||||
backgroundColor: '#7bb8ff',
|
||||
},
|
||||
registerButtonText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
termsContainer: {
|
||||
backgroundColor: '#e8f4ff',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: '#cce5ff',
|
||||
},
|
||||
termsText: {
|
||||
fontSize: 13,
|
||||
color: '#0066cc',
|
||||
textAlign: 'center',
|
||||
lineHeight: 18,
|
||||
},
|
||||
backButton: {
|
||||
paddingVertical: 14,
|
||||
alignItems: 'center',
|
||||
},
|
||||
backButtonText: {
|
||||
color: '#007AFF',
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
Loading…
Reference in New Issue