I'm developing an application with authentication in firebase with Expo, Basically, I have an authentication hook, a registration screen with a form in steps. In my component that represents the last step, it receives a Promise in which it makes the call to the createUserWithEmailAndPassword method.
What I found curious is that when I run it in the original way, the communication with firebase triggers the error, but when I call it directly on the parent component (RegisterScreen), it doesn't trigger the error and the registration flows normally.
Why does it happen?
Here's my code:
// my hook auth.tsximport { createContext, useState, useContext, ReactNode } from 'react';import { auth } from '../services/firebase';import { createUserWithEmailAndPassword,} from 'firebase/auth';type AuthContextType = { isAuthenticated: boolean; user: User | null; token: string; signUpEmailAndPassword: (email: string, password: string) => Promise<void>; signOut: () => Promise<void>;}type User = { uid: string; name: string; email: string; emailVerified: boolean; photo?: string;}type SignInEmailAndPasswordData = { email: string; password: string;}type AuthProviderProps = { children: ReactNode;}const AuthContext = createContext({} as AuthContextType);function AuthProvider({ children }: AuthProviderProps) { const [ user, setUser ] = useState<User | null>(null); const [ token, setToken ] = useState(''); const isAuthenticated = !!user; async function signUpEmailAndPassword(email: string, password: string) { try { const { user } = await createUserWithEmailAndPassword(auth, email, password); console.log(user); } catch (error) { console.error(error); } } async function signOut() {} return (<AuthContext.Provider value={{ isAuthenticated, user, token, signUpEmailAndPassword, signOut, }}> {children}</AuthContext.Provider> );}function useAuth() { const context = useContext(AuthContext); return context}export { AuthProvider, useAuth }
// my firebaseConfigimport { initializeApp } from 'firebase/app';import { getAuth } from 'firebase/auth';const { API_KEY } = process.env;const { AUTH_DOMAIN } = process.env;const { PROJECT_ID } = process.env;const { STORAGE_BUCKET } = process.env;const { MESSAGING_SENDER_ID } = process.env;const { APP_ID } = process.env;const { MEASUREMENT_ID } = process.env;export const firebaseConfig = { // ...};// Initialize Firebaseconst app = initializeApp(firebaseConfig);export const auth = getAuth(app);
// my screen component Register.tsximport React, { useState, useRef } from 'react';import { useNavigation } from '@react-navigation/native';import { BottomSheetModal } from '@gorhom/bottom-sheet';import { Button } from '../../components/Button';import { CpfStep } from '../../components/FormSteps/SignUpSteps/CpfStep';import { FullNameStep } from '../../components/FormSteps/SignUpSteps/FullNameStep';import { BornDate } from '../../components/FormSteps/SignUpSteps/BornDateStep';import { EmailStep } from '../../components/FormSteps/SignUpSteps/EmailStep';import { CellPhone } from '../../components/FormSteps/SignUpSteps/CellPhone';import { PasswordStep } from '../../components/FormSteps/SignUpSteps/PasswordStep';import { ValidationSmsStep } from '../../components/FormSteps/SignUpSteps/ValidationSmsStep';import { ValidationSignUpOptionStep} from '../../components/FormSteps/SignUpSteps/ValidationSignUpOptionStep';import { useAuth } from '../../hooks/auth';import ArrowLeftSvg from '../../assets/icons/arrow-left.svg';import { Container, Header, Main, ModalContent, TitleHeader, TitleModal,} from './styles';type DataProps = { cpf: string; fullName: string; bornDate: string; email: string; cellPhone: string; password: string; confirmPassword: string; codeValidation: string;}interface Steps { id: string; isShow: boolean; component: () => JSX.Element;}export function SignUpWithEmail() { const modalSuccessRef = useRef<BottomSheetModal>(null); const [ data, setData ] = useState<DataProps>({} as DataProps); const [ steps, setSteps ] = useState<Steps[]>([ { id: 'cpfStep', isShow: true, component: () => (<CpfStep onNextStep={handleNextStep} onUpdateData={handleUpdateData} /> ) }, { id: 'fullNameStep', isShow: false, component: () => (<FullNameStep onNextStep={handleNextStep} onUpdateData={handleUpdateData} /> ) }, { id: 'bornDate', isShow: false, component: () => (<BornDate onNextStep={handleNextStep} onUpdateData={handleUpdateData} /> ) }, { id: 'emailStep', isShow: false, component: () => (<EmailStep onNextStep={handleNextStep} onUpdateData={handleUpdateData} /> ) }, { id: 'cellPhone', isShow: false, component: () => (<CellPhone onNextStep={handleNextStep} onUpdateData={handleUpdateData} /> ) }, { id: 'passwordStep', isShow: false, component: () => (<PasswordStep onNextStep={handleNextStep} onUpdateData={handleUpdateData} /> ) }, { id: 'validationSignUpOptionStep', isShow: false, component: () => (<ValidationSignUpOptionStep onNextStep={handleNextStep} /> ) }, { id: 'validationSmsStep', isShow: false, component: () => (<ValidationSmsStep onUpdateData={handleUpdateData} onRegisterNewUser={handleRegisterInFirebase} /> ) }, ]); const { goBack } = useNavigation(); const { signUpEmailAndPassword } = useAuth(); async function handleRegisterInFirebase() { try { await signUpEmailAndPassword(data.email, data.password); } catch (error) { console.error(error); } } function handleUpdateData(value: any) { setData(state => ( { ...state, ...value } )); } function handleNextStep(stepId: string) { setSteps(state => state.map((step) => { if(step.id === stepId) { return { ...step, isShow: true, } } return { ...step, isShow: false, } })); } return (<Container><Header><Button rounded color="secondary" onPress={goBack}><ArrowLeftSvg height={18} width={18} /></Button><TitleHeader>Cadastro</TitleHeader></Header><Main> {steps.map(step => ( step.isShow && <step.component key={step.id} /> ))}</Main><BottomSheetModal ref={modalSuccessRef} snapPoints={['30%', '30%']}><ModalContent><TitleModal> Cadastro realizado com sucesso</TitleModal></ModalContent></BottomSheetModal></Container> );}
// my last component form stepimport React from 'react';import { TouchableWithoutFeedback, Keyboard } from 'react-native';import { useForm } from 'react-hook-form';import { yupResolver } from '@hookform/resolvers/yup';import * as yup from 'yup';import { Button } from '../../../Button';import { InputCodeForm } from '../../../Form/InputCodeForm';import { Container, Form, SubTitle, Title,} from './styles';interface IForm { codeValidation: string;}interface Props { onUpdateData: (value: any) => void; onRegisterNewUser: () => Promise<void>;}const schema = yup.object({ codeValidation: yup .string() .required('Campo obrigatório'),});export function ValidationSmsStep({ onUpdateData, onRegisterNewUser,}: Props) { const { control, formState: { errors }, handleSubmit } = useForm<IForm>({ resolver: yupResolver(schema), }); async function handleSubmitStep(data: IForm) { onUpdateData(data); await onRegisterNewUser(); } return (<TouchableWithoutFeedback onPress={Keyboard.dismiss}><Container><Form><Title>Digite o código enviado por SMS</Title><SubTitle> (00)00000-0000</SubTitle><InputCodeForm name="codeValidation" control={control} cellsNumber={6} error={errors.codeValidation && errors.codeValidation.message} /></Form><Button title="Continuar" colorTitle="secondary" onPress={handleSubmit(handleSubmitStep)} /></Container></TouchableWithoutFeedback> );}
error firebase:
Firebase: Error (auth/admin-restricted-operation).at node_modules/@firebase/component/dist/esm/index.esm2017.js:326:27 in Provider#shouldAutoInitializeat node_modules/@firebase/util/dist/index.esm2017.js:508:0 in <global>at node_modules/@firebase/util/dist/index.esm2017.js:536:20 in createMockUserTokenat node_modules/tslib/tslib.js:308:33 in <anonymous>at node_modules/@firebase/auth/dist/rn/phone-eec7f987.js:340:0 in <global>at node_modules/@firebase/logger/dist/index.cjs.js:41:22 in <anonymous>at http://192.168.0.105:19000/index.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:159385:21 in <unknown>at http://192.168.0.105:19000/index.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:159339:31 in fulfilled