Fix: 회원가입 인증 리다이렉트 처리와 UI 그라디언트 클래스 수정
app/auth/callback/route.ts - 이메일 인증 완료 판별을 세션 생성 시간 기준에서 쿼리 파라미터(auth_type=signup) 기반으로 변경 - 회원가입 인증인 경우 자동 로그인 세션 종료 후 로그인 페이지로 리다이렉트 처리 features/auth/actions.ts - 회원가입 시 이메일 리다이렉트 URL에 auth_type=signup 쿼리 파라미터 추가 app/forgot-password/page.tsx - 배경 및 카드 아이콘의 Tailwind 클래스명 일부 수정(bg-gradient-to→bg-linear-to, radial-gradient var() 구문 정리) app/login/page.tsx - 배경 및 카드 아이콘의 Tailwind 클래스명 일부 정리 및 일관화 app/reset-password/page.tsx - 배경 및 카드 아이콘의 Tailwind 클래스명 일부 정리 및 일관화 app/signup/page.tsx - 배경 및 카드 아이콘의 Tailwind 클래스명 일부 정리 및 일관화 features/auth/components/reset-password-form.tsx - 버튼 그라디언트 클래스명(bg-gradient-to-r→bg-linear-to-r) 수정
This commit is contained in:
@@ -65,20 +65,14 @@ export async function GET(request: NextRequest) {
|
||||
// code 교환으로 세션이 생성된 상태입니다.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
// 회원가입 직후 인증 여부 확인 (생성된 지 1분 이내)
|
||||
// 별도의 type 파라미터 없이 데이터 기반으로 판단합니다.
|
||||
const isNewUser =
|
||||
user &&
|
||||
user.created_at &&
|
||||
new Date(user.created_at).getTime() > Date.now() - 60 * 1000; // 1분 이내 생성
|
||||
// 회원가입 인증 여부 확인 (쿼리 파라미터 기반)
|
||||
// actions.ts의 signup 함수에서 emailRedirectTo에 auth_type=signup을 추가해서 보냅니다.
|
||||
const authType = requestUrl.searchParams.get("auth_type");
|
||||
const isSignupVerification = authType === "signup";
|
||||
|
||||
// 회원가입 인증인 경우:
|
||||
// 이메일 인증만 완료하고, 자동 로그인된 세션은 종료시킨 뒤 로그인 페이지로 보냅니다.
|
||||
if (isNewUser) {
|
||||
if (isSignupVerification) {
|
||||
await supabase.auth.signOut();
|
||||
return NextResponse.redirect(
|
||||
`${origin}${AUTH_ROUTES.LOGIN}?message=${encodeURIComponent(
|
||||
|
||||
@@ -27,9 +27,9 @@ export default async function ForgotPasswordPage({
|
||||
const { message } = await searchParams;
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,_var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-linear-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
|
||||
<div className="absolute left-1/4 top-1/4 h-64 w-64 animate-pulse rounded-full bg-gray-300/20 blur-3xl dark:bg-gray-700/20" />
|
||||
<div className="absolute bottom-1/4 right-1/4 h-64 w-64 animate-pulse rounded-full bg-gray-400/20 blur-3xl delay-700 dark:bg-gray-600/20" />
|
||||
@@ -39,7 +39,7 @@ export default async function ForgotPasswordPage({
|
||||
|
||||
<Card className="border-white/20 bg-white/70 shadow-2xl backdrop-blur-xl dark:border-white/10 dark:bg-gray-900/70">
|
||||
<CardHeader className="space-y-3 text-center">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-linear-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<span className="text-sm font-semibold">MAIL</span>
|
||||
</div>
|
||||
<CardTitle className="text-3xl font-bold tracking-tight">
|
||||
@@ -72,7 +72,7 @@ export default async function ForgotPasswordPage({
|
||||
|
||||
<Button
|
||||
formAction={requestPasswordReset}
|
||||
className="h-11 w-full bg-gradient-to-r from-gray-900 to-black font-semibold text-white shadow-lg transition-all hover:from-black hover:to-gray-800 hover:shadow-xl dark:from-white dark:to-gray-100 dark:text-black dark:hover:from-gray-100 dark:hover:to-white"
|
||||
className="h-11 w-full bg-linear-to-r from-gray-900 to-black font-semibold text-white shadow-lg transition-all hover:from-black hover:to-gray-800 hover:shadow-xl dark:from-white dark:to-gray-100 dark:text-black dark:hover:from-gray-100 dark:hover:to-white"
|
||||
>
|
||||
재설정 링크 보내기
|
||||
</Button>
|
||||
|
||||
@@ -27,17 +27,17 @@ export default async function LoginPage({
|
||||
const { message } = await searchParams;
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-linear-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
{/* ========== 배경 그라디언트 레이어 ========== */}
|
||||
{/* 웹 페이지 전체 배경을 그라디언트로 채웁니다 */}
|
||||
{/* 라이트 모드: 부드러운 그레이 톤 (gray → white → gray) */}
|
||||
{/* 다크 모드: 깊은 블랙 톤으로 고급스러운 느낌 */}
|
||||
|
||||
{/* 추가 그라디언트 효과 1: 우상단에서 시작하는 원형 그라디언트 */}
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
|
||||
{/* 추가 그라디언트 효과 2: 좌하단에서 시작하는 원형 그라디언트 */}
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,_var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
|
||||
{/* ========== 애니메이션 블러 효과 ========== */}
|
||||
{/* 부드럽게 깜빡이는 원형 블러로 생동감 표현 */}
|
||||
@@ -61,7 +61,7 @@ export default async function LoginPage({
|
||||
{/* ========== 카드 헤더 영역 ========== */}
|
||||
<CardHeader className="space-y-3 text-center">
|
||||
{/* 아이콘 배경: 그라디언트 원형 */}
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-linear-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<span className="text-4xl">👋</span>
|
||||
</div>
|
||||
{/* 페이지 제목 */}
|
||||
|
||||
@@ -39,9 +39,9 @@ export default async function ResetPasswordPage({
|
||||
const { message } = params;
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,_var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-linear-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
|
||||
<div className="absolute left-1/4 top-1/4 h-64 w-64 animate-pulse rounded-full bg-gray-300/20 blur-3xl dark:bg-gray-700/20" />
|
||||
<div className="absolute bottom-1/4 right-1/4 h-64 w-64 animate-pulse rounded-full bg-gray-400/20 blur-3xl delay-700 dark:bg-gray-600/20" />
|
||||
@@ -51,7 +51,7 @@ export default async function ResetPasswordPage({
|
||||
|
||||
<Card className="border-white/20 bg-white/70 shadow-2xl backdrop-blur-xl dark:border-white/10 dark:bg-gray-900/70">
|
||||
<CardHeader className="space-y-3 text-center">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-linear-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<span className="text-sm font-semibold">PW</span>
|
||||
</div>
|
||||
<CardTitle className="text-3xl font-bold tracking-tight">
|
||||
|
||||
@@ -17,10 +17,10 @@ export default async function SignupPage({
|
||||
const { message } = await searchParams;
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
<div className="relative flex min-h-screen items-center justify-center overflow-hidden bg-linear-to-br from-gray-50 via-white to-gray-100 px-4 py-12 dark:from-black dark:via-gray-950 dark:to-gray-900">
|
||||
{/* 배경 그라데이션 효과 */}
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,_var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,var(--tw-gradient-stops))] from-gray-200/30 via-gray-100/15 to-transparent dark:from-gray-800/30 dark:via-gray-900/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,var(--tw-gradient-stops))] from-gray-300/30 via-gray-200/15 to-transparent dark:from-gray-700/30 dark:via-gray-800/20" />
|
||||
|
||||
{/* 애니메이션 블러 효과 */}
|
||||
<div className="absolute left-1/4 top-1/4 h-64 w-64 animate-pulse rounded-full bg-gray-300/20 blur-3xl dark:bg-gray-700/20" />
|
||||
@@ -32,7 +32,7 @@ export default async function SignupPage({
|
||||
|
||||
<Card className="border-white/20 bg-white/70 shadow-2xl backdrop-blur-xl dark:border-white/10 dark:bg-gray-900/70">
|
||||
<CardHeader className="space-y-3 text-center">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<div className="mx-auto mb-2 flex h-16 w-16 items-center justify-center rounded-2xl bg-linear-to-br from-gray-800 to-black shadow-lg dark:from-white dark:to-gray-200">
|
||||
<span className="text-4xl">🚀</span>
|
||||
</div>
|
||||
<CardTitle className="text-3xl font-bold tracking-tight">
|
||||
|
||||
@@ -238,7 +238,7 @@ export async function signup(formData: FormData) {
|
||||
// 이메일 인증 완료 후 리다이렉트될 URL
|
||||
// 로컬 개발 환경: http://localhost:3001/auth/callback
|
||||
// 프로덕션: NEXT_PUBLIC_BASE_URL 환경 변수에 설정된 주소
|
||||
emailRedirectTo: `${process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3001"}/auth/callback`,
|
||||
emailRedirectTo: `${process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3001"}/auth/callback?auth_type=signup`,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ export default function ResetPasswordForm() {
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="h-11 w-full bg-gradient-to-r from-gray-900 to-black font-semibold text-white shadow-lg transition-all hover:from-black hover:to-gray-800 hover:shadow-xl dark:from-white dark:to-gray-100 dark:text-black dark:hover:from-gray-100 dark:hover:to-white"
|
||||
className="h-11 w-full bg-linear-to-r from-gray-900 to-black font-semibold text-white shadow-lg transition-all hover:from-black hover:to-gray-800 hover:shadow-xl dark:from-white dark:to-gray-100 dark:text-black dark:hover:from-gray-100 dark:hover:to-white"
|
||||
>
|
||||
{isLoading ? (
|
||||
<span className="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user