비밀번호 변경 기능 개선 및 검증 강화
- 비밀번호 변경 페이지에 확인 Dialog 추가 (로그인/거래취소) - 비밀번호 에러 코드별 상세 메시지 처리 * INVALID_PASSWORD, UPDATE_PASSWORD_FAIL, PREVIOUS_PASSWORD * MERCHANT_INFO_MATCH_PASSWORD, PASSWORD_LENGHT * DISALLOWED_CHARACTERS_INCLUDED, DISALLOWED_WHITE_SPACE * NOT_ENOUGH_COMPLEXITY, REPEATED_CHARACTER_SEQUENCE * COMMON_PASSWORD_DETECTED - 비밀번호 입력 검증 로직 통합 (validatePassword) - 이메일/전화번호 마스킹 기능 추가 - 사용자 추가 페이지 에러 처리 개선 - 다국어 메시지 추가 (한국어/영어) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { snackBar } from '@/shared/lib/toast';
|
||||
import { checkGrant } from '@/shared/lib/check-grant';
|
||||
import { showAlert } from '@/widgets/show-alert';
|
||||
import { maskEmail, maskPhoneNumber } from '@/shared/lib/masking';
|
||||
|
||||
export const UserLoginAuthInfoWrap = ({
|
||||
mid,
|
||||
@@ -417,7 +418,7 @@ export const UserLoginAuthInfoWrap = ({
|
||||
<div className="input-row" key={`existing-email-${index}`}>
|
||||
<input
|
||||
type="email"
|
||||
value={email.content}
|
||||
value={maskEmail(email.content)}
|
||||
placeholder="example@domain.com"
|
||||
readOnly
|
||||
/>
|
||||
@@ -430,24 +431,35 @@ export const UserLoginAuthInfoWrap = ({
|
||||
></button>
|
||||
</div>
|
||||
))}
|
||||
{newEmails.map((email, index) => (
|
||||
<div className="input-row" key={`new-email-${index}`}>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
placeholder="example@domain.com"
|
||||
onChange={(e) => handleNewEmailChange(index, e.target.value)}
|
||||
readOnly={readOnlyEmails.has(index) || index !== editableEmailIndex}
|
||||
/>
|
||||
<button
|
||||
className="icon-btn minus"
|
||||
type="button"
|
||||
aria-label={t('common.delete')}
|
||||
onClick={() => handleRemoveNewEmail(index)}
|
||||
disabled={!isDeleteButtonEnabled()}
|
||||
></button>
|
||||
</div>
|
||||
))}
|
||||
{newEmails.map((email, index) => {
|
||||
const isReadOnly = readOnlyEmails.has(index) || index !== editableEmailIndex;
|
||||
const displayValue = isReadOnly && email ? maskEmail(email) : email;
|
||||
|
||||
return (
|
||||
<div className="input-row" key={`new-email-${index}`}>
|
||||
<input
|
||||
type="email"
|
||||
value={displayValue}
|
||||
placeholder="example@domain.com"
|
||||
onChange={(e) => handleNewEmailChange(index, e.target.value)}
|
||||
onFocus={() => setEditableEmailIndex(index)}
|
||||
onBlur={() => {
|
||||
if (email && isValidEmail(email)) {
|
||||
setEditableEmailIndex(-1);
|
||||
}
|
||||
}}
|
||||
readOnly={isReadOnly}
|
||||
/>
|
||||
<button
|
||||
className="icon-btn minus"
|
||||
type="button"
|
||||
aria-label={t('common.delete')}
|
||||
onClick={() => handleRemoveNewEmail(index)}
|
||||
disabled={!isDeleteButtonEnabled()}
|
||||
></button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="group">
|
||||
@@ -465,7 +477,7 @@ export const UserLoginAuthInfoWrap = ({
|
||||
<div className="input-row" key={`existing-phone-${index}`}>
|
||||
<input
|
||||
type="tel"
|
||||
value={phone.content}
|
||||
value={maskPhoneNumber(phone.content)}
|
||||
placeholder={t('account.enterPhoneNumber')}
|
||||
readOnly
|
||||
/>
|
||||
@@ -478,24 +490,35 @@ export const UserLoginAuthInfoWrap = ({
|
||||
></button>
|
||||
</div>
|
||||
))}
|
||||
{newPhones.map((phone, index) => (
|
||||
<div className="input-row" key={`new-phone-${index}`}>
|
||||
<input
|
||||
type="tel"
|
||||
value={phone}
|
||||
placeholder={t('account.enterPhoneNumber')}
|
||||
onChange={(e) => handleNewPhoneChange(index, e.target.value)}
|
||||
readOnly={readOnlyPhones.has(index) || index !== editablePhoneIndex}
|
||||
/>
|
||||
<button
|
||||
className="icon-btn minus"
|
||||
type="button"
|
||||
aria-label={t('common.delete')}
|
||||
onClick={() => handleRemoveNewPhone(index)}
|
||||
disabled={!isDeleteButtonEnabled()}
|
||||
></button>
|
||||
</div>
|
||||
))}
|
||||
{newPhones.map((phone, index) => {
|
||||
const isReadOnly = readOnlyPhones.has(index) || index !== editablePhoneIndex;
|
||||
const displayValue = isReadOnly && phone ? maskPhoneNumber(phone) : phone;
|
||||
|
||||
return (
|
||||
<div className="input-row" key={`new-phone-${index}`}>
|
||||
<input
|
||||
type="tel"
|
||||
value={displayValue}
|
||||
placeholder={t('account.enterPhoneNumber')}
|
||||
onChange={(e) => handleNewPhoneChange(index, e.target.value)}
|
||||
onFocus={() => setEditablePhoneIndex(index)}
|
||||
onBlur={() => {
|
||||
if (phone && isValidPhone(phone)) {
|
||||
setEditablePhoneIndex(-1);
|
||||
}
|
||||
}}
|
||||
readOnly={isReadOnly}
|
||||
/>
|
||||
<button
|
||||
className="icon-btn minus"
|
||||
type="button"
|
||||
aria-label={t('common.delete')}
|
||||
onClick={() => handleRemoveNewPhone(index)}
|
||||
disabled={!isDeleteButtonEnabled()}
|
||||
></button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="notice-bar">{t('account.tabChangeResetNotice')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user