-
Notifications
You must be signed in to change notification settings - Fork 2
✨Feat: 로그인 폼 구현 #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨Feat: 로그인 폼 구현 #52
Conversation
Walkthrough로그인 페이지와 관련된 새로운 컴포넌트 및 훅이 도입되었습니다. 로그인 폼의 입력값 검증을 위한 스키마와 제출 로직이 추가되었으며, 로그아웃 시 인증 상태의 영구 저장소도 함께 초기화됩니다. 또한, 비활성화된 버튼 스타일을 위한 CSS 클래스가 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant LoginForm
participant useLoginSubmit
participant useAuth
participant Router
participant Toast
User->>LoginForm: 이메일/비밀번호 입력 후 제출
LoginForm->>useLoginSubmit: submit({ email, password })
useLoginSubmit->>useAuth: login(data)
alt 로그인 성공
useLoginSubmit->>Toast: 성공 메시지 표시
useLoginSubmit->>Router: /mydashboard로 이동
else 로그인 실패
useLoginSubmit->>Toast: 에러 메시지 표시
end
Possibly related PRs
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Walkthrough로그인 페이지와 관련된 주요 컴포넌트 및 훅이 새롭게 추가되었습니다. 로그인 폼의 유효성 검사, 제출 처리, 상태 관리, 스타일링 등이 구현되었으며, 로그아웃 시 영속 저장소도 초기화하도록 수정되었습니다. 로그인 폼의 입력 필드와 제출 버튼의 상태가 동적으로 반영됩니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant LoginForm
participant useLoginSubmit
participant useAuth
participant Router
participant Toast
User->>LoginForm: 이메일/비밀번호 입력
LoginForm->>useLoginSubmit: submit({email, password})
useLoginSubmit->>useAuth: login({email, password})
useAuth-->>useLoginSubmit: 로그인 결과 반환
alt 로그인 성공
useLoginSubmit->>Toast: 성공 메시지 표시
useLoginSubmit->>Router: /mydashboard로 이동
else 로그인 실패
useLoginSubmit->>Toast: 에러 메시지 표시
end
Possibly related PRs
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! ✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (6)
src/app/features/auth/hooks/useAuth.ts (1)
24-27: logout을 비동기화하고 스토리지 초기화 오류 처리 권장
persist.clearStorage()는 내부적으로localStorage.removeItem등을 호출하므로 I/O 오류가 발생할 여지가 있습니다. 함수 자체를async로 선언해 예외를 캐치하면 안정성이 증가합니다.- function logout() { - clearAuthState() - useAuthStore.persist.clearStorage() - } + async function logout() { + try { + clearAuthState() + await useAuthStore.persist.clearStorage() + } catch (e) { + // TODO: toast 또는 Sentry 로깅 + console.error('로그아웃 중 스토리지 제거 실패', e) + } + }src/app/features/auth/schemas/loginValidation.ts (1)
1-16: 검증 스키마 세분화 및 상수화 제안현재 스키마로도 동작에는 문제가 없지만, 아래와 같이 가독성과 재사용성을 높일 수 있습니다.
export const loginValidation = { email: { required: '이메일을 입력해 주세요.', pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '유효한 이메일 주소를 입력해주세요', }, + maxLength: { + value: 50, + message: '이메일은 50자 이하로 입력해주세요.', + }, }, password: { required: '비밀번호를 입력해 주세요.', minLength: { value: 8, message: '비밀번호는 최소 8자 이상이어야 합니다.', }, + maxLength: { + value: 30, + message: '비밀번호는 30자 이하로 입력해주세요.', + }, }, }
- 상수(e.g.,
EMAIL_MAX_LENGTH)로 분리하면 여러 스키마에서 재사용 가능- 패스워드에 추가적인 정규식(영문·숫자 혼합 등)을 적용할지 검토해 보세요.
src/app/(auth)/login/page.tsx (1)
5-10: 불필요한 Fragment 제거로 간결화 가능단일 컴포넌트만 반환하므로 React Fragment(
<>...</>) 없이 바로 반환해도 됩니다.export default function Login() { - return ( - <> - <LoginForm /> - </> - ) + return <LoginForm /> }src/app/features/auth/hooks/useLoginSubmit.ts (2)
12-24: 예외 로깅 및 메시지 보강을 권장합니다.
catch블록에서 토스트만 띄우고 예외를 별도로 기록하지 않아 디버깅이 어려울 수 있습니다. 콘솔 출력 또는 Sentry·LogRocket 같은 모니터링 툴로 예외를 전달하는 로직을 추가하면 운영 중 문제 추적이 한결 수월합니다.} catch (e: unknown) { if (axios.isAxiosError(e)) { const message = e.response?.data?.message toast.error(message ?? '로그인 실패') + console.error('Login failed:', e) // 혹은 모니터링 서비스 전송 } else { toast.error('알 수 없는 에러 발생') + console.error('Unknown login error:', e) } }
8-11:submit함수를useCallback으로 메모이제이션하면 재렌더 최적화에 도움이 됩니다.훅을 사용하는 컴포넌트가 빈번히 재렌더될 때마다
submit참조가 바뀌면, 이를 의존성으로 갖는 하위 컴포넌트에서 불필요한 렌더가 발생할 수 있습니다. 의존성이 고정이라면 한 번만 생성되도록 메모이제이션을 고려해 보세요.import { useAuth } from './useAuth' +import { useCallback } from 'react' export function useLoginSubmit() { const { login } = useAuth() const router = useRouter() - async function submit(data: LoginRequest) { + const submit = useCallback(async (data: LoginRequest) => { ... - } + }, [login, router]) return { submit } }Also applies to: 27-28
src/app/features/auth/components/LoginForm.tsx (1)
26-29:allFilled계산식을 간단·견고하게 개선할 수 있습니다.현재 구현은 잘 동작하지만, 불리언 변환을 명시적으로 해 주면 가독성과 안정성이 향상됩니다.
-const allFilled = watch.email?.trim() !== '' && watch.password?.trim() !== '' +const allFilled = !!watch.email?.trim() && !!watch.password?.trim()
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/app/(auth)/login/page.tsx(1 hunks)src/app/(auth)/signin/page.tsx(1 hunks)src/app/features/auth/components/LoginForm.tsx(1 hunks)src/app/features/auth/hooks/useAuth.ts(2 hunks)src/app/features/auth/hooks/useLoginSubmit.ts(1 hunks)src/app/features/auth/schemas/loginValidation.ts(1 hunks)src/app/globals.css(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/app/features/auth/hooks/useAuth.ts (1)
src/app/features/auth/store/useAuthStore.ts (1)
useAuthStore(5-20)
src/app/(auth)/login/page.tsx (1)
src/app/features/auth/components/LoginForm.tsx (1)
LoginForm(11-63)
src/app/features/auth/components/LoginForm.tsx (4)
src/app/features/auth/types/auth.type.ts (1)
LoginRequest(3-6)src/app/features/auth/hooks/useLoginSubmit.ts (1)
useLoginSubmit(8-28)src/app/features/auth/schemas/loginValidation.ts (1)
loginValidation(1-16)src/app/shared/lib/cn.ts (1)
cn(4-6)
🔇 Additional comments (1)
src/app/globals.css (1)
25-27: 버튼 비활성 색상 대비 비율 확인 필요
#9FA6B2배경에text-white(≈ #FFFFFF) 조합은 WCAG AA 기준(4.5 : 1)을 충족하지 못할 가능성이 큽니다. 작은 글씨(※ 버튼 라벨text-lg)에 적용될 때 접근성 경고가 발생할 수 있으니 실제 대비 비율을 확인하고 필요 시 더 어두운 색상으로 조정해 주세요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (8)
src/app/globals.css (1)
25-27: 비활성화 색상에 다크 모드 대응이 없습니다
.BG-blue,.BG-gray등 기존 유틸리티는 다크 모드를 함께 정의하고 있는데,.BG-blue-disabled는 라이트 모드 색상만 지정되어 있습니다. 다크 모드일 때 버튼이 어두운 배경에서 충분한 대비를 갖지 못할 수 있으므로 아래처럼 다크 변형을 포함하는 것이 좋겠습니다.-.BG-blue-disabled { - @apply cursor-not-allowed bg-[#9FA6B2]; -} +.BG-blue-disabled { + @apply cursor-not-allowed bg-[#9FA6B2] dark:bg-[#4B5563]; +}src/app/features/auth/schemas/loginValidation.ts (2)
1-8: 이메일 정규식 범위‧가독성 개선 제안현 정규식은 간단하지만 RFC5322 를 충분히 커버하지 못하고, 유지보수 관점에서도 한눈에 해석하기 어렵습니다.
zod·yup같은 검증 라이브러리를 사용하거나, 최소한 정규식을 상수로 분리해 의도를 명확히 하면 좋겠습니다.- value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, + // RFC5322 간략 버전 + value: /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/,
9-15: 패스워드 정책 상수화 및 재사용 고려
minLength: 8이 하드코딩되어 있어 향후 정책 변경 시 여러 곳을 수정해야 할 수 있습니다.const PASSWORD_MIN = 8형태로 상수화하거나 공통 validation util 로 분리하면 재사용성이 높아집니다.src/app/(auth)/login/page.tsx (1)
5-10: 불필요한 Fragment 제거로 코드 간소화루트가 단일 컴포넌트이므로 빈 fragment (
<>...</>) 는 필요 없습니다.-export default function Login() { - return ( - <> - <LoginForm /> - </> - ) -} +export default function Login() { + return <LoginForm /> +}src/app/features/auth/components/LoginForm.tsx (2)
25-30:useWatch사용 방식 최적화 필요
useWatch로 전체 폼 값을 감시하면서 매 렌더마다 객체가 새로 생성됩니다. 이는 다른 상태가 변해도 로그인 폼이 불필요하게 재렌더링되는 원인이 될 수 있습니다.
필요한 필드만 감시하거나useMemo로 계산값을 캐싱해 성능을 개선해 보세요.- const watch = useWatch({ control }) - const allFilled = watch.email?.trim() !== '' && watch.password?.trim() !== '' + const { email = '', password = '' } = useWatch({ + control, + name: ['email', 'password'], + }) ?? {} + const allFilled = email.trim() !== '' && password.trim() !== ''
43-47:autoComplete="off"→current-password권장
브라우저·패스워드 매니저가 비밀번호 저장/자동완성을 차단하지 않도록 표준 값인current-password를 사용해 주세요.- autoComplete="off" + autoComplete="current-password"src/app/features/auth/hooks/useLoginSubmit.ts (2)
14-17: 성공 후 라우팅 시replace사용 고려
router.push는 히스토리에 로그인 페이지를 남겨 ‘뒤로가기’ 시 다시 로그인 페이지로 돌아가는 UX 를 유발합니다. 로그인은 단발성 페이지이므로replace로 교체하는 편이 일반적입니다.- router.push('/mydashboard') + router.replace('/mydashboard')
18-24: 에러 메시지 파싱 로직 안전성 강화
e.response?.data구조가 API 스펙 변경으로 문자열·배열 등이 될 경우data.message접근에서 런타임 오류가 발생할 수 있습니다. 타입 가드 후 메시지를 문자열로 강제 변환하거나 기본 메시지로 대체하는 방어 코드가 필요합니다.- const message = e.response?.data?.message + const message = + typeof e.response?.data === 'object' && 'message' in (e.response?.data ?? {}) + ? String((e.response?.data as Record<string, unknown>).message) + : undefined
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/app/(auth)/login/page.tsx(1 hunks)src/app/(auth)/signin/page.tsx(1 hunks)src/app/features/auth/components/LoginForm.tsx(1 hunks)src/app/features/auth/hooks/useAuth.ts(2 hunks)src/app/features/auth/hooks/useLoginSubmit.ts(1 hunks)src/app/features/auth/schemas/loginValidation.ts(1 hunks)src/app/globals.css(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/app/(auth)/login/page.tsx (1)
src/app/features/auth/components/LoginForm.tsx (1)
LoginForm(11-63)
src/app/features/auth/hooks/useAuth.ts (1)
src/app/features/auth/store/useAuthStore.ts (1)
useAuthStore(5-20)
🔇 Additional comments (1)
src/app/features/auth/hooks/useAuth.ts (1)
24-27: persist 객체 존재 여부 확인 필요
useAuthStore.persist는zustand/middleware가 정상 적용돼야만 존재합니다. 미들웨어가 제거되거나 이름이 변경되면 런타임 오류가 발생합니다. 안전하게 optional chaining 을 사용하거나 예외 처리를 권장드립니다.- useAuthStore.persist.clearStorage() + useAuthStore.persist?.clearStorage()
dkslel1225
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
폼 구현 고생하셨습니다! 설명 덕분에 수월하게 읽을수 있었습니당⛄️
yuj2n
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인성님 로그인 폼 구현 수고하셨습니다~
이제 로그인으로 사용자 정보 받아오면 되는 걸까용?!
|
네네 해당 PR 머지 완료되면 가능합니다! api 동작이랑 사용자 정보가 zustand에 저장되는 거 확인 했고 만약 문제 있으면 편하게 말씀해주시면 될 거 같습니다! |
📌 변경 사항 개요
✨ 요약
📝 상세 내용
BG-blue-disabled커스텀 클래스 추가loginValidation
requiredpatternminLengthinput에 유효성 검사를 바로 집어넣지 않고 별도의 파일로 분리 했습니다.useLoginSubmit
LoginForm
useForm<LoginRequest>()mode: 'onChange'defaultValueshandleSubmitformStateerrorsisSubmittingcontrol🔗 관련 이슈
#47
🖼️ 스크린샷
✅ 체크리스트
💡 참고 사항
Summary by CodeRabbit
신규 기능
버그 수정
스타일
.BG-blue-disabledCSS 클래스가 추가되었습니다.기타