From 54c84dbc87305ffb9d1b57cf3a2c879f446f26c5 Mon Sep 17 00:00:00 2001 From: geonhee-min Date: Wed, 3 Dec 2025 10:13:37 +0900 Subject: [PATCH] =?UTF-8?q?issue=20#=20Enter=ED=82=A4=20=EB=8F=99=EC=9E=91?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/form/login.schema.ts | 11 ++++++- src/data/form/resetPassword.schema.ts | 4 +-- src/data/form/signup.schema.ts | 7 ++++- src/ui/page/account/login/LoginPage.tsx | 14 ++++++++- .../resetPassword/ResetPasswordPage.tsx | 29 ++++++++++++------- src/util/Validator.ts | 3 +- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/data/form/login.schema.ts b/src/data/form/login.schema.ts index 02dfcb7..cd6cab8 100644 --- a/src/data/form/login.schema.ts +++ b/src/data/form/login.schema.ts @@ -1,11 +1,20 @@ +import { Validator } from '@/util/Validator'; import * as z from 'zod'; export const LoginSchema = z.object({ id: z .string() + .refine((val) => { + if (val.includes('@')) { + return Validator.isEmail(val);; + } + return true; + }, { + message: "이메일 형식이 올바르지 않습니다." + }) , password: z .string() .min(8, "비밀번호는 8-12 자리여야 합니다.") .max(12, "비밀번호는 8-12 자리여야 합니다.") - .regex(/^[a-z](?=.*[0-9])(?=.*[!@#$]).*$/, "비밀번호는 영소문자로 시작하여 숫자, 특수문자(!@#$)를 한 개 이상 포함하여야 합니다.") + .regex(/^(?=.*[0-9])(?=.*[!@#$%^])[a-zA-Z0-9!@#$%^]+$/, "비밀번호는 영소문자로 시작하여 숫자, 특수문자(!@#$)를 한 개 이상 포함하여야 합니다.") }); \ No newline at end of file diff --git a/src/data/form/resetPassword.schema.ts b/src/data/form/resetPassword.schema.ts index 6b6387f..bedde81 100644 --- a/src/data/form/resetPassword.schema.ts +++ b/src/data/form/resetPassword.schema.ts @@ -6,12 +6,12 @@ export const ResetPasswordSchema = z.object({ , code: z .string() .length(8) - .regex(/^[a-z](?=.*[0-9])(?=.*[!@#$%^]).*$/, "영소문자로 시작하고 숫자와 특수문자(!@#$%^)를 포함해야 합니다.") + .regex(/^(?=.*[0-9])(?=.*[!@#$%^])[a-zA-Z0-9!@#$%^]+$/, "영소문자로 시작하고 숫자와 특수문자(!@#$%^)를 포함해야 합니다.") , password: z .string() .min(8, "비밀번호는 8-12 자리여야 합니다.") .max(12, "비밀번호는 8-12 자리여야 합니다.") - .regex(/^[a-z](?=.*[0-9])(?=.*[!@#$%^]).*$/, "영소문자로 시작하고 숫자와 특수문자(!@#$%^)를 포함해야 합니다.") + .regex(/^(?=.*[0-9])(?=.*[!@#$%^])[a-zA-Z0-9!@#$%^]+$/, "영소문자로 시작하고 숫자와 특수문자(!@#$%^)를 포함해야 합니다.") , passwordConfirm: z .string() }) diff --git a/src/data/form/signup.schema.ts b/src/data/form/signup.schema.ts index eb52cf4..5b570a1 100644 --- a/src/data/form/signup.schema.ts +++ b/src/data/form/signup.schema.ts @@ -4,6 +4,11 @@ export const SignUpSchema = z.object({ accountId: z .string() .min(5, "아이디는 5 자리 이상이어야 합니다.") + .refine((val) => { + return /^[a-zA-z-_.]*$/.test(val); + }, { + message: "영문, 숫자, '- _ .' 를 제외한 문자를 사용할 수 없습니다." + }) , email: z .string() .min(5, "이메일을 입력해주십시오.") @@ -11,7 +16,7 @@ export const SignUpSchema = z.object({ .string() .min(8, "비밀번호는 8-12 자리여야 합니다.") .max(12, "비밀번호는 8-12 자리여야 합니다.") - .regex(/^[a-z](?=.*[0-9])(?=.*[!@#$%^]).*$/, "영소문자로 시작하고 숫자와 특수문자(!@#$%^)를 포함해야 합니다.") + .regex(/^(?=.*[0-9])(?=.*[!@#$%^])[a-zA-Z0-9!@#$%^]+$/, "영소문자로 시작하고 숫자와 특수문자(!@#$%^)를 포함해야 합니다.") , name: z .string() .min(1, "이름을 입력해주시십시오.") diff --git a/src/ui/page/account/login/LoginPage.tsx b/src/ui/page/account/login/LoginPage.tsx index 9f262b3..3e54176 100644 --- a/src/ui/page/account/login/LoginPage.tsx +++ b/src/ui/page/account/login/LoginPage.tsx @@ -4,7 +4,7 @@ import { Field, FieldError, FieldLabel } from '@/components/ui/field'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useCallback, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; import { PageRouting } from '@/const/PageRouting'; @@ -98,6 +98,13 @@ export default function LoginPage() { ) } + const handleEnterKeyDown = async (e: React.KeyboardEvent) => { + if (!(e.key === 'Enter')) return; + const result = await loginForm.trigger(); + if (!result) return; + await reqLogin(); + } + return (
@@ -117,6 +124,8 @@ export default function LoginPage() { type="text" id="form-login-id" aria-invalid={fieldState.invalid} + tabIndex={1} + onKeyDown={handleEnterKeyDown} /> @@ -134,6 +143,7 @@ export default function LoginPage() { className="p-0 bg-transparent hover:bg-transparent h-fit w-fit text-xs text-gray-400 hover:text-gray-500 cursor-pointer" onClick={moveToResetPasswordPage} type="button" + tabIndex={3} > 비밀번호를 잊으셨습니까? @@ -143,6 +153,8 @@ export default function LoginPage() { type="password" id="form-login-password" aria-invalid={fieldState.invalid} + tabIndex={2} + onKeyDown={handleEnterKeyDown} /> diff --git a/src/ui/page/account/resetPassword/ResetPasswordPage.tsx b/src/ui/page/account/resetPassword/ResetPasswordPage.tsx index 804dae5..1e17bf0 100644 --- a/src/ui/page/account/resetPassword/ResetPasswordPage.tsx +++ b/src/ui/page/account/resetPassword/ResetPasswordPage.tsx @@ -4,7 +4,7 @@ import { Field, FieldError, FieldLabel } from '@/components/ui/field'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useState, useCallback } from 'react'; +import React, { useState, useCallback } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; import { PageRouting } from '@/const/PageRouting'; @@ -122,7 +122,7 @@ export default function ResetPasswordPage() { } } - const handleThirdStepButton = async () => { + const handleClickThirdStepButton = async () => { if (isLoading) return; const passwordValid = await resetPasswordForm.trigger('password'); if (!passwordValid) return; @@ -159,6 +159,19 @@ export default function ResetPasswordPage() { } + const handleEnterKeyDown = async (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + e.preventDefault(); + if (currentStep === 1) { + await handleClickFirstStepButton(); + return; + } + if (currentStep === 3) { + await handleClickThirdStepButton(); + } + } + } + return ( { - if (e.key === 'Enter') { - e.preventDefault(); - if (email.length === 0) return; - handleClickFirstStepButton(); - } - }} + onKeyDown={handleEnterKeyDown} /> @@ -275,6 +282,7 @@ export default function ResetPasswordPage() { type={ showPassword ? "text" : "password" } id="reset-password-password" aria-invalid={fieldState.invalid} + onKeyDown={handleEnterKeyDown} className="pr-10" /> diff --git a/src/util/Validator.ts b/src/util/Validator.ts index 6ca4bf6..372addd 100644 --- a/src/util/Validator.ts +++ b/src/util/Validator.ts @@ -7,7 +7,8 @@ export class Validator { static validatePasswordFormat = (password: string): boolean => { if (password.length < 8) return false; - + if (password.includes(' ')) return false; + const alphabets = 'abcdefghijklmnopqrstuvwxyz'; const numbers = '0123456789'; const specials = '!@#$%^';