OLD/ChatLink

[ChatLink] Frontend: NextJs v14 - shadcn을 이용한 로그인 / 회원가입 폼 구현

joseph0926 2024. 3. 9. 09:17

1. 사용 기술

- NextJs v14, Tailwind(shadcn-ui)

 

2. 프로젝트 구성

- 초기 next 프로젝트 설치

npx create-next-app@latest <프로젝트명>

 

- 필요 라이브러리 설치

npm i zod // 유효성 검사

// shadcn-ui
npx shadcn-ui@latest init
npx shadcn-ui@latest add input form

 

- 폴더 구조

src/
|-- app/
    |-- layout.ts
    |-- (root)/
         |-- page.tsx
         |-- layout.tsx
         // 메인 레이아웃을 사용하는 페이지들
    |-- sign/
         |-- page.tsx
         |-- layout.tsx
    |-- api/
|-- components/
    |-- auth/
    |-- ui/
|-- lib/
    |-- utils.ts
    |-- uploadthing.ts
|-- schemas/
    // 유효성 스키마
|-- types/
    // 타입
|-- service/
    // api 호출 로직

 

3. 회원가입 / 로그인 폼 구성

- 기본 아이디어

   - 요구되는 값

      - 회원가입: nickname, email, password, profileImage      

      - 로그인: email, password

   - 로직 순서

      - 유저 입력 -> 제출 -> 유효성 검사 -> 백엔드에 요청

 

- 서버 컴포넌트 / 클라이언트 컴포넌트

   - 회원가입 / 로그인 폼을 감싸는 레이아웃 컴포넌트 <= 서버 컴포넌트

   - 회원가입 / 로그인 폼 <= 클라이언트 컴포넌트

 

- 전환 아이디어

  - url 쿼리 파라미터 (type = in | up)

 

- 구현 로직

"use client";

import Link from "next/link";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { signinSchema } from "@/schemas/signin.schema";

export default function SigninForm() {
  const form = useForm<z.infer<typeof signinSchema>>({
    defaultValues: {
      email: "",
      password: "",
    },
    resolver: zodResolver(signinSchema),
  });

  const submitHandler = async (values: z.infer<typeof signinSchema>) => {
    console.log(values);
  };

  return (
    <div className="w-full lg:w-1/2 p-8 flex flex-col items-center justify-center">
      <h1 className="text-3xl font-bold mb-6">ChatLink</h1>
      <Form {...form}>
        <form
          onSubmit={form.handleSubmit(submitHandler)}
          className="flex flex-col gap-4 w-[60%]"
        >
          <FormField
            control={form.control}
            name="email"
            render={({ field }) => (
              <FormItem>
                <FormLabel className="text-lg font-bold">Email</FormLabel>
                <FormControl>
                  <Input type="text" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="password"
            render={({ field }) => (
              <FormItem>
                <FormLabel className="text-lg font-bold">Password</FormLabel>
                <FormControl>
                  <Input type="text" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <div className="flex items-center justify-between w-full mt-4">
            <Link href="/sign?type=up">
              아직 회원이 아니신가요?
              <br />
              <span className="text-indigo-400 font-semibold">회원가입</span>
              으로 이동하기
            </Link>
            <Button variant="outline" className="bg-indigo-400 text-white">
              로그인
            </Button>
          </div>
        </form>
      </Form>
    </div>
  );
}

 

[Github]