본문 바로가기

verdantjuly/Today I Learned

TIL 20240413

728x90

이번 주 목표

Danmi React User Page

오늘 목표

Danmi React User Page

오늘 한 것

Danmi React Signup Component

오늘 스케줄

오후 6:00 Danmi React User Page

오후 11:00 취침

1. zod를 이용한 유효성 검사

import { z } from "zod";

const phoneRegex = /^010\d{8}$/;

export const registerSchema = z.object({
  phone: z
    .string()
    .min(11, "연락처는 11자리여야 합니다.")
    .max(11, "연락처는 11자리여야 합니다.")
    .refine(
      (value) => phoneRegex.test(value),
      "010으로 시작하는 11자리 숫자를 입력해주세요",
    ),
  name: z
    .string()
    .min(2, { message: "이름은 2글자 이상이어야 합니다." })
    .max(100, { message: "이름은 100글자 이하이어야 합니다." }),
  type: z.enum(["member" || "tutor"]),
  mainTutor: z.string(),
  id: z.string().min(4, "아이디는 4글자 이상이어야 합니다"),
  password: z.string().min(4, "비밀번호는 4글자 이상이어야 합니다"),
  credit: z.number().min(0, "크레딧은 0이상이어야 합니다."),
});

 

2. Signup Component 

"use client";

import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";

import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { z } from "zod";
import { registerSchema } from "@/validators/auth";
import React, { useState } from "react";

export function AddMember({ onClose }: { onClose: () => void }) {
  const [showTutorForm, setShowTutorForm] = useState(false);

  const [id, setId] = useState("");
  const [password, setPassword] = useState("");
  const [name, setName] = useState("");
  const [phone, setPhone] = useState("");
  const [type, setType] = useState("member");
  const [mainTutor, setMainTutor] = useState("");
  const [credit, setCredit] = useState(0);
  const [confirm, setConfirm] = useState("");

  async function onSubmit() {
    try {
      registerSchema.parse({
        id,
        password,
        name,
        phone,
        type,
        mainTutor,
        credit,
      });

      if (password !== confirm) {
        alert("비밀번호와 확인 비밀번호가 일치하지 않습니다.");
        setConfirm("");
        return;
      }
      const response = await fetch("http://localhost:4000/users/signup", {
        method: "POST",
        credentials: "include",
        headers: {
          "Content-Type": "application/json",
          Authorization: localStorage.getItem("Authorization") ?? "",
        },
        body: JSON.stringify({
          id,
          password,
          name,
          phone,
          type,
          mainTutor,
          credit,
        }),
      });
      if (response.ok) {
        alert("회원 가입이 정상적으로 이루어졌습니다.");
        onCancel();
      } else {
        alert("오류가 발생하였습니다.");
      }
      const result = response.json();
    } catch (error) {
      if (error instanceof z.ZodError) {
        error.errors.forEach((err) => {
          alert(err.message);
        });
      }
    }
  }

  function onCancel() {
    onClose();
  }

  return (
    <>
      <Card className="w-[350px]">
        <CardHeader>
          <CardTitle>회원 추가</CardTitle>
        </CardHeader>
        <CardContent>
          <div className="relative space-y-3 overflow-x-hidden">
            <div className="grid w-full items-center gap-4">
              <Input
                placeholder="아이디를 입력하세요"
                value={id}
                onChange={(e) => {
                  setId(e.target.value);
                }}
              />
              <Input
                type="password"
                placeholder="비밀번호를 입력하세요"
                value={password}
                onChange={(e) => {
                  setPassword(e.target.value);
                }}
              />
              <Input
                type="password"
                placeholder="확인 비밀번호를 입력하세요"
                value={confirm}
                onChange={(e) => {
                  setConfirm(e.target.value);
                }}
              />
              <Input
                placeholder="이름을 입력하세요"
                value={name}
                onChange={(e) => {
                  setName(e.target.value);
                }}
              />
              <Input
                placeholder="전화번호를 입력하세요"
                value={phone}
                onChange={(e) => {
                  setPhone(e.target.value);
                }}
              />

              <Label>역할</Label>
              <Select
                onValueChange={(value) => {
                  setShowTutorForm(value === "회원");
                  setType(value);
                }}
                defaultValue={type}
                value={type}
              >
                <SelectTrigger>
                  <SelectValue placeholder="역할을 선택해주세요" />
                </SelectTrigger>

                <SelectContent>
                  <SelectItem value="member">회원</SelectItem>
                  <SelectItem value="tutor">강사</SelectItem>
                </SelectContent>
              </Select>

              {showTutorForm && (
                <>
                  <Label>강사</Label>
                  <Select
                    value={mainTutor}
                    defaultValue={mainTutor}
                    onValueChange={(value) => {
                      setMainTutor(value);
                    }}
                  >
                    <SelectTrigger>
                      <SelectValue placeholder="강사를 선택해주세요" />
                    </SelectTrigger>

                    <SelectContent>
                      <SelectItem value="이연지T">이연지T</SelectItem>
                      <SelectItem value="이은지T">이은지T</SelectItem>
                    </SelectContent>
                  </Select>
                </>
              )}
            </div>
          </div>
        </CardContent>
        <CardFooter className="flex justify-between">
          <Button variant="outline" onClick={onCancel}>
            취소
          </Button>
          <Button
            onClick={() => {
              onSubmit();
            }}
          >
            등록
          </Button>
        </CardFooter>
      </Card>
    </>
  );
}

 

 


 

KPT

Keep

뭐든 하기

Problem

시작을 힘들어 하는 것

Try

뭐든 시작해 보기

소감

zod를 한 번 써 보고 싶었는데 좋은 연습이었다.

React를 쓸 때 나만의 스타일이 생긴 것 같다. 

Form 태그의 필요성에 대해 고민해 봐야겠다. 

 

 

 

 

'verdantjuly > Today I Learned' 카테고리의 다른 글

TIL 20240501  (2) 2024.05.01
TIL 20240414  (0) 2024.04.14
TIL 20240406  (0) 2024.04.06
TIL 20240405  (0) 2024.04.06
TIL 20240404  (0) 2024.04.04