How to pass information from components to components in React? - javascript

I have two components named <Add /> and <Modal>. In the <Add /> component I have a state for the click event on the component. When <Add /> is clicked, I set the state to true. I want to use that state information in the <Modal /> component.
I want to hide the modal based on the information from the <Add /> component's state. How can I achieve that?
This is the <Add /> component:
export default function Add() {
const [clicked, setClicked] = useState(false)
return(
<div onClick={() => setClicked(true)} className={`bg-blue-500 inline-block p-4 fixed bottom-10 right-8`}>
<FaPlus />
</div>
)
}
This is the <Modal /> component:
export default function Modal1() {
return (
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 translate-y-3/4">
<div className="w-[300px] border p-4 rounded-md shadow-lg">
<div className="inline-block my-4">
<label className="text-xs opacity-70">Class Name</label>
<input
className="border py-2 px-4 rounded-md w-full"
type="text"
placeholder="Class Name"
/>
</div>
<div className="flex flex-col mb-4">
<label className="text-xs mr-4 opacity-70">Image</label>
<input
className="rounded-md opacity-80"
type="file"
placeholder="Image"
/>
</div>
<div className="flex flex-row items-center justify-end">
<button className="bg-slate-400 rounded-md px-4 py-2 mx-4 text-white">
Cancel
</button>
<button className="bg-blue-500 px-4 py-2 rounded-md text-white">
Add
</button>
</div>
</div>
</div>
);
}
And this is the index.js file:
export default function Home() {
return (
<div className="relative">
<Add />
<Modal />
</div>
);
}
I imported the components correctly. And I'm using Next.js and tailwindcss.
Solution(Edited):
index.js file:
export default function Home(props) {
const [modalShown, setModalShown] = useState(false)
return (
<div className={`relative`}>
<AddButton modalShown={modalShown} setModalShown={setModalShown} />
<Modal1 modalShown={modalShown} setModalShown={setModalShown} />
</div>
);
}
<AddButton /> component:
export default function AddButton({modalShown, setModalShown}) {
return(
<div onClick={() => setModalShown(true)} className={`z-[99] bg-blue-500 inline-block p-4 rounded-full fixed bottom-10 right-8 cursor-pointer`}>
<FaPlus />
</div>
)
}
<Modal /> component:
export default function Modal({modalShown, setModalShown}) {
const [modalShown, setModalShown] = useState(true);
return (
<div className={`${modalShown? '' : 'hidden'} transition-all duration-300 ease-in absolute top-1/2 left-1/2 -translate-x-1/2 translate-y-3/4 select-none`}>
<div className="w-[300px] border p-4 rounded-md shadow-lg">
// Text inputs here
...
...
<div className="flex flex-row items-center justify-end">
<button onClick={() => setModalShown(false)} className="bg-slate-400 rounded-md px-4 py-2 mx-4 text-white">
Cancel
</button>
<button onClick={() => setModalShonw(false)} className="bg-blue-500 px-4 py-2 rounded-md text-white">
Add
</button>
</div>
</div>
</div>
);
}

You'll want to lift the state up into the parent component

so there are a whole lot of ways of passing data between components. Using props is the simpler one. Here is a YT video on how to do so using props. You can also user shared Preferences...
https://www.youtube.com/watch?v=M_Fmvs5CiDo&ab_channel=CemEygiMedia
Best of luck

You can use props for this. To pass data from one component to another, and Yes You can pass Function reference also!

Related

why does react button disabled not working while using tailwind css along

