home, subscription and other fixes
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import React, { useEffect, useMemo, useState, useGlobal } from "reactn";
|
||||
import { Text, View } from "react-native";
|
||||
import {
|
||||
checkIfPasswordIsStrongEnough,
|
||||
handleFirebaseError,
|
||||
} from "../actions/signupActions";
|
||||
import { background } from "../assets";
|
||||
import GradientButton from "../components/GradientButton";
|
||||
import { Input } from "../components/Input";
|
||||
import ItemContainer from "../components/ItemContainer/ItemContainer";
|
||||
import firebase from "../config/firebase";
|
||||
import Page from "../layouts/Page";
|
||||
import { isWeb } from "../hooks/useLayoutType";
|
||||
import { Routes } from "../navigation";
|
||||
import { navigate } from "../navigation/NavigationService";
|
||||
import { Palette } from "../styles";
|
||||
import { FONT_FAMILY } from "../styles/Fonts";
|
||||
|
||||
const PASSWORD_ERROR_MESSAGE =
|
||||
"Ton mot de passe doit contenir au moins 6 caractères et combiner plusieurs types de caractères.";
|
||||
const PASSWORD_MISMATCH_MESSAGE = "Les mots de passe ne correspondent pas.";
|
||||
const INVALID_LINK_MESSAGE =
|
||||
"Ce lien de réinitialisation n'est plus valide. Demande un nouveau mot de passe.";
|
||||
|
||||
const ResetPassword = () => {
|
||||
const route = useRoute();
|
||||
const oobCode = (route?.params?.oobCode || "").trim();
|
||||
|
||||
const [, setTooltip] = useGlobal("_tooltip");
|
||||
const [, setIsLoading] = useGlobal("_isLoading");
|
||||
|
||||
const [email, setEmail] = useState(route?.params?.email || "");
|
||||
const [password, setPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [passwordError, setPasswordError] = useState("");
|
||||
const [confirmError, setConfirmError] = useState("");
|
||||
const [codeError, setCodeError] = useState("");
|
||||
const [isVerifyingCode, setIsVerifyingCode] = useState(true);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const trimmedPassword = useMemo(() => (password || "").trim(), [password]);
|
||||
const trimmedConfirmPassword = useMemo(
|
||||
() => (confirmPassword || "").trim(),
|
||||
[confirmPassword]
|
||||
);
|
||||
|
||||
const isPasswordValid = useMemo(() => {
|
||||
if (!trimmedPassword.length) return false;
|
||||
return checkIfPasswordIsStrongEnough({ password: trimmedPassword });
|
||||
}, [trimmedPassword]);
|
||||
|
||||
const doPasswordsMatch = useMemo(() => {
|
||||
if (!trimmedPassword.length || !trimmedConfirmPassword.length) return false;
|
||||
return trimmedPassword === trimmedConfirmPassword;
|
||||
}, [trimmedPassword, trimmedConfirmPassword]);
|
||||
|
||||
useEffect(() => {
|
||||
const verifyCode = async () => {
|
||||
if (!oobCode) {
|
||||
setCodeError(INVALID_LINK_MESSAGE);
|
||||
setTooltip({ text: INVALID_LINK_MESSAGE, type: "error" });
|
||||
setIsVerifyingCode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const resetEmail = await firebase
|
||||
.auth()
|
||||
.verifyPasswordResetCode(oobCode);
|
||||
setEmail(resetEmail);
|
||||
setCodeError("");
|
||||
} catch (error) {
|
||||
console.log("ResetPassword verify error", error?.message);
|
||||
const message =
|
||||
error?.code && error.code.startsWith("auth/")
|
||||
? handleFirebaseError(error.code)
|
||||
: error?.message || INVALID_LINK_MESSAGE;
|
||||
setCodeError(message || INVALID_LINK_MESSAGE);
|
||||
setTooltip({ text: message || INVALID_LINK_MESSAGE, type: "error" });
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
setIsVerifyingCode(false);
|
||||
}
|
||||
};
|
||||
|
||||
verifyCode();
|
||||
}, [oobCode, setIsLoading, setTooltip]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!password?.length) {
|
||||
setPasswordError("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isPasswordValid) {
|
||||
setPasswordError(PASSWORD_ERROR_MESSAGE);
|
||||
} else {
|
||||
setPasswordError("");
|
||||
}
|
||||
}, [password, isPasswordValid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!confirmPassword?.length) {
|
||||
setConfirmError("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doPasswordsMatch) {
|
||||
setConfirmError(PASSWORD_MISMATCH_MESSAGE);
|
||||
} else {
|
||||
setConfirmError("");
|
||||
}
|
||||
}, [confirmPassword, doPasswordsMatch]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!isPasswordValid) {
|
||||
setPasswordError(PASSWORD_ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (!doPasswordsMatch) {
|
||||
setConfirmError(PASSWORD_MISMATCH_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
setIsLoading(true);
|
||||
await firebase.auth().confirmPasswordReset(oobCode, trimmedPassword);
|
||||
setTooltip({
|
||||
text: "Ton mot de passe a été mis à jour. Tu peux te connecter.",
|
||||
type: "success",
|
||||
});
|
||||
navigate(Routes.Login);
|
||||
} catch (error) {
|
||||
console.log("ResetPassword submit error", error?.message);
|
||||
const message =
|
||||
error?.code && error.code.startsWith("auth/")
|
||||
? handleFirebaseError(error.code)
|
||||
: error?.message || "Impossible de mettre à jour le mot de passe.";
|
||||
setTooltip({ text: message, type: "error" });
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const renderForm = () => (
|
||||
<>
|
||||
<View style={{ gap: 2 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 22,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||
}}
|
||||
>
|
||||
Définis un nouveau mot de passe
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 14,
|
||||
color: Palette.gray,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
}}
|
||||
>
|
||||
Utilise au moins 6 caractères pour sécuriser ton compte.
|
||||
</Text>
|
||||
{email ? (
|
||||
<Text
|
||||
style={{
|
||||
marginTop: 8,
|
||||
fontSize: 12,
|
||||
color: Palette.gray,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
}}
|
||||
>
|
||||
Compte concerné : {email}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<View style={{ gap: 16 }}>
|
||||
<Input
|
||||
placeholder="Nouveau mot de passe"
|
||||
label="Nouveau mot de passe"
|
||||
type="password"
|
||||
value={password}
|
||||
setValue={setPassword}
|
||||
isBlur
|
||||
/>
|
||||
{passwordError ? (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: Palette.red,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
}}
|
||||
>
|
||||
{passwordError}
|
||||
</Text>
|
||||
) : null}
|
||||
<Input
|
||||
placeholder="Confirmer le mot de passe"
|
||||
label="Confirmer le mot de passe"
|
||||
type="password"
|
||||
value={confirmPassword}
|
||||
setValue={setConfirmPassword}
|
||||
isBlur
|
||||
/>
|
||||
{confirmError ? (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: Palette.red,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
}}
|
||||
>
|
||||
{confirmError}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
const renderCodeError = () => (
|
||||
<View style={{ gap: 12 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 18,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||
}}
|
||||
>
|
||||
Lien invalide ou expiré
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 14,
|
||||
color: Palette.gray,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
}}
|
||||
>
|
||||
{codeError || INVALID_LINK_MESSAGE}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const handleFallbackNavigation = () => {
|
||||
navigate(Routes.ForgotPassword);
|
||||
};
|
||||
|
||||
const buttonDisabled = codeError
|
||||
? isSubmitting
|
||||
: isVerifyingCode ||
|
||||
isSubmitting ||
|
||||
!isPasswordValid ||
|
||||
!doPasswordsMatch;
|
||||
|
||||
const buttonLabel = codeError
|
||||
? "Demander un nouveau lien"
|
||||
: isSubmitting
|
||||
? "Mise à jour..."
|
||||
: isVerifyingCode
|
||||
? "Vérification..."
|
||||
: "Mettre à jour le mot de passe";
|
||||
|
||||
const buttonAction = codeError ? handleFallbackNavigation : handleSubmit;
|
||||
|
||||
return (
|
||||
<Page
|
||||
width={isWeb ? 600 : null}
|
||||
backgroundImg={isWeb ? background.loginBgWeb : background.homeBG}
|
||||
headerType="NAVIGATION"
|
||||
title="Réinitialisation"
|
||||
>
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<ItemContainer height={360} disableKeyboardHeight>
|
||||
<View style={{ gap: 32, paddingTop: 5, paddingHorizontal: 5 }}>
|
||||
{codeError ? renderCodeError() : renderForm()}
|
||||
<GradientButton
|
||||
title={buttonLabel}
|
||||
containerStyle={{
|
||||
width: "80%",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
onPress={buttonAction}
|
||||
disabled={buttonDisabled}
|
||||
/>
|
||||
</View>
|
||||
</ItemContainer>
|
||||
</View>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResetPassword;
|
||||
Reference in New Issue
Block a user