Skip to content

Commit

Permalink
Feat: #5 회원가입 페이지 생성 및 Validation 작성 (#37)
Browse files Browse the repository at this point in the history
* Feat: #5 회원가입 페이지 생성 및 마크업, CSS 스타일링

* Feat: #5 회원가입 입력 데이터 유효성 검사 기능 추가

* Design: #5 회원가입 페이지 스타일링 변경 및 프로필 이미지 설정 , 삭제 기능 추가

* Feat: #27 로그인 페이지 작성

* design: 수정된 회원가입 폼으로 UI 수정, 비밀번호 보이기 및 숨김 기능 추가

* Design: #27 수정된 로그인 폼으로 UI 수정

* Formatting: #5 유저관련폼 중복 처리 및 회원가입 폼 변수명 수정

* refactor: 공통 유효성 인증 input 컴포넌트 적용 및 회원가입 폼 디자인 수정사항 반영

* feat: 링크 갯수 제한 기능 추가

* UI: #5 로직에 따른 아이콘 등록 수정

* UI: #5 버튼 라운드 값 수정

* UI: #5 리뷰 반영 디자인 수정

* Chore: 정규식 수정 및 eslint 수정

* Refactor: #5 회원가입 폼에서 유효성 검증 규칙 분리

* Formatting: #5 타입 변수명 컨벤션 지정에 따른 타입 변수명 변경

* Feat: #5 비밀번호 정규식에 특수기호 추가

* UI: #5 필수 입력필드 체크 UI 수정

* UI: #5 input 필드에 sup 태그 적용 및 flex-grow -> grow 수정, form의 noValidate 속성 제거
  • Loading branch information
Yoonyesol authored Jul 9, 2024
1 parent f4acf7e commit 71521a3
Show file tree
Hide file tree
Showing 16 changed files with 634 additions and 11 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ module.exports = {
'import/extensions': 'off',
'jsx-a11y/no-noninteractive-element-interactions': 'warn',
'vitest/valid-title': 'off',
'jsx-a11y/label-has-associated-control': [
2,
{
labelAttributes: ['htmlFor'],
},
],
},
ignorePatterns: [
'dist',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"react-hook-form": "^7.51.4",
"react-icons": "^5.2.1",
"react-router-dom": "^6.23.1",
"tailwind-scrollbar-hide": "^1.1.7",
"zustand": "^4.5.2"
},
"devDependencies": {
Expand Down
8 changes: 8 additions & 0 deletions src/assets/auth_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions src/assets/social_google_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/assets/social_kakao_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 106 additions & 0 deletions src/components/common/ValidationInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useState } from 'react';
import { UseFormRegisterReturn } from 'react-hook-form';
import { RiEyeFill, RiEyeOffFill } from 'react-icons/ri';

/**
* ValidationInput 컴포넌트 params, 모든 params는 optional
*
* @params {string} [label] - 입력 필드의 label 텍스트
* @params {boolean} [required] - 입력 필드 필수 여부
* @params {string} [errors] - 유효성 검증 후 오류 발생 시 표시할 오류 메시지
* @params {UseFormRegisterReturn} [register] - react-hook-form의 resister 함수.
* register('password', {required: ...})부분을 그대로 파라미터에 넣으면 됩니다.
* @params {string} [type] - 입력 필드의 유형(ex: text, password). 기본값은 'text'
* @params {string} [placeholder] - 입력 필드의 placeholder 텍스트
* @params {boolean} [isButtonInput] - 버튼이 포함된 입력 필드인지 여부. 기본값은 'false'
* @params {React.ReactNode} [buttonLabel] - 버튼에 표시할 텍스트 또는 아이콘
* @params {() => void} [onButtonClick] - 버튼 클릭 시 호출할 함수
*
* 예시)
* <ValidationInput
label="비밀번호 확인"
errors={errors.checkPassword?.message}
register={register('checkPassword', {
required: '비밀번호를 한 번 더 입력해 주세요.',
validate: (value) => value === watch('password') || '비밀번호가 일치하지 않습니다.',
})}
type="password"
/>
*/

type ValidationInputProps = {
label?: string;
required?: boolean;
errors?: string;
register?: UseFormRegisterReturn;
type?: string;
placeholder?: string;
isButtonInput?: boolean;
buttonLabel?: React.ReactNode;
onButtonClick?: () => void;
};

export default function ValidationInput({
label,
required = true,
errors,
register,
type = 'text',
placeholder,
isButtonInput = false,
buttonLabel,
onButtonClick,
}: ValidationInputProps) {
const [showPassword, setShowPassword] = useState(false);

const handleTogglePassword = () => {
setShowPassword((prev) => !prev);
};

return (
<div>
<div className="flex flex-row gap-1">
{label && (
<label htmlFor={label} className="font-bold">
{label}
{required && <sup className="font-bold text-main">*</sup>}
</label>
)}
</div>
<div
className={`flex h-30 items-center rounded-lg border px-6 text-sm ${
errors ? 'border-2 border-error' : 'border-input'
}`}
>
<div className="flex h-full w-full flex-row items-center gap-8">
<input
id={label}
{...register}
type={type === 'password' && showPassword ? 'text' : type}
placeholder={placeholder}
className="h-full grow bg-inherit outline-none placeholder:text-default"
/>
{type === 'password' && (
<div className="flex h-20 w-20 items-center text-gray-400">
{showPassword ? (
<RiEyeFill className="h-15 w-15 cursor-pointer" onClick={handleTogglePassword} />
) : (
<RiEyeOffFill className="h-15 w-15 cursor-pointer" onClick={handleTogglePassword} />
)}
</div>
)}
{isButtonInput && (
<button
type="button"
className="flex h-20 w-75 items-center justify-center rounded bg-sub px-8 font-bold shadow-md"
onClick={onButtonClick}
>
{buttonLabel}
</button>
)}
</div>
</div>
{errors && <p className="mt-[.5rem] text-sm text-error">{errors}</p>}
</div>
);
}
Loading

0 comments on commit 71521a3

Please sign in to comment.