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
+55 -3
View File
@@ -1,7 +1,9 @@
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, FlatList, TouchableOpacity, Alert, useWindowDimensions } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
import { useThemeContext } from '../../components/ThemeProvider';
import { useAuth } from '../../hooks/useAuth';
import { spacing, borderRadius, shadows } from '../../constants/theme';
import { LoadingSpinner } from '../../components/LoadingSpinner';
import api from '../../services/api';
@@ -20,17 +22,23 @@ interface NotificationItem {
}
export default function AlertsScreen() {
const router = useRouter();
const { width } = useWindowDimensions();
const isTablet = width >= TABLET_MIN_WIDTH;
const { colors } = useThemeContext();
const { isAuthenticated, isLoading: authLoading } = useAuth();
const [items, setItems] = useState<NotificationItem[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [deletingId, setDeletingId] = useState<string | null>(null);
useEffect(() => {
loadNotifications();
}, []);
if (!authLoading && isAuthenticated) {
loadNotifications();
} else if (!authLoading && !isAuthenticated) {
setIsLoading(false);
}
}, [authLoading, isAuthenticated]);
async function loadNotifications() {
setIsLoading(true);
@@ -123,10 +131,28 @@ export default function AlertsScreen() {
);
}
if (isLoading) {
if (isLoading || authLoading) {
return <LoadingSpinner message="Cargando notificaciones..." />;
}
if (!isAuthenticated) {
return (
<View style={[styles.container, styles.centered, { backgroundColor: colors.background }]}>
<Ionicons name="lock-closed-outline" size={64} color={colors.border} />
<Text style={[styles.loginTitle, { color: colors.text }]}>Inicia sesión para continuar</Text>
<Text style={[styles.loginSubtitle, { color: colors.textSecondary }]}>
Necesitas estar autenticado para ver tus notificaciones
</Text>
<TouchableOpacity
style={[styles.loginButton, { backgroundColor: colors.primary }]}
onPress={() => router.push('/auth/login')}
>
<Text style={[styles.loginButtonText, { color: colors.onPrimaryContainer }]}>Iniciar Sesión</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<View style={[styles.header, isTablet && styles.headerTablet]}>
@@ -172,6 +198,32 @@ const styles = StyleSheet.create({
container: {
flex: 1,
},
centered: {
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: spacing.xl,
gap: spacing.md,
},
loginTitle: {
fontSize: 20,
fontWeight: '600',
textAlign: 'center',
},
loginSubtitle: {
fontSize: 14,
textAlign: 'center',
lineHeight: 20,
},
loginButton: {
paddingHorizontal: spacing.lg,
paddingVertical: spacing.md,
borderRadius: borderRadius.lg,
marginTop: spacing.sm,
},
loginButtonText: {
fontSize: 16,
fontWeight: '600',
},
header: {
paddingHorizontal: spacing.lg,
paddingTop: spacing.lg,