chore: build
This commit is contained in:
@@ -60,7 +60,7 @@ export default function AdminLoginScreen() {
|
||||
heroTitle: {
|
||||
fontSize: screenWidth < 380 ? fontSize.xl : fontSize.xxl,
|
||||
fontWeight: "800",
|
||||
color: colors.textWhite,
|
||||
color: colors.textPrimary,
|
||||
marginTop: spacing.m,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function CabineLoginScreen() {
|
||||
heroTitle: {
|
||||
fontSize: screenWidth < 380 ? fontSize.xl : fontSize.xxl,
|
||||
fontWeight: "800",
|
||||
color: colors.textWhite,
|
||||
color: colors.textPrimary,
|
||||
marginTop: spacing.m,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function DeliveryLoginScreen() {
|
||||
heroTitle: {
|
||||
fontSize: screenWidth < 380 ? fontSize.xl : fontSize.xxl,
|
||||
fontWeight: "800",
|
||||
color: colors.textWhite,
|
||||
color: colors.textPrimary,
|
||||
marginTop: spacing.m,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useMemo } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
@@ -85,9 +85,75 @@ const LoginClient = () => {
|
||||
if (apiError) setApiError("");
|
||||
};
|
||||
|
||||
const styles = useMemo(
|
||||
() =>
|
||||
StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: colors.bgSecondary },
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
padding: 16,
|
||||
},
|
||||
card: {
|
||||
width: "100%",
|
||||
maxWidth: 400,
|
||||
borderRadius: 16,
|
||||
padding: 24,
|
||||
backgroundColor: colors.bgPrimary,
|
||||
},
|
||||
header: { alignItems: "center", marginBottom: 24 },
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
marginTop: 8,
|
||||
color: colors.textPrimary,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
marginTop: 4,
|
||||
textAlign: "center",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
apiError: {
|
||||
backgroundColor: "#fee2e2",
|
||||
color: "#991b1b",
|
||||
padding: 12,
|
||||
borderRadius: 6,
|
||||
marginBottom: 16,
|
||||
textAlign: "center",
|
||||
},
|
||||
inputGroup: { marginBottom: 16 },
|
||||
label: { marginBottom: 4, fontWeight: "500", color: colors.textSecondary },
|
||||
inputWrapper: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
borderColor: colors.border,
|
||||
backgroundColor: colors.bgInput,
|
||||
},
|
||||
icon: { marginRight: 8 },
|
||||
input: { flex: 1, height: 40, color: colors.textPrimary },
|
||||
inputError: { borderColor: "#ef4444" },
|
||||
errorText: { color: "#ef4444", fontSize: 12, marginTop: 4 },
|
||||
eyeButton: { padding: 4 },
|
||||
submitButton: {
|
||||
backgroundColor: colors.accent,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
alignItems: "center",
|
||||
marginTop: 8,
|
||||
},
|
||||
submitText: { color: colors.white, fontWeight: "600", fontSize: 16 },
|
||||
}),
|
||||
[colors],
|
||||
);
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={[styles.container, { backgroundColor: colors.bgSecondary }]}
|
||||
style={styles.container}
|
||||
behavior="padding"
|
||||
>
|
||||
<ScrollView
|
||||
@@ -95,15 +161,13 @@ const LoginClient = () => {
|
||||
keyboardShouldPersistTaps="handled"
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<View style={[styles.card, { backgroundColor: colors.bgPrimary }]}>
|
||||
<View style={styles.card}>
|
||||
<View style={styles.header}>
|
||||
<FontAwesome name="user-circle" size={48} color="#7c3aed" />
|
||||
<Text style={[styles.title, { color: colors.textWhite }]}>
|
||||
<FontAwesome name="user-circle" size={48} color={colors.accent} />
|
||||
<Text style={styles.title}>
|
||||
Connexion Client
|
||||
</Text>
|
||||
<Text
|
||||
style={[styles.subtitle, { color: colors.textMuted }]}
|
||||
>
|
||||
<Text style={styles.subtitle}>
|
||||
Accédez à votre espace personnel
|
||||
</Text>
|
||||
</View>
|
||||
@@ -113,20 +177,10 @@ const LoginClient = () => {
|
||||
) : null}
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text
|
||||
style={[styles.label, { color: colors.textSecondary }]}
|
||||
>
|
||||
<Text style={styles.label}>
|
||||
Username Telegram
|
||||
</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.inputWrapper,
|
||||
{
|
||||
borderColor: colors.border,
|
||||
backgroundColor: colors.bgInput,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Feather
|
||||
name="user"
|
||||
size={20}
|
||||
@@ -134,11 +188,7 @@ const LoginClient = () => {
|
||||
style={styles.icon}
|
||||
/>
|
||||
<TextInput
|
||||
style={[
|
||||
styles.input,
|
||||
{ color: colors.textWhite },
|
||||
errors.username && styles.inputError,
|
||||
]}
|
||||
style={[styles.input, errors.username && styles.inputError]}
|
||||
placeholder="Votre username"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
value={formData.username}
|
||||
@@ -156,20 +206,10 @@ const LoginClient = () => {
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text
|
||||
style={[styles.label, { color: colors.textSecondary }]}
|
||||
>
|
||||
<Text style={styles.label}>
|
||||
Mot de passe
|
||||
</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.inputWrapper,
|
||||
{
|
||||
borderColor: colors.border,
|
||||
backgroundColor: colors.bgInput,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Feather
|
||||
name="lock"
|
||||
size={20}
|
||||
@@ -177,11 +217,7 @@ const LoginClient = () => {
|
||||
style={styles.icon}
|
||||
/>
|
||||
<TextInput
|
||||
style={[
|
||||
styles.input,
|
||||
{ color: colors.textWhite },
|
||||
errors.password && styles.inputError,
|
||||
]}
|
||||
style={[styles.input, errors.password && styles.inputError]}
|
||||
placeholder="••••••"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
secureTextEntry={!showPassword}
|
||||
@@ -215,7 +251,7 @@ const LoginClient = () => {
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator color="white" />
|
||||
<ActivityIndicator color={colors.white} />
|
||||
) : (
|
||||
<Text style={styles.submitText}>Se connecter</Text>
|
||||
)}
|
||||
@@ -227,52 +263,3 @@ const LoginClient = () => {
|
||||
};
|
||||
|
||||
export default LoginClient;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
padding: 16,
|
||||
},
|
||||
card: { width: "100%", maxWidth: 400, borderRadius: 16, padding: 24 },
|
||||
header: { alignItems: "center", marginBottom: 24 },
|
||||
title: { fontSize: 24, fontWeight: "bold", marginTop: 8 },
|
||||
subtitle: { fontSize: 14, marginTop: 4, textAlign: "center" },
|
||||
apiError: {
|
||||
backgroundColor: "#fee2e2",
|
||||
color: "#991b1b",
|
||||
padding: 12,
|
||||
borderRadius: 6,
|
||||
marginBottom: 16,
|
||||
textAlign: "center",
|
||||
},
|
||||
inputGroup: { marginBottom: 16 },
|
||||
label: { marginBottom: 4, fontWeight: "500" },
|
||||
inputWrapper: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
icon: { marginRight: 8 },
|
||||
input: { flex: 1, height: 40 },
|
||||
inputError: { borderColor: "#ef4444" },
|
||||
errorText: { color: "#ef4444", fontSize: 12, marginTop: 4 },
|
||||
eyeButton: { padding: 4 },
|
||||
submitButton: {
|
||||
backgroundColor: "#7c3aed",
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
alignItems: "center",
|
||||
marginTop: 8,
|
||||
},
|
||||
submitText: { color: "white", fontWeight: "600", fontSize: 16 },
|
||||
signup: { marginTop: 16, alignItems: "center" },
|
||||
signupText: {},
|
||||
signupLink: { color: "#a78bfa", fontWeight: "600" },
|
||||
});
|
||||
|
||||
@@ -55,8 +55,17 @@ export default function ProfileScreen() {
|
||||
const [twoFAAdminEnabled, setTwoFAAdminEnabled] = useState(false);
|
||||
const [twoFALoading, setTwoFALoading] = useState(false);
|
||||
|
||||
// Modal confirmation infos par défaut
|
||||
const [showSaveModal, setShowSaveModal] = useState(false);
|
||||
// Modals confirmation sauvegarde
|
||||
const [showSaveModal, setShowSaveModal] = useState(false);
|
||||
const [showConfirmContactModal, setShowConfirmContactModal] = useState(false);
|
||||
const [showConfirmAddressModal, setShowConfirmAddressModal] = useState(false);
|
||||
|
||||
// Modal succès / erreur générique
|
||||
const [showSuccessModal, setShowSuccessModal] = useState(false);
|
||||
const [successTitle, setSuccessTitle] = useState("");
|
||||
const [successMsg, setSuccessMsg] = useState("");
|
||||
const [showErrorModal, setShowErrorModal] = useState(false);
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
|
||||
// Modal changement de mot de passe
|
||||
const [showPasswordModal, setShowPasswordModal] = useState(false);
|
||||
@@ -117,12 +126,17 @@ export default function ProfileScreen() {
|
||||
AsyncStorage.setItem(STORAGE_SIGNAL, signalPseudo.trim()),
|
||||
]);
|
||||
setShowSaveModal(false);
|
||||
Alert.alert("Enregistré", "Informations par défaut sauvegardées");
|
||||
setSuccessTitle("Informations sauvegardées");
|
||||
setSuccessMsg("Téléphone et pseudo Signal seront pré-remplis lors de vos prochaines commandes.");
|
||||
setShowSuccessModal(true);
|
||||
};
|
||||
|
||||
const saveAddress = async () => {
|
||||
setShowConfirmAddressModal(false);
|
||||
await AsyncStorage.setItem(STORAGE_ADDRESS, defaultAddress.trim());
|
||||
Alert.alert("Enregistré", "Adresse par défaut sauvegardée");
|
||||
setSuccessTitle("Adresse sauvegardée");
|
||||
setSuccessMsg("Votre adresse par défaut sera pré-remplie à la prochaine commande.");
|
||||
setShowSuccessModal(true);
|
||||
};
|
||||
|
||||
const handleLinkTelegram = async () => {
|
||||
@@ -157,15 +171,18 @@ export default function ProfileScreen() {
|
||||
|
||||
const handleChangePassword = async () => {
|
||||
if (!currentPwd || !newPwd || !confirmPwd) {
|
||||
Alert.alert("Erreur", "Veuillez remplir tous les champs");
|
||||
setErrorMsg("Veuillez remplir tous les champs.");
|
||||
setShowErrorModal(true);
|
||||
return;
|
||||
}
|
||||
if (newPwd.length < 8) {
|
||||
Alert.alert("Erreur", "Le nouveau mot de passe doit contenir au moins 8 caractères");
|
||||
setErrorMsg("Le nouveau mot de passe doit contenir au moins 8 caractères.");
|
||||
setShowErrorModal(true);
|
||||
return;
|
||||
}
|
||||
if (newPwd !== confirmPwd) {
|
||||
Alert.alert("Erreur", "Les nouveaux mots de passe ne correspondent pas");
|
||||
setErrorMsg("Les nouveaux mots de passe ne correspondent pas.");
|
||||
setShowErrorModal(true);
|
||||
return;
|
||||
}
|
||||
setSavingPassword(true);
|
||||
@@ -174,9 +191,12 @@ export default function ProfileScreen() {
|
||||
if (result.success) {
|
||||
setShowPasswordModal(false);
|
||||
setCurrentPwd(""); setNewPwd(""); setConfirmPwd("");
|
||||
Alert.alert("Succès", "Mot de passe modifié avec succès");
|
||||
setSuccessTitle("Mot de passe modifié");
|
||||
setSuccessMsg("Votre mot de passe a été changé avec succès.");
|
||||
setShowSuccessModal(true);
|
||||
} else {
|
||||
Alert.alert("Erreur", result.message || "Erreur inattendue");
|
||||
setErrorMsg(result.message || "Erreur inattendue lors du changement de mot de passe.");
|
||||
setShowErrorModal(true);
|
||||
}
|
||||
} finally {
|
||||
setSavingPassword(false);
|
||||
@@ -195,13 +215,17 @@ export default function ProfileScreen() {
|
||||
};
|
||||
|
||||
const saveContact = async () => {
|
||||
setShowConfirmContactModal(false);
|
||||
setSavingContact(true);
|
||||
const res = await updateMyProfile({ nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim() });
|
||||
setSavingContact(false);
|
||||
if (res.success) {
|
||||
Alert.alert("Succès", res.message ?? "Profil mis à jour");
|
||||
setSuccessTitle("Compte mis à jour");
|
||||
setSuccessMsg(res.message ?? "Vos informations de compte ont été enregistrées avec succès.");
|
||||
setShowSuccessModal(true);
|
||||
} else {
|
||||
Alert.alert("Erreur", res.message ?? "Erreur lors de la mise à jour");
|
||||
setErrorMsg(res.message ?? "Erreur lors de la mise à jour du profil.");
|
||||
setShowErrorModal(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -422,7 +446,7 @@ export default function ProfileScreen() {
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.saveBtn}
|
||||
onPress={saveContact}
|
||||
onPress={() => setShowConfirmContactModal(true)}
|
||||
disabled={savingContact}
|
||||
>
|
||||
<Ionicons name="save-outline" size={16} color="#fff" />
|
||||
@@ -451,7 +475,7 @@ export default function ProfileScreen() {
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={[styles.saveBtn, styles.saveBtnSecondary, { marginTop: spacing.m }]}
|
||||
onPress={saveAddress}
|
||||
onPress={() => setShowConfirmAddressModal(true)}
|
||||
>
|
||||
<Ionicons name="save-outline" size={16} color={colors.accent} />
|
||||
<Text style={[styles.saveBtnText, styles.saveBtnTextSecondary]}>
|
||||
@@ -797,6 +821,150 @@ export default function ProfileScreen() {
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
||||
{/* Modal confirmation — Enregistrer le compte */}
|
||||
<Modal
|
||||
visible={showConfirmContactModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={() => setShowConfirmContactModal(false)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.modalOverlay}
|
||||
activeOpacity={1}
|
||||
onPress={() => setShowConfirmContactModal(false)}
|
||||
>
|
||||
<TouchableOpacity activeOpacity={1} onPress={() => {}}>
|
||||
<View style={styles.modalBox}>
|
||||
<View style={styles.modalIconWrap}>
|
||||
<Ionicons name="person-outline" size={24} color={colors.accent} />
|
||||
</View>
|
||||
<Text style={styles.modalTitle}>Mettre à jour le compte ?</Text>
|
||||
<Text style={styles.modalBody}>
|
||||
Vos informations (prénom, nom, téléphone) seront enregistrées sur votre compte.
|
||||
</Text>
|
||||
<View style={styles.modalActions}>
|
||||
<TouchableOpacity
|
||||
style={styles.modalBtnCancel}
|
||||
onPress={() => setShowConfirmContactModal(false)}
|
||||
>
|
||||
<Text style={styles.modalBtnCancelText}>Annuler</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.modalBtnConfirm}
|
||||
onPress={saveContact}
|
||||
>
|
||||
<Text style={styles.modalBtnConfirmText}>Confirmer</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
||||
{/* Modal confirmation — Enregistrer l'adresse */}
|
||||
<Modal
|
||||
visible={showConfirmAddressModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={() => setShowConfirmAddressModal(false)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.modalOverlay}
|
||||
activeOpacity={1}
|
||||
onPress={() => setShowConfirmAddressModal(false)}
|
||||
>
|
||||
<TouchableOpacity activeOpacity={1} onPress={() => {}}>
|
||||
<View style={styles.modalBox}>
|
||||
<View style={[styles.modalIconWrap, { borderColor: "#10b98133", backgroundColor: "#10b98111" }]}>
|
||||
<Ionicons name="location-outline" size={24} color="#10b981" />
|
||||
</View>
|
||||
<Text style={styles.modalTitle}>Enregistrer l'adresse ?</Text>
|
||||
<Text style={styles.modalBody}>
|
||||
Cette adresse sera pré-remplie automatiquement lors de vos prochaines commandes.
|
||||
</Text>
|
||||
<View style={styles.modalActions}>
|
||||
<TouchableOpacity
|
||||
style={styles.modalBtnCancel}
|
||||
onPress={() => setShowConfirmAddressModal(false)}
|
||||
>
|
||||
<Text style={styles.modalBtnCancelText}>Annuler</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.modalBtnConfirm, { borderColor: "#10b98166" }]}
|
||||
onPress={saveAddress}
|
||||
>
|
||||
<Text style={[styles.modalBtnConfirmText, { color: "#10b981" }]}>Confirmer</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
||||
{/* Modal succès générique */}
|
||||
<Modal
|
||||
visible={showSuccessModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={() => setShowSuccessModal(false)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.modalOverlay}
|
||||
activeOpacity={1}
|
||||
onPress={() => setShowSuccessModal(false)}
|
||||
>
|
||||
<TouchableOpacity activeOpacity={1} onPress={() => {}}>
|
||||
<View style={styles.modalBox}>
|
||||
<View style={[styles.modalIconWrap, { borderColor: "#10b98133", backgroundColor: "#10b98111" }]}>
|
||||
<Ionicons name="checkmark-circle-outline" size={24} color="#10b981" />
|
||||
</View>
|
||||
<Text style={styles.modalTitle}>{successTitle}</Text>
|
||||
<Text style={styles.modalBody}>{successMsg}</Text>
|
||||
<View style={styles.modalActions}>
|
||||
<TouchableOpacity
|
||||
style={[styles.modalBtnConfirm, { flex: 1, borderColor: "#10b98166" }]}
|
||||
onPress={() => setShowSuccessModal(false)}
|
||||
>
|
||||
<Text style={[styles.modalBtnConfirmText, { color: "#10b981" }]}>Fermer</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
||||
{/* Modal erreur générique */}
|
||||
<Modal
|
||||
visible={showErrorModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={() => setShowErrorModal(false)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.modalOverlay}
|
||||
activeOpacity={1}
|
||||
onPress={() => setShowErrorModal(false)}
|
||||
>
|
||||
<TouchableOpacity activeOpacity={1} onPress={() => {}}>
|
||||
<View style={styles.modalBox}>
|
||||
<View style={[styles.modalIconWrap, { borderColor: "#ef444433", backgroundColor: "#ef444411" }]}>
|
||||
<Ionicons name="alert-circle-outline" size={24} color="#ef4444" />
|
||||
</View>
|
||||
<Text style={styles.modalTitle}>Une erreur est survenue</Text>
|
||||
<Text style={styles.modalBody}>{errorMsg}</Text>
|
||||
<View style={styles.modalActions}>
|
||||
<TouchableOpacity
|
||||
style={[styles.modalBtnConfirm, { flex: 1, borderColor: "#ef444466", backgroundColor: "#ef444411" }]}
|
||||
onPress={() => setShowErrorModal(false)}
|
||||
>
|
||||
<Text style={[styles.modalBtnConfirmText, { color: "#ef4444" }]}>Fermer</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user