How to log into a user account page upon storing login data in session storage? - javascript

I am building a simple login system in React and I am attempting to allow a user to input an email and password to log in, only after this log in data is saved to session storage. The email and password are successfully stored in session storage, but the page does not refresh & subsequent return {} function in my-account.js does not render.
My understanding of how this code works:
the 'useToken()' hook contains a state object with the function 'getToken()' and the state variable 'token', with a state determined by 'useState(getToken())' - which will set the state of 'token' to the session storage variable named 'token'.
useToken() is imported into my-account.js and 'token' and 'setToken()' are both destructured from the parent function, retrieving the correct data in the my-account component.
The 'useToken()' function does not set 'token' and it returns a null, when it should be returning the token that is successfully stored in session storage. I would appreciate any help with this one.
//my-account.js
import React from 'react';
import Login from "../components/login"
import useToken from "../hooks/useToken"
const MyAccount = () =>{
const { token, setToken } = useToken();
if(!token) {
return <Login setToken={setToken} />
}
return (
<div>
<div>
<h1>{token.email ? `Logged in as ${token.email}` : 'Not logged in'}</h1>
</div>
</div>
);
}
export default MyAccount;
//useToken.js
import { useState } from 'react';
export default function useToken() {
const getToken = () => {
const tokenString = localStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken;
};
const [token, setToken] = useState(getToken());
const saveToken = (userToken) => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken);
};
return {
setToken: saveToken,
token,
}
}
//login.js
const Login = ({setToken}) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isLoggingIn, setIsLoggingIn] = useState(false);
const [error, setError] = useState(null);
Login.propTypes = {
setToken: PropTypes.func.isRequired
}
const handleSubmit = async (event) => {
event.preventDefault();
setIsLoggingIn(true);
try {
const { data } = await axios.get("http://localhost:3001/users", { email, password });
console.log(data);
const user = data.find(
(user) => user.email === email && user.password === password
);
if (user) {
console.log("user is found");
// set token to store pass as a prop to store login data in local memory
var token = user;
console.log(token);
setToken(token);
setError(false);
setIsLoggingIn(false);
} else {
setError(new Error("Incorrect email or password"));
setIsLoggingIn(false);
}
} catch (error) {
setError(error);
setIsLoggingIn(false);
}
};
return (
<form onSubmit={handleSubmit} className="login-container">
{error && <div className="error">{error.message}</div>}
<label htmlFor="email">Email:</label>
<input
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
<br />
<label htmlFor="password">Password:</label>
<input
type="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
/>
<br />
<>
<button className="fancyButton defaultBtn" type="submit" disabled={isLoggingIn}>
{isLoggingIn ? 'Logging in...' : 'Log In'}
</button>
</>
<p>If you do not have an account, register <Link to="/register">here</Link></p>
</form>
);
}
export default Login;

The problem must be in <Login>
I made a local copy and it worked just fine. Here is my Login.js
function Login({ setToken }) {
setToken("test");
return <div></div>;
}
export default Login;

Related

Firebase email verification on sign up - best practice