import React, { useState } from "react";
import facebook from "../UI/icons/facebook.png";
import Button from "../UI/Button/Button";
import Card from "../UI/Card/Card";
import twitter from "../UI/icons/twitter.png";
import instagram from "../UI/icons/instagram.png";
const Login = () => {
const [enteredEmail, setEnteredEmail] = useState("");
const [emailIsValid, setEmailIsValid] = useState("");
const [enteredPassword, setEnteredPassword] = useState("");
const [passwordIsValid, setPasswordIsValid] = useState("");
const [formIsValid, setFormIsValid] = useState("");
const emailChangeHandler = (event) => {
setEnteredEmail(event.target.value);
setFormIsValid(
event.target.value.includes("#") && enteredPassword.trim().length > 6
);
};
const passwordChangeHandler = (event) => {
setEnteredPassword(event.target.value);
setFormIsValid(
event.target.value.trim().length > 6 && enteredEmail.includes("#")
);
};
const validateEmailHandler = () => {
setEmailIsValid(enteredEmail.includes("#"));
};
const validatePasswordHandler = () => {
setPasswordIsValid(enteredPassword.trim().length > 6);
};
const submitHandler = (event) => {
event.preventDefault();
console.log(enteredEmail);
console.log(enteredPassword);
};
return (
<Card className="bg-slate-100 border-1 rounded-xl shadow-xl w-[30vw] m-auto mt-20 mb-20">
<div className="flex justify-center text-2xl font-bold pt-4">Login</div>
<div className="flex justify-center px-0 py-5">
<form onSubmit={submitHandler}>
<div>
<label htmlFor="email" className="text-lg font-bold">
E-mail
</label>
<div>
<input
value={enteredEmail}
type="email"
id="email"
placeholder="Type your email"
className={
emailIsValid === false
? "bg-red-200 border-b-[2px] border-red-600 text-white text-lg px-1 rounded shadow-md h-10 w-[19rem] outline-none"
: "border-b-[2px] text-lg px-1 rounded shadow-md border-gray-400 h-10 w-[19rem] outline-none"
}
onChange={emailChangeHandler}
onBlur={validateEmailHandler}
/>
</div>
</div>
<div className="mt-4">
<label className="text-lg font-bold" htmlFor="password">
Password
</label>
<div>
<input
value={enteredPassword}
type="password"
id="password"
placeholder="Type your password"
className={
passwordIsValid === false
? "bg-red-200 border-b-[2px] border-red-600 text-white text-lg px-1 rounded shadow-md h-10 w-[19rem] outline-none"
: "border-b-[2px] text-lg px-1 rounded shadow-md border-gray-400 h-10 w-[19rem] outline-none"
}
onChange={passwordChangeHandler}
onBlur={validatePasswordHandler}
/>
</div>
<div className="flex justify-end">Forget password</div>
</div>
<div className="flex justify-center">
<Button
className="mt-4 border-gray-400 rounded-xl px-32 py-2 cursor-pointer shadow-md bg-slate-400 hover:bg-slate-600 hover:text-white"
type="submit"
disabled={!formIsValid}
>
LOGIN
</Button>
</div>
<div className="flex justify-center mt-4">Or Sign Up Using</div>
<div className="flex justify-center mt-2 ">
<div className="mx-1">
<img src={instagram} alt="facebook" width="30" />
</div>
<div className="mx-1">
<img src={twitter} alt="facebook" width="30" />
</div>
<div className="mx-1">
<img src={facebook} alt="facebook" width="30" />
</div>
</div>
<div className="flex justify-center mt-[9rem]">Or Sign Up Using</div>
<div className="flex justify-center">SIGN UP</div>
</form>
</div>
</Card>
);
};
export default Login;
this is button code where i've error
<Button
className="mt-4 border-gray-400 rounded-xl px-32 py-2 cursor-pointer shadow-md bg-slate-400 hover:bg-slate-600 hover:text-white"
type="submit"
disabled={!formIsValid}
>
LOGIN
</Button>
image
this is my code's output and i want to make this LOGIN button disable while validating fields but it don't work while i am using className that contain tailwind code..
i also have a piic and code where disable works.
<Button
//className="mt-4 border-gray-400 rounded-xl px-32 py-2 cursor-
//pointer shadow-md bg-
//slate-400 hover:bg-slate-600 hover:text-white"
type="submit"
disabled={!formIsValid}
>
LOGIN
</Button>
image
now disable is working as i have commented out className attribute.
It is working, the button is not clickable, but the style isn't changing because you need to choose what the disabled state style looks like using disabled: in your class (You need Tailwind version >= v1.1.0)
Little example of a button
<Button
class="bg-green-300 disabled:bg-gray-400"
disabled={!formIsValid}
>
Click me
</Button>
You also need to enable the disabled variant in your tailwind.config.js with something like this
module.exports = {
variants: {
extend: {
backgroundColor: ["disabled"],
textColor: ["disabled"]
},
}
I am not a react dev so maybe someone can confirm this, but you should also change your useState("") to useState(true) where it is appropriate, basically all your IsValid variables, since they should be Booleans and not Strings
I was struggling with disabling an input field and decided to use a workaround using only the classes with a helper function:
export function classNames(...classes) {
return classes.filter(Boolean).join(' ');
}
which can be used like this
import { classNames } from 'wherever/you/store/helpers';
<Button
className={classNames(
'font-semibold',
formIsValid
? 'bg-green-300 text-green-900'
: 'bg-gray-300 text-gray-600 cursor-not-allowed'
)}
disabled={!formIsValid}
>
Click me
</Button>
This is useful in general for dynamically applying styles, since Tailwind CSS 3 does not support dynamic class names.

react modal unable to open

i am trying to use the headless ui modal but i am trying to launch this modal.js from my home.js file.
so in my home.js file i have something like this
function Home() {
const [isOpen, setIsOpen] = useState(false)
const resultCKDArr = Object.values(responseData.ckd).map((item, i)=>
<section class="text-gray-600 body-font overflow-hidden">
<div class="container px-5 py-10 mx-auto">
<button onClick={() => setIsOpen(!isOpen)} class="flex ml-auto text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded">Buy List</button>
</div>
<Modal isOpen={isOpen} setIsOpen={setIsOpen} />
</section>
)
return (
<>
{resultCKDArr }
</>
);
export default Home;
and this is my modal.js copy from headless ui modal as example to test
import React, { Fragment } from "react";
import { Dialog, Transition } from '#headlessui/react'
export default function Modal( props ) {
const { isOpen, setIsOpen } = props
return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={setIsOpen}>
<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"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-900"
>
Payment successful
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500">
Your payment has been successfully submitted. We’ve sent
you an email with all of the details of your order.
</p>
</div>
<div className="mt-4">
<button
type="button"
className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={setIsOpen}
>
Got it, thanks!
</button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
)
};
maybe this is the error i saw in console
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
when i click on the button, i nothing happen, no modal pop out.
In my case there was an error with Dialog.Panel component. Try changing it to a div.

Why react HeroIcons does not take color?

I am trying to use a hero icon from heroicons, in a react project.
import React, { useState } from 'react';
import { MenuIcon, XIcon } from '#heroicons/react/solid';
export const Sidebar = () => {
const [showSidebar, setShowSidebar] = useState<boolean>(false);
return (
<div
className="flex justify-between items-center
p-2
m-auto"
>
{showSidebar ? (
<div>
<XIcon
onClick={() => setShowSidebar(!showSidebar)}
className="h-5 w-5 text-white cursor-pointer"
/>
</div>
) : (
<div>
<MenuIcon onClick={() => setShowSidebar(!showSidebar)} className="h-5 w-5 text-white" />
</div>
)}
<div
className={`top-0 left-0 w-[45vw] bg-menubar p-10 pl-20 text-white fixed h-full z-40 ${
showSidebar ? 'translate-x-0 ' : 'translate-y-full'
}`}
>
<h2 className="mt-5 text-2xl font-semibold text-white">I am a sidebar</h2>
</div>
</div>
);
};
I am conditionally displaying a sidebar.
XIcon is hwoing in my dom.
But it does not take any color.
how about trying with fill-white instead of text-white e.g:
<XIcon
onClick={() => setShowSidebar(!showSidebar)}
className="h-5 w-5 fill-white cursor-pointer"
/>

Next.js keeps throwing error params is undefined

I have successfully connected my custom server using Node.js and Express.js with Next.js. I'm trying to fetch a car by its id whenever I click it among other cars, so I can have that particular car only. But I keep getting an error saying params is undefined even though I get the id at the back of my link whenever I click on the single car in the browser. I've tried fetching the data using thunder client and everything works fine. I believe something is wrong with my frontend logic.
This is where I'm trying to fetch the data with the id
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import Layout from "#/components/Layout";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import Authorization from "#/HOC/Authorization";
import axios from "axios";
const Car = () => {
const [data, setData] = useState("");
const oneCar = async (params) => {
const { id } = params;
const res = await axios.get(`http://localhost:5000/one-car/${id}`);
setData(res.data);
if (res.status !== 200) {
console.log(res.status);
}
};
useEffect(() => {
oneCar();
}, []);
return (
<Layout>
{data && (
<div className="flex flex-col w-11/12 mx-auto mt-8 justify-center bg-blue-200 rounded-lg shadow">
<div className="flex w-full justify-center mt-6 px-4 mx-auto box-shadow-lg h-2/4 relative">
<Image
src="/assets/images/d17.jpg"
alt="shopping image"
className="mx-auto flex rounded-lg inset-0 w-full h-2/4 object-cover"
width={1000}
height={500}
/>
</div>
<form className="flex-auto p-6">
<div className="flex flex-wrap">
<h1 className="flex-auto text-xl font-semibold text-gray-800">
{data.carName}
</h1>
<div className="text-xl font-semibold text-gray-700 ">
{data.carPrice}
</div>
<div className="w-full flex-none text-sm font-medium text-gray-500 mt-2">
In stock
</div>
</div>
<div className="flex items-baseline mt-4 mb-6 text-gray-800 ">
<Link
href="#"
className="ml-auto hidden md:block text-sm text-gray-500 underline"
>
Size Guide
</Link>
</div>
<div className="flex mb-4 text-sm font-medium">
<button
type="button"
className="py-2 px-4 bg-blue-700 hover:bg-blue-800 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full sm:w-1/4 transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 mx-auto rounded-lg "
>
Buy now
</button>
</div>
<p className="text-sm text-gray-500 text-center ">
Free shipping on all continental US orders.
</p>
</form>
</div>
)}
</Layout>
);
};
export default Authorization(Car);
This is where I fetch all cars and makes the id a parameter to the link address
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import Image from "next/image";
import Layout from "#/components/Layout";
import Pagination from "#/components/Pagination";
import { GiBinoculars } from "react-icons/gi";
import { useGetAllCarsQuery } from "#/store/ReduxStore/getAllCarsApi";
import Link from "next/link";
const Market = () => {
//I use RTK Query to fetch the data, and It was successfully fetched
const { data, isLoading, error } = useGetAllCarsQuery();
return (
<Layout>
<div className="2xl:container 2xl:mx-auto">
<div className=" py-3 lg:px-20 md:px-6 px-4">
<div className=" flex justify-center mt-3 items-center">
<div className=" flex space-x-3 justify-center items-center">
<span className="bg-blue-800 px-4 py-2 rounded-md text-2xl text-white">
<GiBinoculars />
</span>
<input
type="search"
className="border-b-2 w-9/12 border-gray-700 -mb-3 leading-5 text-lg p-2 focus:outline-none"
placeholder="Search for cars here..."
/>
</div>
</div>
<hr className=" w-full bg-gray-200 my-6" />
<div className=" grid lg:grid-cols-4 sm:grid-cols-2 grid-cols-1 lg:gap-y-12 lg:gap-x-8 sm:gap-y-10 sm:gap-x-6 gap-y-6 lg:mt-12 mt-10">
{data?.map((cars, i) => (
<Link
key={i}
href="/[id]"
as={`${cars._id}`}
//I insert the id here
className="relative"
passHref
>
<div>
<div className=" relative group">
<div className="caroverlay"></div>
<Image
width={600}
height={400}
className="rounded-md w-full"
src="/assets/images/d17.jpg"
alt="A girl Posing Img"
/>
<div className=" absolute bottom-0 p-8 w-full opacity-0 group-hover:opacity-100 z-20">
<button className="text-base font-bold leading-4 text-gray-600 hover:bg-gray-300 hover:text-gray-700 bg-white py-3 w-full">
Add to your garage
</button>
<button className=" bg-transparent text-base font-bold leading-4 border-2 hover:bg-gray-300 hover:text-gray-700 border-white py-3 w-full mt-2 text-white">
View Car
</button>
</div>
</div>
<p className=" text-xl leading-5 text-gray-600 md:mt-6 mt-4">
{cars.carName}
</p>
<p className=" font-semibold text-xl leading-5 text-gray-800 mt-4">
<span>$</span> {cars.carPrice}
</p>
</div>
</Link>
))}
</div>
{/* _______________________________________________________ */}
<Pagination />
{/* _______________________________________________________ */}
</div>
</div>
</Layout>
);
};
export default Market;
Here is my backend logic
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
const router = require("express").Router();
const auth = require("../../middleware/auth");
const Car = require("../../Model/CarSchema");
router.get("/onecar/:id", auth, async (req, res) => {
try {
const car = await Car.findById(req.params.id);
res.status(200).json(car);
} catch (err) {
res.status(500).json({ msg: "Server Error" });
}
});
module.exports = router;
To access id in nextjs. I imported useRouter from next/router. Then I const router = useRouter(). Then const {id} = router.query

create component for form errors using react-hook-form

I'm using react-hook-form, and I'm wondering if it's possible to create a component that is passing the form errors using react-hook-form.
I have the following component
import { useForm } from "react-hook-form";
import { XIcon } from "#heroicons/react/outline";
export default function ErrorsPopup() {
const {
formState: { errors },
} = useForm({
criteriaMode: "all",
});
return (
<>
{Object.keys(errors).length > 0 && (
<div className="mt-6 text-white bg-red-600 border-4 border-red-700 alert-start">
<div className="flex justify-between items-center bg-red-700 py-2 px-4">
<div>
<p>The following errors have occurred:</p>
</div>
<div className="cursor-pointer">
<XIcon className="h-6 w-6 text-white alert-close" />
</div>
</div>
<div className="py-2 px-4">
<div className="flex flex-col gap-2">
{Object.entries(errors).map(([index, error]) => (
<div className="flex flex-col gap-y-6 sm:gap-x-8" key={index}>
<p>• {error.message}</p>
</div>
))}
</div>
</div>
</div>
)}
</>
);
}
and I have added this to the following page
import { useState } from "react";
import Head from "next/head";
import Link from "next/link";
import Image from "next/image";
import Background from "../../../public/images/option1.png";
import Router from "next/router";
import { signIn } from "next-auth/client";
import { useForm } from "react-hook-form";
import { SaveIcon } from "#heroicons/react/outline";
import ErrorsPopup from "../../components/ErrorsPopup";
export default function Login() {
const { register, handleSubmit } = useForm();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const onSubmit = async () => {
await signIn("credentials", {
redirect: false,
email: email,
password: password,
});
Router.push("/dashboard");
};
return (
<>
<Head>
<title>Ellis Development - Login</title>
</Head>
<div className="relative">
<div className="md:flex">
{/* Image */}
<div className="flex items-center justify-center bg-blue-700 h-screen lg:w-96">
<Image src={Background} width={350} height={350} layout="fixed" />
</div>
{/* Contact form */}
<div className="flex flex-col justify-center py-10 px-6 sm:px-10 w-full">
<h1 className="text-4xl font-extrabold text-grey-800">Login</h1>
{/* errors */}
<ErrorsPopup />
<form
onSubmit={handleSubmit(onSubmit)}
className="mt-6 flex flex-col gap-y-6 sm:gap-x-8"
>
{/* email field */}
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-gray-900"
>
Email
</label>
<div className="mt-1">
<input
{...register("email", { required: "E-mail is required" })}
type="text"
name="email"
id="email"
className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
onChange={(event) => setEmail(event.target.value)}
/>
</div>
</div>
{/* password field */}
<div>
<label
htmlFor="password"
className="block text-sm font-medium text-gray-900"
>
Password
</label>
<div className="mt-1">
<input
{...register("password", {
required: "Password is required",
})}
type="password"
name="password"
id="password"
className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
onChange={(event) => setPassword(event.target.value)}
/>
</div>
</div>
<div className="flex items-center justify-between sm:col-span-2">
<div>
<button
type="submit"
className="mt-2 mr-2 w-full inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-700 hover:bg-blue-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 sm:w-auto"
>
<SaveIcon className="w-4 h-4 mr-4" />
Login
</button>
</div>
<div>
<Link href="/dashboard/auth/register">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2 mr-4">
Register
</a>
</Link>
<Link href="/dashboard/auth/forgot">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2">
Forgot your password?
</a>
</Link>
</div>
</div>
</form>
</div>
</div>
</div>
</>
);
}
So I'm trying to create a component for all forms where I can simply just show any errors to keep the code DRY, but the component is not showing up.
Sure I'm missing something silly but I'm new to react so any help would be create.
You've have to use FormProvider in your Login component and useFormContext in your ErrorPopup
👉🏻 https://react-hook-form.com/api/useformcontext
I've added a comment // 👈 where I've made changes.
Login.js
import { useState } from "react";
import Head from "next/head";
import Link from "next/link";
import Image from "next/image";
import Background from "../../../public/images/option1.png";
import Router from "next/router";
import { signIn } from "next-auth/client";
import { useForm, FormProvider } from "react-hook-form"; //👈
import { SaveIcon } from "#heroicons/react/outline";
import ErrorsPopup from "../../components/ErrorsPopup";
export default function Login() {
const methods = useForm(); //👈
const { register, handleSubmit } = methods; //👈
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const onSubmit = async () => {
await signIn("credentials", {
redirect: false,
email: email,
password: password,
});
Router.push("/dashboard");
};
return (
<>
<Head>
<title>Ellis Development - Login</title>
</Head>
<div className="relative">
<div className="md:flex">
{/* Image */}
<div className="flex items-center justify-center bg-blue-700 h-screen lg:w-96">
<Image src={Background} width={350} height={350} layout="fixed" />
</div>
{/* Contact form */}
<div className="flex flex-col justify-center py-10 px-6 sm:px-10 w-full">
<h1 className="text-4xl font-extrabold text-grey-800">Login</h1>
<FormProvider {...methods}> //👈
{/* errors */}
<ErrorsPopup />
<form
onSubmit={handleSubmit(onSubmit)}
className="mt-6 flex flex-col gap-y-6 sm:gap-x-8"
>
{/* email field */}
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-gray-900"
>
Email
</label>
<div className="mt-1">
<input
{...register("email", { required: "E-mail is required" })}
type="text"
name="email"
id="email"
className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
onChange={(event) => setEmail(event.target.value)}
/>
</div>
</div>
{/* password field */}
<div>
<label
htmlFor="password"
className="block text-sm font-medium text-gray-900"
>
Password
</label>
<div className="mt-1">
<input
{...register("password", {
required: "Password is required",
})}
type="password"
name="password"
id="password"
className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
onChange={(event) => setPassword(event.target.value)}
/>
</div>
</div>
<div className="flex items-center justify-between sm:col-span-2">
<div>
<button
type="submit"
className="mt-2 mr-2 w-full inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-700 hover:bg-blue-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 sm:w-auto"
>
<SaveIcon className="w-4 h-4 mr-4" />
Login
</button>
</div>
<div>
<Link href="/dashboard/auth/register">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2 mr-4">
Register
</a>
</Link>
<Link href="/dashboard/auth/forgot">
<a className="underline decoration-blue-500 decoration-4 hover:decoration-2">
Forgot your password?
</a>
</Link>
</div>
</div>
</form>
</FormProvider> //👈
</div>
</div>
</div>
</>
);
}
ErrorPopup.js
import { useFormContext } from "react-hook-form"; // 👈
import { XIcon } from "#heroicons/react/outline";
export default function ErrorsPopup() {
const {
formState: { errors },
} = useFormContext({ // 👈
criteriaMode: "all",
});
return (
<>
{Object.keys(errors).length > 0 && (
<div className="mt-6 text-white bg-red-600 border-4 border-red-700 alert-start">
<div className="flex justify-between items-center bg-red-700 py-2 px-4">
<div>
<p>The following errors have occurred:</p>
</div>
<div className="cursor-pointer">
<XIcon className="h-6 w-6 text-white alert-close" />
</div>
</div>
<div className="py-2 px-4">
<div className="flex flex-col gap-2">
{Object.entries(errors).map(([index, error]) => (
<div className="flex flex-col gap-y-6 sm:gap-x-8" key={index}>
<p>• {error.message}</p>
</div>
))}
</div>
</div>
</div>
)}
</>
);
}
I believe you need to use useFormContext instead of useForm in your ErrorsPopup component
https://react-hook-form.com/api/useformcontext

Categories

Resources