My website has two parts one is for registered users and another is for admin.
So after login users are go to dashboard and then suppose they go to a page from dashboard and then they reload the page, after reloading it's still working fine and stay on the current page. here i using user.displayName from useFirebase hook as codition.
But in admin mode after reload the page admin are redirecting to the home,its not staying in the current page.Here i using codition 'admin' from useFirebase hook,admin is true but its not staying in the currrent route after reload.i think may be the loader is not working perfectly there for fetching the data,but i dont undestand how to fix it out.
front end AdminRoute.
const AdminRoute = props => {
const { user, newLoading, admin } = useAuth();
const { children, ...rest } = props;
console.log(newLoading, admin);
const [isLoading, setIsLoading] = useState(false);
// const [isData, setIsData] = useState(false);
useEffect(() => {
if (user) {
setIsLoading(true);
fetch(`http://localhost:3005/users/${user.email}`)
.then(res => res.json())
.then(data => {
localStorage.setItem('userDetails', JSON.stringify(data));
})
.finally(() => setIsLoading(false));
}
}, [user]);
if (isLoading) {
return (
<div className="test10">
<Spinner animation="border" />;
</div>
);
}
return (
<Route
{...rest}
render={({ location }) =>
**admin** ? (
children
) : (
<Redirect
to={{
pathname: '/',
state: { from: location },
}}
></Redirect>
)
}
></Route>
);
};
export default AdminRoute;
here admin is true but still its not staying at the current page after realod but if i use user.displayName which for just users only its works,and staying at the current page after reload.
Server side part,
app.get('/users/:email', async (req, res) => {
const email = req.params.email;
const query = { email: email };
const user = await usersCollection.findOne(query);
let isAdmin = false;
if (user?.role === 'admin') {
isAdmin = true;
}
res.json({ admin: isAdmin, user });
});
Related
I can't seem to figure out how to maintain the login state.
I login, the app shows the condition if logged in, but then if I refresh the page, it asks me to login again.
I am using onAuthStateChanged, I just dont know what else to do.
This shows up when user not logged in
after I click login, this shows up
but when i click refresh, it shows you must login again.
here is my firebase config (the relevant bits)
function useAuth() {
const [currentUser, setCurrentUser] = useState();
useEffect(() => {
const unsubsubscribe = onAuthStateChanged(auth, (user) =>
setCurrentUser(user)
);
return unsubsubscribe;
}, []);
return currentUser;
}
export { app, storage, auth, database, useAuth };
I decide to create a function useAuth() inside firebase.config so i dont have to recreate it everywhere i need it.
Here is the login code
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const currentUser = useAuth();
const [loading, setLoading] = useState(false);
function login(email, password) {
return auth
.setPersistence(browserLocalPersistence)
.then(() => {
signInWithEmailAndPassword(auth, email, password).catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
}
}
And here is the page I want to show if the user is logged in. It shows to correct component if logged in , but when i refresh the page it doesnt remember the logged in user.
here is the code for the page
const Properties = () => {
const currentUser = useAuth();
onAuthStateChanged(auth,(user))
return (
<>
<Head>
<title>Add Property</title>
<meta name="keywords" content="web dev" />
</Head>
<h1>Add Property</h1>
<p>Welcome to the add Property new</p>
{console.log("user logged in? " + currentUser?.email)}
{currentUser ? (
<AddProperty />
) : (
<div>
<p style={{ color: "red" }}>You must be loggedin to add a property</p>{" "}
<Login />
</div>
)}
</>
);
};
export default Properties;
I want to display the Stripe subscription form after user has signed up into the extension. I want to display home to a subscribed user. And whenever the user opens the extension the home should be displayed if he has already subscribed. If not, it should display subscription form.
But the problem is my app is displaying both the home and subscription form to a subscribed user.
Here is my private route code:
const PrivateRoute = ({ component: RouteComponent, ...rest }) => {
const { currentUser, subscriptionStatus } = useContext(AuthContext);
return (
<Route
{...rest}
render={(routeProps) =>
!!currentUser ? (
!!subscriptionStatus ? (
<RouteComponent {...routeProps} />
)
: (
<Redirect to={"/subscribe"} />
)
) : (
<Redirect to={"/login"} />
)
}
/>
);
};
This is my auth context provider:
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const [pending, setPending] = useState(true);
const [emailVerified, setEmailVerified] = useState(true);
const [helper, setHelper] = useState(false);
const [subscriptionStatus, setSubscriptionStatus] = useState(null);
useEffect(() => {
app.auth().onAuthStateChanged(async(user) => {
setCurrentUser(user);
if(!user.emailVerified){
setEmailVerified(false);
}else{
setEmailVerified(true);
const fetchData = async () => {
const token = user && (await user.getIdToken());
const payloadHeader = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
};
const status = await fetch('http://localhost:3000/is-subscribed', payloadHeader).then(r => r.json());
if(status == 'active'){
setSubscriptionStatus(status);
setPending(false);
}else{
setPending(false);
}
}
fetchData();
}
});
}, []);
if (pending && helper) {
return <Loader />;
}
if(!emailVerified){
return <>Please verify your email</>
}
return (
<AuthContext.Provider
value={{
currentUser, subscriptionStatus
}}
>
{children}
</AuthContext.Provider>
);
};
Any idea on this?
The easiest option would be redirecting your customers to Checkout to pay, and handling the successful payments in your Firebase app via webhooks, but you can also use the custom flow if you prefer.
I have a custom route that renders a page or redirects the user to the login page based on if the user logged in or not.
const AuthenticatedRoute = ({ children, ...rest }) => {
const auth = useContext(AuthContext);
const [isAuthenticated, setIsAuthenticated] = useState(null);
useEffect(() => {
const getAuth = async () => {
const res = await auth.isAuthenticated();
setIsAuthenticated(() => res);
};
getAuth()
}, [auth]);
return (
<Route
{...rest}
render={() => {
return isAuthenticated ? (
<>{children}</>
) : (
<Redirect to="/login" />
);
}}
></Route>
);
};
As you see inside useEffect I run an async method. The problem is that whenever the component wants to mount, the default value of isAuthenticated will be used and redirects the user to the login page. I'm a little confused about how to handle this situation. I don't want the component to be rendered when the async method is not completely run.
i believe it will process all your code before sending html to client's browser.
I am trying to create a project in that login functionality is good and working properly but when I logged in and refreshed the screen the logout button disappears and the login link will come and then again logout button will come.to understand perfectly watch the video https://drive.google.com/file/d/1UvTPXPvHf4EhcrifxDEfPuPN0ojUV_mN/view?usp=sharing, this is because of
const AuthContext = React.createContext()
//useauth will return the AuthContext
export const useAuth = () => {
return useContext(AuthContext)
}
export const Authprovider = ({ children }) => {
var name
auth.onAuthStateChanged((user) => {
name = user
})
const [currentuser, setcurrentuser] = useState(name)
const [load, setload] = useState(true)
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setcurrentuser(user)
setload(false)
})
return unsubscribe
}, [])
const value = {
currentuser,
signup,
login,
load,
}
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}
I wrapped the AuthProvider component around the app component so that I can use the values like current user .
in Header component where login link, logout button is there
const { currentuser, load } = useAuth()
const logout = () => {
try {
auth.signOut().then(() => {
console.log('logged out')
})
} catch {
alert('logout is not possible')
}
}
//some code
{currentuser ? (
<button onClick={logout}>Logout</button>
) : (
<Link to='/login'>Login</Link>
)}
if there is a current user then the logout button will appear otherwise login link will appear but when refreshing there is some problem I tried many ways now I am out of ideas. "Even I refresh the page when logged in the logout button should not disappear" can you tell me how to do this?
to understan watch the video in the link
That's because you're not using load state try this:
//some code
{ load ? <div>loading</div>
: currentuser ? (
<button onClick={logout}>Logout</button>
) : (
<Link to='/login'>Login</Link>
)}
I have a function that fires when a user signs into the app.
signin: (email, password, setErrors, setUser, setUserIdToken) => {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(res => {
const user = res.user
const isVerified = user.emailVerified
firebase
.auth()
.currentUser.getIdTokenResult()
.then(idTokenResult => {
setUserIdToken(idTokenResult)
})
.catch(error => console.log(error))
setUser(user)
const db = firebase.firestore()
if (isVerified) {
db.collection('/users')
.doc(user.uid)
.update({ isVerified: true })
}
})
.catch(err => {
setErrors(prev => [...prev, err.message])
})
},
I have another component that uses the user and userIdToken from the signIn method.
const Home = () => {
const { handleSignout, user, userIdToken } = useContext(firebaseAuth)
const { emailVerified, email } = user
const { claims } = userIdToken
return (
<div>
Home page component
<SurveyResults />
{emailVerified && email.endsWith('xxx') && !claims.admin ? (
<button type="button">hi</button>
) : null}
<button type="submit" onClick={handleSignout}>
sign out
</button>
</div>
)
}
export default Home
I don't have access to the properties of userIdToken immediatly when Home renders, as I am still waiting for the promise to resolve..But I also need to check the props of userIdToken to render a button. I'm not sure how to do that?