Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions src/components/auth/findPwStep/Step01VerifyEmail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { useEffect, useState } from "react";
import { type SubmitHandler, useForm, useWatch } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { toast } from "sonner";
import type { z } from "zod";

import { step01Schema } from "@/utils/validation";

import CommonAuthInput from "@/components/auth/CommonAuthInput";
import Button from "@/components/common/Button";

import useAuthStore from "@/store/useAuthStore";

interface IStep01VerifyEmailProps {
onNext: () => void;
}

type TStep01FormValues = z.infer<typeof step01Schema>;

export default function Step01VerifyEmail({ onNext }: IStep01VerifyEmailProps) {
const { setEmail } = useAuthStore();

const [sendCode, setSendCode] = useState(false);
const [, setCodeVerify] = useState(false);
const [codeError, setCodeError] = useState("");

const {
register,
handleSubmit,
control,
trigger,
formState: { errors, isValid },
} = useForm<TStep01FormValues>({
mode: "onBlur",
resolver: zodResolver(step01Schema),
});

const watchedEmail = useWatch({ control, name: "email" });
const watchedCode = useWatch({ control, name: "code" });

const postSendCode = async () => {
setCodeVerify(false);
const isEmailValid = await trigger("email");
if (isEmailValid && watchedEmail) {
setSendCode(true);
toast.success("인증번호가 발송되었습니다.", {
description: "테스트용: 아무 번호나 입력하세요",
});
}
};

const onSubmit: SubmitHandler<TStep01FormValues> = async (data) => {
setEmail(data.email);
onNext();
};

useEffect(() => {
setCodeVerify(false);
setCodeError("");
}, [watchedCode, watchedEmail]);

useEffect(() => {
setSendCode(false);
}, [watchedEmail]);

return (
<div className="w-full min-h-screen bg-white flex items-center justify-center">
<div className="w-full max-w-130 px-6 pb-12">
<h1 className="text-start font-heading2 text-text-main mb-10">
<p>비밀번호 찾기를 위해</p>
<p>이메일 인증을 진행할게요</p>
</h1>

<div className="flex flex-col gap-6">
{!sendCode ? (
<div className="flex gap-2 w-full items-start">
<div className="flex-1">
<CommonAuthInput
placeholder="메일을 입력하세요"
type="email"
{...register("email")}
error={!!errors.email}
errorMessage={errors.email?.message}
/>
</div>
<Button
variant="custom"
className="shrink-0 h-13.5! border border-brand-400 text-status-blue bg-white hover:bg-gray-50 px-4 rounded-15 font-body2 whitespace-nowrap"
onClick={postSendCode}
type="button"
>
인증번호 받기
</Button>
</div>
) : (
<CommonAuthInput
type="text"
value={watchedEmail || ""}
readOnly
className="w-full h-13.5 px-5 border rounding-15 text-body1 text-text-main bg-white border-brand-400 focus:outline-none focus:border-brand-400"
/>
)}

<CommonAuthInput
placeholder={
sendCode
? "이메일로 발송된 6자리 인증번호"
: "인증번호를 입력하세요"
}
type="text"
timer={sendCode ? "03:00" : undefined}
{...register("code")}
error={!!errors.code || !!codeError}
errorMessage={errors.code?.message || codeError}
/>
</div>

<div className="mt-10">
<Button
size="big"
fullWidth
onClick={handleSubmit(onSubmit)}
variant="gradient"
disabled={!isValid}
>
다음으로
</Button>
</div>

{sendCode && (
<div className="mt-6 flex justify-center">
<button
type="button"
onClick={() => setSendCode(false)}
className="font-body2 text-text-placeholder underline underline-offset-4 hover:text-text-auth-sub"
>
인증번호 다시 받기
</button>
</div>
)}
</div>
</div>
);
}
77 changes: 77 additions & 0 deletions src/components/auth/findPwStep/Step02ResetPassword.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { type SubmitHandler, useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { zodResolver } from "@hookform/resolvers/zod";
import { toast } from "sonner";
import type { z } from "zod";

import { step02Schema } from "@/utils/validation";

import CommonAuthInput from "@/components/auth/CommonAuthInput";
import Button from "@/components/common/Button";

import useAuthStore from "@/store/useAuthStore";

type TStep02FormValues = z.infer<typeof step02Schema>;

export default function Step02ResetPassword() {
const navigate = useNavigate();
const { setPassword } = useAuthStore();
const {
register,
handleSubmit,
formState: { errors, isValid },
} = useForm<TStep02FormValues>({
mode: "onBlur",
resolver: zodResolver(step02Schema),
});

const onSubmit: SubmitHandler<TStep02FormValues> = (data) => {
setPassword(data.password);
toast.success("비밀번호가 변경되었습니다.", {
description: "로그인 페이지로 이동합니다.",
});
navigate("/auth/login");
};

return (
<div className="w-full min-h-screen bg-white flex items-center justify-center">
<div className="w-full max-w-130 px-6 pb-12">
<h1 className="text-start font-heading2 text-text-main mb-10">
<p>새로운 비밀번호를 </p>
<p>입력해 주세요</p>
</h1>

<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-7">
<CommonAuthInput
title="비밀번호"
placeholder="비밀번호를 입력하세요"
type="password"
{...register("password")}
error={!!errors.password}
errorMessage={errors.password?.message}
/>
<CommonAuthInput
title="비밀번호 확인"
placeholder="한번 더 입력해 주세요."
type="password"
{...register("repassword")}
error={!!errors.repassword}
errorMessage={errors.repassword?.message}
/>

<div className="mt-10">
<Button
size="big"
fullWidth
type="submit"
variant="gradient"
disabled={!isValid}
>
비밀번호 변경하기
</Button>
</div>
</form>
</div>
</div>
);
}
18 changes: 17 additions & 1 deletion src/pages/auth/FindPw.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
import { useState } from "react";

import Step01VerifyEmail from "@/components/auth/findPwStep/Step01VerifyEmail";
import Step02ResetPassword from "@/components/auth/findPwStep/Step02ResetPassword";

export default function FindPw() {
return <div>FindPw</div>;
const [step, setStep] = useState<number>(1);

const handleNextStep = () => {
setStep((prev) => prev + 1);
};

return (
<>
{step === 1 && <Step01VerifyEmail onNext={handleNextStep} />}
{step === 2 && <Step02ResetPassword />}
</>
);
}
2 changes: 1 addition & 1 deletion src/pages/auth/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function Login() {
/>

<Link
to="/auth/find-pw"
to="/auth/find-email"
className="block w-full text-center mt-3 font-caption text-text-sub underline underline-offset-4 hover:text-text-auth-sub"
>
이메일/비밀번호를 잊어버렸어요
Expand Down