>  기사  >  백엔드 개발  >  비밀번호 재설정 기능: 프런트엔드

비밀번호 재설정 기능: 프런트엔드

DDD
DDD원래의
2024-10-02 12:07:01996검색

Password Reset Feature: Frontend

프런트엔드

프론트엔드 부분은 백엔드 부분에 비해 매우 쉽습니다. 내가 해야 할 일은 모달을 만들고 이를 사용하여 데이터를 두 번 보내는 것뿐입니다.

  • 먼저 OTP를 보낼 이메일을 보내세요.
  • 그런 다음 OTP와 새 비밀번호를 보내 변경하세요.

모달을 생성하기 위해 이전 프로젝트 Chat-Nat의 MessageModal 구성 요소에서 모달 캡슐화를 위한 일부 코드인 classNames를 복사했습니다.

계획

'비밀번호를 잊으셨나요?'를 추가하겠습니다. 로그인 페이지의 버튼을 클릭하고 모달을 열도록 onClick 핸들러를 설정합니다

OTP를 요청하기 전에 사용자의 이메일로 OTP가 전송되었는지 여부를 표시하기 위해 부울 상태를 사용해야 합니다. 나는 상태 이름을 isOTPSent

로 지정합니다.
  • !isOTPSent인 경우 -> 이메일 주소를 요청하고 API 요청을 보낸 다음 성공하면 setOTPSent(true)
  • OTPS가 전송된 경우 -> 이제 OTP와 새 비밀번호도 요청한 다음 성공하면 모달을 닫습니다.

다음은 이 프로젝트의 기존 프런트엔드에서 재사용하고 있는 몇 가지 구성 요소와 후크입니다.

  • 상자 -> 로그인 및 등록 페이지를 페이지 중앙에 있는 카드에 깔끔하게 포장하고 여기에서 "비밀번호 재설정"이라는 제목으로 재사용했습니다.
  • 인증 양식 -> 단지 양식이지만 서버의 응답을 기다릴 때 제출 버튼을 비활성화하고 버튼 텍스트를 "로드 중..."으로 설정하도록 코딩했습니다.
  • 양식 입력 -> 값 설정기와 onChange 핸들러, 선택적으로 isRequired 부울이 있는 자체 레이블이 있는 입력 필드
  • useAxios -> 토큰 새로 고침이 필요한 서버의 응답을 처리하기 위한 사용자 지정 후크입니다. 일반 요청 전송을 위한 apiReq 함수, 경고() 및 새로 고침 토큰을 표시하는 일부 사용자 정의 오류 처리, 인증 토큰을 새로 고치고 초기 요청을 다시 시도하는 RefreshReq 함수.

모달의 전체 코드는 다음과 같습니다.

// src/components/PasswordResetModal.tsx
import React, { useState } from "react"
import AuthForm from "./AuthForm";
import FormInput from "./FormInput";
import Box from "./Box";
import { useAxios } from "../hooks/useAxios";

interface FormData {
    email: string,
    new_password: string,
    otp: string,
}

interface Props {
    isVisible: boolean,
    onClose: () => void,
}

const PasswordResetModal: React.FC<Props> = ({ isVisible, onClose }) => {
    const [formData, setFormData] = useState<FormData>({
        email: "",
        new_password: "",
        otp: ""
    });
    const [isLoading, setLoading] = useState<boolean>(false);
    const [isOTPSent, setOTPSent] = useState<boolean>(false);
    const { apiReq } = useAxios();

    const handleClose = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
        if ((e.target as HTMLElement).id === "wrapper") {
            onClose();

            // could have setOTPSent(false), but avoiding it in case user misclicks outside
        }
    };

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        setFormData({
            ...formData,
            [name]: value,
        });
    };

    const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        setLoading(true);

        if (!isOTPSent) { // first request for sending otp,
            const response = await apiReq<unknown, FormData>("post", "/api/reset-password", formData)

            if (response) {
                alert("OTP has been sent to your email");
                setOTPSent(true);
            }
        } else { // then using otp to change password
            const response = await apiReq<unknown, FormData>("put", "/api/reset-password", formData)

            if (response) {
                alert("Password has been successfully reset\nPlease log in again");

                // clear the form
                setFormData({
                    email: "",
                    otp: "",
                    new_password: "",
                })

                // close modal
                onClose();
            }
        }

        setLoading(false);
    };

    if (!isVisible) return null;

    return (
        <div
            id="wrapper"
            className="fixed inset-0 bg-black bg-opacity-25 backdrop-blur-sm flex justify-center items-center"
            onClick={handleClose}>
            <Box title="Password Reset">
                <AuthForm
                    submitHandler={handleSubmit}
                    isLoading={isLoading}
                    buttonText={isOTPSent ? "Change Password" : "Send OTP"}>
                    <FormInput
                        id="email"
                        label="Your email"
                        type="email"
                        value={formData.email}
                        changeHandler={handleChange}
                        isRequired />

                    {isOTPSent && (<>
                        <FormInput
                            id="otp"
                            label="OTP"
                            type="text"
                            value={formData.otp}
                            changeHandler={handleChange}
                            isRequired />
                        <FormInput
                            id="new_password"
                            label="New Password"
                            type="password"
                            value={formData.new_password}
                            changeHandler={handleChange}
                            isRequired />
                    </>)}
                </AuthForm>
            </Box>
        </div>
    )
}

export default PasswordResetModal

로그인 양식에서 모달의 조건부 렌더링을 처리하는 방법은 다음과 같습니다

// src/pages/auth/Login.tsx
import PasswordResetModal from "../../components/PasswordResetModal";

const Login: React.FC = () => {
    const [showModal, setShowModal] = useState<boolean>(false);

    return (
        <Section>
            <Box title="Login">
                <div className="grid grid-flow-col">
                    {/* link to the register page here */}
                    <button 
                    type="button"
                    onClick={() => setShowModal(true)}
                    className="text-blue-700 hover:text-white border border-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-2 text-center me-2 mb-2 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-500 dark:focus:ring-blue-800">
                        Forgot Password?
                    </button>

                    <PasswordResetModal isVisible={showModal} onClose={() => setShowModal(false)} />
                </div>
            </Box>
        </Section>
    )

끝났습니다! 아니면 그렇다고 생각했어요.

개발 환경에서 앱을 실행하던 중 백엔드를 오랫동안 실행한 경우 이메일이 전달되지 않는 버그를 발견했습니다.

다음 게시물에서 이 버그를 수정하겠습니다

위 내용은 비밀번호 재설정 기능: 프런트엔드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.