Why there is no userID? it is undefined - reactjs

Hello my friends i am trying to save data to firebase while using userID However i could not make it ! Please can anyone help me ?
class ImportScreen extends Component {
writeuserdata( name, surname, age, userId) {
firebase.database().ref('Users/' + userId).set({
name,
surname,
age
}).then((data) => {
console.log('data', data)
}).catch ((error) => {
console.log('eror',error)
})
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'white' }}>
<TextInput
placeholder="Enter a name"
onChangeText={(name) => this.setState({ name })}
/>
<TextInput
placeholder="Enter a surname"
onChangeText={(surname) => this.setState({ surname })}
/>
<TextInput
placeholder="Enter age"
onChangeText={(age) => this.setState({ age })}
/>
<Button
title="Save"
onPress={() => this.writeuserdata(this.state.name, this.state.surname, this.state.age)} />
</View>
);
}
}
enter image description here

You're calling writeuserdata with:
this.writeuserdata(this.state.name, this.state.surname, this.state.age)}
Since writeuserdata expects 4 parameters, and you're only passing 3, the 4th argument is going to be undefined.
If you want to also pass the UID of the current Firebase Authentication user, that'd be something like:
this.writeuserdata(this.state.name, this.state.surname, this.state.age, firebase.auth().currentUser.uid)}

Related

Using expo secure-store to store and retrieve user credentials and populate email & password fields

