refactor: XKeypad 구현 롤백 및 일반 password input으로 변경
- XKeypad 관련 모든 코드 제거 - 일반 password input 필드로 복원 - 불필요한 ref, useEffect 제거 - select 요소 value 속성으로 변경 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useRef, useEffect, ChangeEvent } from 'react';
|
import { useState } from 'react';
|
||||||
import { PATHS } from '@/shared/constants/paths';
|
import { PATHS } from '@/shared/constants/paths';
|
||||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||||
import { HeaderType } from '@/entities/common/model/types';
|
import { HeaderType } from '@/entities/common/model/types';
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
import { useUserChangeCancelPasswordMutation } from '@/entities/user/api/use-user-change-cancel-password-mutation';
|
import { useUserChangeCancelPasswordMutation } from '@/entities/user/api/use-user-change-cancel-password-mutation';
|
||||||
import { useStore } from '@/shared/model/store';
|
import { useStore } from '@/shared/model/store';
|
||||||
import { XKeypad, XKeypadManager, createPasswordKeypad } from '@/utils/xkeypad';
|
import { snackBar } from '@/shared/lib/toast';
|
||||||
|
|
||||||
export const PasswordModifyCancelPasswordPage = () => {
|
export const PasswordModifyCancelPasswordPage = () => {
|
||||||
const { navigate } = useNavigate();
|
const { navigate } = useNavigate();
|
||||||
@@ -20,69 +20,20 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
const [mid, setMid] = useState<string>(userMid);
|
const [mid, setMid] = useState<string>(userMid);
|
||||||
const [password, setPassword] = useState<string>('');
|
const [password, setPassword] = useState<string>('');
|
||||||
const [confirmPassword, setConfirmPassword] = useState<string>('');
|
const [confirmPassword, setConfirmPassword] = useState<string>('');
|
||||||
const [isKeypadLoaded, setIsKeypadLoaded] = useState(false);
|
|
||||||
|
|
||||||
// Input refs for xkeypad
|
|
||||||
const passwordInputRef = useRef<HTMLInputElement>(null);
|
|
||||||
const confirmPasswordInputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
// XKeypad instances
|
|
||||||
const passwordKeypadRef = useRef<XKeypad | null>(null);
|
|
||||||
const confirmPasswordKeypadRef = useRef<XKeypad | null>(null);
|
|
||||||
|
|
||||||
// RSA Keys (실제 프로덕션에서는 서버에서 받아와야 함)
|
|
||||||
const RSA_MODULUS = "C4F7B39E2E93DB19C016C7A0C1C05B028A1D57CB9B91E13F5B7353F8FB5AC6CE6BE31ABEB8E8F7AD18B90C08F4EBC011A6A8FCE614EA879ED5B96296B969CE92923BC9BAD6FD87F00E08F529F93010EA77E40937BDAC1C866E79ACE2F2822A3ECD982F90532D5301CF90D9BF89E953A0593AB6C5F31E99B690DD582FB85F85A9";
|
|
||||||
const RSA_EXPONENT = "10001";
|
|
||||||
|
|
||||||
const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({
|
const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
// snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
||||||
// Clear form and keypads
|
// Clear form
|
||||||
setPassword('');
|
setPassword('');
|
||||||
setConfirmPassword('');
|
setConfirmPassword('');
|
||||||
if (passwordKeypadRef.current) passwordKeypadRef.current.clear();
|
|
||||||
if (confirmPasswordKeypadRef.current) confirmPasswordKeypadRef.current.clear();
|
|
||||||
if (passwordInputRef.current) passwordInputRef.current.value = '';
|
|
||||||
if (confirmPasswordInputRef.current) confirmPasswordInputRef.current.value = '';
|
|
||||||
// Navigate back
|
// Navigate back
|
||||||
navigate(PATHS.account.password.manage);
|
navigate(PATHS.account.password.manage);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
// snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Initialize XKeypad
|
|
||||||
useEffect(() => {
|
|
||||||
const initializeKeypad = async () => {
|
|
||||||
try {
|
|
||||||
const manager = XKeypadManager.getInstance({
|
|
||||||
modulus: RSA_MODULUS,
|
|
||||||
exponent: RSA_EXPONENT
|
|
||||||
});
|
|
||||||
|
|
||||||
await manager.loadScripts();
|
|
||||||
|
|
||||||
// RSA 키 설정을 명시적으로 다시 한번 수행
|
|
||||||
manager.setRSAPublicKey(RSA_MODULUS, RSA_EXPONENT);
|
|
||||||
|
|
||||||
setIsKeypadLoaded(true);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to load XKeypad:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
initializeKeypad();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// Cleanup keypads on unmount
|
|
||||||
if (passwordKeypadRef.current) {
|
|
||||||
passwordKeypadRef.current.destroy();
|
|
||||||
}
|
|
||||||
if (confirmPasswordKeypadRef.current) {
|
|
||||||
confirmPasswordKeypadRef.current.destroy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useSetHeaderTitle('거래취소 비밀번호 변경');
|
useSetHeaderTitle('거래취소 비밀번호 변경');
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
@@ -100,97 +51,10 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle password keypad
|
|
||||||
const handlePasswordKeypad = async () => {
|
|
||||||
if (!passwordInputRef.current || !isKeypadLoaded) return;
|
|
||||||
|
|
||||||
// Close other keypad if open
|
|
||||||
if (confirmPasswordKeypadRef.current) {
|
|
||||||
confirmPasswordKeypadRef.current.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or initialize password keypad
|
|
||||||
if (!passwordKeypadRef.current) {
|
|
||||||
passwordKeypadRef.current = createPasswordKeypad(passwordInputRef.current, {
|
|
||||||
keyType: 'qwertysmart',
|
|
||||||
viewType: 'half',
|
|
||||||
maxInputSize: 16,
|
|
||||||
useOverlay: true,
|
|
||||||
useModal: false,
|
|
||||||
hasPressEffect: true,
|
|
||||||
isE2E: false, // E2E 모드 비활성화
|
|
||||||
onInputChange: (length: number) => {
|
|
||||||
// Update password state as typing
|
|
||||||
if (passwordKeypadRef.current) {
|
|
||||||
const plainText = passwordKeypadRef.current.getPlainText();
|
|
||||||
console.log('passwordKeypadRef:', plainText, passwordInputRef.current?.value);
|
|
||||||
setPassword(plainText);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeypadClose: () => {
|
|
||||||
// Final update when keypad closes
|
|
||||||
if (passwordKeypadRef.current) {
|
|
||||||
const plainText = passwordKeypadRef.current.getPlainText();
|
|
||||||
setPassword(plainText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await passwordKeypadRef.current.initialize(passwordInputRef.current);
|
|
||||||
if (result !== 0) {
|
|
||||||
console.error('Failed to initialize password keypad');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle confirm password keypad
|
|
||||||
const handleConfirmPasswordKeypad = async () => {
|
|
||||||
if (!confirmPasswordInputRef.current || !isKeypadLoaded) return;
|
|
||||||
|
|
||||||
// Close other keypad if open
|
|
||||||
if (passwordKeypadRef.current) {
|
|
||||||
passwordKeypadRef.current.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or initialize confirm password keypad
|
|
||||||
if (!confirmPasswordKeypadRef.current) {
|
|
||||||
confirmPasswordKeypadRef.current = createPasswordKeypad(confirmPasswordInputRef.current, {
|
|
||||||
keyType: 'qwertysmart',
|
|
||||||
viewType: 'half',
|
|
||||||
maxInputSize: 16,
|
|
||||||
useOverlay: true,
|
|
||||||
useModal: false,
|
|
||||||
hasPressEffect: true,
|
|
||||||
isE2E: false, // E2E 모드 비활성화
|
|
||||||
onInputChange: (length: number) => {
|
|
||||||
// Update confirm password state as typing
|
|
||||||
if (confirmPasswordKeypadRef.current) {
|
|
||||||
const plainText = confirmPasswordKeypadRef.current.getPlainText();
|
|
||||||
console.log('confirmPasswordKeypadRef:', plainText, confirmPasswordInputRef.current?.value);
|
|
||||||
setConfirmPassword(plainText);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeypadClose: () => {
|
|
||||||
// Final update when keypad closes
|
|
||||||
if (confirmPasswordKeypadRef.current) {
|
|
||||||
const plainText = confirmPasswordKeypadRef.current.getPlainText();
|
|
||||||
setConfirmPassword(plainText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await confirmPasswordKeypadRef.current.initialize(confirmPasswordInputRef.current);
|
|
||||||
if (result !== 0) {
|
|
||||||
console.error('Failed to initialize confirm password keypad');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 저장 버튼 클릭 핸들러
|
// 저장 버튼 클릭 핸들러
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (!isFormValid()) return;
|
if (!isFormValid()) return;
|
||||||
|
|
||||||
// 평문 비밀번호 사용 (E2E 모드가 꺼져있으므로)
|
|
||||||
changeCancelPasswordMutation.mutate({
|
changeCancelPasswordMutation.mutate({
|
||||||
mid,
|
mid,
|
||||||
password: password
|
password: password
|
||||||
@@ -208,15 +72,15 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
<div className="ua-label">가맹점 <span className="red">*</span></div>
|
<div className="ua-label">가맹점 <span className="red">*</span></div>
|
||||||
<select
|
<select
|
||||||
className="wid-100"
|
className="wid-100"
|
||||||
value={ mid }
|
value={mid}
|
||||||
onChange={ (e: ChangeEvent<HTMLSelectElement>) => setMid(e.target.value) }
|
onChange={(e) => setMid(e.target.value)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
midOptions.map((value, index) => (
|
midOptions.map((value) => (
|
||||||
<option
|
<option
|
||||||
key={ value.value }
|
key={value.value}
|
||||||
value={ value.value }
|
value={value.value}
|
||||||
>{ value.name }</option>
|
>{value.name}</option>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
@@ -224,27 +88,21 @@ export const PasswordModifyCancelPasswordPage = () => {
|
|||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">변경 비밀번호 <span className="red">*</span></div>
|
<div className="ua-label">변경 비밀번호 <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
ref={passwordInputRef}
|
|
||||||
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="클릭하여 비밀번호 입력"
|
placeholder="비밀번호를 입력하세요"
|
||||||
value={password}
|
value={password}
|
||||||
onClick={handlePasswordKeypad}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
readOnly
|
|
||||||
style={{ cursor: 'pointer' }}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ua-row">
|
<div className="ua-row">
|
||||||
<div className="ua-label">변경 비밀번호 재입력 <span className="red">*</span></div>
|
<div className="ua-label">변경 비밀번호 재입력 <span className="red">*</span></div>
|
||||||
<input
|
<input
|
||||||
ref={confirmPasswordInputRef}
|
|
||||||
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
className={`wid-100 ${confirmPassword && password !== confirmPassword ? 'error' : ''}`}
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="클릭하여 비밀번호 재입력"
|
placeholder="비밀번호를 다시 입력하세요"
|
||||||
value={confirmPassword}
|
value={confirmPassword}
|
||||||
onClick={handleConfirmPasswordKeypad}
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||||
readOnly
|
|
||||||
style={{ cursor: 'pointer' }}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{confirmPassword && password !== confirmPassword && (
|
{confirmPassword && password !== confirmPassword && (
|
||||||
|
|||||||
Reference in New Issue
Block a user