chore: add change password
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
StyleSheet,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
import { Feather } from "@expo/vector-icons";
|
||||
import { useAuth } from "../../auth/AuthContext";
|
||||
import { useTheme } from "../../context/ThemeContext";
|
||||
import { changePassword } from "../../api/api";
|
||||
|
||||
export default function ChangePasswordScreen() {
|
||||
const { setMustChangePassword } = useAuth();
|
||||
const { colors } = useTheme();
|
||||
|
||||
const [currentPassword, setCurrentPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [showCurrent, setShowCurrent] = useState(false);
|
||||
const [showNew, setShowNew] = useState(false);
|
||||
const [showConfirm, setShowConfirm] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleChangePassword = async () => {
|
||||
if (!currentPassword || !newPassword || !confirmPassword) {
|
||||
Alert.alert("Erreur", "Veuillez remplir tous les champs");
|
||||
return;
|
||||
}
|
||||
if (newPassword.length < 8) {
|
||||
Alert.alert(
|
||||
"Erreur",
|
||||
"Le nouveau mot de passe doit contenir au moins 8 caractères",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (newPassword !== confirmPassword) {
|
||||
Alert.alert("Erreur", "Les nouveaux mots de passe ne correspondent pas");
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await changePassword(currentPassword, newPassword);
|
||||
if (result.success) {
|
||||
setMustChangePassword(false);
|
||||
} else {
|
||||
Alert.alert("Erreur", result.message || "Erreur inattendue");
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { backgroundColor: colors.bgPrimary }]}>
|
||||
<View style={styles.iconWrapper}>
|
||||
<Feather name="lock" size={48} color="#7c3aed" />
|
||||
</View>
|
||||
<Text style={[styles.title, { color: colors.textPrimary }]}>
|
||||
Changez votre mot de passe
|
||||
</Text>
|
||||
<Text style={[styles.subtitle, { color: colors.textSecondary }]}>
|
||||
Pour accéder à l'application, vous devez définir un nouveau mot de
|
||||
passe personnel.
|
||||
</Text>
|
||||
|
||||
<View style={[styles.inputWrapper, { backgroundColor: colors.bgSecondary, borderColor: colors.border }]}>
|
||||
<Feather name="lock" size={18} color={colors.textMuted} style={styles.inputIcon} />
|
||||
<TextInput
|
||||
style={[styles.input, { color: colors.textPrimary }]}
|
||||
placeholder="Mot de passe actuel"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
secureTextEntry={!showCurrent}
|
||||
value={currentPassword}
|
||||
onChangeText={setCurrentPassword}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setShowCurrent(!showCurrent)}>
|
||||
<Feather name={showCurrent ? "eye-off" : "eye"} size={18} color={colors.textMuted} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={[styles.inputWrapper, { backgroundColor: colors.bgSecondary, borderColor: colors.border }]}>
|
||||
<Feather name="key" size={18} color={colors.textMuted} style={styles.inputIcon} />
|
||||
<TextInput
|
||||
style={[styles.input, { color: colors.textPrimary }]}
|
||||
placeholder="Nouveau mot de passe (min. 8 car.)"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
secureTextEntry={!showNew}
|
||||
value={newPassword}
|
||||
onChangeText={setNewPassword}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setShowNew(!showNew)}>
|
||||
<Feather name={showNew ? "eye-off" : "eye"} size={18} color={colors.textMuted} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={[styles.inputWrapper, { backgroundColor: colors.bgSecondary, borderColor: colors.border }]}>
|
||||
<Feather name="check-circle" size={18} color={colors.textMuted} style={styles.inputIcon} />
|
||||
<TextInput
|
||||
style={[styles.input, { color: colors.textPrimary }]}
|
||||
placeholder="Confirmer le nouveau mot de passe"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
secureTextEntry={!showConfirm}
|
||||
value={confirmPassword}
|
||||
onChangeText={setConfirmPassword}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setShowConfirm(!showConfirm)}>
|
||||
<Feather name={showConfirm ? "eye-off" : "eye"} size={18} color={colors.textMuted} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.button, loading && styles.buttonDisabled]}
|
||||
onPress={handleChangePassword}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#fff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>Confirmer</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 24,
|
||||
justifyContent: "center",
|
||||
},
|
||||
iconWrapper: {
|
||||
alignItems: "center",
|
||||
marginBottom: 16,
|
||||
},
|
||||
title: {
|
||||
fontSize: 22,
|
||||
fontWeight: "bold",
|
||||
marginBottom: 10,
|
||||
textAlign: "center",
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
marginBottom: 32,
|
||||
textAlign: "center",
|
||||
lineHeight: 20,
|
||||
},
|
||||
inputWrapper: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
height: 50,
|
||||
marginBottom: 14,
|
||||
},
|
||||
inputIcon: {
|
||||
marginRight: 8,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: 15,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: "#7c3aed",
|
||||
height: 50,
|
||||
borderRadius: 8,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginTop: 8,
|
||||
},
|
||||
buttonDisabled: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
buttonText: {
|
||||
color: "#fff",
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
},
|
||||
});
|
||||
@@ -60,7 +60,7 @@ const LoginClient = () => {
|
||||
formData.password,
|
||||
);
|
||||
if (result.success && result.access_token) {
|
||||
await loginClient(result.access_token);
|
||||
await loginClient(result.access_token, result.user?.must_change_password ?? false);
|
||||
} else {
|
||||
const errorMessage =
|
||||
result.message || "Identifiants incorrects";
|
||||
|
||||
Reference in New Issue
Block a user