Im working on a web application with React and firebase 9.9.4
My goal is to have a sign up form that asks for the user's email address as well as password.
When the user signs up he gets an email to verify his email address. He clicks on the confirmation link which leads him to a confirmation page. After clicking the link, the user is stored as a user in the firebase database with his password. After this process, he is now able to log in with his email and password.
I used the firebase methods sendSignInLinkToEmail, isSignInWithEmailLink and signInWithEmailLink as described here: https://firebase.google.com/docs/auth/web/email-link-auth?authuser=0&hl=de
But I don't know how to provide the password and how to check if everything worked well.
Here is my signup.js component
import React, {useState} from "react";
import { useAuth } from "../../contexts/AuthContext";
import { Link } from "react-router-dom";
export default function SignUp(){
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const { signuplink } = useAuth()
async function handleSubmit(e) {
e.preventDefault()
try {
setError("")
await signuplink(email, password)
} catch {
console.log("Failed to sign in")
setError("Failed to sign in")
}
}
const handleEmailChange = (e) => {
setEmail(e.target.value);
}
const handlePasswordChange = (e) => {
setPassword(e.target.value);
}
return (
<form onSubmit={(e) => { handleSubmit(e) }}>
{error}
<h3> Sign-up Form </h3>
<label>
Email:
</label><br />
<input type="email" value={email} required onChange={(e) => { handleEmailChange(e) }} /><br />
<label>
Password:
</label><br />
<input type="password" value={password} required onChange={(e) => { handlePasswordChange(e) }} /><br />
<input type="submit" value="Submit" />
<div>
Already have an account? <Link to="/login">Log In</Link>
</div>
</form>
)
}
Here is my signuplink method to send a verification link
function signuplink(email, password) {
const auth = getAuth();
const actionCodeSettings = {
url: 'http://localhost:3000/register-complete',
handleCodeInApp: true
};
sendSignInLinkToEmail(auth, email, actionCodeSettings)
.then(() => {
console.log("mail send")
window.localStorage.setItem('emailForSignIn', email);
window.localStorage.setItem('passwordForSignIn', password);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(errorCode)
console.log(errorMessage)
});
}
Here is my RegisterComplete.js component that shows up after the user clicked on the verification link:
import React from "react";
import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth";
export default function RegisterComplete(){
const auth = getAuth();
if (isSignInWithEmailLink(auth, window.location.href)) {
let email = window.localStorage.getItem('emailForSignIn');
let password = window.localStorage.getItem('passwordForSignIn');
if (!email) {
email = window.prompt('Please provide your email for confirmation');
}
signInWithEmailLink(auth, email, window.location.href)
.then((result) => {
window.localStorage.removeItem('emailForSignIn');
console.log("signInWithEmailLink")
})
.catch((error) => {
});
}
return (
<>foo</>
)
}
The only way I couldn't think of to save email and password information before the user's email is verified is to store both in localStorage. But if the user opens the link on another device then this information is not present. I think at some point I should call a createUserWithEmailAndPassword to store the password? But I don't know where?
This spund like a pretty common process, so is there any best practice how to do it?
Thanks!

Login and navigate to next page when credentials received

I am trying to navigate to the next page if the credentials and token are received. This is a react app and I am using react router to navigate to the other pages. Could you please help me understand what is needed to navigate to the next page? Can I use the hook useNavigate to only submit the login form if the credentials match the database? I included the code from the login.jsx page and the users-service.js file.
Login.jsx and users-service.js shown below
Login.jsx
import React from 'react'
import Form from 'react-bootstrap/Form'
import Button from "react-bootstrap/Button"
import { useState, useEffect } from 'react'
import {login} from '../utilities/users-service'
import { useNavigate } from 'react-router-dom'
const Login = () => {
const [message, setMessage] = useState("We'll never share your email with anyone else.")
const [credentials, setCredentials] = useState({
email:'',
password:'',
})
const handleChange = e => {
setCredentials({...credentials, [e.target.name]: e.target.value })
}
//submit
let navigate = useNavigate()
const handleSubmit = async e => {
e.preventDefault()
try{
console.log("didi----------", credentials)
login(credentials)
navigate('/workouts', {replace: true})
}catch(e){
setMessage('log in failed -Try again')
}
}
return (
<Form className='mx-auto w-50 border p-3' onSubmit={handleSubmit}>
<Form.Group className="mb-3" >
<Form.Label htmlFor="exampleInputEmail1" className="form-label">Email</Form.Label>
<input type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name='email'
onChange={handleChange}
value={credentials.email}/>
<Form.Text className="text">{message}
</Form.Text>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label htmlFor="exampleInputPassword1">Password</Form.Label>
<input type="password" className="form-control" id="exampleInputPassword1" placeholder="Password" name='password'
onChange={handleChange}
value={credentials.password} />
</Form.Group>
<Button className="mb-3" variant="primary" type="submit" >
Sign In
</Button>
</Form>
)
}
export default Login
users-service.js
import axios from "axios"
import { useNavigate } from "react-router-dom"
const BASE_URL = 'http://localhost:8080/api/v1/users'
export const login = async credentials => {
try {
console.log('We are in user-serviced', credentials)
const token = await axios.post(`${BASE_URL}/login`, credentials)
console.log(token.data)
//Persist then token using the Window local storage
//setItem() first argument is the property name and the second argument is the value
localStorage.setItem('token', token.data)
getToken()
} catch(e) {
console.log(e)
}
}
export const getToken = () =>{
//use property/key/field name to grab our token
const token =localStorage.getItem('token')
//getItem() return null if there is no key
if(!token) return null
//console.log('grabing', token)
//Parse our token, split using the "." to isolate our payload and use logic to handle our exp date
//After we decode our token using atob() which decodes encryted base64 string into a JS object
//JWT is encryted in base64
const payload = JSON.parse(atob(token.split('.')[1]))
console.log(payload)
//JWT's expiration is in seconds, not milliseconds
//
if(payload.exp < Date.now() / 1000){
localStorage.removeItem('token')
return null
}
return token
}
export const getUser = () => {
const token = getToken()
return token ? JSON.parse(atob(token.split('.')[1])).user : null
}
You can store your return value from login(credentials) in a variable then check whether token (or token.data in your case) exists to navigate:
const handleSubmit = async (e) => {
const token = await login(credentials)
if (token.data) {
navigate('/workouts')
}
}
Don't forget to return some value from your login(credentials):
export const login = async credentials => {
try {
const token = await axios.post(`${BASE_URL}/login`, credentials)
console.log(token.data)
localStorage.setItem('token', token.data)
return token
} catch(e) {
console.log(e)
}
}
For your last question, no, useNavigate has nothing to do with your database. Check out the documentation:
https://reactrouter.com/docs/en/v6/hooks/use-navigate

