Reputation: 55
I've built a todo app. I'm using nextjs as a framework, tailwind for css, and firebase to authenticate users to login via Google. I've got a component that adds todo items (called ToDoEntry.jsx), a component that shows the resulting todos which can be edited or deleted (called ToDoCard.jsx), and a Navbar component with a login and logout functionality called Navbar.jsx. All of these components show up on the same page called page.jsx, where ToDoCard.jsx and ToDoEntry.jsx only show up if I am logged via the Google login in from the navbar. I've also got a firebase configuration file called fbconfig.js, and a login authentication file called AuthHelper.js to help manage the user's login state.
The functionality worked JUST FINE before but I wanted to hide the ToDoEntry.jsx and ToDoCard.jsx components behind the login feature. I wanted to make it such page.jsx checks if the user is logged in before rendering those components.
Below is the last version of what the app looked like on vercel before I broke it:
https://todo-app-jet-pi.vercel.app/
My current problem is that after adding the AuthHelper.js and importing it into the Navbar.jsx, the login button in the navbar is no longer working, and the user is stuck on the main page. Clicking the button does not do anything, and the signInWithPopup method I used to have directly on the Navbar (but now in Authhelper.js) no longer works. I've pasted below the page.jsx, Navbar.jsx, fbconfig.js (minus the actual config details) and AuthHelper.js. Can someone tell me why the login button is not working?
P.S.: the firebase configuration and the login popup was working 100% just fine until I tried to hide components behind a login screen.
page.jsx
import ToDoEntry from "@/components/ToDoEntry";
import ToDoCard from "@/components/ToDoCard";
import Navbar from "@/components/Navbar";
import { useState } from "react";
export default function Home() {
const [loggedIn, setLoggedIn] = useState(false);
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
return (
<div>
<Navbar setLoggedIn={setLoggedIn} setUser={setUser} />
{loading ? (
<div>Loading...</div>
) : loggedIn ? (
<>
<ToDoEntry user={user} />
<ToDoCard user={user} />
</>
) : (
<div className="flex flex-col items-center justify-top h-screen mt-10">
<h1 className="text-center text-4xl font-medium">
✏️ Welcome to{" "}
<span className="underline decoration-blue-500/30">
Walid's to-do list!
</span>{" "}
</h1>
<p className="mt-3 font-medium py-2 px-4">
Please login to continue.
</p>
</div>
)}
</div>
);
}
Navbar.jsx
import { FaGoogle, FaSignOutAlt } from "react-icons/fa";
import { auth } from "../app/fbconfig";
import { handleLogin } from "../app/AuthHelper";
export default function Navbar({ setLoggedIn, setUser }) {
const [user, setAuthUser] = useState(null);
useEffect(() => {
auth.onAuthStateChanged((user) => {
if (user) {
setAuthUser(user);
setLoggedIn(true);
setUser(user);
} else {
setAuthUser(null);
setLoggedIn(false);
setUser(null);
}
});
}, [setLoggedIn, setUser]);
const handleLogout = async () => {
try {
await auth.signOut();
setAuthUser(null);
setLoggedIn(false);
} catch (error) {
console.error(error);
}
};
const handleNavbarLogin = async () => {
const user = await handleLogin();
if (user) {
setAuthUser(user);
setLoggedIn(true);
setUser(user);
}
};
return (
<nav className="bg-blue-500">
<div className="flex p-4 justify-center">
{user ? (
<div className="flex">
<div className="flex items-center mr-3 text-white">
{user ? "Welcome, " + user.displayName : ""}
</div>
<button
className="flex bg-white text-blue-500 font-medium p-2 rounded-lg justify-items-center hover:bg-blue-800 hover:text-white transition-left duration-500 ease-in-out"
onClick={handleLogout}
>
<p className="mr-1">Logout</p>{" "}
<FaSignOutAlt className="my-auto" />
</button>
</div>
) : (
<button
className="flex bg-white text-blue-500 font-medium p-2 rounded-lg justify-items-center hover:bg-blue-800 hover:text-white transition-left duration-500 ease-in-out"
onClick={handleNavbarLogin}
>
<p className="mr-1">Login with</p> <FaGoogle className="my-auto" />
</button>
)}
</div>
</nav>
);
}
AuthHelper.js
const handleLogin = async () => {
try {
const result = await auth.signInWithPopup(provider);
return result.user;
} catch (error) {
console.error(error);
return null;
}
};
export { handleLogin };
fbconfig.js
import { getAuth, GoogleAuthProvider } from "firebase/auth";
const firebaseConfig = {
apiKey: "XXX",
authDomain: "XXX",
projectId: "XXX",
storageBucket: "XXX",
messagingSenderId: "XXX",
appId: "XXX",
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const provider = new GoogleAuthProvider();
export { auth, provider };
Here's the console error I get in runtime when I try to click login:
react_devtools_backend.js:4012 TypeError: _fbconfig__WEBPACK_IMPORTED_MODULE_0__.auth.signInWithPopup is not a function
at handleLogin (webpack-internal:///(:3000/app-client)/./app/AuthHelper.js:9:74)
at handleNavbarLogin (webpack-internal:///(:3000/app-client)/./components/Navbar.jsx:47:88)
Upvotes: 1
Views: 771
Reputation: 55
The Authhelper.js was not working the way it should because I wrote
const result = await auth.signInWithPopup(provider);
instead of
const result = await signInWithPopup(auth, provider);
import { signInWithPopup } from "firebase/auth";
const handleLogin = async () => {
try {
const result = await signInWithPopup(auth, provider);
return result.user;
} catch (error) {
console.error(error);
return null;
}
};
export { handleLogin };
Upvotes: 0