Fixes and tickets

This commit is contained in:
Thomas Demirdjian
2025-10-28 15:43:18 +01:00
parent 2599a25d77
commit d1be3c19a2
31 changed files with 6663 additions and 795 deletions
+345 -104
View File
@@ -1,23 +1,32 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import React, { useEffect, useMemo, useState } from "react";
import * as AppleAuthentication from "expo-apple-authentication";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
ActivityIndicator,
FlatList,
KeyboardAvoidingView,
Modal,
Platform,
Pressable,
StyleSheet,
Text,
TextInput,
View,
} from "react-native";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { BlurView } from "expo-blur";
import Svg, { Path } from "react-native-svg";
import { background } from "../assets";
import BorderGradientButton from "../components/BorderGradientButton";
import { Input } from "../components/Input";
import ItemContainer from "../components/ItemContainer/ItemContainer";
import COUNTRIES from "../constants/countries";
import firebase from "../config/firebase";
import { isWeb } from "../hooks/useLayoutType";
import useSocialAuth from "../hooks/useSocialAuth";
import Page from "../layouts/Page";
import { Routes } from "../navigation";
import { navigate } from "../navigation/NavigationService";
import { navigate, reset } from "../navigation/NavigationService";
import { Palette } from "../styles";
import { FONT_FAMILY } from "../styles/Fonts";
@@ -33,6 +42,23 @@ const Register = () => {
const [isCountryModalVisible, setIsCountryModalVisible] = useState(false);
const [preferredLanguage, setPreferredLanguage] = useState(null);
const afterSocialAuth = useCallback(async () => {
const uid = firebase.auth().currentUser?.uid;
if (!uid) throw new Error("Aucun utilisateur après connexion");
reset({ index: 0, routes: [{ name: Routes.BottomTab }] });
}, []);
const {
signInWithGoogle,
signInWithApple,
isAppleSignInAvailable,
isLoading: socialLoading,
} = useSocialAuth({
onSuccess: afterSocialAuth,
});
const isBusy = socialLoading;
useEffect(() => {
AsyncStorage.getItem(LANGUAGE_STORAGE_KEY)
.then((storedLanguage) => {
@@ -51,7 +77,7 @@ const Register = () => {
return COUNTRIES;
}
return COUNTRIES.filter((country) =>
country.name.toLowerCase().includes(query)
country.name.toLowerCase().includes(query),
);
}, [countrySearch]);
@@ -73,6 +99,118 @@ const Register = () => {
setCountrySearch("");
};
const renderFormContent = () => (
<View style={styles.formContent}>
<Text style={styles.title}>Renseigne tes informations</Text>
{preferredLanguage && !isWeb ? (
<Text style={styles.languageInfo}>
Langue choisie :{" "}
<Text style={styles.languageInfoValue}>
{preferredLanguage === "fr" ? "Français" : "English"}
</Text>
</Text>
) : null}
<View style={{ gap: 16 }}>
<View style={{ gap: 12 }}>
<Input
placeholder="Prénom"
label="Prénom"
isBlur
value={firstName}
setValue={setFirstName}
/>
<Input
placeholder="Nom"
label="Nom"
isBlur
value={lastName}
setValue={setLastName}
/>
<View style={styles.countryField}>
<Text style={styles.inputLabel}>Pays</Text>
<BlurView
tint="dark"
style={[
styles.countryBlurWrapper,
selectedCountry ? styles.countryButtonFilled : null,
]}
>
<Pressable
style={({ pressed }) => [
styles.countryButton,
pressed ? styles.countryButtonPressed : null,
]}
onPress={() => setIsCountryModalVisible(true)}
>
<Text
style={[
styles.countryButtonText,
!selectedCountry && styles.countryButtonPlaceholder,
]}
>
{selectedCountry ? selectedCountry.name : "Choisis ton pays"}
</Text>
</Pressable>
</BlurView>
</View>
<Input
placeholder="Ville"
label="Ville"
isBlur
value={city}
setValue={setCity}
/>
</View>
<Input
placeholder="Adresse mail"
label="Adresse mail"
isBlur
type="email"
value={email}
setValue={setEmail}
/>
</View>
<BorderGradientButton
title="Créer mon compte"
containerStyle={{
width: "90%",
alignSelf: "center",
}}
onPress={() =>
navigate(Routes.CreatePassword, {
email: email.trim(),
firstName: firstName.trim(),
lastName: lastName.trim(),
city: city.trim(),
country: selectedCountry,
preferredLanguage,
})
}
disabled={!isFormValid || isBusy}
/>
<View style={styles.socialWrapper}>
{isAppleSignInAvailable ? (
<AppleAuthButton
onPress={signInWithApple}
disabled={isBusy}
loading={socialLoading}
/>
) : null}
<GoogleAuthButton
onPress={signInWithGoogle}
disabled={isBusy}
loading={socialLoading}
/>
</View>
<View style={styles.footer}>
<Text style={styles.terms}>
En tinscrivant, tu acceptes nos conditions générales{"\n"}
dutilisation et notre politique de confidentialité.
</Text>
</View>
</View>
);
return (
<Page
width={isWeb ? 600 : null}
@@ -81,103 +219,39 @@ const Register = () => {
title="Inscription"
>
<View style={styles.pageContent}>
<ItemContainer height={680} disableKeyboardHeight>
<View style={styles.formContent}>
<Text style={styles.title}>Renseigne tes informations</Text>
{preferredLanguage && (
<Text style={styles.languageInfo}>
Langue choisie :{" "}
<Text style={styles.languageInfoValue}>
{preferredLanguage === "fr" ? "Français" : "English"}
</Text>
</Text>
)}
<View style={{ gap: 16 }}>
<View style={{ gap: 12 }}>
<Input
placeholder="Prénom"
label="Prénom"
isBlur
value={firstName}
setValue={setFirstName}
/>
<Input
placeholder="Nom"
label="Nom"
isBlur
value={lastName}
setValue={setLastName}
/>
<View style={styles.countryField}>
<Text style={styles.inputLabel}>Pays</Text>
<Pressable
style={[
styles.countryButton,
selectedCountry ? styles.countryButtonFilled : null,
]}
onPress={() => setIsCountryModalVisible(true)}
>
<Text
style={[
styles.countryButtonText,
!selectedCountry && styles.countryButtonPlaceholder,
]}
>
{selectedCountry
? selectedCountry.name
: "Choisis ton pays"}
</Text>
</Pressable>
</View>
<Input
placeholder="Ville"
label="Ville"
isBlur
value={city}
setValue={setCity}
/>
</View>
<Input
placeholder="Adresse mail"
label="Adresse mail"
isBlur
type="email"
value={email}
setValue={setEmail}
/>
</View>
<BorderGradientButton
title="Créer mon compte"
containerStyle={{
width: "80%",
alignSelf: "center",
}}
onPress={() =>
navigate(Routes.CreatePassword, {
email: email.trim(),
firstName: firstName.trim(),
lastName: lastName.trim(),
city: city.trim(),
country: selectedCountry,
preferredLanguage,
})
}
disabled={!isFormValid}
/>
<View style={styles.footer}>
<Text style={styles.terms}>
En tinscrivant, tu acceptes nos conditions générales{"\n"}
dutilisation et notre politique de confidentialité.
</Text>
<Pressable onPress={() => navigate(Routes.Login)}>
<Text style={styles.loginText}>
Tu as déjà un compte?{" "}
<Text style={styles.loginLink}>Se connecter</Text>
</Text>
</Pressable>
</View>
</View>
<ItemContainer
height={isWeb ? 720 : undefined}
disableKeyboardHeight
style={!isWeb ? styles.mobileItemContainer : styles.webItemContainer}
>
{isWeb ? (
renderFormContent()
) : (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.mobileAvoider}
>
<KeyboardAwareScrollView
contentContainerStyle={styles.mobileScrollContent}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
>
{renderFormContent()}
</KeyboardAwareScrollView>
</KeyboardAvoidingView>
)}
</ItemContainer>
<View style={styles.bottomLoginPrompt}>
<Text style={styles.bottomFooterText}>
Tu as déjà un compte ?{" "}
<Text
style={styles.bottomFooterLink}
onPress={() => navigate(Routes.Login)}
>
Se connecter
</Text>
</Text>
</View>
</View>
<Modal
transparent
@@ -224,6 +298,76 @@ const Register = () => {
);
};
const AppleAuthButton = ({ onPress, disabled, loading }) => {
if (isWeb) {
return null;
}
return (
<View style={styles.nativeButtonWrapper}>
<AppleAuthentication.AppleAuthenticationButton
buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_UP}
buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.WHITE}
style={styles.nativeButton}
cornerRadius={12}
onPress={onPress}
disabled={disabled}
/>
{loading ? (
<View style={styles.nativeLoadingOverlay}>
<ActivityIndicator size="small" color={Palette.black} />
</View>
) : null}
</View>
);
};
const GoogleAuthButton = ({ onPress, disabled, loading }) => (
<Pressable
accessibilityRole="button"
onPress={onPress}
disabled={disabled}
style={({ pressed }) => [
styles.socialButton,
pressed && !disabled ? styles.socialButtonPressed : null,
disabled ? styles.socialButtonDisabled : null,
]}
>
<View style={styles.socialButtonContent}>
<View style={styles.socialIconContainer}>
<GoogleLogo />
</View>
<Text style={styles.socialButtonText}>Continuer avec Google</Text>
{loading ? (
<ActivityIndicator size="small" color="#4285F4" />
) : (
<View style={styles.socialRightSpacer} />
)}
</View>
</Pressable>
);
const GoogleLogo = () => (
<Svg width={24} height={24} viewBox="0 0 18 18">
<Path
fill="#4285F4"
d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.71v2.26h2.9c1.68-1.55 2.7-3.83 2.7-6.61Z"
/>
<Path
fill="#34A853"
d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.9-2.26c-.8.54-1.83.86-3.06.86a5.31 5.31 0 0 1-5.02-3.69H.96v2.32A9 9 0 0 0 9 18Z"
/>
<Path
fill="#FBBC05"
d="M3.98 10.73c-.18-.54-.28-1.12-.28-1.73s.1-1.19.28-1.73V4.95H.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.05l3.02-2.32Z"
/>
<Path
fill="#EA4335"
d="M9 3.54c1.32 0 2.5.45 3.43 1.33l2.57-2.57C13.47.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.02 2.32A5.31 5.31 0 0 1 9 3.54Z"
/>
</Svg>
);
export default Register;
const styles = StyleSheet.create({
@@ -232,6 +376,22 @@ const styles = StyleSheet.create({
justifyContent: "center",
alignItems: "center",
},
webItemContainer: {
width: "100%",
maxWidth: 680,
},
mobileItemContainer: {
width: "100%",
minHeight: 720,
},
mobileAvoider: {
flex: 1,
},
mobileScrollContent: {
flexGrow: 1,
justifyContent: "center",
paddingVertical: 24,
},
formContent: {
gap: 32,
paddingTop: 5,
@@ -251,17 +411,19 @@ const styles = StyleSheet.create({
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
},
countryButton: {
countryBlurWrapper: {
borderRadius: 12,
borderWidth: 1,
borderColor: Palette.ultraLightWhite,
backgroundColor: Palette.glass,
overflow: "hidden",
},
countryButton: {
minHeight: 50,
justifyContent: "center",
paddingHorizontal: 16,
width: "100%",
},
countryButtonFilled: {
borderColor: Palette.primary,
countryButtonPressed: {
opacity: 0.85,
},
countryButtonText: {
fontSize: 14,
@@ -297,6 +459,85 @@ const styles = StyleSheet.create({
loginLink: {
fontFamily: FONT_FAMILY.InterSemiBold,
},
bottomLoginPrompt: {
marginTop: 16,
paddingHorizontal: 24,
},
bottomFooterText: {
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
textAlign: "center",
},
bottomFooterLink: {
fontFamily: FONT_FAMILY.InterSemiBold,
color: Palette.white,
},
socialWrapper: {
width: "100%",
gap: 16,
alignItems: "center",
},
socialButton: {
alignSelf: "center",
borderRadius: 12,
width: "90%",
backgroundColor: Palette.white,
borderWidth: 1,
borderColor: "#E3E7EF",
paddingVertical: 12,
paddingHorizontal: 20,
shadowColor: "rgba(12, 6, 34, 0.08)",
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.3,
shadowRadius: 16,
elevation: 2,
},
socialButtonPressed: {
backgroundColor: "#F4F7FF",
},
socialButtonDisabled: {
opacity: 0.7,
},
socialButtonContent: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
gap: 12,
},
socialIconContainer: {
justifyContent: "center",
alignItems: "center",
width: 28,
height: 28,
},
socialButtonText: {
flex: 1,
textAlign: "center",
fontSize: 15,
color: "#202124",
fontFamily: FONT_FAMILY.InterSemiBold,
},
socialRightSpacer: {
width: 24,
height: 24,
},
nativeButtonWrapper: {
alignSelf: "center",
width: "90%",
height: 50,
justifyContent: "center",
},
nativeButton: {
width: "100%",
height: 50,
},
nativeLoadingOverlay: {
...StyleSheet.absoluteFillObject,
alignItems: "center",
justifyContent: "center",
},
modalOverlay: {
flex: 1,
backgroundColor: Palette.transparentBlack,