본문 바로가기

Today I Learned (TIL)

24.01.20

728x90
반응형

회원 가입시에 유효성 검사가 많이 없어 추가로 몇가지 구현했습니다

import React, { useState } from 'react';
import { supabase } from 'shared/supabase';
import { Link, useNavigate } from 'react-router-dom';
import { StyledSignup, StyledForm, StyledInput, StyledButton, StyledH1, StyledLabel } from './styles';
interface FormData {
  email: string;
  password: string;
  displayName: string;
}

const isValidConfirmPassword = (password: string, confirmPassword: string) => {
  // 비밀번호 확인 검사
  return password === confirmPassword;
};

const isValidEmail = (email: string) => {
  // 이메일 형식 검사
  const re =
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(String(email).toLowerCase());
};

const isValidPassword = (password: string) => {
  // 비밀번호 길이 검사
  return password.length >= 6;
};

const isValidDisplayName = (displayName: string) => {
  // 닉네임 길이 검사
  return displayName.length >= 2 && displayName.length <= 10;
};

function Signup() {
  const navigate = useNavigate();

  const [confirmPassword, setConfirmPassword] = useState('');

  const [formData, setFormData] = useState<FormData>({
    email: '',
    password: '',
    displayName: ''
  });

  const [errors, setErrors] = useState<Record<string, string>>({});

  const handleConfirmPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 비밀번호 확인 변경 핸들러
    setConfirmPassword(e.target.value);
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value
    });
  };

  const handleSignup = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    if (!isValidEmail(formData.email)) {
      alert('유효한 이메일 형식이 아닙니다.');
      return;
    }

    if (!isValidPassword(formData.password)) {
      alert('비밀번호는 최소 6자리 이상이어야 합니다.');
      return;
    }

    if (!isValidConfirmPassword(formData.password, confirmPassword)) {
      alert('비밀번호와 비밀번호 확인이 일치하지 않습니다.');
      return;
    }

    if (!isValidDisplayName(formData.displayName)) {
      alert('닉네임은 최소 2자리, 최대 10자리로 작성해주세요.');
      return;
    }

    try {
      const { data, error } = await supabase.auth.signUp({
        email: formData.email,
        password: formData.password,
        options: {
          data: {
            displayName: formData.displayName
          }
        }
      });
      if (error) {
        console.error(error.name);
        alert('중복된 이메일 입니다 다른 이메일을 사용해주세요');
      }
      if (error) {
        console.error(error);
        alert('ID와 password를 확인해주세요');
      } else {
        console.log(data);
        alert('회원가입을 환영합니다');
        navigate('/login');
      }
    } catch (error) {
      console.error(error);
      alert('An error occurred during signup');
    }
  };

  return (
    <StyledSignup>
      <StyledH1>회원 가입</StyledH1>
      <StyledForm onSubmit={handleSignup}>
        {/* <div>
          <label htmlFor="displayname">이메일</label>
          <input type="displayname" id="displayname" name="displayname" value={formData.displayname} onChange={handleChange} />
          {errors.displayname && <p>{errors.displayname}</p>}
        </div> */}
        <StyledLabel htmlFor="email">이메일</StyledLabel>
        <StyledInput
          placeholder="이메일"
          type="email"
          id="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
        />
        {errors.email && <p>{errors.email}</p>}

        <StyledLabel htmlFor="password">비밀번호</StyledLabel>
        <StyledInput
          placeholder="비밀번호"
          type="password"
          id="password"
          name="password"
          value={formData.password}
          onChange={handleChange}
        />
        {errors.password && <p>{errors.password}</p>}

        <StyledLabel htmlFor="confirmPassword">비밀번호 확인</StyledLabel>
        <StyledInput
          placeholder="비밀번호 확인"
          type="password"
          id="confirmPassword"
          name="confirmPassword"
          value={confirmPassword}
          onChange={handleConfirmPasswordChange}
        />
        {errors.confirmPassword && <p>{errors.confirmPassword}</p>}

        <StyledLabel htmlFor="displayName">닉네임</StyledLabel>
        <StyledInput
          placeholder="닉네임"
          type="text"
          id="displayName"
          name="displayName"
          value={formData.displayName}
          onChange={handleChange}
        />
        {errors.displayName && <p>{errors.displayName}</p>}

        <StyledButton type="submit">가입하기</StyledButton>
      </StyledForm>

      <Link to="/login">
        <StyledButton>로그인 하러 가기</StyledButton>
      </Link>
    </StyledSignup>
  );
}

export default Signup;
 

수파베이스 signup error 중에 error.name 가 중복 이메일 오류 더군요.튜터님이 유효성 검사를 좀더

세분화 해서 알려줬으면 한다는 피드백이있어 따로 분리해서 alert을 만들었습니다

이렇게 4가지 종류가 더있는데 그냥 error 해놓아도 다 잡긴하지만

ux를 위해서라면 나머지 error.cause error.message error.stack error.status

