Skip to content

Commit

Permalink
Merge pull request #438 from iamExony/feat/HNG-18-login-with-magic-link
Browse files Browse the repository at this point in the history
feat: implement login with magic link
  • Loading branch information
mrcoded authored Jul 22, 2024
2 parents 515436f + 770f93c commit cb7ad02
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 1 deletion.
3 changes: 3 additions & 0 deletions public/images/shield.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
93 changes: 93 additions & 0 deletions src/app/auth/Login.tsx
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"
>
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;
3 changes: 2 additions & 1 deletion src/app/guides/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ const StyleGuide: FC = () => {
<br />
icon<span className="text-pink-400">?: </span>React.ReactNode;
<br />
children<span className="text-pink-400">?: </span>React.ReactNode;
children<span className="text-pink-400">?: </span>
React.ReactNode;
<br />
isLoading<span className="text-pink-400">?: </span>boolean;
<br />
Expand Down
22 changes: 22 additions & 0 deletions src/test/MagicLogin.test.tsx
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();
});
});

0 comments on commit cb7ad02

Please sign in to comment.