Skip to content

Commit

Permalink
feat : add register API Integration
Browse files Browse the repository at this point in the history
  • Loading branch information
0xC0FFE2 committed Jan 21, 2025
1 parent 6d25fe4 commit 75d0148
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 22 deletions.
13 changes: 12 additions & 1 deletion src/components/auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const LoginForm: React.FC<LoginFormProps> = ({ formData, onInputChange }) => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [isPinModalOpen, setIsPinModalOpen] = useState(false);
const [captchaToken, setCaptchaToken] = useState<string | null>(null); // 리캡챠 토큰 상태 추가

const handleAppLogin = async () => {
try {
Expand Down Expand Up @@ -63,6 +64,11 @@ const LoginForm: React.FC<LoginFormProps> = ({ formData, onInputChange }) => {
redirectUrl: "/home",
};

if (!captchaToken) {
toast.error("리캡챠 만료되었습니다. 다시 시도해주세요.");
return;
}

await AuthService.execute(loginData);
toast.success("로그인 성공!");
} catch (err) {
Expand All @@ -75,6 +81,10 @@ const LoginForm: React.FC<LoginFormProps> = ({ formData, onInputChange }) => {
}
};

const handleCaptchaTokenChange = (newToken: string) => {
setCaptchaToken(newToken);
};

return (
<div className="flex-1 flex items-center justify-center p-6">
<div className="w-auto min-w-[280px]">
Expand Down Expand Up @@ -168,10 +178,11 @@ const LoginForm: React.FC<LoginFormProps> = ({ formData, onInputChange }) => {
isOpen={isPinModalOpen}
onClose={() => setIsPinModalOpen(false)}
onSubmit={(pin, captchaToken) => handlePinSubmit(pin, captchaToken)}
onCaptchaChange={handleCaptchaTokenChange} // 리캡챠 토큰 변경시 호출
/>
</div>
</div>
);
};

export default LoginForm;
export default LoginForm;
22 changes: 17 additions & 5 deletions src/components/auth/PinAuthModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,24 @@ interface PinAuthModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (pin: string, captchaToken: string) => void;
onCaptchaChange: (newToken: string) => void; // 추가된 부분
}

const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit }) => {
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) => {
setRecaptchaToken(token);
if (token) {
console.log(token) // PostMan 로그인용 출력
setRecaptchaToken(token);
onCaptchaChange(token); // 부모 컴포넌트로 토큰 전달
setStep('pin');
setCaptchaExpired(false);
} else {
setRecaptchaToken(null);
setCaptchaExpired(true);
}
};

Expand Down Expand Up @@ -61,8 +67,14 @@ const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit }
<ReCAPTCHA
sitekey="6LdSu74qAAAAAKFs8haQHu4HO9y_QLeXzvsYdUWV"
onChange={handleRecaptchaChange}
onExpired={() => setCaptchaExpired(true)}
/>
</div>
{captchaExpired && (
<div className="text-red-500 text-sm text-center mt-4">
리캡챠 인증이 만료되었습니다. 다시 인증을 진행해주세요.
</div>
)}
<button
onClick={onClose}
className="w-full py-3 text-gray-500 hover:text-gray-700"
Expand Down Expand Up @@ -103,7 +115,7 @@ const PinAuthModal: React.FC<PinAuthModalProps> = ({ isOpen, onClose, onSubmit }
</button>
<button
onClick={handleSubmit}
disabled={pin.length !== 6}
disabled={pin.length !== 6 || !recaptchaToken}
className="w-1/2 py-3 bg-blue-600 text-white rounded-lg disabled:bg-blue-300"
>
확인
Expand Down
5 changes: 4 additions & 1 deletion src/components/auth/RegisterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface RegisterFormProps {
onPinChange: (name: string, value: string) => void;
onRegister: () => void;
isMobile?: boolean;
redirectUrl?: string;
}

const RegisterForm: React.FC<RegisterFormProps> = ({
Expand Down Expand Up @@ -373,7 +374,9 @@ const RegisterForm: React.FC<RegisterFormProps> = ({
return (
<div className={styles.container} onKeyDown={handleKeyDown} tabIndex={0}>
<div className={isMobile ? "w-full" : "w-[310px]"}>
<h1 className={styles.title}>회원가입</h1>
<h1 className={styles.title}>
회원가입
</h1>
<div
ref={containerRef}
className={`transform ${
Expand Down
43 changes: 28 additions & 15 deletions src/pages/RegisterPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,56 @@ import LoginContainer from "../components/auth/LoginContainer";
import LoginBanner from "../components/auth/LoginBanner";
import RegisterForm from "../components/auth/RegisterForm";
import { RegisterFormData } from "../types/Auth";
import { RegisterService } from "../services/RegisterService";
import { toast } from "react-toastify";

const RegisterPage = () => {
const [formData, setFormData] = useState({
email: '',
password: '',
confirmPassword: '',
name: '',
birthDate: '',
pin: '',
confirmPin: '',
termsAccepted: false
email: "",
password: "",
confirmPassword: "",
name: "",
birthDate: "",
pin: "",
confirmPin: "",
termsAccepted: false,
});
const navigate = useNavigate();

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value, type, checked } = e.target;
setFormData(prev => ({
setFormData((prev) => ({
...prev,
[name]: type === 'checkbox' ? checked : value
[name]: type === "checkbox" ? checked : value,
}));
};

const handlePinChange = (name: string, value: string) => {
setFormData(prev => ({
setFormData((prev) => ({
...prev,
[name]: value
[name]: value,
}));
};

const handleRegister = () => {
console.log('Register:', formData);
const handleRegister = async () => {
try {
await RegisterService.register({
email: formData.email,
password: formData.password,
name: formData.name,
birthDate: formData.birthDate,
pin: formData.pin,
redirectUrl: "/home",
});
} catch (error) {
toast.error("회원가입에 실패했습니다.");
}
};

return (
<LoginContainer>
<LoginBanner />
<RegisterForm
<RegisterForm
formData={formData}
onInputChange={handleInputChange}
onPinChange={handlePinChange}
Expand Down
46 changes: 46 additions & 0 deletions src/services/RegisterService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import SERVICE_API_URL from "./ServiceEndPoint";
const BASE_URL = SERVICE_API_URL.BASE_URL;

export class RegisterService {
static async register(data: {
redirectUrl?: string;
email: string;
password: string;
name: string;
birthDate: string;
pin: string;
}): Promise<void> {
const deviceToken = window.nanu_androidgw?.devicetoken || "WEB_NONE";
const requestBody = {
deviceToken: deviceToken,
pin: data.pin,
password: data.password,
name: data.name,
email: data.email,
birthDate: data.birthDate,
};

const endpoint = `${BASE_URL}/auth/register`;

const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
mode: "cors",
});

const result = await response.json();

if (!response.ok) {
throw new Error(result.message || "회원가입 중 오류가 발생했습니다.");
}

if (data.redirectUrl) {
window.location.href = data.redirectUrl;
} else {
window.location.href = "/home";
}
}
}
7 changes: 7 additions & 0 deletions src/types/Global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare global {
interface Window {
nanu_androidgw?: {
devicetoken?: string;
};
}
}

0 comments on commit 75d0148

Please sign in to comment.