각 오류마다 따로 alert을 만들어 놓아도 좋을거같습니다

 

디자이너분이 만들어주신대로 바꿔봤습니다

 

왼쪽은 일단 기능 만들때 대충 만든거였고 오른쪽은 원래 피그마 디자인 처럼 제대로 만들어봤습니다

역시 디자이너....!

import React, { useState } from 'react';
import { supabase } from 'shared/supabase';
import { Link, useNavigate } from 'react-router-dom';
import { StyledSignup, StyledForm, StyledInput, StyledButton, StyledH1, StyledLabel, StInputGroup } from './styles';
interface FormData {
  email: string;
  password: string;
  displayName: string;
}

const isValidPassword = (password: string) => {
  // 비밀번호 유효성 검사: 8~16자 영문, 숫자, 특수문자를 조합
  const regex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,16}$/;
  return regex.test(password);
};
const isValidConfirmPassword = (password: string, confirmPassword: string) => {
  // 비밀번호 확인 검사
  return password === confirmPassword;
};

const isValidEmail = (email: string) => {
  // 이메일 형식 검사
  const re =
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(String(email).toLowerCase());
};

const isValidPasswordlength = (password: string) => {
  // 비밀번호 길이 검사
  return password.length >= 8;
};

const isValidDisplayName = (displayName: string) => {
  // 닉네임 길이 검사
  return displayName.length >= 2 && displayName.length <= 10;
};

function Signup() {
  const navigate = useNavigate();
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');

  const [formData, setFormData] = useState<FormData>({
    email: '',
    password: '',
    displayName: ''
  });

  const [errors, setErrors] = useState<Record<string, string>>({});

  const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setPassword(e.target.value);
  };

  const handleConfirmPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 비밀번호 확인 변경 핸들러
    setConfirmPassword(e.target.value);
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value
    });
  };

  const handleSignup = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    if (!isValidEmail(formData.email)) {
      alert('유효한 이메일 형식이 아닙니다.');
      return;
    }
    if (!isValidPassword(formData.password)) {
      alert('비밀번호는 8자 이상이며, 영문, 숫자, 특수문자를 모두 포함해야 합니다.');
      return;
    }

    if (!isValidPasswordlength(formData.password)) {
      alert('비밀번호는 최소 8자리 이상이어야 합니다.');
      return;
    }

    if (!isValidConfirmPassword(formData.password, confirmPassword)) {
      alert('비밀번호와 비밀번호 확인이 일치하지 않습니다.');
      return;
    }

    if (!isValidDisplayName(formData.displayName)) {
      alert('닉네임은 최소 2자리, 최대 6자리로 작성해주세요.');
      return;
    }

    try {
      const { data, error } = await supabase.auth.signUp({
        email: formData.email,
        password: formData.password,
        options: {
          data: {
            displayName: formData.displayName
          }
        }
      });
      if (error) {
        console.error(error.name);
        alert('중복된 이메일 입니다 다른 이메일을 사용해주세요');
      }
      if (error) {
        console.error(error);
        alert('ID와 password를 확인해주세요');
      } else {
        console.log(data);
        alert('회원가입을 환영합니다');
        navigate('/login');
      }
    } catch (error) {
      console.error(error);
      alert('An error occurred during signup');
    }
  };

  return (
    <StyledSignup>
      <StyledH1>회원 가입</StyledH1>
      <StyledForm onSubmit={handleSignup}>
        <StInputGroup>
          {' '}
          <StyledLabel htmlFor="displayName">닉네임</StyledLabel>
          <StyledInput
            placeholder="사용할 닉네임을 적어주세요."
            type="text"
            id="displayName"
            name="displayName"
            value={formData.displayName}
            onChange={handleChange}
          />
          {errors.displayName && <p>{errors.displayName}</p>}
        </StInputGroup>

        <StInputGroup>
          <StyledLabel htmlFor="email">이메일</StyledLabel>
          <StyledInput
            placeholder="이메일을 입력해 주세요."
            type="email"
            id="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
          />
          {errors.email && <p>{errors.email}</p>}
        </StInputGroup>
        <StInputGroup>
          <StyledLabel htmlFor="password">비밀번호</StyledLabel>
          <StyledInput
            placeholder="비밀번호를 입력해 주세요."
            type="password"
            id="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
          />
          {errors.password && <p>{errors.password}</p>}
          <StyledLabel htmlFor="password">8~16자 영문, 숫자, 특수문자를 조합해 주세요.</StyledLabel>
        </StInputGroup>
        <StInputGroup>
          <StyledLabel htmlFor="confirmPassword">비밀번호 확인</StyledLabel>
          <StyledInput
            placeholder="비밀번호 확인"
            type="password"
            id="confirmPassword"
            name="confirmPassword"
            value={confirmPasswo
 

유효성 검사를 몇가지 더 추가했는데 정규식은 검색해서 쓰는게 편한거같습니다

728x90
반응형