chore: build

This commit is contained in:
2026-06-11 23:23:29 +02:00
parent 92e1e50a5d
commit 88030da8be
5 changed files with 263 additions and 108 deletions
@@ -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,
},
+79 -92
View File
@@ -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" },
});
+181 -13
View File
@@ -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>
);
}