feat(mobile): improve login, profile, alerts screens and dark mode background
Run Tests on Branches / Detect Changes (push) Successful in 8s
Run Tests on Branches / Backend Tests (push) Has been skipped
Run Tests on Branches / Frontend Tests (push) Successful in 1m41s
Run Tests on Branches / Frontend Mobile Tests (push) Successful in 1m46s

- Unify login/register into single screen with tab switcher, logo, and themed inputs
- Redesign profile with header card, segmented theme toggle, icon-based menu, and bottom-sheet modals
- Add auth guard to alerts screen showing login prompt instead of 401 error
- Switch ImageBackground to explicit Image+View layering for reliable rendering
- Add dark mode background image switching in root layout
- Add dark mode override for recent-tag in PWA search view
This commit is contained in:
Antoni Nuñez Romeu
2026-07-10 16:39:59 +02:00
parent bf519e43c9
commit 2a7ab64bbf
7 changed files with 763 additions and 1255 deletions
+3 -165
View File
@@ -1,167 +1,5 @@
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
KeyboardAvoidingView,
Platform,
Alert
} from 'react-native';
import { useRouter } from 'expo-router';
import { register } from '../../services/auth';
import { useThemeContext } from '../../components/ThemeProvider';
import { spacing, borderRadius } from '../../constants/theme';
import { Redirect } from 'expo-router';
export default function RegisterScreen() {
const router = useRouter();
const { colors } = useThemeContext();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);
const handleRegister = async () => {
if (!username || !password || !confirmPassword) {
Alert.alert('Error', 'Por favor completa todos los campos');
return;
}
if (password !== confirmPassword) {
Alert.alert('Error', 'Las contraseñas no coinciden');
return;
}
setIsLoading(true);
try {
await register(username, password);
router.replace('/(tabs)');
} catch (error) {
Alert.alert('Error', 'No se pudo crear la cuenta');
} finally {
setIsLoading(false);
}
};
return (
<KeyboardAvoidingView
style={[styles.container, { backgroundColor: colors.background }]}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<View style={styles.form}>
<Text style={[styles.title, { color: colors.text }]}>Crear Cuenta</Text>
<Text style={[styles.subtitle, { color: colors.textSecondary }]}>Regístrate para empezar</Text>
<View style={styles.inputContainer}>
<Text style={[styles.label, { color: colors.text }]}>Usuario</Text>
<TextInput
style={[styles.input, { backgroundColor: colors.card, color: colors.text }]}
value={username}
onChangeText={setUsername}
placeholder="Elige un usuario"
placeholderTextColor={colors.textSecondary}
autoCapitalize="none"
autoCorrect={false}
/>
</View>
<View style={styles.inputContainer}>
<Text style={[styles.label, { color: colors.text }]}>Contraseña</Text>
<TextInput
style={[styles.input, { backgroundColor: colors.card, color: colors.text }]}
value={password}
onChangeText={setPassword}
placeholder="Elige una contraseña"
placeholderTextColor={colors.textSecondary}
secureTextEntry
/>
</View>
<View style={styles.inputContainer}>
<Text style={[styles.label, { color: colors.text }]}>Confirmar Contraseña</Text>
<TextInput
style={[styles.input, { backgroundColor: colors.card, color: colors.text }]}
value={confirmPassword}
onChangeText={setConfirmPassword}
placeholder="Repite la contraseña"
placeholderTextColor={colors.textSecondary}
secureTextEntry
/>
</View>
<TouchableOpacity
style={[styles.button, isLoading && styles.buttonDisabled]}
onPress={handleRegister}
disabled={isLoading}
>
<Text style={styles.buttonText}>
{isLoading ? 'Creando cuenta...' : 'Crear Cuenta'}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.linkButton}
onPress={() => router.back()}
>
<Text style={[styles.linkText, { color: colors.primary }]}>¿Ya tienes cuenta? Inicia sesión</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
export default function RegisterRedirect() {
return <Redirect href="/auth/login" />;
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
form: {
flex: 1,
justifyContent: 'center',
padding: spacing.xl,
},
title: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: spacing.sm,
},
subtitle: {
fontSize: 16,
marginBottom: spacing.xl,
},
inputContainer: {
marginBottom: spacing.md,
},
label: {
fontSize: 14,
fontWeight: '500',
marginBottom: spacing.xs,
},
input: {
borderRadius: borderRadius.md,
padding: spacing.md,
fontSize: 16,
},
button: {
backgroundColor: '#7fbf8f',
borderRadius: borderRadius.md,
padding: spacing.md,
alignItems: 'center',
marginTop: spacing.md,
},
buttonDisabled: {
opacity: 0.6,
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: '600',
},
linkButton: {
marginTop: spacing.lg,
alignItems: 'center',
},
linkText: {
fontSize: 14,
},
});