上一回,我們完成了登入表單,這一次我們要來做註冊表單,我們並不需要從零開始,因為我們已經使用類似物件導向的概念完成了大部分的元件,只需要重複使用登入表單的程式碼,並做些修改就能完成登入表單。
我們先在Hooks資料夾,新增useRegisterModal.tsx,大部分的內容來自useLoginModal.tsx。
import { create } from "zustand";
interface RegisterModalStore{
isOpen: boolean;
onOpen: () => void;
onClose: () => void;
}
const useRegisterModal = create<RegisterModalStore>((set) => ({
isOpen: false,
onOpen: () => set({isOpen: true}),
onClose: () => set({isOpen: false}),
}));
export default useRegisterModal;
在Modals資料夾下,建立RegisterModal.tsx,內容修改自LoginModal.tsx,除了原有的欄位,我們還增加了Name用來輸入姓名、Username輸入用戶名。
'use client'
import useLoginModal from "@/app/Hooks/useLoginModal";
import { useCallback, useState } from "react";
import Input from "../Input";
import Modal from "../Modal";
import useRegisterModal from "@/app/Hooks/useRegisterModal";
const RegisterModal = () => {
const loginModal = useLoginModal();
const registerModal = useRegisterModal();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [name, setName] = useState("");
const [username, setUsername] = useState("");
const [isLoading, setIsLoading] = useState(false);
const onSubmit = useCallback(async () => {
try {
setIsLoading(true);
registerModal.onClose();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
}, [registerModal]);
const bodyContent = (
<div className="flex flex-col gap-4">
<Input
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
value={email}
disabled={isLoading}
/>
<Input
placeholder="Name"
onChange={(e) => setName(e.target.value)}
value={name}
disabled={isLoading}
/>
<Input
placeholder="Username"
onChange={(e) => setUsername(e.target.value)}
value={username}
disabled={isLoading}
/>
<Input
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
value={password}
disabled={isLoading}
/>
</div>
);
return (
<Modal
disabled={isLoading}
isOpen={registerModal.isOpen}
title="Create an account"
actionLabel="Register"
onClose={registerModal.onClose}
onSubmit={onSubmit}
body={bodyContent}
/>
);
};
export default RegisterModal;
暫時對useRegisterModal.tsx做修改
isOpen: true,
和_app.tsx新增
<RegisterModal />
就能看到註冊表單顯示在畫面上了。
接下來,我們完善註冊表單的一些細節,有些人可能已經完成註冊了想要登入,需要提供切換到登入表單的功能。
修改RegisterModal.tsx實現這個功能。
'use client'
import useLoginModal from "@/Hooks/useLoginModal";
import { useCallback, useState } from "react";
import Input from "../Input";
import Modal from "../Modal";
import useRegisterModal from "@/Hooks/useRegisterModal";
const RegisterModal = () => {
const loginModal = useLoginModal();
const registerModal = useRegisterModal();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [name, setName] = useState("");
const [username, setUsername] = useState("");
const [isLoading, setIsLoading] = useState(false);
const onToggle = useCallback(() => {
if(isLoading){
return;
}
registerModal.onClose();
loginModal.onOpen();
}, [isLoading, registerModal, loginModal]);
const onSubmit = useCallback(async () => {
try {
setIsLoading(true);
registerModal.onClose();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
}, [registerModal]);
const bodyContent = (
<div className="flex flex-col gap-4">
<Input
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
value={email}
disabled={isLoading}
/>
<Input
placeholder="Name"
onChange={(e) => setName(e.target.value)}
value={name}
disabled={isLoading}
/>
<Input
placeholder="Username"
onChange={(e) => setUsername(e.target.value)}
value={username}
disabled={isLoading}
/>
<Input
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
value={password}
disabled={isLoading}
/>
</div>
);
const footerContent = (
<div className="text-neutral-400 text-center mt-4">
<p>
Already have an account?
<span onClick={onToggle} className="text-white cursor-pointer hover:underline">
Sign in
</span>
</p>
</div>
)
return (
<Modal
disabled={isLoading}
isOpen={registerModal.isOpen}
title="Create an account"
actionLabel="Register"
onClose={registerModal.onClose}
onSubmit={onSubmit}
body={bodyContent}
footer={footerContent}
/>
);
};
export default RegisterModal;
對_app.tsx做修改,讓註冊表單和登入表單可以顯示在網頁上。
import Layout from "@/Components/Layout"
import LoginModal from "@/Components/Modals/LoginModal"
import RegisterModal from "@/Components/Modals/RegisterModal"
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
return (
<Layout>
<RegisterModal />
<LoginModal />
<Component {...pageProps} />
</Layout>
)
}
點選Sign in就能切換到登入表單。
有些人沒有帳號但是點到了登入,我們要在登入界面引導這些人註冊帳號,把onToggle和footerContent的部分複製貼到LoginModal.tsx,並針對細節做修改。
'use client'
import useLoginModal from "@/Hooks/useLoginModal";
import { useCallback, useState } from "react";
import Input from "../Input";
import Modal from "../Modal";
import useRegisterModal from "@/Hooks/useRegisterModal";
const LoginModal = () => {
const loginModal = useLoginModal();
const registerModal = useRegisterModal();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const onToggle = useCallback(() => {
if(isLoading){
return;
}
loginModal.onClose();
registerModal.onOpen();
}, [isLoading, registerModal, loginModal]);
const onSubmit = useCallback(async () => {
try {
setIsLoading(true);
loginModal.onClose();
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
}, [loginModal]);
const bodyContent = (
<div className="flex flex-col gap-4">
<Input
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
value={email}
disabled={isLoading}
/>
<Input
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
value={password}
disabled={isLoading}
/>
</div>
);
const footerContent = (
<div className="text-neutral-400 text-center mt-4">
<p>
First time using X?
<span onClick={onToggle} className="text-white cursor-pointer hover:underline">
Create an account
</span>
</p>
</div>
)
return (
<Modal
disabled={isLoading}
isOpen={loginModal.isOpen}
title="Login"
actionLabel="Sign in"
onClose={loginModal.onClose}
onSubmit={onSubmit}
body={bodyContent}
footer={footerContent}
/>
);
};
export default LoginModal;
現在只要按下Create an account,我們能從登入表單切換到註冊表單了。當然,先從註冊表單回到登入表單也是可以的。