Asking this since my last question got closed while none of the examples helped at all. I have some invite codes set up in a firebase realtime database, and I am checking the Invite Code input by a user when they are using the SignUp page. Once they click subit, the 'doSubmit' function triggers, and the first part of that function uses a function in the firebase.js file to check if the invite code exists. If it does, the function is supposed to return 'ADMIN' and if not it returns 'GENERAL'. I now see that once() is an Async function, so I need to implement some sort of promise chaining for the checkInviteCodes function. I tried adding promise chaining when calling the checkInviteCode, but was giving me some errors saying that checkInviteCodes is not a function. I also tried adding some chaining inside the checkInviteCodes function but still did not get the desired result. The indes.js and Firebase.js files are below and any help is appreciated.
../SignUp/index.js
import React, {useState} from 'react';
import {Link as RouterLink, withRouter} from 'react-router-dom'
import {compose} from 'recompose';
import {withFirebase} from '../Firebase'
import * as ROUTES from '../../constants/routes'
import Avatar from '@material-ui/core/Avatar';
import Button from '@material-ui/core/Button';
import CssBaseline from '@material-ui/core/CssBaseline';
import TextField from '@material-ui/core/TextField';
import Link from '@material-ui/core/Link';
import Grid from '@material-ui/core/Grid';
import Box from '@material-ui/core/Box';
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
import Typography from '@material-ui/core/Typography';
import {makeStyles} from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import {SignInLink} from "../SignIn";
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
const SignUpPage = () => (
<div>
<SignUpForm/>
</div>
);
const SignUpFormBase = (props) => {
const classes = useStyles();
const [ username, setUsername ] = useState('');
const [ email, setEmail ] = useState('');
const [ passwordOne, setPasswordOne ] = useState('');
const [ passwordTwo, setPasswordTwo ] = useState('');
const [ inviteCode, setInviteCode] = useState('');
const [ error, setError ] = useState(null);
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === '' ||
email === '' ||
username === '';
const doSubmit = event => {
const role = props.firebase.checkInviteCode(inviteCode);
console.log('Logging invite code and role');
console.log(inviteCode);
console.log(role);
props.firebase
.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
return props.firebase
.user(authUser.user.uid)
.set({
username,
email,
role,
});
})
.then(authUser => {
setUsername(username);
setPasswordOne(passwordOne);
setPasswordTwo(passwordTwo);
setEmail(email);
setInviteCode(inviteCode);
props.history.push(ROUTES.HOME);
})
.catch(error => {
setError(error);
console.log(error);
});
event.preventDefault();
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline/>
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon/>
</Avatar>
<Typography component="h1" variant="h5">
Sign up
</Typography>
<form className={classes.form} noValidate onSubmit={doSubmit}>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
autoComplete="fname"
name="username"
variant="outlined"
required
fullWidth
id="username"
label="Username"
autoFocus
value={username}
onChange={event => setUsername(event.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
value={email}
onChange={event => setEmail(event.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
value={passwordOne}
onChange={event => setPasswordOne(event.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Confirm Password"
type="password"
id="password"
autoComplete="confirm-password"
value={passwordTwo}
onChange={event => setPasswordTwo(event.target.value)}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="inviteCode"
label="InviteCode"
id="inviteCode"
autoComplete="inviteCode"
value={inviteCode}
onChange={event => setInviteCode(event.target.value)}
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
className={classes.submit}
disabled={isInvalid}
>
Sign Up
</Button>
{error && <p>{error.message}</p>}
<Grid container justifyContent="flex-end">
<Grid item>
<SignInLink href="#" variant="body2"/>
</Grid>
</Grid>
</form>
</div>
<Box mt={5}>
<Copyright/>
</Box>
</Container>
)
}
const SignUpLink = () => (
<p>
<RouterLink to={ROUTES.SIGN_UP}>Don't have an account? Sign Up</RouterLink>
</p>
);
const SignUpForm = compose(
withFirebase,
withRouter,
)(SignUpFormBase);
export default SignUpPage;
export {SignUpForm, SignUpLink};
firebase.js
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import * as ROLES from '../../constants/roles';
const config = {
apiKey: process.env.REACT_APP_API_KEY,
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_DATABASE_URL,
projectId: process.env.REACT_APP_PROJECT_ID,
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
};
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
this.db = app.database();
}
// *** Auth API ***
doCreateUserWithEmailAndPassword = (email, password) =>
this.auth.createUserWithEmailAndPassword(email, password);
doSignInWithEmailAndPassword = (email, password) =>
this.auth.signInWithEmailAndPassword(email, password);
doSignOut = () => this.auth.signOut();
doPasswordReset = email => this.auth.sendPasswordResetEmail(email);
doPasswordUpdate = password =>
this.auth.currentUser.updatePassword(password);
// *** Merge Auth and DB User API ***
onAuthUserListener = (next, fallback) =>
this.auth.onAuthStateChanged(authUser => {
if (authUser) {
this.user(authUser.uid)
.once('value')
.then(snapshot => {
const dbUser = snapshot.val();
// default empty roles
if (!dbUser.role) {
dbUser.role = {};
}
// merge auth and db user
authUser = {
uid: authUser.uid,
email: authUser.email,
...dbUser,
};
next(authUser);
});
} else {
fallback();
}
});
// *** User API ***
user = uid => this.db.ref(`users/${uid}`);
users = () => this.db.ref('users');
checkInviteCode = code => {
const role = '';
this.db.ref(`invites`).orderByChild("value").equalTo(code).once('value').then(snapshot => {
console.log('Found the value');
if (snapshot.exists()) {
console.log('Setting role to ADMIN');
this.role = ROLES.ADMIN;
} else {
console.log('Setting role to GENERAL')
this.role = ROLES.GENERAL;
}
})
if (this.role !== ROLES.ADMIN)
this.role = ROLES.GENERAL;
console.log('Role in firebase.js : ' + this.role);
return this.role;
}
}
export default Firebase;
console log statements
Role in firebase.js : GENERAL - firebase.js:90
Logging invite code and role - index.js:80
testCode - index.js:81
GENERAL - index.js:82
Found the value - firebase.js:77
Setting role to ADMIN - firebase.js:79
Putting this answer here to see if there is another way to do it that follows best practices. If not it might help someone else as well. Based on the comment by @Jaromanda X, I did a lot of attempts at making checkInviteCode
return a promise. Once that was figured out I had to make the implementation of that function to use the returned promise as the user role. I was originally taking the returned promise and setting the role state to be the returned promise, but that was never setting the state before actually creating the user, so I went with using the returned promise directly to set the role as the user in the db was created. Below is the code for both the function and the implementation.
firebase.js
checkInviteCode = code => {
console.log('Checking invite code in firebase : ' + code);
return this.db.ref(`invites`).orderByChild("value").equalTo(code).once('value').then(function(snapshot) {
if (snapshot.exists()) {
return ROLES.ADMIN;
} else {
return ROLES.GENERAL;
}
}, function(error) {
return ROLES.GENERAL;
});
}
../SignUp/index.js
props.firebase
.checkInviteCode(inviteCode)
.then(role => {
props.firebase
.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
return props.firebase
.user(authUser.user.uid)
.set({
username,
email,
role,
});
})
.then(authUser => {
setUsername(username);
setPasswordOne(passwordOne);
setPasswordTwo(passwordTwo);
setEmail(email);
setInviteCode(inviteCode);
props.history.push(ROUTES.HOME);
})
.catch(error => {
setError(error);
});
})
.catch(error => {
// Implement something to do with error here
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.