Add a good settings page

This commit is contained in:
Arthur Belleville 2025-07-19 19:10:29 +02:00
parent 490eef9b43
commit 73cbe6356f
No known key found for this signature in database
2 changed files with 470 additions and 2 deletions

View file

@ -8,9 +8,8 @@ import { useColorScheme } from "@/hooks/useColorScheme";
import {
MessageCircle,
Calendar,
List,
Home,
Grid3X3,
Settings,
} from "lucide-react-native";
export default function TabLayout() {
@ -76,6 +75,7 @@ export default function TabLayout() {
/>
),
tabBarLabel: "Discussions",
// tabBarBadge: 10, TODO: Add badge for notifications
}}
/>
<Tabs.Screen
@ -108,6 +108,21 @@ export default function TabLayout() {
tabBarBadge: undefined, // You can set this to a number for notifications
}}
/>
<Tabs.Screen
name="settings"
options={{
title: "Paramètres",
tabBarIcon: ({ focused, color, size }) => (
<Settings
size={focused ? 24 : 22}
color={color}
strokeWidth={focused ? 2.2 : 2}
/>
),
tabBarLabel: "Paramètres",
tabBarBadge: undefined,
}}
/>
</Tabs>
);
}

View file

@ -0,0 +1,453 @@
import React, { useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
StatusBar,
ScrollView,
Switch,
Alert,
Linking,
} from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import { useAuth } from "@/stores/auth";
import { useUser } from "@/providers/UserProvider";
import {
User,
Bell,
Moon,
Shield,
HelpCircle,
Info,
MessageSquare,
LogOut,
ChevronRight,
Smartphone,
Globe,
Lock,
Heart,
} from "lucide-react-native";
import { router } from "expo-router";
export default function SettingsScreen() {
const signOut = useAuth((state) => state.signOut);
const user = useUser();
// Settings state
const [pushNotifications, setPushNotifications] = useState(true);
const [emailNotifications, setEmailNotifications] = useState(true);
const [darkMode, setDarkMode] = useState(false);
const [biometricAuth, setBiometricAuth] = useState(false);
const handleSignOut = () => {
Alert.alert("Déconnexion", "Êtes-vous sûr de vouloir vous déconnecter ?", [
{
text: "Annuler",
style: "cancel",
},
{
text: "Se déconnecter",
style: "destructive",
onPress: signOut,
},
]);
};
const handleContactSupport = () => {
Linking.openURL("mailto:support@xtablo.com?subject=Support XTablo");
};
const handleRateApp = () => {
// Replace with your actual app store URL
Alert.alert(
"Évaluer l'application",
"Vous aimez XTablo ? Laissez-nous un avis sur l'App Store !",
[
{ text: "Plus tard", style: "cancel" },
{ text: "Évaluer", onPress: () => console.log("Rate app") },
]
);
};
const renderSettingsSection = (title: string, children: React.ReactNode) => (
<View style={styles.section}>
<Text style={styles.sectionTitle}>{title}</Text>
<View style={styles.sectionContent}>{children}</View>
</View>
);
const renderSettingsItem = (
icon: React.ReactNode,
title: string,
subtitle?: string,
onPress?: () => void,
rightComponent?: React.ReactNode,
showArrow: boolean = true
) => (
<TouchableOpacity
style={styles.settingsItem}
onPress={onPress}
disabled={!onPress}
activeOpacity={onPress ? 0.7 : 1}
>
<View style={styles.settingsItemLeft}>
<View style={styles.iconContainer}>{icon}</View>
<View style={styles.settingsItemContent}>
<Text style={styles.settingsItemTitle}>{title}</Text>
{subtitle && (
<Text style={styles.settingsItemSubtitle}>{subtitle}</Text>
)}
</View>
</View>
<View style={styles.settingsItemRight}>
{rightComponent}
{showArrow && onPress && (
<ChevronRight size={20} color="#9ca3af" style={{ marginLeft: 8 }} />
)}
</View>
</TouchableOpacity>
);
const renderSwitchItem = (
icon: React.ReactNode,
title: string,
subtitle: string,
value: boolean,
onValueChange: (value: boolean) => void
) =>
renderSettingsItem(
icon,
title,
subtitle,
undefined,
<Switch
value={value}
onValueChange={onValueChange}
trackColor={{ false: "#e5e7eb", true: "#3b82f6" }}
thumbColor={value ? "#ffffff" : "#ffffff"}
ios_backgroundColor="#e5e7eb"
/>,
false
);
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
{/* Header */}
<LinearGradient
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
style={styles.headerGradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
<View style={styles.headerContent}>
<Text style={styles.headerTitle}>Paramètres</Text>
<Text style={styles.headerSubtitle}>
Gérez vos préférences et votre compte
</Text>
</View>
{/* Decorative Elements */}
<View style={styles.decorativeCircle1} />
<View style={styles.decorativeCircle2} />
</LinearGradient>
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
{/* Account Section */}
{renderSettingsSection(
"Compte",
<>
{renderSettingsItem(
<User size={20} color="#3b82f6" />,
"Profil utilisateur",
`${user.name || "Non défini"}${user.email}`,
() => router.push("/user/profile"),
undefined,
true
)}
</>
)}
{/* Notifications Section */}
{renderSettingsSection(
"Notifications",
<>
{renderSwitchItem(
<Bell size={20} color="#10b981" />,
"Notifications push",
"Recevoir des notifications sur votre appareil",
pushNotifications,
setPushNotifications
)}
{renderSwitchItem(
<Smartphone size={20} color="#10b981" />,
"Notifications par email",
"Recevoir des notifications par email",
emailNotifications,
setEmailNotifications
)}
</>
)}
{/* Appearance Section */}
{renderSettingsSection(
"Apparence",
<>
{renderSwitchItem(
<Moon size={20} color="#6366f1" />,
"Mode sombre",
"Utiliser le thème sombre",
darkMode,
setDarkMode
)}
</>
)}
{/* Security Section */}
{renderSettingsSection(
"Sécurité et confidentialité",
<>
{renderSwitchItem(
<Lock size={20} color="#ef4444" />,
"Authentification biométrique",
"Utiliser votre empreinte ou Face ID",
biometricAuth,
setBiometricAuth
)}
{renderSettingsItem(
<Shield size={20} color="#ef4444" />,
"Politique de confidentialité",
"Consulter notre politique de confidentialité",
() => Linking.openURL("https://xtablo.com/privacy-policy"),
undefined,
true
)}
</>
)}
{/* Help & Support Section */}
{renderSettingsSection(
"Aide et support",
<>
{renderSettingsItem(
<HelpCircle size={20} color="#f59e0b" />,
"Centre d'aide",
"FAQ et guides d'utilisation",
() => Linking.openURL("https://xtablo.com/help"),
undefined,
true
)}
{renderSettingsItem(
<MessageSquare size={20} color="#f59e0b" />,
"Contacter le support",
"Envoyez-nous un email",
handleContactSupport,
undefined,
true
)}
{renderSettingsItem(
<Heart size={20} color="#ec4899" />,
"Évaluer l'application",
"Aidez-nous à améliorer XTablo",
handleRateApp,
undefined,
true
)}
</>
)}
{/* About Section */}
{renderSettingsSection(
"À propos",
<>
{renderSettingsItem(
<Info size={20} color="#6b7280" />,
"Version de l'application",
"1.0.0 (Build 1)",
undefined,
undefined,
false
)}
{renderSettingsItem(
<Globe size={20} color="#6b7280" />,
"Site web",
"Visitez notre site web",
() => Linking.openURL("https://xtablo.com"),
undefined,
true
)}
</>
)}
{/* Sign Out Section */}
<View style={styles.signOutSection}>
<TouchableOpacity
style={styles.signOutButton}
onPress={handleSignOut}
activeOpacity={0.8}
>
<LinearGradient
colors={["#ef4444", "#dc2626"]}
style={styles.signOutGradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
>
<LogOut size={20} color="white" />
<Text style={styles.signOutText}>Se déconnecter</Text>
</LinearGradient>
</TouchableOpacity>
</View>
{/* Bottom Spacing */}
<View style={styles.bottomSpacing} />
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f8fafc",
},
headerGradient: {
paddingTop: 50,
paddingBottom: 25,
paddingHorizontal: 20,
position: "relative",
overflow: "hidden",
},
headerContent: {
zIndex: 10,
},
headerTitle: {
fontSize: 28,
color: "white",
fontWeight: "bold",
marginBottom: 4,
},
headerSubtitle: {
fontSize: 16,
color: "rgba(255, 255, 255, 0.8)",
fontWeight: "400",
},
decorativeCircle1: {
position: "absolute",
top: -50,
right: -30,
width: 120,
height: 120,
borderRadius: 60,
backgroundColor: "rgba(255, 255, 255, 0.1)",
},
decorativeCircle2: {
position: "absolute",
bottom: -20,
left: -20,
width: 80,
height: 80,
borderRadius: 40,
backgroundColor: "rgba(255, 255, 255, 0.08)",
},
content: {
flex: 1,
backgroundColor: "#f8fafc",
marginTop: -10,
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
paddingTop: 20,
},
section: {
marginBottom: 24,
paddingHorizontal: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: "600",
color: "#1f2937",
marginBottom: 12,
marginLeft: 4,
},
sectionContent: {
backgroundColor: "white",
borderRadius: 16,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 3,
overflow: "hidden",
},
settingsItem: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: 20,
paddingVertical: 16,
borderBottomWidth: 1,
borderBottomColor: "#f3f4f6",
},
settingsItemLeft: {
flexDirection: "row",
alignItems: "center",
flex: 1,
},
iconContainer: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#f3f4f6",
justifyContent: "center",
alignItems: "center",
marginRight: 12,
},
settingsItemContent: {
flex: 1,
},
settingsItemTitle: {
fontSize: 16,
fontWeight: "500",
color: "#1f2937",
marginBottom: 2,
},
settingsItemSubtitle: {
fontSize: 14,
color: "#6b7280",
},
settingsItemRight: {
flexDirection: "row",
alignItems: "center",
},
signOutSection: {
paddingHorizontal: 20,
marginTop: 20,
marginBottom: 20,
},
signOutButton: {
borderRadius: 16,
shadowColor: "#ef4444",
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 6,
},
signOutGradient: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
paddingVertical: 16,
paddingHorizontal: 24,
borderRadius: 16,
},
signOutText: {
color: "white",
fontSize: 16,
fontWeight: "600",
marginLeft: 8,
},
bottomSpacing: {
height: 100,
},
});