DEV Community

Cover image for Lite tip
Raksina Kongjua
Raksina Kongjua

Posted on

Lite tip

this post, we will dive deep into the critical sections of the code that power the blog application. It uses Next.js, Prisma ORM for database management, and various utility functions to handle authentication, validation, and user interaction. Let’s break it down into key sections.

1. Validation Schema Using Zod

const addSchema = z.object({
    email: z.string().email().max(20),
    password: z.string().min(3),
    remember: z
        .union([z.string(), z.undefined()])
        .transform((val) => val === "on"),  
})
Enter fullscreen mode Exit fullscreen mode

The Zod schema is used for validating the incoming form data. In this case, we’re validating the email, password, and remember fields from the login form.

  • The email field is required to be a valid email address and has a maximum length of 20 characters.
  • The password must have a minimum length of 3 characters.
  • The remember field checks if the value is 'on', transforming it into a boolean true for remembering the session, or false if undefined.

2. Handling Form Submission and Login Logic

export default async function login(prevState: unknown, formData: FormData) {
    const result = addSchema.safeParse(Object.fromEntries(formData.entries()));
    if (result.success === false) {
        return { error: result.error.formErrors.fieldErrors }
    }

    const data = result.data;
    let { email, password, remember } = data;

    try {
        const user = await prisma.user.findUnique({
            where: { email },
        });

        if (user && await isValidPassword(password, user.password)) {
            return await loginUser(user, remember);
        } else {
            return { error: { message: "Incorrect user or password" } }
        }
    } catch (error) {
        return { error: { message: error + "" } }
    }
}
Enter fullscreen mode Exit fullscreen mode

The login function handles the core login process.

First, it validates the form data using the previously defined Zod schema.
If validation fails, it returns error messages for the respective fields.
The function then queries the database using Prisma to check if a user with the provided email exists. If found, it compares the provided password with the hashed password stored in the database using the isValidPassword function.
If the password is correct, it triggers a login process via the loginUser function.
If no matching user is found or the password is incorrect, an error message is returned.

3. Prisma Database Schema

model User {
  id       Int    @id @default(autoincrement())
  email    String @unique
  name     String
  password String
  posts    Post[]
}
Enter fullscreen mode Exit fullscreen mode

Here, we define the User model in the Prisma schema. It has the following fields:

  • id: A unique identifier for each user.
  • email: The user's email address (unique).
  • name: The user's name.
  • password: The hashed password of the user.
  • posts: A one-to-many relationship where each user can have multiple posts.

4. Rendering Posts in the Blog Page

export default async function Blog() {
    const posts = await prisma.post.findMany({
        include: { user: true },
    });
    const user = await getSession();

    return (
        <div className="mb-10">
            {posts.map((post) => (
                <div key={post.id} className="post-container">
                    <div>{post.subject}</div>
                    <div>{post.user.name}</div>
                    <div>{post.detail}</div>
                    <span>{post.like} <LikeButton id={post.id} /></span>
                </div>
            ))}
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

In the Blog component, the posts are fetched from the database using Prisma’s findMany method. The code renders each post’s subject, detail, and user name. If the user is logged in, they can also interact with the posts (like/unlike posts, edit, or delete).

  • Post Rendering: Each post is displayed with its subject, - details, and the associated user.
  • Like/Unlike: A LikeButton component is used to handle the interaction of liking or unliking a post.
  • Edit/Delete Options: If the logged-in user is the author of the post, they can edit or delete their posts.

5. Handling Post Deletion and Like/Unlike Logic

import { likePost, unlikePost } from "./_actions/likePost";
import deletePost from "./_actions/deletePost";
Enter fullscreen mode Exit fullscreen mode

These helper functions, imported from the _actions folder, provide the functionality to manage post likes and deletions. The likePost and unlikePost functions update the like count for each post, while deletePost removes a post from the database.

6. Logout and Authentication Handling

The Logout and getSession functions help manage user authentication. The getSession function checks whether a user is logged in, and the Logout component handles logging out the user.

Top comments (0)