I'm building a mobile app on both iOS and Android, and I'm attempting to store user credentials with expo's secure-storage. I can successfully store them, as tested with console.log, however what I want to achieve is populating my email and password fields on the app with the stored credentials, so that users can simply select one field and both become populated, leading to a quicker login.
I've placed textContentType='email/password' and autoComplete='email/password' in my TextInput tags but I'm unsure how to propery achieve and ensure that the two fields are populated with the stored information.
const authHandler = async () => {
if (true) {
// sign up
} else {
try {
// login
let password = localState.inputValues.password;
await save('emailAddress', userEmail);
await save('password', localState.inputValues.password);
await save('userinfo', JSON.stringify({userEmail, password}));
await getValueFor('emailAddress');
await getValueFor('password');
await getValueFor('userinfo');
}
async function save(key, value) {
await SecureStore.setItemAsync(key, value);
}
async function getValueFor(key) {
let result = await SecureStore.getItemAsync(key);
if (result) {
console.log("🔐 Here's your value 🔐 \n" + result);
} else {
console.log('No values stored under that key.');
}
}
return (
<View style={{ paddingHorizontal: "8%" }}>
<TextInputWrapper
onFocus={() => {
setEmailSelected(true);
}}
onBlur={() => {
setEmailSelected(false);
}}
label="Email"
onChangeText={(input) => inputChangeHandler("email", input)}
placeholder="me#example.com"
value={localState.inputValues.email}
textContentType='emailAddress'
autoComplete='email'
/>
</View>
</View>
{/* password input */}
<View
style={{
paddingVertical: "2%",
flexDirection: "row",
alignItems: "center",
}}
>
<View style={{ paddingHorizontal: "8%" }}>
<TextInputWrapper
onFocus={() => {
setPwSelected(true);
}}
onBlur={() => {
setPwSelected(false);
}}
label="Password"
onChangeText={(input) => inputChangeHandler("password", input)}
placeholder="At least 6 characters required"
secureTextEntry
value={localState.inputValues.password}
textContentType='password'
autoComplete='password'
/>
</View>
</View>

React Native Form only submitting one value at a time

When I submit a form to my api, its weirdly only sending the last input that I filled out on the form. I have all of my form attributes saved to a const object and then sent with an axios post request. This is my first react native app, I don't know what's the cause of this issue. I have another form that doesn't have nested attributes, but saves without issue. How can I send all form inputs together in one api call with my nested form object?
SERVER LOGS
Started POST "/api/v1/applicant_forms" for 127.0.0.1 at 2021-05-02 13:08:14 -0400
Processing by Api::V1::ApplicantFormsController#create as JSON
Parameters: {"applicant_form"=>{"user_id"=>"11", "personal_info_attributes"=>{"prefix"=>"Mr"}}}
ApplicantForm.js
handleSubmit(e) {
e.preventDefault();
const {applicant_form: {personal_info_attributes: {prefix, first_name}}, user_id} = this.state;
const data_obj = {
applicant_form: {
user_id,
personal_info_attributes: {
prefix,
first_name
}
}
}
const { navigation } = this.props;
return axios({
url: `http://127.0.0.1:3000/api/v1/applicant_forms`,
method: 'POST',
data: data_obj,
}).then(response => {
console.log("Successful Response" + response)
navigation.navigate('home')
}).catch(err => {
showMessage({
message: "Something went wrong!",
description: "Testing",
type: 'danger'
})
})
}
render() {
return(
<KeyboardAvoidingView behavior="padding">
<View style={{paddingVertical: 5, paddingHorizontal: 14}}>
<View style={{backgroundColor: '#fff', width: Dimensions.get('window').width * 0.9, minHeight: 50, padding: 2, borderColor: 'gray', borderRadius: 4, borderWidth: 1, height: Dimensions.get('window').height * 0.8}}>
<View style={styles.centerText}>
<Text>Applicant Profile</Text>
</View>
<ScrollView>
<Text>Prefix</Text>
<FormInput
inputStyle={styles.input}
autoCapitalize="none"
onSubmitEditing={() => this.applicant_form.personal_info_attributes.prefix}
autoCorrect={false}
keyboardType='default'
returnKeyType="next"
placeholder='Prefix: Mr. Mrs. Ms., etc'
onChangeText={prefix => this.setState({ applicant_form: {personal_info_attributes: {prefix: prefix} }})}
// value={this.state.applicant_form.personal_info_attributes.prefix}
/>
<Text>First Name</Text>
<FormInput
inputStyle={styles.input}
autoCapitalize="none"
onSubmitEditing={() => this.applicant_form.personal_info_attributes.first_name}
autoCorrect={false}
keyboardType='default'
returnKeyType="next"
placeholder='First Name'
onChangeText={first_name => this.setState({ applicant_form: {personal_info_attributes: {first_name: first_name} }})}
// value={this.state.applicant_form.personal_info_attributes.first_name}
/>
<TouchableOpacity style={styles.saveButtoncontainer} onPress={e=>{this.handleSubmit(e)}}>
<Text style={styles.buttontext}>Save Employment Profile</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
)
You are overwriting the applicant_form value every-time that a text field is edited.
The following code replaces the content in the state applicant_form to be {personal_info_attributes: {prefix: prefix} }. If you had set first_name before, it'll get removed.
<FormInput
...
onChangeText={prefix => this.setState({ applicant_form: {personal_info_attributes: {prefix: prefix} }})}
/>
To prevent this overwriting the object, you can use the spread operator to make sure that the values are cloned and updated accordingly.
<FormInput
onChangeText={prefix =>
this.setState(prevState => ({
applicant_form: {
...prevState.applicant_form,
personal_info_attributes: {
...prevState.applicant_form.personal_info_attributes,
prefix: prefix,
}
}
}))
}
/>
You can read more about this here: What's the best alternative to update nested React state property with setState()?

how to navigate to a new page in an onsubmit function react native

I have a form that should store data and pass it as a parameter while navigating to a new screen. I have it structured like so. The formik form:
return (
<View style={styles.container}>
<Formik
initialValues={{
first_name: '',
last_name: '',
}}
// Form submission action
onSubmit={(values) => {
const d = addData(values);
this.props.navigation.navigate('Cart', {
screen: 'Process Payment',
params: {data: d},
});
}}>
{(props) => (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}
style={{flex: 1, width: '100%'}}>
<ScrollView style={styles.inner}>
<TextInput
style={styles.input}
placeholder="first name"
onChangeText={props.handleChange('first_name')}
value={props.values.first_name}
/>
<TextInput
style={styles.input}
placeholder="last name"
onChangeText={props.handleChange('last_name')}
value={props.values.last_name}
/>
<View style={[{width: '90%', margin: 10, alignSelf: 'center'}]}>
<Button
title="place order"
color="maroon"
onPress={props.handleSubmit}
style={{padding: 3, width: '80%'}}
/>
</View>
</ScrollView>
</KeyboardAvoidingView>
)}
</Formik>
</View>
);
}
Onsubmit function:
onSubmit={(values) => {
const d = addData(values);
this.props.navigation.navigate('Cart', {
screen: 'Process Payment',
params: {data: d},
});
}}>
My Error:
Warning: An unhandled error was caught from submitForm() [TypeError: undefined is not an object (evaluating '_this.props.navigation')]
I'm not sure how to navigate to a new screen within the onsubmit function
onSubmit={(values) => {
const d = addData(values);
props.navigation.navigate('Cart', {
screen: 'Process Payment',
params: {data: d},
});
}}>
I took out the "this" and just called props.navigation.navigate

Keyboard hides automatically on key press in react native

I'm creating a form, where I need to input the data in the field. But as soon as I press the key, the keyboard is hiding automatically and I'm unable to do persistent typing.
Suppose, I'm typing a Product name or stock anything the typing is persistent but when I type in variants section on every keypress keyboards hides automatically.
Here is the codebase-
AddNewProductScreen.js
....
constructor(props) {
super(props);
this.state = {
product: {
name: '',
category: '',
type: 'packet',
brand: '',
variants: [
{
value: '',
price: '',
},
],
stock: '',
},
};
....
<Input
inputContainerStyle={{borderBottomColor: 'transparent'}}
inputComponent={() => (
<View>
{this.state.product.variants.map((item, index) => (
<View key={index} style={[mainStyles.row, {marginTop: 10}]}>
<View style={mainStyles.col6}>
<Input
label="Value"
placeholder="500 gm or 1 pc"
value={this.state.product.variants[index].value}
onChangeText={value => {
let variants = this.state.product.variants;
variants[index].value = value;
this.setState({
product: {
...this.state.product,
variants,
},
});
}}
/>
</View>
<View style={mainStyles.col5}>
<Input
label="Price"
keyboardType="numeric"
placeholder="50"
value={this.state.product.variants[index].price}
onChangeText={price => {
let variants = this.state.product.variants;
variants[index].price = price;
this.setState({
product: {
...this.state.product,
variants,
},
});
}}
/>
</View>
<View style={[mainStyles.col1, {justifyContent: 'center'}]}>
<Icon
name="times"
size={25}
color="red"
type="font-awesome"
containerStyle={{
display: `${
this.state.product.variants.length > 1 ? 'flex' : 'none'
}`,
}}
onPress={() => {
let variants = this.state.product.variants;
variants.splice(index, 1);
this.setState({
product: {
...this.state.product,
variants,
},
});
}}
/>
</View>
</View>
))}
</View>
)}
/>
....
Expectation: Inside the variants input(Value & Price), I need persistent typing as of other input fields.
Thanks in advance.
P.S- adding the screenshot for reference
{this.state.product.variants.map((item, index) => (
<View key={index} style={[mainStyles.row, {marginTop: 10}]}>
<View style={mainStyles.col6}>
<Input
label="Value"
placeholder="500 gm or 1 pc"
value={this.state.product.variants[index].value}
onChangeText={value => {
let variants = this.state.product.variants;
variants[index].value = value;
this.setState({
product: {
...this.state.product,
variants,
},
});
}}
/>
</View>
Problem here is that this.state.product.variants is changing based on values in the input fields, and thus the contents in this list is mounted again on each keypress. I suggest you try an approach that does not map the input fields and they will remain in the component tree throughout the lifecycle of the parent.

How to find if users exist in Firebase?

I am using Firebase Web SDK and know methods to check whether a child in a collection exists or not. However I can't find a concise example checking the existence of a user, without trying to sign him/her in.
export class Email extends Component {
constructor (props) {
super(props)
this.state = { email: '' }
}
checkEmail () {
const { email } = this.state
FirebaseApp.auth()
.createUserWithEmailAndPassword(email, uuid.v4())
.then((User) => Actions.Password({ User }))
.catch((error) => {
// Handle Errors here.
console.log('firebase', {error})
this.setState({error})
// ...
})
// Actions.password()
}
render () {
return (
<View style={{ ...styles.onboarding, backgroundColor: 'purple' }}>
<View style={{ borderBottomWidth: 3, borderColor: 'black', padding: 10 }}>
<TextInput ref='email'
style={styles.input}
keyboardType='email-address'
placeholder='Your email'
value={this.state.email}
onChangeText={(email) => this.setState({email: email.toLowerCase()})} />
</View>
{!this.state.error ? null
: <Text>
{this.state.error.message}
</Text>
}
<TouchableOpacity onPress={() => this.checkEmail()} style={{ ...styles.button, margin: 20, borderColor: 'black' }}>
<Text style={styles.buttonText}>Next</Text>
</TouchableOpacity>
</View>
)
}
}
Do you have any piece of code we could reuse?
For the moment, and because it complies with my app security policy and setup, I created an email collection indexed precisely by ids.
firebase.ref(`emails/${user.email}`).set(true)

Resources