Implement email verification on signup
The prompt requests to implement email verification logic during the signup process.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Label } from "@/components/ui/label";
|
||||
@@ -6,12 +7,15 @@ import { Button } from "@/components/ui/button";
|
||||
import { ArrowRight, Mail, KeyRound, User, Eye, EyeOff } from "lucide-react";
|
||||
import { useToast } from "@/hooks/useToast.wrapper";
|
||||
import { verifyServerConnection } from "@/contexts/auth/auth.utils";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
interface RegisterFormProps {
|
||||
signUp: (email: string, password: string, username: string) => Promise<{
|
||||
error: any;
|
||||
user: any;
|
||||
redirectToSettings?: boolean;
|
||||
emailConfirmationRequired?: boolean;
|
||||
}>;
|
||||
serverStatus: {
|
||||
checked: boolean;
|
||||
@@ -40,6 +44,7 @@ const RegisterForm: React.FC<RegisterFormProps> = ({
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [emailConfirmationSent, setEmailConfirmationSent] = useState(false);
|
||||
|
||||
const { toast } = useToast();
|
||||
const navigate = useNavigate();
|
||||
@@ -119,7 +124,7 @@ const RegisterForm: React.FC<RegisterFormProps> = ({
|
||||
|
||||
try {
|
||||
// 회원가입 시도
|
||||
const { error, user, redirectToSettings } = await signUp(email, password, username);
|
||||
const { error, user, redirectToSettings, emailConfirmationRequired } = await signUp(email, password, username);
|
||||
|
||||
if (error) {
|
||||
// 오류 메시지 출력
|
||||
@@ -164,14 +169,23 @@ const RegisterForm: React.FC<RegisterFormProps> = ({
|
||||
});
|
||||
}
|
||||
} else if (user) {
|
||||
// 회원가입 성공
|
||||
toast({
|
||||
title: "회원가입 성공",
|
||||
description: "회원가입이 완료되었습니다. 로그인 페이지로 이동합니다.",
|
||||
});
|
||||
|
||||
// 로그인 페이지로 이동
|
||||
navigate("/login");
|
||||
// 이메일 확인이 필요한 경우
|
||||
if (emailConfirmationRequired) {
|
||||
setEmailConfirmationSent(true);
|
||||
toast({
|
||||
title: "이메일 인증 필요",
|
||||
description: `${email}로 인증 메일이 발송되었습니다. 메일함을 확인하고 인증을 완료해주세요.`,
|
||||
});
|
||||
} else {
|
||||
// 이메일 확인이 필요하지 않은 경우 (자동 승인 등)
|
||||
toast({
|
||||
title: "회원가입 성공",
|
||||
description: "회원가입이 완료되었습니다. 로그인 페이지로 이동합니다.",
|
||||
});
|
||||
|
||||
// 로그인 페이지로 이동
|
||||
navigate("/login");
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("회원가입 처리 중 예외 발생:", error);
|
||||
@@ -187,6 +201,48 @@ const RegisterForm: React.FC<RegisterFormProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 이메일 인증 안내 화면 (인증 메일이 발송된 경우)
|
||||
if (emailConfirmationSent) {
|
||||
return (
|
||||
<div className="neuro-flat p-8 mb-6">
|
||||
<div className="text-center space-y-6">
|
||||
<Mail className="w-16 h-16 mx-auto text-neuro-income" />
|
||||
<h2 className="text-2xl font-bold">이메일 인증이 필요합니다</h2>
|
||||
<p className="text-gray-600">
|
||||
<strong>{email}</strong>로 인증 링크가 포함된 이메일을 보냈습니다.
|
||||
이메일을 확인하고 링크를 클릭하여 계정 등록을 완료해주세요.
|
||||
</p>
|
||||
|
||||
<Alert className="bg-blue-50 border-blue-200 my-6">
|
||||
<InfoIcon className="h-5 w-5 text-blue-600" />
|
||||
<AlertTitle className="text-blue-700">인증 이메일이 보이지 않나요?</AlertTitle>
|
||||
<AlertDescription className="text-blue-600">
|
||||
스팸 폴더를 확인해보세요. 또는 다른 이메일 주소로 다시 시도하실 수 있습니다.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div className="space-y-4 pt-4">
|
||||
<Button
|
||||
onClick={() => navigate("/login")}
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
>
|
||||
로그인 페이지로 이동
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setEmailConfirmationSent(false)}
|
||||
variant="ghost"
|
||||
className="w-full"
|
||||
>
|
||||
회원가입 양식으로 돌아가기
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 일반 회원가입 양식
|
||||
return (
|
||||
<div className="neuro-flat p-8 mb-6">
|
||||
<form onSubmit={handleRegister}>
|
||||
@@ -264,6 +320,15 @@ const RegisterForm: React.FC<RegisterFormProps> = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Alert className="bg-amber-50 border-amber-200">
|
||||
<InfoIcon className="h-5 w-5 text-amber-600" />
|
||||
<AlertTitle className="text-amber-700">이메일 인증 필요</AlertTitle>
|
||||
<AlertDescription className="text-amber-600">
|
||||
회원가입 후 이메일로 인증 링크가 발송됩니다.
|
||||
이메일 인증을 완료해야 로그인이 가능합니다.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full bg-neuro-income hover:bg-neuro-income/80 text-white py-6 h-auto"
|
||||
|
||||
@@ -73,12 +73,13 @@ export const signUp = async (email: string, password: string, username: string)
|
||||
|
||||
// 회원가입 성공
|
||||
if (data && data.user) {
|
||||
// 이메일 확인이 필요한지 확인
|
||||
const isEmailConfirmationRequired = data.user.identities &&
|
||||
data.user.identities.length > 0 &&
|
||||
!data.user.identities[0].identity_data?.email_verified;
|
||||
|
||||
if (isEmailConfirmationRequired) {
|
||||
showAuthToast('회원가입 성공', '이메일 인증을 완료해주세요.', 'default');
|
||||
showAuthToast('회원가입 성공', '이메일 인증을 완료해주세요. 인증 메일이 발송되었습니다.', 'default');
|
||||
return {
|
||||
error: null,
|
||||
user: data.user,
|
||||
@@ -93,11 +94,12 @@ export const signUp = async (email: string, password: string, username: string)
|
||||
|
||||
// 사용자 데이터가 없는 경우 (드물게 발생)
|
||||
console.warn('회원가입 응답은 성공했지만 사용자 데이터가 없습니다');
|
||||
showAuthToast('회원가입 성공', '계정이 생성되었습니다. 로그인해주세요.', 'default');
|
||||
showAuthToast('회원가입 성공', '계정이 생성되었습니다. 이메일 인증을 완료한 후 로그인해주세요.', 'default');
|
||||
return {
|
||||
error: null,
|
||||
user: { email },
|
||||
message: '회원가입 완료'
|
||||
message: '회원가입 완료',
|
||||
emailConfirmationRequired: true
|
||||
};
|
||||
} catch (error: any) {
|
||||
console.error('기본 회원가입 프로세스 예외:', error);
|
||||
|
||||
Reference in New Issue
Block a user