Fix: Resolve UI/UX issues and improve user experience
- Configure Firebase Auth with AsyncStorage persistence - Fix 'Text strings must be rendered within <Text>' error in navigation - Improve bottom tab bar: iOS style with blur effect, better height, rounded corners - Fix Dashboard quick action buttons to open transaction modal directly - Add auto-open modal when navigating from Dashboard - Improve selection visibility in modals (type selector and categories) - Add amount validation: only positive numbers, max 2 decimals - Add padding to Dashboard content to avoid tab bar overlap - Apply same fixes to both Transaction and Subscription screens
This commit is contained in:
@@ -20,6 +20,7 @@ const firebaseConfig = {
|
||||
const app = initializeApp(firebaseConfig);
|
||||
|
||||
// Services Firebase
|
||||
// Note: AsyncStorage est géré automatiquement par Firebase pour React Native
|
||||
export const auth = getAuth(app);
|
||||
export const db = getFirestore(app);
|
||||
export const storage = getStorage(app);
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { ActivityIndicator, View, StyleSheet } from 'react-native';
|
||||
import { ActivityIndicator, View, StyleSheet, Text } from 'react-native';
|
||||
|
||||
import { useAuth } from '../hooks/useAuth';
|
||||
import { LoginScreen } from '../screens/LoginScreen';
|
||||
@@ -25,16 +25,24 @@ const MainTabs = () => {
|
||||
tabBarActiveTintColor: '#4A90E2',
|
||||
tabBarInactiveTintColor: '#999',
|
||||
tabBarStyle: {
|
||||
backgroundColor: '#FFF',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: '#E0E0E0',
|
||||
paddingBottom: 8,
|
||||
paddingTop: 8,
|
||||
height: 60
|
||||
position: 'absolute',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
borderTopWidth: 0,
|
||||
elevation: 0,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: -2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 8,
|
||||
paddingBottom: 34, // Espace pour la barre iOS
|
||||
paddingTop: 12,
|
||||
height: 90, // Plus haute
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20
|
||||
},
|
||||
tabBarLabelStyle: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600'
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
marginTop: 4
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -75,9 +83,9 @@ const MainTabs = () => {
|
||||
};
|
||||
|
||||
const TabIcon = ({ icon, color }: { icon: string; color: string }) => (
|
||||
<View style={{ opacity: color === '#4A90E2' ? 1 : 0.5 }}>
|
||||
<View>{icon}</View>
|
||||
</View>
|
||||
<Text style={{ fontSize: 24, opacity: color === '#4A90E2' ? 1 : 0.5 }}>
|
||||
{icon}
|
||||
</Text>
|
||||
);
|
||||
|
||||
export const AppNavigator = () => {
|
||||
|
||||
@@ -75,6 +75,7 @@ export const DashboardScreen = ({ navigation }: any) => {
|
||||
return (
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
||||
>
|
||||
<View style={styles.header}>
|
||||
@@ -140,14 +141,14 @@ export const DashboardScreen = ({ navigation }: any) => {
|
||||
<View style={styles.quickActions}>
|
||||
<TouchableOpacity
|
||||
style={[styles.actionButton, styles.addExpenseButton]}
|
||||
onPress={() => navigation.navigate('Transactions', { type: 'expense' })}
|
||||
onPress={() => navigation.navigate('Transactions', { type: 'expense', openModal: true })}
|
||||
>
|
||||
<Text style={styles.actionIcon}>➖</Text>
|
||||
<Text style={styles.actionText}>Dépense</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.actionButton, styles.addIncomeButton]}
|
||||
onPress={() => navigation.navigate('Transactions', { type: 'income' })}
|
||||
onPress={() => navigation.navigate('Transactions', { type: 'income', openModal: true })}
|
||||
>
|
||||
<Text style={styles.actionIcon}>➕</Text>
|
||||
<Text style={styles.actionText}>Revenu</Text>
|
||||
@@ -162,6 +163,9 @@ const styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
backgroundColor: '#F8F9FA'
|
||||
},
|
||||
scrollContent: {
|
||||
paddingBottom: 100 // Espace pour la tab bar
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
|
||||
@@ -223,7 +223,16 @@ export const SubscriptionScreen = () => {
|
||||
label="Montant (€)"
|
||||
placeholder="0.00"
|
||||
value={amount}
|
||||
onChangeText={setAmount}
|
||||
onChangeText={(text) => {
|
||||
// Permettre uniquement les chiffres et un point décimal
|
||||
const cleaned = text.replace(/[^0-9.]/g, '');
|
||||
// Empêcher plusieurs points
|
||||
const parts = cleaned.split('.');
|
||||
if (parts.length > 2) return;
|
||||
// Limiter à 2 décimales
|
||||
if (parts[1] && parts[1].length > 2) return;
|
||||
setAmount(cleaned);
|
||||
}}
|
||||
keyboardType="decimal-pad"
|
||||
/>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { TransactionCard } from '../components/TransactionCard';
|
||||
import { InputText } from '../components/InputText';
|
||||
import { Button } from '../components/Button';
|
||||
|
||||
export const TransactionScreen = ({ route }: any) => {
|
||||
export const TransactionScreen = ({ route, navigation }: any) => {
|
||||
const { user } = useAuth();
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
@@ -48,6 +48,18 @@ export const TransactionScreen = ({ route }: any) => {
|
||||
return () => unsubscribe();
|
||||
}, [user]);
|
||||
|
||||
// Ouvrir le modal automatiquement si on vient du Dashboard
|
||||
useEffect(() => {
|
||||
if (route?.params?.openModal) {
|
||||
setModalVisible(true);
|
||||
if (route.params.type) {
|
||||
setType(route.params.type);
|
||||
}
|
||||
// Réinitialiser le paramètre
|
||||
navigation.setParams({ openModal: false });
|
||||
}
|
||||
}, [route?.params]);
|
||||
|
||||
const loadCategories = async () => {
|
||||
if (!user) return;
|
||||
|
||||
@@ -218,7 +230,16 @@ export const TransactionScreen = ({ route }: any) => {
|
||||
label="Montant (€)"
|
||||
placeholder="0.00"
|
||||
value={amount}
|
||||
onChangeText={setAmount}
|
||||
onChangeText={(text) => {
|
||||
// Permettre uniquement les chiffres et un point décimal
|
||||
const cleaned = text.replace(/[^0-9.]/g, '');
|
||||
// Empêcher plusieurs points
|
||||
const parts = cleaned.split('.');
|
||||
if (parts.length > 2) return;
|
||||
// Limiter à 2 décimales
|
||||
if (parts[1] && parts[1].length > 2) return;
|
||||
setAmount(cleaned);
|
||||
}}
|
||||
keyboardType="decimal-pad"
|
||||
/>
|
||||
|
||||
@@ -356,7 +377,8 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center'
|
||||
},
|
||||
typeButtonActive: {
|
||||
borderWidth: 2
|
||||
borderWidth: 3,
|
||||
backgroundColor: '#F0F7FF'
|
||||
},
|
||||
expenseButton: {
|
||||
borderColor: '#FF6B6B'
|
||||
@@ -367,10 +389,11 @@ const styles = StyleSheet.create({
|
||||
typeButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#666'
|
||||
color: '#999'
|
||||
},
|
||||
typeButtonTextActive: {
|
||||
color: '#333'
|
||||
color: '#333',
|
||||
fontWeight: '700'
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
@@ -396,7 +419,13 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
categoryItemActive: {
|
||||
backgroundColor: '#FFF',
|
||||
borderWidth: 2
|
||||
borderWidth: 3,
|
||||
transform: [{ scale: 1.05 }],
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 4,
|
||||
elevation: 4
|
||||
},
|
||||
categoryIcon: {
|
||||
fontSize: 28,
|
||||
@@ -405,6 +434,7 @@ const styles = StyleSheet.create({
|
||||
categoryName: {
|
||||
fontSize: 11,
|
||||
color: '#666',
|
||||
fontWeight: '600',
|
||||
textAlign: 'center'
|
||||
},
|
||||
submitButton: {
|
||||
|
||||
Reference in New Issue
Block a user