Built Twitter Like App - 7

Install Zustand

1
npm install zustand

Add Hooks

Add file hooks/useLoginModal.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { create } from "zustand";

interface LoginModalStore{
isOpen: boolean;
onOpen: ()=> void;
onClose: ()=> void;
};

const useLoginModal = create<LoginModalStore>((set) =>({
isOpen: true,
onOpen: () => set({ isOpen: true}),
onClose: () => set({ isOpen: false})
}));

export default useLoginModal;

Add file hooks/useRegisterModal.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { create } from "zustand";

interface useRegisterModal{
isOpen: boolean;
onOpen: ()=> void;
onClose: ()=> void;
};

const useRegisterModal = create<useRegisterModal>((set) =>({
isOpen: false,
onOpen: () => set({ isOpen: true}),
onClose: () => set({ isOpen: false})
}));

export default useRegisterModal;

Add LoginModal Page

Add file modals/LoginModal.tsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { useCallback, useState } from "react";
import useLoginModal from "../../hooks/useLoginModal";
import Input from "../Input";
import ModalBox from "../ModalBox";
import RegisterModal from "./RegisterModal";
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, loginModal,registerModal]);

const onSubmit = useCallback(async ()=> {
try{
setIsLoading(true);

// TODO Login
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 Twiter?
<span
onClick={onToggle}
className="
text-white
cursor-pointer
hover:underline
"
> Creat an account</span>
</p>
</div>
)

return (
<ModalBox
disabled={isLoading}
isOpen={loginModal.isOpen}
title="Login"
actionLabel="Sign In"
onClose={loginModal.onClose}
onSubmit={onSubmit}
body={bodyContent}
footer={footerContent}
/>
);
}

export default LoginModal

Add file modals/RegisterModal.tsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import { useCallback, useState } from "react";
import useLoginModal from "../../hooks/useLoginModal";
import useRegisterModal from "../../hooks/useRegisterModal";
import Input from "../Input";
import ModalBox from "../ModalBox";

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, loginModal,registerModal]);

const onSubmit = useCallback(async ()=> {
try{
setIsLoading(true);

// TODO Register and Login
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 (
<ModalBox
disabled={isLoading}
isOpen={registerModal.isOpen}
title="Create an account"
actionLabel="Register"
onClose={registerModal.onClose}
onSubmit={onSubmit}
body={bodyContent}
footer={footerContent}
/>
);
}

export default RegisterModal

Run Demo

Modify file pages/_app.tsx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import '../styles/globals.css'
import type { AppProps } from 'next/app'

import Layout from '../components/Layout'
import ModalBox from '../components/ModalBox'

export default function App({ Component, pageProps }: AppProps) {
return (
<>
<LoginModal />
<RegisterModal />
<Layout>
<Component {...pageProps} />
</Layout>
</>
)
}

Run:

1
npm run dev

Login Modal Screen:

Click “Create an account”:

请我喝杯咖啡吧~

支付宝
微信