iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
自我挑戰組

模仿知名網站的外觀系列 第 18

【Day18】模仿知名網站的外觀 X(5) 註冊表單

  • 分享至 

  • xImage
  •  

上一回,我們完成了登入表單,這一次我們要來做註冊表單,我們並不需要從零開始,因為我們已經使用類似物件導向的概念完成了大部分的元件,只需要重複使用登入表單的程式碼,並做些修改就能完成登入表單。

我們先在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 />

就能看到註冊表單顯示在畫面上了。

Untitled

接下來,我們完善註冊表單的一些細節,有些人可能已經完成註冊了想要登入,需要提供切換到登入表單的功能。

修改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就能切換到登入表單。

Untitled

有些人沒有帳號但是點到了登入,我們要在登入界面引導這些人註冊帳號,把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,我們能從登入表單切換到註冊表單了。當然,先從註冊表單回到登入表單也是可以的。

Untitled


上一篇
【Day17】模仿知名網站的外觀 X(4) 登入表單
下一篇
【Day19】模仿知名網站的外觀 X(6) 顯示登錄視窗與後端設定
系列文
模仿知名網站的外觀30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言