-
Notifications
You must be signed in to change notification settings - Fork 264
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #438 from iamExony/feat/HNG-18-login-with-magic-link
feat: implement login with magic link
- Loading branch information
Showing
4 changed files
with
120 additions
and
1 deletion.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"use client"; | ||
|
||
import Image from "next/image"; | ||
import { useState } from "react"; | ||
|
||
import Footer from "~/components/layouts/Footer"; | ||
import Navbar from "~/components/layouts/Navbar"; | ||
import { Button } from "~/components/ui/button"; | ||
|
||
const MagicLogin = () => { | ||
const [email, setEmail] = useState(""); | ||
const [error, setError] = useState(""); | ||
const [isValidEmail, setIsValidEmail] = useState(false); | ||
|
||
const emailBlacklist = new Set(["gail.com", "yhoo.com", "hotmal.com"]); | ||
|
||
const validateEmail = (email: string) => { | ||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||
const emailDomain = email.split("@")[1]; | ||
return emailRegex.test(email) && !emailBlacklist.has(emailDomain); | ||
}; | ||
|
||
const handleSubmit = () => { | ||
const isEmailValid = validateEmail(email); | ||
setIsValidEmail(isEmailValid); | ||
setError(isEmailValid ? "" : "Please enter a valid email"); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Navbar /> | ||
<div className="flex min-h-screen flex-col items-center justify-center gap-6 bg-white p-4"> | ||
<h2 className="mb-4 text-center text-4xl font-semibold text-neutral-dark-2 sm:text-sm md:text-4xl"> | ||
Login With Email Link | ||
</h2> | ||
<div className="w-full max-w-md px-4"> | ||
<div className="mb-4 flex flex-col"> | ||
<label | ||
className="mb-2 text-sm font-normal text-neutral-dark-1" | ||
htmlFor="email" | ||
> | ||
</label> | ||
<input | ||
className={`h-12 w-full rounded-lg border bg-white px-4 py-2 focus:border-primary focus:bg-background focus:outline-none sm:h-16 ${ | ||
error | ||
? "border-error" | ||
: isValidEmail | ||
? "border-primary" | ||
: "border-border" | ||
}`} | ||
id="email" | ||
placeholder="Enter Email Address" | ||
type="email" | ||
value={email} | ||
onChange={(event) => setEmail(event.target.value)} | ||
/> | ||
{error && <p className="mt-2 text-sm text-error">{error}</p>} | ||
</div> | ||
<Button | ||
className="inline-flex h-12 w-full items-center justify-center gap-2 whitespace-nowrap rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" | ||
role="button" | ||
onClick={handleSubmit} | ||
> | ||
Get Magic Link | ||
</Button> | ||
</div> | ||
<div className="mt-4 flex w-full max-w-md items-center justify-start px-4 text-center text-sm text-foreground md:text-xs"> | ||
<Image | ||
alt="shield image" | ||
className="mr-1 hidden md:block" | ||
src="/images/shield.svg" | ||
width={12} | ||
height={12} | ||
/> | ||
<span> | ||
By logging in, you agree to the{" "} | ||
<a className="font-bold text-primary" href="#"> | ||
Terms of Service | ||
</a>{" "} | ||
and{" "} | ||
<a className="font-bold text-primary" href="#"> | ||
Privacy Policy | ||
</a> | ||
</span> | ||
</div> | ||
</div> | ||
<Footer /> | ||
</> | ||
); | ||
}; | ||
|
||
export default MagicLogin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { fireEvent, render, screen } from "@testing-library/react"; | ||
|
||
import MagicLogin from "~/app/auth/Login"; | ||
|
||
describe("login Component", () => { | ||
it("shows error for common typos in email domains", async () => { | ||
expect.assertions(1); | ||
|
||
render(<MagicLogin />); | ||
|
||
const emailInput = screen.getByPlaceholderText("Enter Email Address"); | ||
const submitButton = screen.getByRole("button", { | ||
name: /get magic link/i, | ||
}); | ||
|
||
fireEvent.change(emailInput, { target: { value: "[email protected]" } }); | ||
fireEvent.click(submitButton); | ||
|
||
const errorMessage = await screen.findByText(/please enter a valid email/i); | ||
expect(errorMessage).toBeInTheDocument(); | ||
}); | ||
}); |