Get value from firebase and use it in useState React native - firebase

First the user chooses his allergies by clicking on a toggle button. If the state is true or false the state is being added successfully to firebase.
Allergy Selctor Page
Then in my homepage I want to retrieve that allergy state and apply it in the allergy list state located on home page.
Home Page Image
I am able to get the state value from firebase using this
useEffect(() => {
firebase
.firestore()
.collection("userDb")
.where("userId", "==", user.email)
.onSnapshot(
(querySnapshot) => {
const newTypes = [];
querySnapshot.forEach((doc) => {
const type = doc.data();
newTypes.push(type);
});
setTypes(newTypes[0].Dairy);
setStatus(type);
},
(error) => {
console.log(error);
}
);
}, []);
useEffect(() => {
const fetchFav = async () => {
try {
const list = [];
await firebase
.firestore()
.collection("userDb")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const { Dairy, Peanut } = doc.data();
list.push({
userid: doc.id,
dairy: Dairy,
peanut: Peanut,
});
});
});
setPosts(list);
if (loading) {
setLoading(false);
}
} catch (e) {
console.log(e);
}
};
fetchFav();
searchApi(term);
}, []);
But I don't know how to apply this to my state. I wanted to use type in status(type) which gets the actual true/false value when I console log it gets the right value from firebase but for some reason its always true in status(type);
const [status, setStatus] = useState(type);
<Button
onPress={() => setStatus(!status)}
title={`Prevent Dairy: ${
status ? "on (search again for new results)" : "off"
}`}
></Button>
I want it to be dynamic as the user can change his allergies so I didn't use route.params for the allergies.
Any ideas appreciated. Thanks.

Related

Uncaught (in promise) TypeError: (0 , _firebase__WEBPACK_IMPORTED_MODULE_5__.db) is not a function

I am trying to use the Stripe Extension on Firebase to handle payments for my project. But when I try to go to stripe's checkout I get this error Uncaught (in promise) TypeError: (0 , firebase__WEBPACK_IMPORTED_MODULE_5_.db) is not a function.
This is the error
This is my Plans.js
const loadCheckout = async (priceId) => {
const docRef = doc(db("customers", `${user?.uid}`));
const docSnap = await getDoc(docRef);
const addedRef = await addDoc(
docSnap(collection(db, "checkout_sessions"), {
price: priceId,
success_url: window.location.origin,
cancel_url: window.location.origin,
})
);
const unsub = onSnapshot(addedRef, async (snap) => {
const { error, sessionId } = snap.data();
if (error) {
// Show an error to your customer and
// inspect your Cloud Function logs in the Firebase console
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
// We have a session, let's redirect to Checkout
// Init Stripe
const stripe = await loadStripe(
"PRIVATE_STRIPE_KEY"
);
stripe.redirectToCheckout({ sessionId });
}
});
};
return (
<div className="plans">
{Object.entries(products).map(([productId, productData]) => {
// Add some logic to check if the user's subscriptio is active
return (
<div className="plans-subscription">
<div className="plans-info">
<h5>{productData?.name}</h5>
<h6>{productData?.description}</h6>
</div>
<button onClick={() => loadCheckout(productData?.prices?.priceId)}>
Subscribe
</button>
</div>
);
})}
</div>
);
I am trying to do the same thing as a video but they're using Firebase v8.
This is what they did
const loadCheckout = async (priceld) => {
const docRef = await db
.collection("custoners")
.doc(user.uid)
.collection("checkout_sessions")
.add({
price: priceld,
success_url: window. location.origin,
cancel_url: window. location. origin,
}):
docRef.onSnapshot(async (snap) => {
const { error, sessionId } = snap.data():
if (error) (
// Show an error to your custoner and
// Inspect your Cloud Function logs in the Firebase console
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
// We have a session, let's redirect to Checkout
// Init Stripe
const stripe = await loadStripe(
"PRIVATE_STRIPE_KEY"
);
stripe.redirectToCheckout({ sessionId });
}
});
};
Perhaps I did not correctly did the conversion to v9 ? Thank you for your help you all
The db is not a function but you are trying to call it. Also, docSnap isn't one either. Try refactoring the code as shown below:
const docRef = doc(db, "customers", `${user?.uid}`);
const docSnap = await getDoc(docRef);
const addedRef = await addDoc(collection(docRef, "checkout_sessions"), {
price: priceId,
success_url: window.location.origin,
cancel_url: window.location.origin,
})
);

Firestore - How to store current user data and keep previews one?

