I am attempting to set up a slack invite based on this tutorial: https://www.robinwieruch.de/slack-invite-javascript-react
I have everything set up the same as the example but I'm getting this error
TypeError: onUserAuthSignUp is not a function
I can see in the code where it's being destructured:
const { onUserAuthSignUp } = this.props
But I cannot see what I'm missing, i'm still learning JS and React so i'm thinking it's something really obvious.
Full code for the form is below, <Form /> is then imported into the index.js file.
// Form.js
import React, { Component } from "react"
import axios from 'axios';
var SLACK_TOKEN = 'slack-token';
var SLACK_INVITE_ENDPOINT = 'https://slack.com/api/users.admin.invite';
function inviteSuccess() {
console.log('success');
}
function inviteError() {
console.log('error');
}
function inviteToSlack(email) {
var QUERY_PARAMS = `email=${email}&token=${SLACK_TOKEN}&set_active=true`;
axios.get(`${SLACK_INVITE_ENDPOINT}?${QUERY_PARAMS}`)
.then(inviteSuccess)
.catch(inviteError);
}
export class Form extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
passwordOne: '',
passwordTwo: '',
username: '',
isSlackInvite: true,
};
this.onSubmit = this.onSubmit.bind(this);
this.onCheckSlackInvite = this.onCheckSlackInvite.bind(this);
}
onCheckSlackInvite(e) {
this.setState(prevState => ({ isSlackInvite: !prevState.isSlackInvite }));
}
onSubmit(e) {
e.preventDefault();
const {
email,
passwordOne,
username,
isSlackInvite,
} = this.state;
const { onUserAuthSignUp } = this.props;
if (isSlackInvite) {
inviteToSlack(email);
}
onUserAuthSignUp(email, passwordOne, username);
}
render() {
const {
email,
passwordOne,
passwordTwo,
username,
isSlackInvite,
} = this.state;
return (
<form onSubmit={this.onSubmit}>
<input
type="text"
placeholder="Full Name"
value={username}
onChange={e => this.setState({ username: e.target.value})}
/>
<input
type="text"
placeholder="Email Address"
value={email}
onChange={e => this.setState({ email: e.target.value})}
/>
<input
type="password"
placeholder="Password"
value={passwordOne}
onChange={e => this.setState({ passwordOne: e.target.value})}
/>
<input
type="password"
placeholder="Confirm Password"
value={passwordTwo}
onChange={e => this.setState({ passwordTwo: e.target.value})}
/>
<div>
<label>Join Slack Group</label>
<input
type="checkbox"
checked={isSlackInvite}
onChange={this.onCheckSlackInvite}
/>
</div>
<button
disabled={passwordOne !== passwordTwo || passwordOne === '' || username === ''}
type="submit"
className="btn"
>
Sign Up
</button>
</form>
)
}
}
Tutorial author here. Sorry for being unclear in the tutorial!
The SignUp component only showcases how it can be used afterward (e.g. in a sign up process). But it doesn't show how to implement the whole sign up, it merely shows how the Slack invite can be used as an opt-in in such a form:
if (isSlackInvite) {
inviteToSlack(email);
}
If you are curious to implement the whole sign up process, checkout the Complete Firebase in React authentication tutorial. There you will implement the SignUp form where you can opt-in the Slack invite afterward.
Related
I am writing a full stack web application to register a user. I have state variables to reflect the back-end errors, which are then used in the jsx code. I re-render the component whenever the alerts change (which are app-level state managed by redux whose content are generated by the backend). The problem I am facing is that, when the first time I don't enter the required info and hit submit, I display the errors successfully below the corresponding wrongly entered field for 1 second before dispatching a clear alert action, and although alerts state are updated according to redux devtool, the error message would still be there after 1 s in the component. I think the problem is that I need to reset the local state variable that corresponds to the field that was cleared, but I am not sure how to implement that. The errors are captured in errorsData state variable below. Here is my component
import React, { useState, useEffect } from 'react';
import { setAlert } from '../../actions/alert';
import { connect } from 'react-redux';
import { registerUser } from '../../actions/auth';
const Register = ({ setAlert, alerts, registerUser }) => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
password2: '',
});
const [errorsData, setErrorsData] = useState({
nameErr: '',
emailErr: '',
passwordErr: '',
});
const { name, email, password, password2 } = formData;
const { nameErr, emailErr, passwordErr } = errorsData;
const handleOnChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleOnSubmit = async (e) => {
e.preventDefault();
if (password !== password2) {
console.log('Passwords do not match');
} else {
registerUser({ name, email, password });
}
};
useEffect(() => {
alerts.forEach((alert) => {
if (alert.errField === 'name') {
setErrorsData({ ...errorsData, nameErr: alert.msg });
}
if (alert.errField === 'email') {
setErrorsData({ ...errorsData, emailErr: alert.msg });
}
if (alert.errField === 'password') {
setErrorsData({ ...errorsData, passwordErr: alert.msg });
}
});
}, [alerts]);
return (
<form className='form' onSubmit={handleOnSubmit}>
<div className='input-field'>
<label htmlFor='name'>Name</label>
<input
type='text'
name='name'
value={name}
id='name'
placeholder='Enter your name'
onChange={handleOnChange}
/>
<small className='error error--name'>{nameErr}</small>
</div>
<div className='input-field'>
<label htmlFor='email'>Email</label>
<input
type='email'
name='email'
value={email}
id='email'
placeholder='Enter a valid email'
onChange={handleOnChange}
/>
<small className='error error--email'>{emailErr}</small>
</div>
<div className='input-field'>
<label htmlFor='password'>Passwrod</label>
<input
type='password'
name='password'
value={password}
id='password'
placeholder='Enter password'
onChange={handleOnChange}
/>
<small className='error error--password'>{passwordErr}</small>
</div>
<div className='input-field'>
<label htmlFor='password2'>Confirm password</label>
<input
type='password'
name='password2'
value={password2}
id='password2'
placeholder='Confirm password'
onChange={handleOnChange}
/>
</div>
<input className='submit' type='submit' value='Submit' />
</form>
);
};
const mapStateToProps = (state) => ({
alerts: state.alert,
});
export default connect(mapStateToProps, { setAlert, registerUser })(Register);
Your component is setup incorrectly because you are trying to use connect with functional components when you must be using useDispatch and useTypedSelector for redux with functional components. Instead you should do something like this.
import React, { useState, useEffect } from "react";
/* Hooks */
**import { useDispatch, useSelector } from "react-redux";**
/* Actions */
import { registerUser } from "../../actions/auth";
import { setAlert } from "../../actions/alert";
const Register = () => {
// Hooks
**const dispatch = useDispatch();**
// Store
**const alerts = useSelector(state => state.alert);**
// Local state
const [formData, setFormData] = useState({
name: "",
email: "",
password: "",
password2: "",
});
const [errorsData, setErrorsData] = useState({
nameErr: "",
emailErr: "",
passwordErr: "",
});
const { name, email, password, password2 } = formData;
const { nameErr, emailErr, passwordErr } = errorsData;
// Event handlers
const handleOnChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });
const handleOnSubmit = async e => {
e.preventDefault();
if (password !== password2) console.log("Passwords do not match");
else dispatch(registerUser({ name, email, password }));
};
// Effects
useEffect(() => {
alerts.forEach(alert => {
switch(alert.errField) {
case "name":
setErrorsData({ ...errorsData, nameErr: alert.msg });
break;
case "email":
setErrorsData({ ...errorsData, emailErr: alert.msg });
break;
case "password":
setErrorsData({ ...errorsData, passwordErr: alert.msg });
break;
default:
break;
};
});
}, [alerts, errorsData]);
// Rendering
return (
<form className="form" onSubmit={handleOnSubmit}>
<div className="input-field">
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
value={name}
id="name"
placeholder="Enter your name"
onChange={handleOnChange}
/>
<small className="error error--name">{nameErr}</small>
</div>
<div className="input-field">
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
value={email}
id="email"
placeholder="Enter a valid email"
onChange={handleOnChange}
/>
<small className="error error--email">{emailErr}</small>
</div>
<div className="input-field">
<label htmlFor="password">Passwrod</label>
<input
type="password"
name="password"
value={password}
id="password"
placeholder="Enter password"
onChange={handleOnChange}
/>
<small className="error error--password">{passwordErr}</small>
</div>
<div className="input-field">
<label htmlFor="password2">Confirm password</label>
<input
type="password"
name="password2"
value={password2}
id="password2"
placeholder="Confirm password"
onChange={handleOnChange}
/>
</div>
<input className="submit" type="submit" value="Submit" />
</form>
);
};
**export default Register;**
Major changes are highlighted.
So I have a form where I am validating it with merely with HTML5.
I have some fields that are required and just don't. So I would like to know what can I do with React, to check if those fields are not empty.
Like this is the form:
<form className="step-three-form">
<Container className="step-one">
<Row>
<Col md={{ span: 6, offset: 3 }}>
<FormField
type="text"
label="First Name"
isRequired="required"
controlId="firstName"
placeholder="First Name"
onChange={e => {
startupThirdStepFormActionHandler({
firstName: e.target.value,
});
}}
value={startupThirdStepForm.firstName}
/>
<FormField
type="text"
isRequired={false} // THIS IS NOT REQUIRED.
label="Middle Name"
controlId="middleName"
placeholder="Middle Name"
onChange={e =>
startupThirdStepFormActionHandler({
middleName: e.target.value,
})
}
value={startupThirdStepForm.middleName}
/>
<div className="choose-profile-separator">
<PrimaryButton
type="submit"
btnText="NEXT"
primaryBtnClasses="form-button"
onClick={handleNextFunctionality}
isDisabled={areFieldsFilledOut()}
/>
</div>
</Col>
</Row>
</Container>
</form>
I am using react bootstrap but I am not using any of its validation methods.
So I need to do is something like:
const checkFormValidation = () => {
if (form has all of its inputs filled out) return performSomething.
}
Its hard to give precise answer without looking rest of the code.
This is normally we do it.
this.isRequireEmpty = () => {
if (this.props.personStore.person.firstName === '') {
return true;
}
return false;
};
}
and call isRequireEmpty in handleNextFunctionality method which you are calling on click..
I mentioned this this.props.personStore.person.firstName which can be different according to your rest of code. I used mobx for state management.
PersonStore look something like this.
import {
configure,
observable,
decorate,
action,
} from 'mobx';
configure({ enforceActions: 'observed' });
class PersonStore {
constructor() {
this.person = {
firstName: '',
Lastname: '',
};
this.setPerson = (property, value) => {
this.person[property] = value;
};
}
async addPerson() {
// some functionality to call add api
}
}
decorate(PersonStore, {
person: observable,
setPerson: action,
});
export default PersonStore;
I'm new to React and have written the following form which sends the data to Firebase, this part works but on submit I want to redirect to /thankyou.html which is outside of the react app.
Can anyone advise how I redirect after submit please?
My form is as follows:
import React, { Component } from 'react';
import firebase from '../firebase.js';
class Form extends Component {
constructor(){
super();
this.state = {
name : "",
email : "",
phone : "",
message : "",
formError: false
}
}
getName = (e) =>{
let username = e.target.value;
this.setState({
name: username
});
}
getPhone = (e) =>{
let userphone = e.target.value;
this.setState({
phone: userphone
});
}
getEmail = (e) =>{
let userEmail = e.target.value;
//the most important thing is that we use a RegEx
//in order to manage the input of the email
//at least we can get a some what valid email
if(userEmail.match(/^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/)){
this.setState({
email: userEmail
});
}else{
this.setState({
email: ""
});
}
}
getDescription = (e) =>{
let userMessage = e.target.value;
this.setState({
message: userMessage
});
}
//send the form
submitForm = (e) =>{
e.preventDefault()
const itemsRef = firebase.database().ref('items');
if(this.state.name === "" || this.state.email === "" || this.state.phone === "" || this.state.message === "" ){
this.setState({
formError: true
})
return false;
}else{
this.setState({
formError: false
})
const item = {
Name: this.state.name,
Email: this.state.email,
Phone: this.state.phone,
Message: this.state.message
}
itemsRef.push(item);
this.setState({
name: '',
email: '',
phone: '',
message: ''
})
}
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{/* I am just sending a basic error message */}
{this.state.formError &&
<p className="error">
Fill all the input fields please.
</p>
}
<div>
<label htmlFor="name">Name</label>
<input type="text" name="name" placeholder="Your name here please" onChange={this.getName} />
</div>
<div>
<label htmlFor="email">Email</label>
<input type="email" name="email" placeholder="We will contact you after reviewing your message" onChange={this.getEmail} />
</div>
<div>
<label htmlFor="phone">Phone</label>
<input type="phone" name="phone" placeholder="We will contact you after reviewing your message" onChange={this.getPhone} />
</div>
<div>
<label htmlFor="name">Message</label>
<textarea onChange={this.getDescription} maxLength="450"></textarea>
</div>
<div>
<p>We will answer as soon as possible</p>
<input type="submit" name="submit" value="Send" onClick= {this.submitForm} />
</div>
</form>
);
}
}
export default Form;
in firebase push() can have a callback function as a second parameter which you can use in your case to check whenever the save process to firebase is done redirect to thank you page.
so after submitting the form and save to firebase, you can redirect to another page like that :
itemsRef.push(item, ()=>{
window.location.href = "/thankyou.html"; // similar behavior as clicking on a link
});
Use react-router-dom npm package.
import {withRouter, BrowserRouter } from 'react-router-dom';
Wrap your App.js component with BrowserRouter
<BrowserRouter><App /></BrowserRouter >
Now Wrap your component with withRouter where you have submit handler function.
export default withRouter(yourcomponentname);
submitForm = (e) =>{
this.props.history.push('/url');
}
Try this in your submitForm function after doing all stuff. hope it will help you.
document.location = "/thankyou.html" if the file is in root directory, and document.location = "thankyou.html" if the file is in relative directory.
submitForm = (e) =>{
this.props.history.push('/thankyou');
}
I want to check the validation of Re-password in React, I wrote this code for that but when you set(for Example) passsword:"1234" and Re-password:"1234" it doesn't apply as true but when you enter the fifth character for Re-password it becomes True .
Do you know what is issue?
import React , { Component } from 'react';
export default class RegistrationForm extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
email:'',
password :'',
password_re:'',
password_has_error:false
};
}
checkPassword() {
if(!this.state.password || this.state.password != this.state.password_re) {
this.setState({password_has_error:true});
}
else {
this.setState({password_has_error:false});
}
}
handleChange(event) {
this.setState({[event.target.name] : event.target.value });
if (event.target.name == 'password' || event.target.name == 'password_re')
this.checkPassword();
}
handleSubmit(event) {
event.preventDefault();
// TODO: will submit the form here
}
render(){
return (
<form onSubmit={(event)=>this.handleSubmit(event)}>
<div>
<label>Name</label>
<input
type="text"
name="name"
value={this.state.name}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<div>
<label>Email address</label>
<input
name="email"
type="email"
value={this.state.email}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<div>
<label>Password</label>
<input
type="password"
name="password"
value={this.state.password}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<div>
<label>Re-enter password</label>
<input
type="password"
name="password_re"
value={this.state.password_re}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<button type="submit">Submit</button>
</form>
)
}
}
Edit:This is my React component
This is because, setState is async, it will not update the state value immediately.
Write it like this, by using setState callback method:
handleChange(event) {
const { name, value } = e.target
this.setState({
[name] : value
}, () => {
if (name == 'password' || name == 'password_re')
this.checkPassword();
}
}
);
}
Check this for more details about setState async behaviour.
Without the bind.(this) on the this.updateEmail.bind(this) the input field value changes but I receive in error saying cannot set this.setState of undefind. So I add .bind(this) but it doesn't work at all.. a bit confused
import React, { Component } from 'react';
import Request from 'superagent';
class App extends Component {
constructor(){
super()
this.state = {
email: 'asdf',
password: ''
}
}
updateEmail(e){
this.setState={
email: e.target.value
}
}
createUser(e){
var query = 'star';
e.preventDefault()
console.log(this.state.email)
var url = `http://www.omdbapi.com?s=${query}&y=&r=json&plot=short`;
Request.get(url).then((response) => {
console.log(response)
this.setState({
movies: response.body.Search,
total: response.body.totalResults
});
});
}
render() {
return (
<div className="App">
<div className="App-header">
<form onSubmit={this.createUser.bind(this)}>
<input type="text"
name="email"
onChange={this.updateEmail.bind(this)}
value={this.state.email}
placeholder="email"/>
<br/>
<input type="text"
name="password"
value={this.state.password}
onChange={this.updatePassword}
placeholder="password"/>
<br/>
<input type="submit" value="submit"/>
</form>
</div>
</div>
);
}
}
export default App;
setState is a function, you should call it as such:
this.setState({ foo: 'bar' });