diff --git a/api/src/controllers/user.js b/api/src/controllers/user.js index 0962f716a..b3410b967 100644 --- a/api/src/controllers/user.js +++ b/api/src/controllers/user.js @@ -26,36 +26,40 @@ router.post( "/signup", catchErrors(async (req, res) => { const { email, password, matomoId } = req.body || {}; + console.log("signup", email, password, matomoId); if (!matomoId) return res.status(400).json({ ok: false, error: "no matomo id" }); if (!email || !password) { return res.status(400).json({ ok: false, error: "missing email or password" }); } + console.log("validator.isEmail(email)", validator.isEmail(email)); if (!validator.isEmail(email)) { return res.status(400).json({ ok: false, error: "invalid email" }); } + console.log("validatePassword(password)", validatePassword(password)); if (!validatePassword(password)) { return res.status(400).json({ ok: false, error: "password is not strong enough" }); } const user = await prisma.user.findUnique({ where: { email }, }); + console.log("user", user); if (user) { return res.status(400).json({ ok: false, error: "email already exists" }); } const hashedPassword = await bcrypt.hash(password, 10); + const updateObj = {}; + updateObj.email = email; + updateObj.password = hashedPassword; await prisma.user.upsert({ where: { matomo_id: matomoId }, update: updateObj, create: { - email, - password: hashedPassword, matomo_id: matomoId, - created_from, ...updateObj, }, }); diff --git a/expo/src/Router.js b/expo/src/Router.js index ab1549d83..34ea27153 100644 --- a/expo/src/Router.js +++ b/expo/src/Router.js @@ -51,6 +51,10 @@ import SuccessStrategyModal from "./scenes/Craving/SuccessStrategyModal"; import ExportedDataDone from "./scenes/Craving/ExportedDataDone"; import SigninScreen from "./scenes/Auth/Signin"; import SignupScreen from "./scenes/Auth/Signup"; +import EmailConfirmationScreen from "./scenes/WelcomeScreen/EmailConfirmationScreen"; +import ForgotPassword from "./scenes/Auth/ForgotPassword"; +import ReinitialisePassword from "./scenes/Auth/ReinitialisePassword"; +import ChangeAccountModal from "./scenes/Infos/ChangeAccountModal"; const Label = ({ children, focused, color }) => ( @@ -180,6 +184,9 @@ const App = () => { + + + @@ -365,6 +372,15 @@ const Router = () => { animation: "fade", }} /> + ( + + + + + +); + +export default AccountGearIcon; diff --git a/expo/src/scenes/Auth/ForgotPassword.js b/expo/src/scenes/Auth/ForgotPassword.js new file mode 100644 index 000000000..5e40c702c --- /dev/null +++ b/expo/src/scenes/Auth/ForgotPassword.js @@ -0,0 +1,61 @@ +import React, { useEffect, useState } from "react"; +import { View, TextInput, TouchableOpacity, Text, SafeAreaView, KeyboardAvoidingView, Platform } from "react-native"; +import API from "../../services/api"; +import { storage } from "../../services/storage"; +import AntDesign from "@expo/vector-icons/AntDesign"; +import Entypo from "@expo/vector-icons/Entypo"; +import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons"; + +const ForgotPassword = ({ navigation }) => { + const [email, setEmail] = useState(""); + const [validEmail, setValidEmail] = useState(false); + const [isButtonDisabled, setIsButtonDisabled] = useState(true); + + const handleEmailChange = (text) => { + setEmail(text); + const emailRegex = new RegExp("^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$"); + setValidEmail(emailRegex.test(text)); + }; + + useEffect(() => { + setIsButtonDisabled(!validEmail); + }, [validEmail]); + + return ( + + + + Réinitialiser mon mot de passe + + + Renseignez ci-dessous l’adresse e-mail utilisée pour vous connecter à votre compte Oz. + + + + E-mail + + + + + navigation.navigate("EMAIL_CONFIRMATION")} + className={`rounded-full px-6 py-3 ${isButtonDisabled ? "bg-[#EA6C96]" : "bg-[#de285e]"}`} + disabled={isButtonDisabled} + > + Valider + + + + + ); +}; + +export default ForgotPassword; diff --git a/expo/src/scenes/Auth/ReinitialisePassword.js b/expo/src/scenes/Auth/ReinitialisePassword.js new file mode 100644 index 000000000..4f25d1dc9 --- /dev/null +++ b/expo/src/scenes/Auth/ReinitialisePassword.js @@ -0,0 +1,140 @@ +import React, { useEffect, useState } from "react"; +import { View, TextInput, TouchableOpacity, Text, SafeAreaView, KeyboardAvoidingView, Platform } from "react-native"; +import AntDesign from "@expo/vector-icons/AntDesign"; +import Entypo from "@expo/vector-icons/Entypo"; +import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons"; + +const ReinitialisePassword = ({ navigation }) => { + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [isStrongPassword, setIsStrongPassword] = useState(false); + const [isMatching, setIsMatching] = useState(false); + const [isButtonDisabled, setIsButtonDisabled] = useState(true); + const [hidePassword, setHidePassword] = useState(true); + const [passwordChecks, setPasswordChecks] = useState({ + minLength: false, + hasUpperCase: false, + hasLowerCase: false, + hasNumber: false, + hasSpecialChar: false, + }); + + const checkPassword = (password) => { + const checks = { + minLength: password.length >= 12, + hasUpperCase: /[A-Z]/.test(password), + hasLowerCase: /[a-z]/.test(password), + hasNumber: /[0-9]/.test(password), + hasSpecialChar: /[!@#\$%\^&\*]/.test(password), + }; + setPasswordChecks(checks); + setIsStrongPassword(Object.values(checks).every((check) => check)); + setIsMatching(password === confirmPassword); + }; + + const handleConfirmPasswordChange = (text) => { + setConfirmPassword(text); + setIsMatching(password === text); + }; + + useEffect(() => { + if (isStrongPassword && isMatching) { + setIsButtonDisabled(false); + } else { + setIsButtonDisabled(true); + } + console.log("isStrongPassword", isStrongPassword); + console.log("isMatching", isMatching); + }, [isStrongPassword, isMatching]); + + const numberOfChecksPassed = Object.values(passwordChecks).filter(Boolean).length; + + return ( + + + + Réinitialiser mon mot de passe + Entrez ci-dessous votre nouveau mot de passe. + + Mot de passe + + doit contenir au minimum 12 caractères, 1 Majuscule, 1 chiffre, 1 caractère spécial + + + { + setPassword(text); + checkPassword(text); + }} + secureTextEntry={hidePassword} + className="text-black flex-1" + /> + setHidePassword(!hidePassword)}> + {hidePassword ? ( + + ) : ( + + )} + + + + {[...Array(5)].map((_, index) => ( + + ))} + + + + Confirmation du mot de passe + + + setHidePassword(!hidePassword)}> + {hidePassword ? ( + + ) : ( + + )} + + + {confirmPassword && ( + + {isMatching ? ( + + ) : ( + + )} + + {isMatching ? "Mots de passe similaires" : "Mots de passe différents"} + + + )} + + + + navigation.push("TABS")} + className={`rounded-full px-6 py-3 ${isButtonDisabled ? "bg-[#EA6C96]" : "bg-[#de285e]"}`} + // disabled={isButtonDisabled} + > + Valider + + + + + ); +}; + +export default ReinitialisePassword; diff --git a/expo/src/scenes/Auth/Signup.js b/expo/src/scenes/Auth/Signup.js index f78092fa7..165eca89d 100644 --- a/expo/src/scenes/Auth/Signup.js +++ b/expo/src/scenes/Auth/Signup.js @@ -1,81 +1,180 @@ -import React, { useState } from "react"; -import ButtonPrimary from "../../components/ButtonPrimary"; -import { Image, View, TextInput, TouchableOpacity, Text } from "react-native"; -import Wave from "../../components/illustrations/onboarding/Wave"; -import { screenWidth } from "../../styles/theme"; +import React, { useEffect, useState } from "react"; +import { View, TextInput, TouchableOpacity, Text, SafeAreaView, KeyboardAvoidingView, Platform } from "react-native"; import API from "../../services/api"; import { storage } from "../../services/storage"; import { initMatomo } from "../../services/logEventsWithMatomo"; +import AntDesign from "@expo/vector-icons/AntDesign"; +import Entypo from "@expo/vector-icons/Entypo"; +import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons"; const SignupScreen = ({ navigation }) => { - const matomoId = storage.getString("@UserIdv2"); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [isStrongPassword, setIsStrongPassword] = useState(false); + const [isMatching, setIsMatching] = useState(false); + const [validEmail, setValidEmail] = useState(false); + const [isButtonDisabled, setIsButtonDisabled] = useState(true); + const [hidePassword, setHidePassword] = useState(true); + const [passwordChecks, setPasswordChecks] = useState({ + minLength: false, + hasUpperCase: false, + hasLowerCase: false, + hasNumber: false, + hasSpecialChar: false, + }); + + const checkPassword = (password) => { + const checks = { + minLength: password.length >= 12, + hasUpperCase: /[A-Z]/.test(password), + hasLowerCase: /[a-z]/.test(password), + hasNumber: /[0-9]/.test(password), + hasSpecialChar: /[!@#\$%\^&\*]/.test(password), + }; + setPasswordChecks(checks); + setIsStrongPassword(Object.values(checks).every((check) => check)); + setIsMatching(password === confirmPassword); + }; + + const handleConfirmPasswordChange = (text) => { + setConfirmPassword(text); + setIsMatching(password === text); + }; + + const handleEmailChange = (text) => { + setEmail(text); + const emailRegex = new RegExp("^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$"); + setValidEmail(emailRegex.test(text)); + }; const signup = async () => { - initMatomo(email, password); + // initMatomo(email, password); const matomoId = storage.getString("@UserIdv2"); - const response = await API.post("user/signup", { - matomoId, - email, - password, + const response = await API.post({ + path: "/user/signup", + body: { + matomoId, + email, + password, + }, }); if (response.ok) { storage.set("@Email", email); storage.set("@Token", response.token); - navigation.push("WELCOME_SWIPER"); + navigation.navigate("EMAIL_CONFIRMATION"); } else { alert("Erreur lors de l'inscription"); } }; + useEffect(() => { + if (isStrongPassword && isMatching && validEmail) { + setIsButtonDisabled(false); + } else { + setIsButtonDisabled(true); + } + }, [isStrongPassword, isMatching, validEmail]); + + const numberOfChecksPassed = Object.values(passwordChecks).filter(Boolean).length; + return ( - - - - - - - - Email - - Mot de passe - + + + + + Créer un compte + + + E-mail + + + + Mot de passe + + doit contenir au minimum 12 caractères, 1 Majuscule, 1 minuscule, 1 chiffre et 1 caractère spécial + + + { + setPassword(text); + checkPassword(text); + }} + secureTextEntry={hidePassword} + className="text-black flex-1" + /> + setHidePassword(!hidePassword)}> + {hidePassword ? ( + + ) : ( + + )} + + + + {[...Array(5)].map((_, index) => ( + + ))} + + + + Confirmation du mot de passe + + + setHidePassword(!hidePassword)}> + {hidePassword ? ( + + ) : ( + + )} + + + {confirmPassword && ( + + {isMatching ? ( + + ) : ( + + )} + + {isMatching ? "Mots de passe similaires" : "Mots de passe différents"} + + + )} + - - navigation.push("FORGOT_PASSWORD")}> - Mot de passe oublié ? + + navigation.navigate("EMAIL_CONFIRMATION")} + className={`rounded-full px-6 py-3 ${isButtonDisabled ? "bg-[#EA6C96]" : "bg-[#de285e]"}`} + // disabled={isButtonDisabled} + > + Valider - - - - - - { - signup(); - }} - /> - navigation.push("SIGNUP")}> - Créer un compte - - - + + ); }; diff --git a/expo/src/scenes/Infos/AccountInfo.js b/expo/src/scenes/Infos/AccountInfo.js new file mode 100644 index 000000000..95fccae5b --- /dev/null +++ b/expo/src/scenes/Infos/AccountInfo.js @@ -0,0 +1,54 @@ +import React, { useEffect, useState } from "react"; +import { Dimensions, Text, TouchableOpacity, View, TextInput } from "react-native"; +import BackButton from "../../components/BackButton"; +import { storage } from "../../services/storage"; + +const AccountInfo = ({ navigation }) => { + const currentEmail = storage.getString("@Email"); + const [email, setEmail] = useState(currentEmail); + const [isButtonDisabled, setIsButtonDisabled] = useState(true); + const [isEmailValid, setIsEmailValid] = useState(false); + storage.set("@Email", "yoan.roszak@selego.co"); + + const handleEmailChange = (text) => { + setEmail(text); + const emailRegex = new RegExp("^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$"); + setIsEmailValid(emailRegex.test(text)); + }; + + useEffect(() => { + setIsButtonDisabled(!isEmailValid || email === currentEmail); + }, [isEmailValid, email]); + return ( + + + + Mon compte + E-mail + + + navigation.navigate("ROUTER", { screen: "ChangeAccountModal" })} + className={`mt-2 rounded-full px-6 py-2 ${isButtonDisabled ? "bg-[#EA6C96]" : "bg-[#de285e]"}`} + // disabled={isButtonDisabled} + > + Modifier mon email + + + Mot de passe + + Pour modifier votre mot de passe, cliquez ici + + + + ); +}; + +export default AccountInfo; diff --git a/expo/src/scenes/Infos/AccountMenu.js b/expo/src/scenes/Infos/AccountMenu.js new file mode 100644 index 000000000..a4591fc6f --- /dev/null +++ b/expo/src/scenes/Infos/AccountMenu.js @@ -0,0 +1,86 @@ +import React, { useEffect, useState } from "react"; +import { createStackNavigator } from "@react-navigation/stack"; +import { Dimensions, Text, TouchableOpacity, View } from "react-native"; +import Background from "../../components/Background"; +import HeaderBackground from "../../components/HeaderBackground"; +import Export from "./Export"; +import { useToggleCTA } from "../AddDrink/AddDrinkCTAButton"; +import FakeData from "../../reference/mocks/FakeData"; +import ArrowRight from "../../components/ArrowRight"; +import Transfer from "./Transfer"; +import BackButton from "../../components/BackButton"; +import AccountGearIcon from "../../components/illustrations/icons/AccountGearIcon"; +import AccountInfo from "./AccountInfo"; +import Support from "./Support"; +import DeleteAccount from "./DeleteAccount"; + +const AccountStack = createStackNavigator(); + +const Account = () => { + useToggleCTA({ navigator: "Account" }); + return ( + + + + + + + + + + + ); +}; + +const AccountMenu = ({ navigation }) => { + return ( + + + + + Mon compte + + + { + navigation.push("ACCOUNT_INFO"); + }} + /> + + + { + navigation.push("TRANSFER"); + }} + /> + + navigation.push("SUPPORT")} /> + + navigation.push("DELETE")} /> + + + ); +}; + +const MenuItem = ({ caption, onPress, disabled }) => { + const screenWidth = Dimensions.get("window").width; + const basis = screenWidth <= 350 ? 200 : "auto"; // reduce size of text container for screens ~ iphone SE + return ( + + + + + {caption} + + + + + + + + ); +}; + +export default Account; diff --git a/expo/src/scenes/Infos/ChangeAccountModal.js b/expo/src/scenes/Infos/ChangeAccountModal.js new file mode 100644 index 000000000..f682a0656 --- /dev/null +++ b/expo/src/scenes/Infos/ChangeAccountModal.js @@ -0,0 +1,79 @@ +import React, { useState, useEffect } from "react"; +import { Path, Svg } from "react-native-svg"; +import { View, Text, TouchableOpacity, TextInput } from "react-native"; +import { hitSlop } from "../../styles/theme"; +import { SafeAreaView } from "react-native-safe-area-context"; +import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons"; + +const ChangeAccountModal = ({ navigation, route }) => { + const [password, setPassword] = useState(""); + const [hidePassword, setHidePassword] = useState(true); + const [isButtonDisabled, setIsButtonDisabled] = useState(true); + + useEffect(() => { + setIsButtonDisabled(password.length === 0); + }, [password]); + + return ( + + + + + { + navigation.navigate("CRAVING", { screen: "CRAVING_STRATEGIES" }); + }} + > + + + + + + + Modifier l'e-mail + + Afin de confirmer la modification de l’adresse e-mail du compte, veuillez saisir votre mot de passe + ci-dessous. + + Mot de passe + + + setHidePassword(!hidePassword)}> + {hidePassword ? ( + + ) : ( + + )} + + + + + { + navigation.goBack(); + }} + > + Valider + + + + + + ); +}; + +export default ChangeAccountModal; diff --git a/expo/src/scenes/Infos/DeleteAccount.js b/expo/src/scenes/Infos/DeleteAccount.js new file mode 100644 index 000000000..af29248de --- /dev/null +++ b/expo/src/scenes/Infos/DeleteAccount.js @@ -0,0 +1,29 @@ +import React from "react"; +import { Text, TouchableOpacity, View } from "react-native"; +import BackButton from "../../components/BackButton"; + +const DeleteAccount = ({ navigation }) => { + return ( + + + + Supprimer mon compte + Etes-vous certain de vouloir supprimer votre compte ? + + Attention, cette action est irréversible et va ecraser l’ensemble de vos données (ajout de consommations, + contexte, humeur, notes, objectif, badges gagnés, etc...) . + + + } + className=" rounded-full px-6 py-2 bg-[#de285e] mt-8" + > + Supprimer mon Compte + + + + + ); +}; + +export default DeleteAccount; diff --git a/expo/src/scenes/Infos/Infos.js b/expo/src/scenes/Infos/Infos.js index 2ba29319d..13edf367c 100644 --- a/expo/src/scenes/Infos/Infos.js +++ b/expo/src/scenes/Infos/Infos.js @@ -24,14 +24,15 @@ import AbstinenceIcon from "../../components/illustrations/icons/AbstinenceIcon" import ExportDataIcon from "../../components/illustrations/icons/ExportDataIcon"; import ShareAppIcon from "../../components/illustrations/icons/ShareAppIcon"; import RateAppIcon from "../../components/illustrations/icons/RateAppIcon"; +import AccountGearIcon from "../../components/illustrations/icons/AccountGearIcon"; import GiveFeedbackIcon from "../../components/illustrations/icons/GiveFeedbackIcon"; import FilesIcon from "../../components/illustrations/icons/FilesIcon"; import OfficialIcon from "../../components/illustrations/icons/OfficialIcon"; import Transfer from "./Transfer"; -import TransferIcon from "../../components/illustrations/icons/TransferIcon"; import { logEvent } from "../../services/logEventsWithMatomo"; import { isOnboardedSelector } from "../../recoil/gains"; import Official from "./Official"; +import Account from "./AccountMenu"; const InfosStack = createStackNavigator(); @@ -55,6 +56,7 @@ const Infos = () => { + ); @@ -74,6 +76,14 @@ const InfosMenu = ({ navigation }) => { NOUS AIDER + { + navigation.push("ACCOUNT"); + }} + /> + { caption={"Donner mon avis"} Icon={GiveFeedbackIcon} onPress={() => { - logEvent({ - category: "NPS", - action: "NPS_OPEN_FROM_INFOS", - }); navigation.navigate("NPS_SCREEN", { triggeredFrom: "Infos" }); }} /> @@ -125,11 +131,6 @@ const InfosMenu = ({ navigation }) => { caption={"Mon objectif par semaine"} Icon={GoalSetup} onPress={() => { - logEvent({ - category: "GAINS", - action: "GOAL_OPEN", - name: "INFOS", - }); if (isOnboarded) { navigation.navigate("GAINS_MY_OBJECTIVE"); } else { @@ -142,11 +143,6 @@ const InfosMenu = ({ navigation }) => { caption={"Mon rappel"} Icon={ReminderIcon} onPress={() => { - logEvent({ - category: "REMINDER", - action: "REMINDER_OPEN", - name: "INFOS", - }); navigation.navigate("GAINS_REMINDER", { enableContinueButton: true, onPressContinueNavigation: ["GAINS_NAVIGATOR", { screen: "GAINS_MAIN_VIEW" }], @@ -158,11 +154,6 @@ const InfosMenu = ({ navigation }) => { caption={"Compteur d'abstinence"} Icon={AbstinenceIcon} onPress={() => { - logEvent({ - category: "ABSTINENCE", - action: "ABSTINENCE_OPEN", - name: "INFOS", - }); navigation.navigate("ABSTINENCE_SELECTION", { parent: "Infos" }); }} /> @@ -178,19 +169,6 @@ const InfosMenu = ({ navigation }) => { navigation.push("EXPORT"); }} /> - - - { - logEvent({ - category: "TRANSFER", - action: "TRANSFER_OPEN", - }); - navigation.push("TRANSFER"); - }} - /> INFORMATIONS diff --git a/expo/src/scenes/Infos/Support.js b/expo/src/scenes/Infos/Support.js new file mode 100644 index 000000000..33578d41a --- /dev/null +++ b/expo/src/scenes/Infos/Support.js @@ -0,0 +1,44 @@ +import React, { useEffect, useState } from "react"; +import { Text, TouchableOpacity, View, TextInput } from "react-native"; +import BackButton from "../../components/BackButton"; + +const Support = ({ navigation }) => { + const [message, setMessage] = useState(""); + const [isButtonDisabled, setIsButtonDisabled] = useState(true); + + useEffect(() => { + setIsButtonDisabled(!message); + }, [message]); + return ( + + + + Aide & Support + + Pour toute demande, veuillez compléter le champ ci-dessous afin de contacter l’equipe support. + + Message + + + navigation.navigate("EMAIL_CONFIRMATION")} + className={`mt-2 rounded-full px-6 py-2 ${isButtonDisabled ? "bg-[#EA6C96]" : "bg-[#de285e]"}`} + // disabled={isButtonDisabled} + > + Envoyer + + + + + ); +}; + +export default Support; diff --git a/expo/src/scenes/WelcomeScreen/EmailConfirmationScreen.js b/expo/src/scenes/WelcomeScreen/EmailConfirmationScreen.js new file mode 100644 index 000000000..19c240dd1 --- /dev/null +++ b/expo/src/scenes/WelcomeScreen/EmailConfirmationScreen.js @@ -0,0 +1,84 @@ +import React, { useState, useRef } from "react"; +import { Image, View, Text, TouchableOpacity, TextInput, Alert } from "react-native"; +import { SafeAreaView } from "react-native-safe-area-context"; +import RNRestart from "react-native-restart"; +import { storage } from "../../services/storage"; + +const EmailConfirmationScreen = ({ navigation }) => { + const isOldUser = storage.getBoolean("@IsOldUser"); + // const isReinitialisingPassword = storage.getBoolean("@IsReinitialisingPassword"); + const isReinitialisingPassword = true; + const [code, setCode] = useState(["", "", "", "", "", ""]); + const inputRefs = useRef([]); + const handleCodeChange = (text, index) => { + if (/^\d$/.test(text)) { + const newCode = [...code]; + newCode[index] = text; + setCode(newCode); + + if (index < 5) { + inputRefs.current[index + 1].focus(); + } else { + inputRefs.current[index].blur(); + } + } else if (text === "") { + const newCode = [...code]; + newCode[index] = ""; + setCode(newCode); + if (index > 0) { + inputRefs.current[index - 1].focus(); + } + } + }; + + return ( + + + + + + Confirmez votre e-mail + + + Entrez ci-dessous le code de confirmation que vous avez reçu par e-mail. + + + {code.map((digit, index) => ( + + {index === 3 && } {/* Adds extra space after the third box */} + + handleCodeChange(text, index)} + maxLength={1} + keyboardType="number-pad" + className="text-black text-xl text-center" + ref={(el) => (inputRefs.current[index] = el)} + /> + + + ))} + + { + if (isOldUser) RNRestart.restart(); + else if (isReinitialisingPassword) navigation.navigate("REINITIALISE_PASSWORD"); + else navigation.navigate("USER_SURVEY_START", { from: "NEW_USER" }); + }} + className="rounded-full px-8 py-3 bg-[#DE285E]" + > + Valider + + + Alert.alert("Code renvoyé", "Un nouveau code de confirmation vous a été envoyé par e-mail.")} + > + Renvoyer code + + + + + ); +}; + +export default EmailConfirmationScreen; diff --git a/expo/src/scenes/WelcomeScreen/Screens.js b/expo/src/scenes/WelcomeScreen/Screens.js index 959fcd29b..b7ab9419b 100644 --- a/expo/src/scenes/WelcomeScreen/Screens.js +++ b/expo/src/scenes/WelcomeScreen/Screens.js @@ -1,11 +1,54 @@ import React from "react"; import TextStyled from "../../components/TextStyled"; import Agreement from "./Agreement"; -import { Image, View } from "react-native"; +import { Image, View, Text } from "react-native"; import { screenWidth } from "../../styles/theme"; import Wave from "../../components/illustrations/onboarding/Wave"; import ButtonPrimary from "../../components/ButtonPrimary"; import NotificationService from "../../services/notifications"; +import MaterialIcons from "@expo/vector-icons/MaterialIcons"; + +export const ScreenFeedback = ({ onPressNext }) => ( + + + + Nos utilisateurs en parlent + + + + + + + + “ Permet de faire le point et de se fixer des objectifs simplement et sans culpabilité. ” + + + + + + + + “ Application très bien pensée et indispensable si vous voulez suivre votre consommation. ” + + + + + + + + “L’app est fabuleuse en terme d’accompagnement, de recommandations et de suivi au quotidien” + + + + + + + + + + + +); export const ScreenCalendar = ({ onPressNext }) => ( @@ -22,25 +65,10 @@ export const ScreenCalendar = ({ onPressNext }) => ( className="h-full w-full" /> - - - - Notée 4.8 sur les stores {"\n"}avec + de 1000 avis - - - - + ( - + @@ -97,7 +125,32 @@ export const ScreenDefi = ({ onPressNext }) => ( - + + + + + +); + +export const ScreenCraving = ({ onPressNext }) => ( + + + + + Surmontez une envie intense de consommer avec des activités et conseils + + + + + + + + + @@ -122,15 +175,10 @@ export const ScreenAdvice = ({ onStartPress, agreed, setAgreed }) => ( - + setAgreed(!agreed)} agreed={agreed} className="" /> - + ); diff --git a/expo/src/scenes/WelcomeScreen/ScreensOldUser.js b/expo/src/scenes/WelcomeScreen/ScreensOldUser.js index 6bdc6ca1b..64198c3d1 100644 --- a/expo/src/scenes/WelcomeScreen/ScreensOldUser.js +++ b/expo/src/scenes/WelcomeScreen/ScreensOldUser.js @@ -11,6 +11,7 @@ import * as DocumentPicker from "expo-document-picker"; import { Alert } from "react-native"; import RNRestart from "react-native-restart"; import API from "../../services/api"; +import AntDesign from "@expo/vector-icons/AntDesign"; export const StepOne = ({ onPressNext }) => ( @@ -92,10 +93,10 @@ export const StepTwo = ({ onPressNext }) => ( - + importData(onPressNext)} + className="justify-center space-x-1 items-center flex-row rounded-3xl bg-[#4030A5] p-3" > Importer mes données Oz @@ -105,30 +106,25 @@ export const StepTwo = ({ onPressNext }) => ( ); -export const Validation = ({ onStartPress, agreed, setAgreed }) => ( +export const Validation = ({ onPressNext }) => ( - - - Recevez des conseils personnalisés + + + - - + + Vos données ont été importées avec succès ! - setAgreed(!agreed)} agreed={agreed} className="" /> - + ); -const importData = async () => { +const importData = async (onPressNext) => { logEvent({ category: "TRANSFER", action: "IMPORT_DATA" }); try { const result = await DocumentPicker.getDocumentAsync({ type: "application/json" }); @@ -136,6 +132,7 @@ const importData = async () => { const fileContents = await fetch(fileUri).then((response) => response.text()); const pushNotifToken = storage.getString("STORAGE_KEY_PUSH_NOTIFICATION_TOKEN"); await overwriteData(fileContents, pushNotifToken); + onPressNext(); } catch (err) { if (DocumentPicker.isCancel(err)) { logEvent({ category: "TRANSFER", action: "CANCEL_IMPORT_DATA", name: "DOCUMENT_PICKER_CANCEL" }); @@ -169,10 +166,32 @@ const overwriteData = async (dataImported, pushNotifToken) => { } else { logEvent({ category: "TRANSFER", action: "IMPORT_DATA_SUCCESS", name: "PUSH_NOTIF_TOKEN_NOT_SYNC" }); } - onPressNext(); }); } catch (error) { Alert.alert("Une erreur est survenue lors de l'importation des données"); logEvent({ category: "TRANSFER", action: "IMPORT_DATA_FAILURE" }); } }; +export const ScreenAdvice = ({ onStartPress, agreed, setAgreed }) => ( + + + + Recevez des conseils personnalisés + + + + + + + + + + setAgreed(!agreed)} agreed={agreed} className="" /> + + + +); diff --git a/expo/src/scenes/WelcomeScreen/WelcomeSwiper.js b/expo/src/scenes/WelcomeScreen/WelcomeSwiper.js index 448b9c8a3..90a7ae102 100644 --- a/expo/src/scenes/WelcomeScreen/WelcomeSwiper.js +++ b/expo/src/scenes/WelcomeScreen/WelcomeSwiper.js @@ -1,7 +1,7 @@ import React, { useRef, useState } from "react"; import Swiper from "react-native-swiper"; import { storage } from "../../services/storage"; -import { ScreenCalendar, ScreenStats, ScreenDefi, ScreenAdvice } from "./Screens"; +import { ScreenCalendar, ScreenStats, ScreenDefi, ScreenAdvice, ScreenFeedback, ScreenCraving } from "./Screens"; import Dot from "../../components/SwiperDot"; import { View } from "react-native"; @@ -17,7 +17,7 @@ const WelcomeSwiper = ({ navigation }) => { const onStartPress = async () => { storage.set("@OnboardingDoneWithCGU", true); - navigation.navigate("USER_SURVEY_START", { from: "NEW_USER" }); + navigation.navigate("SIGNUP_SCREEN"); }; const onPressNext = () => swiperRef?.current?.scrollBy(1); @@ -38,10 +38,13 @@ const WelcomeSwiper = ({ navigation }) => { paginationStyle={{ justifyContent: "center", bottom: 108, - }}> + }} + > + + diff --git a/expo/src/scenes/WelcomeScreen/WelcomeSwiperOldUser.js b/expo/src/scenes/WelcomeScreen/WelcomeSwiperOldUser.js index d6f6b6568..a00146259 100644 --- a/expo/src/scenes/WelcomeScreen/WelcomeSwiperOldUser.js +++ b/expo/src/scenes/WelcomeScreen/WelcomeSwiperOldUser.js @@ -1,7 +1,7 @@ import React, { useRef, useState } from "react"; import Swiper from "react-native-swiper"; import { storage } from "../../services/storage"; -import { StepOne, StepTwo, Validation } from "./ScreensOldUser"; +import { ScreenAdvice, StepOne, StepTwo, Validation } from "./ScreensOldUser"; import Dot from "../../components/SwiperDot"; import { View } from "react-native"; @@ -17,7 +17,7 @@ const WelcomeSwiperOldUser = ({ navigation }) => { const onStartPress = async () => { storage.set("@OnboardingDoneWithCGU", true); - navigation.navigate("USER_SURVEY_START", { from: "NEW_USER" }); + navigation.navigate("SIGNUP_SCREEN"); }; const onPressNext = () => swiperRef?.current?.scrollBy(1); @@ -42,7 +42,8 @@ const WelcomeSwiperOldUser = ({ navigation }) => { > - + + diff --git a/expo/src/scenes/WelcomeScreen/WelcomeUserType.js b/expo/src/scenes/WelcomeScreen/WelcomeUserType.js index a3601309f..ab6fd3a91 100644 --- a/expo/src/scenes/WelcomeScreen/WelcomeUserType.js +++ b/expo/src/scenes/WelcomeScreen/WelcomeUserType.js @@ -1,6 +1,5 @@ import React from "react"; -import ButtonPrimary from "../../components/ButtonPrimary"; -import { Image, View, Text } from "react-native"; +import { Image, View, Text, TouchableOpacity } from "react-native"; import Wave from "../../components/illustrations/onboarding/Wave"; import { screenWidth } from "../../styles/theme"; @@ -8,40 +7,41 @@ const WelcomeUserType = ({ navigation }) => { return ( - - - - - Etes-vous un utilisateur de l’app OZ Ensemble ? - - - - Vous avez la possibilité de récupérer l’ensemble des données de votre application Oz Ensemble pour les - transférer sur celle-ci. {"\n\n"}Pour commencer, cliquez sur le bouton “Importer mes données Oz” ci-dessous.{" "} + + + + + + Etes-vous un utilisateur de l’app OZ Ensemble ? + + + Importer l’ensemble de vos données pour ne pas perdre votre historique + + { + navigation.push("WELCOME_SWIPER_OLD_USER"); + }} + className="rounded-full px-8 py-3 bg-[#DE285E]" + > + Importer mes données Oz + - { - navigation.push("WELCOME_SWIPER_OLD_USER"); - }} - /> + { + navigation.push("WELCOME_SWIPER"); + }} + className="rounded-full px-8 py-3 bg-white" + > + Passer cette étape + + - Vous pouvez aussi passer cette {"\n"} étape - { - navigation.push("WELCOME_SWIPER"); - }} - /> );