I'm trying to store user data on Firestore which is I have multiple things to add such as (taskIndex,levelName,step,steps) and I did it successfully also I'm getting that user info after refresh or killing the app, but the problem here is that on my App I have multiple indexes and Levels and each of them has their special steper, once I add current user data previews one gets deleted, so how can I fix this?
This is what i did for storing the data
//Set userInfo
useEffect(() => {
const setUser = async () => {
await setDoc(doc(db, 'user', uid), {
uid: uid,
step: step,
steps: steps,
taskIndex: taskIndex,
levelName: levelName,
});
};
And getting data
// Get userInfo
const userRef = collection(db, 'user');
useEffect(() => {
const getUserInfo = async () => {
const data = await getDocs(userRef);
setUserData(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
getUserInfo();
}, []);
useEffect(() => {
const userInfo =
userData &&
userData.map((items) => {
setStep(items.step);
setSteps(items.steps);
setTaskIndex(items.taskIndex);
setLevelName(items.levelName);
});
}, [userData]);

Firebase auth().onAuthStateChanged not wait until auth().signInWithCredential finish

I have login code in react native using firebase and google signin auth.
So when new user sign in using google account, I set new data. And if user has signed in before, user go to main page.
My problem is when new user sign in > code start to get signInWithCredential > set new data user, before set data finish, onAuthStateChanged was detect there is change in auth and start to get user document / data. But because it's not finish yet, it throw error 'Can Not Get UID / Undefined UID'.
This is my login page code:
const _signIn = async () => {
setInitializing(true);
try {
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
const credential = auth.GoogleAuthProvider.credential(
userInfo.idToken,
userInfo.accessToken,
);
await auth()
.signInWithCredential(credential)
.then(response => {
const uid = response.user.uid;
const data = {
uid: uid,
email: userInfo.user.email,
fullname: userInfo.user.name,
bio: 'Halo!! ..',
username: uid.substring(0, 8),
};
const usersRef = firestore().collection('users');
usersRef
.doc(uid)
.get()
.then(firestoreDocument => {
if (!firestoreDocument.exists) {
usersRef
.doc(data.uid)
.set(data)
.then(() => {
setInitializing(false); return;
})
.catch(error => {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
});
} else {
setInitializing(false);
return;
}
})
.catch(error => {
Alert.alert(JSON.stringify(error.message));
console.log('Error getting document:', error);
return;
});
});
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
setInitializing(false);
Alert.alert('Sign in canceled');
} else if (error.code === statusCodes.IN_PROGRESS) {
setInitializing(false);
Alert.alert('Signin in progress');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
setInitializing(false);
Alert.alert('PLAY_SERVICES_NOT_AVAILABLE');
} else {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
}
}};
And this is my index page code to check auth user:
useEffect(() => {
try {
NetInfo.fetch().then(state => {
if(state.isConnected === false){
Alert.alert('No Internet Connection Detected');
setInitializing(false);
return;
}
});
setInitializing(true);
await auth().onAuthStateChanged(user => {
if (user) {
const usersRef = firestore().collection('users');
usersRef
.doc(user.uid)
.get()
.then(document => {
const userData = document.data().uid;
setisLogin(userData);
})
.then(() => {
setInitializing(false);
})
.catch(error => {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
});
} else {
setInitializing(false);
}
});
} catch (error) {
Alert.alert(error);
} }, []);
How to wait auth().signInWithCredential finish? Thankyou.
If you need to perform more actions such read data from database or so after the user logs in, you should ideally unsubscribe from onAuthStateChanged. Essentially it won't trigger when the auth state changes (i.e. user logs in) and let you do your own custom actions. Once your processing is done, then you manually redirect the user to where the onAuthStateChange would have redirected is the user wa s logged in.
const authStateListenter = await auth().onAuthStateChanged(user => {
//...
})
// Unsubscribe auth state observer when _signIn function runs
const _signIn = async () => {
setInitializing(true);
authStateListenter()
}
Calling authStateListener will disable the auth state observer. It's similar to detaching Firestore's listeners.

How to mock firebase firestore using jest with #react-native-firebase/firestore

I'm new to testing and I'm trying to fake a document update call using Jest. To do so I'm using react-native-testing-library and react-native-firebase.
Below is my test suite. I have one input, and when I'm changing its value the document should be updated
import firestore from "#react-native-firebase/firestore"
jest.mock("#react-native-firebase/firestore", () => {
return () => ({
collection: jest.fn(() => ({
doc: jest.fn(() => ({
update: jest.fn(),
})),
})),
});
});
describe("<EditInfosStudy>", () => {
const willSave = true;
const setDidChanged = jest.fn();
test("will update", async () => {
const { getByTestId } = render(
<EditInfosStudy willSave={willSave} setDidChanged={setDidChanged} />
);
const input = getByTestId("EditInfosStudy_TextInput");
fireEvent.changeText(input, "study text");
expect(input.props.value).toBe("study text");
// expect(firestore().collection('collection').doc('doc').update({})).toHaveBeenCalled()
// this is where i'm stuck
});
});
After Running the test Jest indicate a console.log from the function (below) to confirm that the document was updated and the test passes.
What I don't understand is how do I check if the document were updated on the last line using the expect method expect(firestore()…) I’m really confused on the whole mocking part, any help would be greatly appreciated!
belove is the function being called :
if (localChange && willSave) {
(async () => {
try {
await firestore()
.collection("users")
.doc(user.uid)
.update({ study });
setUser({ study });
console.log("study updated");
} catch (err) {
console.error(err);
}
})();
}

Why are my redux actions not firing correctly?

I am trying to implement a check for authentication and to login/logout users using redux and firebase. I have the following code:
Action Types:
export const LOGIN_REQ = 'AUTH_REQ';
export const LOGOUT_REQ = 'LOGOUT_REQ';
export const AUTH_SUCCESS = 'AUTH_SUCCESS';
export const AUTH_FAILED = 'AUTH_FAILED';
export const GET_AUTH = 'GET_AUTH';
Reducers:
import * as ActionTypes from './ActionTypes';
export const auth = (state = {
isAuth: false,
user: null
}, action) => {
switch (action.type) {
case ActionTypes.LOGIN_REQ:
return { ...state, isAuth: false, user: null };
case ActionTypes.LOGOUT_REQ:
return { ...state, isAuth: false, user: null };
case ActionTypes.AUTH_FAILED:
return { ...state, isAuth: false, user: null };
case ActionTypes.AUTH_SUCCESS:
return { ...state, isAuth: true, user: action.payload };
case ActionTypes.GET_AUTH:
return state;
default:
return state;
}
}
Thunks:
export const getAuth = () => (dispatch) => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('Get AUTH called');
dispatch(authSuccess());
}
else {
console.log('Get AUTH called');
dispatch(authFailed());
}
});
}
export const loginReq = (email, password, remember) => (dispatch) => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then((cred) => {
if (remember === false) {
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);
console.log('Logged In with Redux without persist');
}
else {
console.log('Logging in with Persist');
}
console.log('Dispatching Success !');
dispatch(authSuccess(cred.user.uid));
})
.catch((err) => {
console.log(err);
dispatch(authFailed(err));
});
}
export const logoutReq = () => (dispatch) => {
firebase.auth().signOut()
.then(() => dispatch(getAuth()))
.catch((err) => console.log(err));
}
export const authSuccess = (uid = null) => ({
type: ActionTypes.AUTH_SUCCESS,
payload: uid
});
export const authFailed = (resp) => ({
type: ActionTypes.AUTH_FAILED,
payload: resp
});
And I am calling it from a component as shown below:
const mapStateToProps = state => {
return {
isAuth: state.isAuth,
user: state.user
}
}
const mapDispatchToProps = dispatch => ({
getAuth: () => { dispatch(getAuth()) },
loginReq: (email, password, remember) => { dispatch(loginReq(email, password, remember)) },
logoutReq: () => { dispatch(logoutReq()) }
})
handleLogin() {
this.props.loginReq(this.state.email, this.state.password, this.state.remember);
}
handleLogOut() {
this.props.logoutReq();
}
<BUTTON onClick=()=>this.handleLogOut()/handleLogin()>
I am close to tears because I cannot figure out why my loginReq fires one or many gitAuth() methods even when i click on the button once. This happens only for the loginReq() action. I have not specified anywhere that loginReq() should fire it.
Also i have called the getAuth() method in the component did mount method of my main screen which checks authentication status once at the start of the app.
EDIT: I have console logged in the component did mount method in the main component so I know that this getAuth() call is not coming from there.
Imo the answer is badly done, try to reestructure it better, what you call "Thunks" are actually "Actions". But if I were to tell you something that could help is that maybe the problem lies in the thunk middleware config or with the way firebase is beign treated by the dispatcher, so I would say that you better try coding an apporach with the react-redux-firebase library (this one: http://react-redux-firebase.com/docs/getting_started ) it makes easier to connect redux with a firebase back end. Other great reference, the one that I learned with, is The Net Ninja's tutorial playlist about react, redux and firebase.
A friend of mine told me this has to do with something known as an 'Observer' which is in the onAuthStateChange() provided by firebase. Basically there is a conflict between me manually considering the user as authenticated and the observer doing so.

Resources