Authentication with context API, keep redirecting to login page

I try to do RequierAuth lock to protect against an unauthorized user. First created the context where auth should accept the token:
AuthProvider.js:
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState({});
return (
<AuthContext.Provider value={{ auth, setAuth }}>
{children}
</AuthContext.Provider>
)
}
export default AuthContext;
Next created a hook for the above context:
useAuth.js
const useAuth = () => {
return useContext(AuthContext);
}
export default useAuth;
Next, the actual "lock" for protection, where I check if there is a token and return either the page or send the user to the login page:
RequierAuth.js
const RequierAuth = () => {
const {auth} = useAuth();
const location = useLocation();
return (
auth.token?<Outlet/> : <Navigate to = "/auth" state = {{from:location}} replace />
);
}
export default RequierAuth;
App.js
function App() {
return (
<>
...
<div className="App">
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route path="auth" element={<Login />} />
<Route path="reg" element={<Register />} />
<Route element = {<RequierAuth/>}>
<Route path="home" element={<Home />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
</div>
</>
);
}
export default App;
index.js
root.render(
<React.StrictMode>
<AuthProvider>
<App />
</AuthProvider>
</React.StrictMode>
);
And actually the question is that now when I call setAuth on the login page:
LoginForm.js
const Login = () =>{
const {auth,setAuth} = useAuth();
const [authResponce,setAuthResponce] = useState(null);
const [login,setLogin] = useState("");
const onChangeLogin = (e) => {
e.preventDefault();
const username = e.target.value;
setLogin(username);
};
const [password,setPassword] = useState("");
const onChangePassword = (e) => {
const password = e.target.value;
setPassword(password);
};
const instance = axios.create({
baseURL: "http://localhost:8080",
headers: {
"Content-Type": "application/json",
},
});
const postUser = async (user) =>{
return instance.post("http://localhost:8080/auth", user);
}
const onLogin = (e) =>{
e.preventDefault();
const user = {
login: login,
password: password,
};
(async() => {
const response = await postUser(user);
const data = response.data;
console.log(data);
const token = data.token;
console.log(token);
setAuth({token});
console.log(auth);
console.log(auth.token);
})();
};
return (
<div className="Auth-form-container">
<form className="Auth-form" onSubmit={onLogin}>
<div className="Auth-form-content">
<h3 className="Auth-form-title">Sign In</h3>
<div className="form-group mt-3">
<label>Login</label>
<input
type="login"
className="form-control mt-1"
placeholder="Enter login"
value={login}
onChange={onChangeLogin}
/>
</div>
<div className="form-group mt-3">
<label>Password</label>
<input
type="password"
className="form-control mt-1"
placeholder="Enter password"
value={password}
onChange={onChangePassword}
/>
</div>
<div className="d-grid gap-2 mt-3">
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</div>
</form>
</div>
)
};
export default Login;
First, if you get a token for the first time, then why is the value not printed in the console, if you get it again on the form, it already prints the expected value, but when you switch to home, it sends it back to the login.
I set breakpoint and at the moment of checking auth.token? indicates that the value is not set, although setAuth has set the value.
The check itself seems to work, if you put the default value in auth and try to compare with it, then we will normally get to /home.
I've only recently started studying and I can't figure out what the error is, so I'll be glad for help to figure it out.
Issue
First, updating a state is an "asynchronous" task. A re-render is needed in order to have the updated value. Which is why you are not seeing change with those lines that you have inside onLogin:
setAuth({token});
console.log(auth);
Second, after the login process, you said in the comments that you are using the browser to redirect to /home. Well, you should know that doing so refreshes the page, so all your states come to their initial values, so auth would be {}. This is why it's redirecting to "/auth".
Solution
You should use React Router Dom's redirection mechanism, useNavigate for example. Change LoginForm.js slightly, like so (I added comments in the code):
import { useEffect } from "react"; // line to add
import { useNavigate } from "react-router-dom"; // line to add
const Login = () => {
const navigate = useNavigate(); // line to add
const { auth, setAuth } = useAuth();
const [authResponce, setAuthResponce] = useState(null);
const [login, setLogin] = useState("");
const onChangeLogin = (e) => {
e.preventDefault();
const username = e.target.value;
setLogin(username);
};
const [password, setPassword] = useState("");
const onChangePassword = (e) => {
const password = e.target.value;
setPassword(password);
};
const instance = axios.create({
baseURL: "http://localhost:8080",
headers: {
"Content-Type": "application/json",
},
});
const postUser = async (user) => {
return instance.post("http://localhost:8080/auth", user);
};
// useEffect to add
useEffect(() => {
if (auth) {
console.log(auth); // add your logs here to see the updates after re-render
navigate("/home");
}
}, [auth]);
const onLogin = (e) => {
e.preventDefault();
const user = {
login: login,
password: password,
};
(async () => {
const response = await postUser(user);
const data = response.data;
console.log(data);
const token = data.token;
console.log(token);
setAuth({ token });
})();
};
return (
<div className="Auth-form-container">
<form className="Auth-form" onSubmit={onLogin}>
<div className="Auth-form-content">
<h3 className="Auth-form-title">Sign In</h3>
<div className="form-group mt-3">
<label>Login</label>
<input
type="login"
className="form-control mt-1"
placeholder="Enter login"
value={login}
onChange={onChangeLogin}
/>
</div>
<div className="form-group mt-3">
<label>Password</label>
<input
type="password"
className="form-control mt-1"
placeholder="Enter password"
value={password}
onChange={onChangePassword}
/>
</div>
<div className="d-grid gap-2 mt-3">
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</div>
</form>
</div>
);
};
export default Login;
Improvement
The above solution works, but if you refresh the page manually, there is no way to remember that a user has been logged in. If you want that feature, you can use localStorage.
For that, change the useEffect I added inside LoginForm.js to the below code:
useEffect(() => {
if (auth) {
console.log(auth); // add your logs here to see the updates after re-render
localStorage.setItem("token", auth.token); // so you get it later
navigate("/home");
}
}, [auth]);
Change AuthProvider.js so you get the token form localStorage if there is one:
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState({ token: localStorage.getItem("token") });
return <AuthContext.Provider value={{ auth, setAuth }}>{children}</AuthContext.Provider>;
};
export default AuthContext;

