I am trying to pass the username from signup1 to signup 2:
handleSignUp = () => {
console.log(this.state.username) <------------- This logs correctly
try {
this.props.navigation.navigate('Signup2', {
username: this.state.username, <------------- Passing here
});
} catch (error) {
console.log(error);
}
}
Here is the code from Signup2:
const Signup2 = (props, route, navigation) => {
const { username } = route.params; <----------- Trying to access it here
I get the following error:
undefined is not an object (evaluating 'route.params.username')
I have also tried this:
const { username } = props.route.params
And neither work.
How can I access the route params?
I believe you would need to destructure your route and navigation properties if you'd like to access them as intended.
You can go for:
const Signup2 = ({route, navigation}) => {
const { username } = route.params
}
Or maybe:
const Signup2 = (props) => {
const { username } = props.route.params
}
Related
i have a firebase issue, whenever I try to authenticate with firebase i get this problem
App.js:27 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'onSnapshot')
App.js :
{
const {setCurrentUser} = this.props
this.authListener = auth.onAuthStateChanged(async userAuth =>{
if(userAuth)
{
const userRef = await handleUserProfile(userAuth)
userRef.onSnapshot(snapchot=>{
setCurrentUser(
{
id:snapchot.id,
...snapchot.data(),
}
)
})
}
setCurrentUser(userAuth)
})
}
firebase.js :
export const handleUserProfile = async({ userAuth, additionalData }) => {
if (!userAuth) return;
const { uid } = userAuth;
const userRef = firestore.doc(`users/${uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { displayName, email } = userAuth;
const timestamp = new Date();
const userRoles = ['user'];
try {
await userRef.set({
displayName,
email,
createdDate: timestamp,
userRoles,
...additionalData
});
} catch (err) {
console.log(err);
}
}
return userRef;
};
I cant get eventually the redux state of the currentUser,
I am trying to save the currentUser when is logged in
:
const mapStatetoProps = ({user}) =>
({
currentUser:user.currentUser
})
const mapDispatchToProps = dispatch =>({
setCurrentUser:user => dispatch(setCurrentUser(user))
})
export default connect(mapStatetoProps,mapDispatchToProps)(App)
Here you are destructuring userAuth from the object you receive as a parameter in this function
export const handleUserProfile = async({ userAuth, additionalData }) => {
And here you are directly passing the userAuth:
const userRef = await handleUserProfile(userAuth)
Instead, here you should write:
const userRef = await handleUserProfile({userAuth})
This will pass the userAuth in an object, hence the destructuring will be successful!
I'm trying to add MFA inside my web app and the multiFactor property is missing.
Check the code:
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.2/firebase-app.js";
import { getAuth, RecaptchaVerifier, PhoneAuthProvider, signInWithEmailAndPassword }
from "https://www.gstatic.com/firebasejs/9.6.2/firebase-auth.js";
const firebaseConfig = {
...
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
auth.onAuthStateChanged((user) => {
const userEl = document.getElementById('user');
if (user) {
userEl.innerHTML = `${user.email} logged in. ${JSON.stringify(
user.multiFactor.enrolledFactors
)}`;
} else {
userEl.innerHTML = 'signed out';
}
});
window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {
'size': 'invisible',
'callback': (response) => {
console.log('captcha solved!');
}
}, auth);
const enrollBtn = document.getElementById('enroll-button');
enrollBtn.onclick = () => {
signInWithEmailAndPassword(auth, 'blabla#gmail.com', 'foobar').then(() => {
const user = auth.currentUser;
if (!user) {
return alert('User not logged!');
}
const phoneNumber = document.getElementById('enroll-phone').value;
console.log(user);
user.multiFactor.getSession().then((session) => {
const phoneOpts = {
phoneNumber,
session,
};
const phoneAuthProvider = new PhoneAuthProvider();
phoneAuthProvider.verifyPhoneNumber(
phoneOpts,
window.recaptchaVerifier
).then((verificationId) => {
window.verificationId = verificationId;
alert('sms text sent!');
});
});
});
};
In the code above the user.multiFactor is undefined. The signIn is returning the user normally, but without this property.
error on console:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'getSession')
The Firebase project have MFA enabled:
enter image description here
**************** UPDATE *******************
Apparently change the code to this worked:
const mfaUser = multiFactor(user);
mfaUser.getSession().then((session) => {
But now I'm getting this error when I call verifyPhoneNumber:
VM21778 index.html:315 TypeError: Cannot read properties of undefined (reading 'tenantId')
at _addTidIfNecessary (firebase-auth.js:1934:14)
at startEnrollPhoneMfa (firebase-auth.js:6778:125)
at _verifyPhoneNumber (firebase-auth.js:8500:40)
However I'm not using Multi-Tenancy option, this is disabled in my project.
Changed to:
const mfaUser = multiFactor(user);
mfaUser.getSession().then((session) => {
and:
const phoneAuthProvider = new PhoneAuthProvider(auth);
I don't know if Firebase Auth docs is deprecated or I'm doing something different. XD
My Code looks like this:
interface MutationProps{
username: any,
Mutation: any
}
const UseCustomMutation: React.FC<MutationProps> = (MutationProps: MutationProps) => {
const [myFunc, {data, error}] = useMutation(MutationProps.Mutation);
useEffect(() => {
myFunc({variables:{username: MutationProps.username}})
console.log(JSON.stringify(data))
console.log(JSON.stringify(error, null , 2))
}, [])
return data
}
export const DisplayUser = () => {
const GET_USER = gql`
mutation GetUser($username: String!){
getUser(username: $username) {
pfp
username
password
age
CurrentLive
ismod
description
fullname
}
}
`
const {username} : {username: any} = useParams()
const MyData = UseCustomMutation(username, GET_USER)
console.log(JSON.stringify(MyData))
But I get this error back: ×
Argument of undefined passed to parser was not a valid GraphQL DocumentNode. You may need to use >'graphql-tag' or another method to convert your operation into a document
How about your code looks like this:
interface MutationProps {
username: string;
Mutation: any;
}
const UseCustomMutation: React.FC<MutationProps> = ({ username, Mutation }) => {
const [functionForDoingAction, { data, loading, error }] = useMutation(
Mutation,
{
variables: {
username,
},
}
);
useEffect(() => {
// fn trigger for change data
functionForDoingAction({
variables: {
username: "string_value",
},
});
console.log(JSON.stringify(data));
console.log(JSON.stringify(error, null, 2));
}, []);
if (loading) return "loading...";
if (error) return `Submission error! ${error.message}`;
return data;
};
export const DisplayUser = () => {
const GET_USER = gql`
mutation GetUser($username: String!) {
getUser(username: $username) {
pfp
username
password
age
CurrentLive
ismod
description
fullname
}
}
`;
const { username }: { username: string } = useParams();
const MyData = UseCustomMutation(username, GET_USER);
console.log(JSON.stringify(MyData));
};
you can pass an argument directly to the useMutation hook which they provide as an Options parameter. Or is the direct trigger function from the hook you get.
I would like to redirect users when they sign in with Github or others based on whether they are a new user or a returning user. I'm having trouble accessing the isNewUser property referenced in this answer: How to differentiate signin and signup user in firebase using google auth?
I have a standard sign in function:
const signinWithGoogle = () => {
return auth.signInWithPopup(googleProvider)
.then((response) => {
handleUser(response.user)
})
}
This is the handleUser function:
const handleUser = (rawUser) => {
if (rawUser) {
const currentUser = formatUser(rawUser)
createUser(currentUser.uid, currentUser)
setCurrentUser(currentUser)
if (currentUser.providerData[0].isNewUser===true) {
history.push("/onboarding")
} else {
history.push("/")
}
return currentUser
}
else {
setCurrentUser(false)
return false
}
}
And this is formatUser:
const formatUser = (user) => {
return {
uid: user.uid,
email: user.email,
name: user.displayName,
provider: user.providerData[0].providerId,
avatar: user.photoURL,
}
}
Can anyone see what I'm doing wrong, please?
Cheers, Matt
EDIT:
If we pass the response to the HandleUser function and console log response.additionalUserInfo.isNewUser we get 'true'. However, if we use that in our if statement, it seems to be ignored for some reason
const handleUser = (response) => {
if (response) {
console.log("response: ", response.additionalUserInfo.isNewUser)
const currentUser = formatUser(response.user)
createUser(currentUser.uid, currentUser)
setCurrentUser(currentUser)
console.log('response', response)
console.log('additional info', response.additionalUserInfo)
const isNew = response.additionalUserInfo.isNewUser
console.log('isNewUser', isNewUser)
if (isNew) {
console.log('redirecting to /onboarding')
history.push("/onboarding")
} else {
console.log('redirecting to /')
history.push("/")
}
return currentUser
}
else {
setCurrentUser(false)
return false
}
}
EDIT 2: Here is the output from the console logs
That error is coming from the signInWithGithub function in the modal
async function signInGitHub() {
try {
await signinWithGitHub()
}
catch(err) {
console.log("Error: ",err.code)
}
finally {
closeModal();
}
}
It looks like you are passing a User to that function and not the raw response. The isNewUser is present on the additionalUserInfo property. Please try refactoring as shown below:
const handleUser = (rawUser) => {
if (rawUser) {
const currentUser = formatUser(rawUser.user)
createUser(currentUser.uid, currentUser)
setCurrentUser(currentUser)
if (currentUser.additionalUserInfo.isNewUser) {
history.push("/onboarding")
} else {
history.push("/")
}
return currentUser
}
else {
setCurrentUser(false)
return false
}
}
Also make sure you pass the raw response:
handleUser(response.user)
I'm coming from React/Redux-land and am slowly getting acquainted to Svelte design patterns using stores.
Currently I'm curious to figure out if this is an acceptable pattern or if not, what is a better way to pursue this kind of communication. The basic premise is I want to be able to update multiple custom stores (which are using writable) from an adjacent store.
In the example below I have "loading.js" and "error.js" stores which would be used globally, commented out in the "session.js" store. I'd like to update these based on the result of an API request to create a session, in order to keep most of my heavy lifting out side of components.
My current thinking is that I'd pass each store needed through the "createSessionStore" function, but it feels a little clunky as it would highly depend on the declaration order of each store within "store.js"
The long term intention for wishing to do it this way is so I can add any kind of communication layer (such as web sockets) in to the mix and update the global loading or error store from any layer.
Thanks for the help.
Component.svelte
<script>
import { onMount } from "svelte";
import { error, loading, session } from "./store";
onMount(() => {
session.fetchSession();
});
</script>
{#if $loading}
<div>Loading...</div>
{/if}
{#if $error}
<div>Something went wrong: {$error}</div>
{/if}
store.js
import { createErrorStore } from "./error";
import { createLoadingStore } from "./loading";
import { createSessionStore } from "./session";
export const error = createErrorStore();
export const loading = createLoadingStore();
export const session = createSessionStore();
session.js
import { writable } from "svelte/store";
const INITIAL_STORE = {
token: null
};
export const createSessionStore = (initialStore = INITIAL_STORE) => {
const { subscribe, set } = writable(initialStore);
const fetchSession = async () => {
// loading.set(true);
try {
const response = await fetch("MY_API_ENDPOINT/auth/token", {
method: "POST",
});
if (!response.ok) {
const err = new Error("Network response was not ok.");
// error.set(err);
// loading.set(false);
return;
}
const data = await response.json();
set(data.token);
// loading.set(false);
} catch (err) {
// error.set(err);
// loading.set(false);
}
};
const reset = () => {
set(initialStore);
};
return {
subscribe,
fetchSession,
reset
};
};
error.js
import { writable } from "svelte/store";
const INITIAL_STORE = false;
export const createErrorStore = (initialStore = INITIAL_STORE) => {
const { subscribe, set } = writable(initialStore);
const reset = () => {
set(initialStore);
};
return {
subscribe,
set,
reset
};
};
loading.js
import { writable } from "svelte/store";
const INITIAL_STORE = false;
export const createLoadingStore = (initialStore = INITIAL_STORE) => {
const { subscribe, set } = writable(initialStore);
const reset = () => {
set(initialStore);
};
return {
subscribe,
set,
reset
};
};
Interesting idea.
The problem here is that during the creation of the stores, not all of them exists yet. The only solution that I see for this is to add the references after creating them.
Here's my idea:
In the session.js:
import { writable } from "svelte/store";
const INITIAL_STORE = {
token: null
};
export const createSessionStore = (initialStore = INITIAL_STORE) => {
const { subscribe, set } = writable(initialStore);
const fetchSession = async () => {
// loading.set(true);
try {
otherStores.loading && otherStores.loading.set(true);
const response = await fetch("MY_API_ENDPOINT/auth/token", {
method: "POST",
});
if (!response.ok) {
const err = new Error("Network response was not ok.");
otherStores.error && otherStores.error.set(err);
otherStores.loading && otherStores.loading.set(false);
return;
}
const data = await response.json();
set(data.token);
} catch (err) {
otherStores.error && otherStores.error.set(err);
otherStores.loading && otherStores.loading.set(false);
}
};
const reset = () => {
set(initialStore);
};
let otherStores = {}
const setOtherStores = (stores) => {
otherStores=stores
};
return {
subscribe,
fetchSession,
reset,
setOtherStores
};
};
In the store.js:
import { createErrorStore } from "./error";
import { createLoadingStore } from "./loading";
import { createSessionStore } from "./session";
export const error = createErrorStore();
export const loading = createLoadingStore();
export const session = createSessionStore();
session.setOtherStores({error,loading})
You can use the same pattern for any of the other stores (if needed), and after creation pass them the references to the other stores.