Firebase.auth().currentuser not working on nextjs - reactjs

I'm currently building a next.js app and I've run into an issue with Firebase (v8) Authentication where eventhough I can login, (and it works) I can't access the logged in user in my header since the the property of the user image is apparently undefinedeventhough on the console it appears!
import Image from "next/image";
import { MenuIcon, UserCircleIcon, SearchIcon, UsersIcon } from '#heroicons/react/solid';
import { useState } from "react"
import 'react-date-range/dist/styles.css'; // main style file
import 'react-date-range/dist/theme/default.css'; // theme css file
import { DateRange } from 'react-date-range';
import { useRouter } from "next/router";
import firebase from "../firebase/clientApp";
import { useAuthState } from 'react-firebase-hooks/auth'
function Header({ placeholder }) {
const [searchInput, setSearchInput] = useState("");
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());
const [noOfGuests, setNoOfGuests] = useState(1);
const router = useRouter();
return(
<header className='sticky top-0 z-50 grid grid-cols-3 bg-white shadow-md p-5 md:px-10'>
{/* left */}
<div className='relative flex items-center h-10 cursor-pointer my-auto'>
</div>
{/* middle - search */}
<div className='flex items-center mb:border-2 rounded-full py-2 md:shadow-sm'>
<input
value = {searchInput}
className='flex-grow pl-5 bg-transparent outline-none text-sm text-gray-600 placeholder-gray-400'
type="text"
/>
<SearchIcon
className='hidden md:inline-flex h-8 bg-blue-800 text-white rounded-full p-2 cursor-pointer md:mx-2'
/>
</div>
{/* right */}
<div className='flex items-center space-x-4 justify-end text-gray-500'>
<p className='hidden md:inline cursor-pointer'>Become a host</p>
<div className='flex items-center space-x-2 border-2 p-2 rounded-full cursor-pointer'>
<div className="flex items-center space-x-2" onClick={() => router.push("/login")}>
<MenuIcon className='h-6'/>
{/* Icon change - Here is where the code kabooms */}
{firebase.auth().currentUser !== null ?
(<Image className="h-6" src={firebase.auth().photoURL} width="100%" height="100%" objectFit="cover"/>):(<UserCircleIcon className='h-6'/>)}
</div>
</div>
</div>
</header>
);
}
export default Header

