Skip to content

Commit

Permalink
feat: login modal with validation
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoEscaleira committed Jan 2, 2024
1 parent 5a02adb commit 3b60336
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 192 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,29 @@
},
"dependencies": {
"@heroicons/react": "^2.1.1",
"@hookform/resolvers": "^3.3.3",
"graphql": "^16.8.1",
"mapbox-gl": "^3.0.1",
"next": "14.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.49.2",
"react-map-gl": "^7.1.7",
"react-modal-global": "^2.3.4",
"react-modal": "^3.16.1",
"react-simple-maps": "^3.0.0",
"react-tooltip": "^5.25.1",
"yup": "^1.3.3",
"zustand": "^4.4.7"
},
"devDependencies": {
"@types/mapbox-gl": "^2.7.19",
"@types/node": "^20.9.2",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@types/react-modal": "^3.16.3",
"@types/react-simple-maps": "^3.0.4",
"@types/react-tooltip": "^4.2.4",
"@types/yup": "^0.32.0",
"autoprefixer": "^10.0.1",
"eslint": "^8.54.0",
"eslint-config-next": "14.0.3",
Expand Down
22 changes: 22 additions & 0 deletions src/app/globals.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,25 @@ body {
.mapboxgl-ctrl-logo {
display: none !important;
}

.ReactModal__Overlay {
opacity: 0;
transition: opacity 250ms ease-in-out;
z-index: 11;
background-color: rgba(229, 231, 235, 0.75) !important;
}

.ReactModal__Overlay--after-open {
opacity: 1;
}

.ReactModal__Overlay--before-close {
opacity: 0;
}

.modal-popup {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
3 changes: 1 addition & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Metadata } from "next";
import { Roboto } from "next/font/google";
import { Footer, Header } from "@/components";
import "react-modal-global/styles/modal.scss";
import "./globals.scss";

const roboto = Roboto({
Expand All @@ -23,7 +22,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
return (
<>
<html lang="en">
<body className={roboto.className}>
<body className={roboto.className} id="root">
<Header />
<main className="relative flex h-screen w-screen flex-col">{children}</main>
<Footer />
Expand Down
18 changes: 7 additions & 11 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
"use client";
import { UserIcon } from "@heroicons/react/24/solid";
import { ModalContainer } from "react-modal-global";
import { Modal, ModalType } from "@/components";
import Link from "next/link";
import { LoginModal } from "@/components";

export function Header() {
let isClient = typeof window !== "undefined";

return (
<>
<header className="absolute left-0 top-0 z-10 w-full px-4 py-2 sm:px-6 sm:py-4">
<div className="flex items-center justify-end">
<UserIcon
className="h-10 w-8 cursor-pointer sm:w-10"
onClick={() => {
Modal.openNamed(ModalType.LoginForm);
}}
/>
<Link href="#login">
<UserIcon className="h-10 w-8 cursor-pointer sm:w-10" />
</Link>
</div>
</header>
{isClient && <ModalContainer controller={Modal} />}

<LoginModal />
</>
);
}
15 changes: 0 additions & 15 deletions src/components/Login/LoginForm.tsx

This file was deleted.

108 changes: 108 additions & 0 deletions src/components/Login/LoginModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"use client";
import { useEffect, useState } from "react";
import { XMarkIcon } from "@heroicons/react/24/solid";
import { yupResolver } from "@hookform/resolvers/yup";
import { useParams } from "next/navigation";
import { useForm } from "react-hook-form";
import ReactModal from "react-modal";
import { object, string } from "yup";

ReactModal.setAppElement("#root");

const schema = object().shape({
email: string().email().required(),
password: string().required().min(4),
});

export function LoginModal() {
const [isOpen, setIsOpen] = useState(false);
const params = useParams();
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
mode: "onSubmit",
resolver: yupResolver(schema),
});

useEffect(() => {
if (window.location.hash.includes("login")) {
setIsOpen(true);
history.replaceState("", document.title, location.pathname + location.search);
}
}, [params]);

const loginFormSubmit = handleSubmit(data => {
// handle submitting the form
console.log(data);
});

return (
<ReactModal
isOpen={isOpen}
shouldCloseOnEsc
className="modal-popup"
onRequestClose={() => setIsOpen(false)}
shouldCloseOnOverlayClick
>
<div className="w-full rounded-lg bg-white p-4 shadow">
<div className="flex w-96 items-center justify-between rounded-t border-b p-4 md:p-5">
<h3 className="text-xl font-semibold text-gray-900">Sign in</h3>
<XMarkIcon onClick={() => setIsOpen(false)} className="h-6 w-6 cursor-pointer sm:w-10" />
</div>

<form className="space-y-4 p-4 md:p-5" onSubmit={loginFormSubmit}>
<div>
<label
htmlFor="email"
className={`mb-2 block text-sm font-medium ${errors.email ? "text-red-400" : "text-gray-900"}`}
>
Your email
</label>
<input
type="email"
id="email"
className={`block w-full rounded-lg border bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 ${
errors.email ? "border-red-400" : "border-gray-300"
}`}
placeholder="[email protected]"
{...register("email")}
/>
{errors.email && <p className="text-sm text-red-500">Enter a valid email.</p>}
</div>
<div>
<label
htmlFor="password"
className={`mb-2 block text-sm font-medium ${errors.password ? "text-red-400" : "text-gray-900"}`}
>
Your password
</label>
<input
type="password"
id="password"
placeholder="••••••••"
className={`block w-full rounded-lg border bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 ${
errors.password ? "border-red-400" : "border-gray-300"
}`}
{...register("password")}
/>
{errors.password && <p className="text-sm text-red-500">Enter a password.</p>}
</div>
<button
type="submit"
className="w-full rounded-lg bg-blue-700 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300"
>
Login to your account
</button>
<div className="text-sm font-medium text-gray-500">
Not registered?{" "}
<a href="#" className="text-blue-700 hover:underline">
Create account
</a>
</div>
</form>
</div>
</ReactModal>
);
}
39 changes: 0 additions & 39 deletions src/components/Modal/DrawerLayout.scss

This file was deleted.

27 changes: 0 additions & 27 deletions src/components/Modal/DrawerLayout.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions src/components/Modal/Modal.tsx

This file was deleted.

41 changes: 0 additions & 41 deletions src/components/Modal/PopupLayout.scss

This file was deleted.

27 changes: 0 additions & 27 deletions src/components/Modal/PopupLayout.tsx

This file was deleted.

5 changes: 1 addition & 4 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
export * from "./Modal/Modal";
export * from "./Modal/PopupLayout";
export * from "./Modal/DrawerLayout";
export * from "./Login/LoginForm";
export * from "./Login/LoginModal";
export * from "./Footer/Footer";
export * from "./Header/Header";
Loading

0 comments on commit 3b60336

Please sign in to comment.