Skip to content

Commit

Permalink
feat: ✨ feat(email-verification): Implement email verification functi…
Browse files Browse the repository at this point in the history
…onality

Description:
This commit introduces the email verification functionality. The changes are part of the ongoing work on the `email-verification` branch.
- In `README.md`, updates have been made to reflect the current state of the project.
- In `components/spinner.tsx`, changes have been made to improve the loading spinner.
- The file `data/verificiation-token.ts` has been deleted and replaced with `data/verification-token.ts` to correct a typo.
- In `lib/mail.ts` and `lib/tokens.ts`, updates have been made to handle the email verification process.
- New files `actions/new-verification.ts`, `app/auth/new-verification/`, and `components/auth/new-verification-form.tsx` have been added to handle the new verification process.

Changes:
- Update `README.md` to reflect current project state
- Improve loading spinner in `components/spinner.tsx`
- Delete `data/verificiation-token.ts` and add `data/verification-token.ts`
- Update `lib/mail.ts` and `lib/tokens.ts` for email verification
- Add new files for handling new verification process

This commit doesn't introduce any breaking changes. The updates are compatible with the existing codebase.
Co-authored-by: Ricardo Esteves <[email protected]>
  • Loading branch information
RicardoGEsteves and RicardoGEsteves committed Jan 10, 2024
1 parent 09c9061 commit 0fe5180
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 7 deletions.
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ Auth.js V5 Toolkit is a specialized toolkit designed to streamline the process o
- **Auth.js V5 & OAuth 2:** Implement advanced authentication features using Auth.js V5 and OAuth 2 for secure authentication flows.
- **Prisma & PostgreSQL:** Leverage Prisma ORM with PostgreSQL for efficient database management and queries.
- **Shadcn-ui:** Utilize UI components from Shadcn-ui for visually appealing interfaces.
- **Bcrypt:** Implement secure password hashing using Bcrypt for enhanced security.
- **Bcryptjs:** Implement secure password hashing using Bcrypt for enhanced security.
- **React-hook-form & React-icons:** Manage forms efficiently and use icons for a better user experience.
- **React-spinners:** Integrate loading spinners for a smoother user interaction.
- **Resend & Sonner:** Manage asynchronous tasks and scheduling effectively.
- **Zod:** Ensure data validation with Zod's schema-first approach.
- **Server Actions:** Implement server actions for authentication flows and providers.
Expand All @@ -49,10 +48,9 @@ Auth.js V5 Toolkit is a specialized toolkit designed to streamline the process o
- Prisma
- PostgreSQL
- Shadcn-ui
- Bcrypt
- Bcryptjs
- React-hook-form
- React-icons
- React-spinners
- Resend
- Sonner
- Zod
Expand Down Expand Up @@ -92,7 +90,7 @@ NEXT_PUBLIC_APP_URL=

## Contributions

Contributions are encouraged! Please adhere to the guidelines specified in the CONTRIBUTING.md file for contributing to this project.
Contributions are encouraged! Get in touch to contributing to this project.

## License

Expand Down
39 changes: 39 additions & 0 deletions actions/new-verification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use server";

import { db } from "@/lib/db";
import { getUserByEmail } from "@/data/user";
import { getVerificationTokenByToken } from "@/data/verification-token";

export const newVerification = async (token: string) => {
const existingToken = await getVerificationTokenByToken(token);

if (!existingToken) {
return { error: "Token does not exist!" };
}

const hasExpired = new Date(existingToken.expires) < new Date();

if (hasExpired) {
return { error: "Token has expired!" };
}

const existingUser = await getUserByEmail(existingToken.email);

if (!existingUser) {
return { error: "User not registered!" };
}

await db.user.update({
where: { id: existingUser.id },
data: {
emailVerified: new Date(),
email: existingToken.email,
},
});

await db.verificationToken.delete({
where: { id: existingToken.id },
});

return { success: "Account verified!" };
};
5 changes: 5 additions & 0 deletions app/auth/new-verification/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import NewVerificationForm from "@/components/auth/new-verification-form";

export default function NewVerificationPage() {
return <NewVerificationForm />;
}
57 changes: 57 additions & 0 deletions components/auth/new-verification-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"use client";

import { useCallback, useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";

import { newVerification } from "@/actions/new-verification";
import CardWrapper from "@/components/auth/card-wrapper";
import FormError from "@/components/form-error";
import FormSuccess from "@/components/form-success";
import Spinner from "../spinner";

const NewVerificationForm = () => {
const [error, setError] = useState<string | undefined>();
const [success, setSuccess] = useState<string | undefined>();

const searchParams = useSearchParams();

const token = searchParams.get("token");

const onSubmit = useCallback(() => {
if (success || error) return;

if (!token) {
setError("Missing token!");
return;
}

newVerification(token)
.then((data) => {
setSuccess(data.success);
setError(data.error);
})
.catch(() => {
setError("Something went wrong!");
});
}, [token, success, error]);

useEffect(() => {
onSubmit();
}, [onSubmit]);

return (
<CardWrapper
headerLabel="Confirming your verification"
backButtonLabel="Back to login"
backButtonHref="/auth/login"
>
<div className="flex items-center w-full justify-center">
{!success && !error && <Spinner />}
{!success && <FormError message={error} />}
{success && <FormSuccess message={success} />}
</div>
</CardWrapper>
);
};

export default NewVerificationForm;
1 change: 1 addition & 0 deletions components/spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Spinner = () => {
<>
<svg
aria-hidden="true"
// TODO: In the future pass the color and size as a prop
className="inline w-8 h-8 text-gray-200 animate-spin dark:text-muted fill-sky-400"
viewBox="0 0 100 101"
fill="none"
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions lib/mail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const sendVerificationEmail = async (email: string, token: string) => {
from: "Acme <[email protected]>",
to: email,
subject: "Verify your email.",
// TODO: Add a template for this email
html: `<p>Click <a href="${confirmLink}">here</a> to verify email.</p>`,
});
};
2 changes: 1 addition & 1 deletion lib/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import crypto from "crypto";
import { v4 as uuidv4 } from "uuid";

import { db } from "@/lib/db";
import { getVerificationTokenByEmail } from "@/data/verificiation-token";
import { getVerificationTokenByEmail } from "@/data/verification-token";

export const generateVerificationToken = async (email: string) => {
const token = uuidv4();
Expand Down
2 changes: 1 addition & 1 deletion routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* These routes do not require authentication
* @type {string[]}
*/
export const publicRoutes = ["/"];
export const publicRoutes = ["/", "/auth/new-verification"];

/**
* An array of routes that are used for authentication
Expand Down

0 comments on commit 0fe5180

Please sign in to comment.