How to add firebase authentication data to a firestore collection in React?

Currently, when a user signs up they are being created as a user in the firebase authentication. I am trying to add that newly created user directly into a firestore collection upon creation.
The following is the AuthContext.js
import React, { useContext, useState, useEffect } from "react";
import { auth } from "../firebase";
const AuthContext = React.createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [loading, setLoading] = useState(true);
function signup (email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password);
}
function logout() {
return auth.signOut();
}
function resetPassword(email) {
return auth.sendPasswordResetEmail(email);
}
function updateEmail(email) {
return currentUser.updateEmail(email);
}
function updatePassword(password) {
return currentUser.updatePassword(password);
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setCurrentUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const value = {
currentUser,
login,
signup,
logout,
resetPassword,
updateEmail,
updatePassword,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
The following is Signup.js
import React, { useRef, useState } from 'react'
import { Form, Button, Card, Alert } from "react-bootstrap"
import { Link, useHistory } from "react-router-dom"
import { useAuth } from './contexts/AuthContext'
export default function Signup() {
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
const { signup } = useAuth()
const [error, setError] = useState("")
const [loading, setLoading] = useState(false)
const history = useHistory()
async function handleSubmit(e){
e.preventDefault()
if (passwordRef.current.value !==
passwordConfirmRef.current.value) {
return setError('Passwords do not match')
}
try{
setError('')
setLoading(true)
await signup(emailRef.current.value,passwordRef.current.value)
history.push("/")
} catch {
setError('Failed to create an account')
}
setLoading(false)
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Sign Up</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef} required />
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef} required />
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control type="password" ref={passwordConfirmRef} required />
</Form.Group>
<Button disabled={loading} className="w-100" type="submit">
Sign Up
</Button>
</Form>
<div className="w-100 text-center mt-2">
Already have an account? <Link to="/login">Log In</Link>
</div>
</Card.Body>
</Card>
</>
)
}
Thank you in advance, any help will be greatly appreciated.
The creation of the user in Firebase Auth will happen no matter what you do, but you can take advantage of that by creating a Cloud Function that triggers everytime a user is created in Firebase auth and then create a new document in Firestore representing that user. Here is a Cloud Function example that does just that:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.createUser = functions.auth.user().onCreate((user) => {
const { uid } = user;
const userCollection = db.collection('users');
userCollection.doc(uid).set({
someData: "123"
});
});
Also in the documentation you can see how to deploy Cloud Functions, in case you are not familiar with it.