You would find photoURL property inside currentUser.
Change <Image className="h-6" src={firebase.auth().photoURL} width="100%" height="100%" objectFit="cover"/> to (<Image className="h-6" src={firebase.auth().currentUser.photoURL} width="100%" height="100%" objectFit="cover"/>

Related

Why am i getting "Invalid hook call" and "Cannot read properties of null (reading 'useState')"

I'm coding a searchbar that returns the book that the user searched for and it's informations. But i'm getting these errors
I already tried to fix these errors, i copied a perfect working code in order to fix this bug but i only go t the same errors again.
SearchBooks.jsx
import React, { useState } from "react"
import axios from 'axios'
function SearchBooks(){
const [book, setBook] = useState('');
const [result, setResult] = useState([]);
const [apiKey, setApiKey] = useState("myapikey")
function handleChange(event){
setBook(event.target.value)
}
function handleSubmit(event){
event.preventDefault();
axios.get(`https://www.googleapis.com/books/v1/volumes?q=${book}&key=${apiKey}&maxResults=40`)
.then(data => {
console.log(data.data.items);
setResult(data.data.items);
})
}
return(
<div className="w-full mt-10 bg-gray-100 flex justify-center items-center">
<div className="container mx-auto dark:bg-gray-900 rounded-lg p-14">
<form onSubmit={handleSubmit}>
<h1 className="text-center font-bold text-white text-4xl">Find your perfect books </h1> <br />
<div className="sm:flex items-center bg-white rounded-lg overflow-hidden px-2 py-1 justify-between">
<input className="text-base text-gray-400 flex-grow outline-none px-2 " type="text" placeholder="Search for books" onChange={handleChange} value={book}/>
<div className="ms:flex items-center px-2 rounded-lg space-x-4 mx-auto ">
<button className="dark:bg-gray-900 text-white text-base rounded-lg px-4 py-2 font-thin">Search</button>
</div>
</div>
</form>
</div>
</div>
)
}
export default SearchBooks
app.jsx
import Header from '/components/Header'
import SearchBooks from '/components/SearchBooks'
import AboutInfo from '/components/AboutInfo'
import Tips from '/components/Tips'
import Cards from '/components/Cards'
function App() {
return (
<>
<Header />
<SearchBooks />
<AboutInfo />
<Tips />
<Cards />
</>
);
}
export default App;

RangeError: Invalid time value after refreshing local page

I've been trying to figure out my invalid time value issue. I built an airbnb clone and I'm using daterangepicker to work with the calendar, save the range selected in state and use that information to display it as a placeholder in the search bar after the search. I followed the video online precisely but for some reason I get this error and the person online didn't. I searched related posts here but nothing really helped so hopefully someone can help me resolve the issue so that I can finally deploy it. It all works fine without any issues on my local server but once I refresh the results page it defaults to this error
RangeError: Invalid time value in pages/search.js
15 | //ES6 destructuring
16 | const { location, startDate, endDate, noOfGuests} = router.query;
> 17 | const formattedStartDate = format(new Date(startDate), "MM/dd/yy");
| ^
18 | const formattedEndDate = format(new Date(endDate), "MM/dd/yyyy");
19 | const range = `${formattedStartDate} - ${formattedEndDate}`;
Here is the search component:
```
import React from 'react'
import Header from '../components/Header'
import Footer from '../components/Footer'
import { useRouter } from 'next/dist/client/router'
import {format} from 'date-fns'
import InfoCard from '../components/InfoCard'
import searchResults from '../files/searchResults.JSON'
function Search() {
const router = useRouter();
//ES6 destructuring
const { location, startDate, endDate, noOfGuests} = router.query;
const formattedStartDate = format(new Date(startDate), "MM/dd/yy");
const formattedEndDate = format(new Date(endDate), "MM/dd/yyyy");
const range = `${formattedStartDate} - ${formattedEndDate}`;
return (
<div>
<Header
placeholder= {`${location} | ${formattedStartDate}| ${formattedEndDate} | ${noOfGuests} guests `}
/>
<main className='flex'>
<section className='flex-grow pt-14 px-6'>
<p className='text-xs '>500+ Stays - {range} - {noOfGuests} guests</p>
<h1 className='text-3xl font-semibold mb-6 mt-2'>Stays in {location}</h1>
<div className='hidden md:inline-flex mb-5 space-x-3 text-gray-800 whitespace-nowrap'>
<p className='button'>Cancellation Flexibilty</p>
<p className='button'>Type of Place</p>
<p className='button'>Price</p>
<p className='button'>Rooms and Beds</p>
<p className='button'>More Filters</p>
</div>
<div className='flex flex-col'>
{searchResults.map(({ key, img, description, location, star, price, total, title, long, lat }) => (
<InfoCard
key={key}
img= {img}
location = {location}
title={title}
description={description}
star={star}
price={price}
total={total}
long={long}
lat={lat}
/>
))}
</div>
</section>
</main>
<Footer />
</div>
)
}
export default Search;
```
And here is the Header component containing the daterangepicker
```
import React from 'react';
import Image from 'next/image';
import {SearchIcon, GlobeAltIcon, MenuIcon, UserCircleIcon, UserIcon} from "#heroicons/react/solid"
import {useState} from "react"
import 'react-date-range/dist/styles.css'; // main style file
import 'react-date-range/dist/theme/default.css'; // theme css file
import { DateRangePicker } from 'react-date-range';
import { useRouter } from 'next/dist/client/router';
function Header({placeholder}) {
const [searchInput, setSearchInput] = useState("");
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());
const [noOfGuests, setNoOfGuests] = useState(1);
const router = useRouter();
const selectionRange = {
startDate: startDate,
endDate: endDate,
key: "selection"
};
const handleSelect = (ranges) => {
setStartDate(ranges.selection.startDate);
setEndDate(ranges.selection.endDate);
};
const resetInput = () => {
setSearchInput("");
};
const search = () => {
router.push({
pathname: '/search',
query: {
location: searchInput,
startDate: startDate.toISOString(),
endDate: endDate.toISOString(),
noOfGuests,
}
});
}
return (
<header className='sticky top-0 z-50 grid grid-cols-3 bg-white my-0 shadow-md p-5 w-full md:px-10'>
<div onClick={() => router.push("/")} className="relative flex items-center h-10 cursor-pointer my-auto">
<Image src="https://links.papareact.com/qd3"
layout="fill"
objectFit="contain"
objectPosition="left"
alt=''
/>
</div>
<div className='flex item-center md:border-2 rounded-full py-2 md:shadow-sm'>
<input value={searchInput} onChange={(e) => setSearchInput(e.target.value)}
type="text" placeholder={placeholder} className='pl-5 bg-transparent outline-none flex-grow text-sm text-gray-600 placeholder-gray-400' />
<SearchIcon onClick={search} className='hidden md:inline-flex h-8 bg-red-400 text-white rounded-full p-2 cursor-pointer md:mx-2' />
</div>
<div className='flex items-center space-x-4 justify-end text-gray-400'>
<p className='hidden md:inline cursor-pointer'>Become a Host</p>
<GlobeAltIcon className='h-6 cursor-pointer' />
<div className='flex items-center space-x-2 border-2 p-2 rounded-full'>
<MenuIcon className='h-6 cursor-pointer'/>
<UserCircleIcon className='h-6 cursor-pointer' />
</div>
</div>
{searchInput && (
<div className='flex flex-col col-span-3 mx-auto'>
<DateRangePicker
ranges={[selectionRange]}
minDate={new Date()}
rangeColors={["#FD5B61"]}
onChange={handleSelect}
/>
<div className='flex items-center border-b mb-4'>
<h2 className='text-2xl flex-grow font-semibold'>Number of Guests</h2>
<UserIcon className='h-5' />
<input onChange={e => setNoOfGuests(e.target.value)} value={noOfGuests} type="number" min="1" className='w-12 pl-2 text-lg outline-none text-red-400' />
</div>
<div className='flex'>
<button className='flex-grow text-gray-500' onClick={search}>Search</button>
<button className='flex-grow text-red-400' onClick={resetInput}>Cancel</button>
</div>
</div>
)}
</header>
)
}
export default Header
```

React tailwind css -right position show scroll bar

I have sticky box with show hide button as shown in image. It is working but if I tried to hide there is horizontal scroll bar and can see the box as shown in image 2. To colapse the box, I change right-0 to -right-24. Is there anyway not to show the horizontal scroll bar.
Image 1 -: showing sticky bar and can click setting icon to hide the bar. There is no horizontal scroll bar.
Image 2 -: after hide the bar, horizontal scroll bar is appeared and can see the box when I scroll.
const TrackPage = () => {
const handleMenuCollapse = (e) => {
e.preventDefault();
setColapse(!colapse);
};
return (
<>
<div>
<div
className={`flex w-24 h-96 absolute top-[calc((100vh-384px)/2)] ${
colapse ? "-right-24" : "right-0"
} " bg-primary rounded-b-lg items-center justify-center`}
>
<div
className="flex w-12 h-12 absolute -top-0 -left-12 cursor-pointer bg-primary rounded-l-lg items-center justify-center"
onClick={handleMenuCollapse}
>
<SettingIcon />
</div>
Setting
</div>
</div>
</>
);
};
export default TrackPage;
App.jsx
import React, { useState, useEffect } from "react";
import Header from "./components/header";
import SideMenu from "./components/side_menu";
import AppRoutes from "./routes";
import withUser from "./hocs/with_user";
import { isMobile } from "react-device-detect";
import { useLocation } from "react-router-dom";
import { AuthProvider, setAccessToken } from
"./auth/auth_provider";
import { Toaster } from "react-hot-toast";
import AppContext from "./components/app_context";
import "./i18n";
import "./App.css";
function App(props) {
const [colapse, setColapse] = useState(isMobile);
const [sideBarFull] = useState(true);
const location = useLocation();
const IsNormalPage = () => {
const blankPages = ["/login"];
for (let i = 0; i < blankPages.length; i++) {
if (location.pathname.startsWith(blankPages[i])) return
false;
}
return true;
};
useEffect(() => {
if (props.user) setAccessToken(props.user.t);
}, []);
const PageHeader = () => {
return (
<div className="h-[72px] w-full flex items-center align-middle justify-center bg-neutral shadow">
<div className="w-full text-center">
<Header />
</div>
</div>
);
};
return (
<AuthProvider user={props.user}>
<AppContext.Provider
value={{
colapse: colapse,
setColapse: setColapse,
}}
>
<div className="relative w-full min-h-screen h-full">
<div className="flex flex-row min-h-screen">
<div className="w-auto z-0 ">
<div className="flex-1 w-full max-h-screen mx-auto text-lg h-full shadow-lg bg-white overflow-y-auto">
{IsNormalPage() && <SideMenu showFullMenu={sideBarFull} />}
</div>
</div>
<div className="w-full max-h-screen flex flex-col z-10">
{IsNormalPage() && <PageHeader />}
<div className="flex-1 w-full max-h-screen mx-auto text-lg h-full shadow-lg bg-white overflow-y-auto">
<Toaster />
<AppRoutes />
</div>
</div>
</div>
</div>
</AppContext.Provider>
</AuthProvider>
);
}
export default withUser(App);
I figured out a solution for this
First let's divide this section into two sections (the settings icon and the bigger div that you want to hide)
Then add this to the big div className: ${colapse ? "hidden" : "right-0"} so it will just be hidden instead of -right-24
and for the icon div add this to its className:${colapse ? "animate-pulse right-0": "right-24"} the animation is of course optional I just added it.
This is the code but I forgot and named the component Side.jsx instead of TrackPage.jsx
import React, { useState } from "react";
function Side() {
const [colapse, setColapse] = useState(true);
const handleMenuCollapse = (e) => {
e.preventDefault();
setColapse(!colapse);
};
return (
<div>
{/** the big div */}
<div
className={`flex w-24 h-96 bg-indigo-500 absolute top-[calc((100vh-384px)/2)] ${
colapse ? "hidden" : "right-0"
} " bg-primary rounded-b-lg items-center justify-center`}
>
Setting
</div>
{/** the icon div */}
<div
className={`flex w-12 absolute top-[calc((100vh-384px)/2)] h-12 bg-indigo-500
${colapse ? "animate-pulse right-0" : "right-24"}
cursor-pointer bg-primary rounded-l-lg items-center justify-center`}
onClick={handleMenuCollapse}
>
<div className="w-5 h-5 bg-white rounded-full " />
</div>
</div>
);
}
export default Side;
take a look Live on codesandbox.

TailwindCSS fade in Element on click

So I'm making this app and I need to fade in the menu when I click the button. I have it rendering on click using state, but I can't get it to fade in / fade out on click. When I edit the opacity value inside Chrome Dev Console the transition works fine, but when I want to change it using state it doesn't.
Any help? Thanks in advance!
import React, { useState } from "react";
import { useRouter } from "next/router";
import { MenuIcon, XIcon } from "#heroicons/react/outline";
function Header() {
const router = useRouter();
const [popCard, setPopCard] = useState("hidden");
const [fade, setFade] = useState(true);
const handleMenuClick = () => {
setPopCard("inline-block");
setFade(true);
};
const handleXClick = () => {
setPopCard("hidden");
setFade(false);
};
return (
<div className="text-center">
<header className="sticky z-50 top-0 shadow-md bg-white border-b p-5">
<div className="flex justify-between items-center">
<h1
className="text-6xl text-red-500 cursor-pointer"
onClick={() => router.push("/")}
>
Velvet
</h1>
<MenuIcon
className="h-8 text-red-500 cursor-pointer"
onClick={handleMenuClick}
/>
</div>
</header>
<div
className={
popCard +
" w-[60%] flex-col border my-10 pb-3 rounded-3xl shadow-lg transition duration-300 ease-in-out " +
`${fade === true ? "opacity-100" : "opacity-0"}`
}
>
<div className="flex justify-end">
<XIcon
className="h-6 text-red-500 cursor-pointer mt-2 mr-2 opacity-70"
onClick={handleXClick}
/>
</div>
<div className="space-y-8 text-3xl text-center mt-5 mb-10 text-red-500">
<h1>Contac</h1>
<h1>About Us</h1>
</div>
</div>
</div>
);
}
export default Header;
codesandbox: Sandbox
Just to be clear, I want the menu card to fade in when I click the menu button, and I want the menu card to fade out when I click the close button.
The solution is, you need to add duration, like this:
`transition-all duration-200 ${fade ? "opacity-100" : "opacity-0"}`
Here is my forked sandbox you had given, I've removed extra inline CSS, so it may become evident.
Here is the complete code:
function Header() {
const [popCard, setPopCard] = useState("hidden");
const [fade, setFade] = useState(false);
const handleMenuClick = () => {
setPopCard("inline-block");
setFade(true);
};
const handleXClick = () => {
setPopCard("hidden");
setFade(false);
};
console.log(fade, "fade");
return (
<div className="text-center">
<header className="sticky z-50 top-0 shadow-md bg-white border-b p-5">
<div className="flex justify-between items-center">
<h1 className="text-6xl text-red-500 cursor-pointer">Velvet</h1>
<button
className="text-3xl border rounded-lg px-5"
onClick={handleMenuClick}
>
Menu
</button>
</div>
</header>
<div className="p-10">
<div
className={`transition-all duration-200 ${
fade ? "opacity-100" : "opacity-0"
}`}
>
<div className="flex justify-end">
<button className="mt-2 mr-2 border p-2" onClick={handleXClick}>
Close
</button>
</div>
<div className="space-y-2 text-3xl text-center mt-5 mb-10 mx-5 text-red-500">
<h1>Kontakt</h1>
<h1>O Velvetu</h1>
</div>
</div>
</div>
</div>
);
}
export default Header;
Sandbox: https://codesandbox.io/s/sweet-swartz-mr3nru?file=/pages/index.js:41-1396

TypeError: Cannot read property '_context' of undefined

I am creating a simple Todo List using React, Next.js, and TailwindCSS. For some reasons, I got this error: TypeError: Cannot read property '_context' of undefined.
This error occurs in TodoForm.js. I have defined showModal in index.js using TodoContext.Provider, but why does this error occur?
TodoContext.js
import { createContext } from "react";
const TodoContext = createContext(null);
export default TodoContext;
index.js
import { useState } from "react";
import Modal from "../components/Modal";
import TodoForm from "../components/TodoForm";
import TodoList from "../components/TodoList";
import TodoContext from "./TodoContext";
export default function Home() {
const [open, setOpen] = useState(true);
const [alertType, setAlertType] = useState("success");
const [alertMessage, setAlertMessage] = useState("");
const showModal = (type, msg) => {
setAlertType(type);
setAlertMessage(msg);
setOpen(true);
};
return (
<TodoContext.Provider value={{ showModal }}>
<div className="flex flex-col min-h-screen py-2 w-full items-center">
<TodoForm />
<Modal setOpen={setOpen} alertMessage={alertMessage} open={open} />
<TodoList />
</div>
</TodoContext.Provider>
);
}
TodoForm.js
import { addDoc, collection, serverTimestamp } from "#firebase/firestore";
import { useContext, useState } from "react";
import { db } from "../firebase";
const TodoForm = () => {
const [todo, setTodo] = useState({ title: "", detail: "" });
const { showModal } = useContext();
const onSubmit = async () => {
const collectionRef = collection(db, "todos");
const docRef = await addDoc(collectionRef, {
...todo,
timestamp: serverTimestamp(),
});
setTodo({ title: "", detail: "" });
showModal(
"bg-blue-200",
`Todo with id ${docRef.id} is added successfully! `
);
};
return (
<div className="flex w-3/6 flex-col justify-center mt-6">
<pre>{JSON.stringify(todo)}</pre>
<input
id="title"
type="text"
placeholder="Title"
value={todo.title}
onChange={(e) => setTodo({ ...todo, title: e.target.value })}
/>
<input
id="detail"
type="text"
placeholder="Detail"
value={todo.detail}
onChange={(e) => setTodo({ ...todo, detail: e.target.value })}
/>
<button
type="button"
onClick={onSubmit}
>
ADD A NEW TODO
</button>
</div>
);
};
export default TodoForm;
Modal.js
import { Fragment, useRef, useState } from "react";
import { Dialog, Transition } from "#headlessui/react";
import { ExclamationIcon } from "#heroicons/react/outline";
export default function Modal({ setOpenClick, alertMessage, open }) {
const cancelButtonRef = useRef(null);
return (
<Transition.Root show={open} as={Fragment}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
initialFocus={cancelButtonRef}
onClose={setOpenClick}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
​
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<ExclamationIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<div className="mt-2">
<p className="text-sm text-gray-500">{alertMessage}</p>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
onClick={() => setOpenClick(false)}
>
Deactivate
</button>
<button
type="button"
className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
onClick={() => setOpenClick(false)}
ref={cancelButtonRef}
>
Cancel
</button>
</div>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
);
}
Would you let me know what I am missing here?
This is the image of showing error when using const showModal = useContext(TodoContext) on TodoForm.js
You are trying to destruct the context from the object
const { showModal } = useContext();
But the initial value is null
const TodoContext = createContext(null);
One solution is to give an initial value:
const TodoContext = createContext({showModal:()=>{}});
At Times This Issue Is As A Result Of Importing Something That Does Not Exist. Ensure That The Exported And Imported Names Are Correct.

Resources