Skip to content

Commit

Permalink
chore : change PinAuthModal
Browse files Browse the repository at this point in the history
  • Loading branch information
0xC0FFE2 committed Jan 21, 2025
1 parent 8df6095 commit 2f209df
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 39 deletions.
14 changes: 8 additions & 6 deletions src/components/auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ interface LoginFormProps {
rememberMe: boolean;
};
onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onAppLogin: () => void; // APP 간편인증 로그인 함수
onPinSubmit: (pin: string, captchaToken: string) => void; // PIN 인증 로그인 함수
onAppLogin: () => void;
onPinSubmit: (pin: string, captchaToken: string) => void;
isLoading: boolean;
error: string | null;
isPinModalOpen: boolean;
Expand Down Expand Up @@ -92,15 +92,17 @@ const LoginForm: React.FC<LoginFormProps> = ({
<div className="flex justify-between space-x-3 pt-4">
<button
type="button"
onClick={onAppLogin} // 여기에서 APP 간편인증 로그인 호출
onClick={onAppLogin}
className="w-[48%] bg-blue-600 text-white py-3 rounded hover:bg-blue-700 transition-colors disabled:bg-blue-300"
disabled={isLoading}
>
{isLoading ? "처리중..." : "APP 간편인증 로그인"}
</button>
<button
type="button"
onClick={() => setIsPinModalOpen(true)} // PIN 인증 로그인 모달 여는 버튼
onClick={() => {
setIsPinModalOpen(true);
}}
className="w-[48%] bg-blue-600 text-white py-3 rounded hover:bg-blue-700 transition-colors disabled:bg-blue-300"
disabled={isLoading}
>
Expand All @@ -122,8 +124,8 @@ const LoginForm: React.FC<LoginFormProps> = ({
<PinAuthModal
isOpen={isPinModalOpen}
onClose={() => setIsPinModalOpen(false)}
onSubmit={onPinSubmit} // PIN 인증 처리
onCaptchaChange={onCaptchaChange} // 리캡챠 토큰 변경시 호출
onSubmit={onPinSubmit}
onCaptchaChange={onCaptchaChange}
/>
</div>
</div>
Expand Down
56 changes: 33 additions & 23 deletions src/components/auth/PinAuthModal.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import ReCAPTCHA from "react-google-recaptcha";
import VirtualKeypad from "./VirtualKeypad";

interface PinAuthModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (pin: string, captchaToken: string) => void;
onCaptchaChange: (newToken: string) => void; // 추가된 부분
onCaptchaChange: (newToken: string) => void;
}

const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit, onCaptchaChange }) => {
const [step, setStep] = useState<'captcha' | 'pin'>('captcha');
const PinAuthModal: React.FC<PinAuthModalProps> = ({
isOpen,
onClose,
onSubmit,
onCaptchaChange,
}) => {
const [step, setStep] = useState<"captcha" | "pin">("captcha");
const [recaptchaToken, setRecaptchaToken] = useState<string | null>(null);
const [pin, setPin] = useState<string>('');
const [pin, setPin] = useState<string>("");
const [captchaExpired, setCaptchaExpired] = useState<boolean>(false);

const handleRecaptchaChange = (token: string | null) => {
if (token) {
setRecaptchaToken(token);
onCaptchaChange(token); // 부모 컴포넌트로 토큰 전달
setStep('pin');
onCaptchaChange(token);
setStep("pin");
setCaptchaExpired(false);
} else {
setRecaptchaToken(null);
Expand All @@ -29,22 +34,22 @@ const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit,

const handleKeyPress = (key: string) => {
if (pin.length < 6) {
setPin(prev => prev + key);
setPin((prev) => prev + key);
}
};

const handleDelete = () => {
setPin(prev => prev.slice(0, -1));
setPin((prev) => prev.slice(0, -1));
};

const handleClear = () => {
setPin('');
setPin("");
};

const handleSubmit = () => {
if (pin.length === 6 && recaptchaToken) {
onSubmit(pin, recaptchaToken);
setPin('');
setPin("");
onClose();
}
};
Expand All @@ -54,12 +59,13 @@ const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit,
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div className="bg-white rounded-2xl p-6 w-[400px] max-w-[90vw]">
{step === 'captcha' ? (
{step === "captcha" ? (
<div className="space-y-6">
<div className="text-center">
<h2 className="text-xl font-semibold mb-2">보안 인증</h2>
<p className="text-gray-600 text-sm mb-6">
NANU ID 앱을 설치하면 불필요한 캡챠 인증을 생략하고<br />
NANU ID 앱을 설치하면 불필요한 캡챠 인증을 생략하고
<br />
빠르게 로그인할 수 있습니다
</p>
</div>
Expand All @@ -86,18 +92,22 @@ const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit,
<div className="space-y-6">
<div className="text-center">
<h2 className="text-xl font-semibold mb-2">PIN 입력</h2>
<p className="text-gray-600 text-sm">6자리 PIN 번호를 입력해주세요</p>
<p className="text-gray-600 text-sm">
6자리 PIN 번호를 입력해주세요
</p>
</div>

<div className="flex justify-center space-x-2">
{Array(6).fill(0).map((_, i) => (
<div
key={i}
className="w-10 h-12 border-2 rounded-lg flex items-center justify-center"
>
{pin[i] ? '•' : ''}
</div>
))}
{Array(6)
.fill(0)
.map((_, i) => (
<div
key={i}
className="w-10 h-12 border-2 rounded-lg flex items-center justify-center"
>
{pin[i] ? "•" : ""}
</div>
))}
</div>

<VirtualKeypad
Expand Down
6 changes: 2 additions & 4 deletions src/components/auth/VirtualKeypad.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,15 @@ const VirtualKeypad: React.FC<VirtualKeypadProps> = ({
"0",
];

// Fisher-Yates Shuffle 알고리즘을 사용하여 숫자들만 랜덤 섞기
useEffect(() => {
const shuffled = [...numbers];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; // swap
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
setShuffledNumbers(shuffled);
}, []); // 컴포넌트가 처음 렌더링될 때 한 번만 실행
}, []);

// 최종 배열에 숫자와 clear, delete 버튼 추가
const finalKeys = [...shuffledNumbers, "clear", "delete"];

return (
Expand Down
30 changes: 24 additions & 6 deletions src/pages/mobile/MobileLoginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import MobileContainer from "../../components/mobile/MobileContainer";
import { Link } from "react-router-dom";
import PinAuthModal from "../../components/auth/PinAuthModal";

const MobileLoginPage = () => {
const [formData, setFormData] = React.useState({
Expand All @@ -9,6 +10,8 @@ const MobileLoginPage = () => {
rememberMe: false,
});

const [isPinModalOpen, setIsPinModalOpen] = React.useState(false);

const handleInputChange = (e: {
target: { name: any; value: any; type: any; checked: any };
}) => {
Expand All @@ -21,6 +24,17 @@ const MobileLoginPage = () => {

const handleLogin = (type: string) => {
console.log(`Logging in with ${type}`, formData);
if (type === "pin") {
setIsPinModalOpen(true);
}
};

const handlePinSubmit = (pin: string, captchaToken: string) => {
setIsPinModalOpen(false);
};

const handleCaptchaChange = (newToken: string) => {
console.log("Captcha token changed:", newToken);
};

return (
Expand Down Expand Up @@ -56,24 +70,28 @@ const MobileLoginPage = () => {
<div className="space-y-3 pt-4">
<button
type="button"
onClick={() => handleLogin("app")}
onClick={() => handleLogin("pin")}
className="w-full bg-blue-600 text-white py-4 rounded-lg font-medium hover:bg-blue-700 transition-colors"
>
서비스 로그인
PIN 인증 로그인
</button>
</div>
</form>

<div className="mt-8 text-center text-sm text-gray-600">
계정이 없으신가요?{" "}
<Link
to="/app/register"
className="text-blue-600 hover:underline"
>
<Link to="/app/register" className="text-blue-600 hover:underline">
NANU ID 생성하기
</Link>
</div>
</div>

<PinAuthModal
isOpen={isPinModalOpen}
onClose={() => setIsPinModalOpen(false)}
onSubmit={handlePinSubmit}
onCaptchaChange={handleCaptchaChange}
/>
</MobileContainer>
);
};
Expand Down

0 comments on commit 2f209df

Please sign in to comment.