The code in the then method is not executed and error handling is performed

I'm developing a web app in React and firebase and I'm having trouble getting it to work.
Here is my code
import React, { useRef, useState } from "react"
import { Form, Button, Card, Alert } from "react-bootstrap"
import { useAuth } from "../contexts/AuthContext"
import { Link, useHistory, Redirect, Route } from "react-router-dom"
import { db } from "../firebase"
import Dashboard from "../components/Dashboard"
export default function UpdateProfile() {
const usernameRef = useRef()
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
const { updateUser, currentUser, updatePassword } = useAuth()
const [error, setError] = useState("")
const [loading, setLoading] = useState(false)
const history = useHistory()
function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match")
}
if (passwordRef.current.value) {
updatePassword(passwordRef.current.value)
}
const uid = currentUser.uid
db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
try {
setLoading(true)
setError("")
updateUser(usernameRef.current.value, emailRef.current.value, data)
history.push('/dashboard')
} catch {
setError("Failed to update account")
}
setLoading(false)
})
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Update Profile</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="username">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
ref={usernameRef}
required
defaultValue={currentUser.username}
/>
</Form.Group>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
ref={emailRef}
required
defaultValue={currentUser.email}
/>
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
ref={passwordRef}
placeholder="Leave blank to keep the same"
/>
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control
type="password"
ref={passwordConfirmRef}
placeholder="Leave blank to keep the same"
/>
</Form.Group>
<Button disabled={loading} className="w-100" type="submit">
Update
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
<Link to="/">Cancel</Link>
</div>
</>
)
}
This is the code for the user's edit function: enter a value in the form and press the button to run handleSubmit.
function updateUser(username, email, data) {
const uid = data.uid
db.collection('users').doc(uid).set({
email: email,
username: username,
}, {merge: true})
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(async(user) => {
if (user) {
const uid = user.uid
console.log(uid)
await db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
setCurrentUser(data)
setLoading(false)
})
}
})
return unsubscribe
}, [])
And the following code rewrites the firestore data After this updateUser function is executed, we want to do a history.push in then of handleSubmit to redirect to /dashboard, but we want to get the console to say "success! in the console and the "failure! in the console and the message "success!" appears on the app.
When I looked at the firestore data, I found that the values I entered were properly reflected in the firestore.
This tells me that the then part of handleSubmit is not working, but I don't know why it's not working.
If you have a solution, I'd love to hear it.
Thank you.
You need to
Either await or put a .catch onto the updateUser Promise chain (the try/catch around it will only catch async errors if the Promise is awaited)
Return the Promise from updateUser
Pass a function to the .then callback - your .then(console.log("success!!")) invokes console.log immediately and passes undefined to the .then
function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match")
}
if (passwordRef.current.value) {
updatePassword(passwordRef.current.value)
}
const uid = currentUser.uid
db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
setLoading(true)
setError("")
return updateUser(usernameRef.current.value, emailRef.current.value, data);
})
.then(() => {
// Success
history.push('/dashboard')
})
.catch((error) => {
setError("failed!!")
})
.finally(() => {
setLoading(false)
});
}
function updateUser(username, email, data) {
const uid = data.uid
return db.collection('users').doc(uid).set({
email: email,
username: username,
}, { merge: true })
.then(() => console.log("success!!"))
}

Categories

Resources