Built Twitter Like App - 21

Post Tweet

  1. Add post API
  2. Add hook
  3. Add component Form
  4. Add Form to Home page

Add Post API

Add file page/api/posts/index.ts

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
import { NextApiRequest, NextApiResponse } from "next";
import prisma from '@/libs/prismadb';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if( req.method !== 'GET' && req.method !== 'POST' ){
return res.status(405).end();
}

try {
if (req.method === 'POST') {
const { body } = req.body;
const { user } = req.query;

const userId = Number(user);
const post = await prisma.post.create({
data: {
body,
userId
}
});

return res.status(200).json(post);
}

if (req.method === 'GET') {
const { user } = req.query;
const userId = Number(user);

let posts;

if ( userId && typeof userId === 'number' ){
posts = await prisma.post.findMany({
where: {
userId
},
include: {
user: true,
comments: true
},
orderBy: {
createdAt: 'desc'
}
})
} else {
posts = await prisma.post.findMany({
include: {
user: true,
comments: true
},
orderBy: {
createdAt: 'desc'
}
});
}

return res.status(200).json(posts);
}
} catch(error) {
console.log(error);
return res.status(400).end();
} finally {

}
}

Add Hook

Add file hooks/usePosts.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import useSWR from 'swr';

import fetcher from '../libs/fetcher';

const usePosts = (userId:string) => {
const url = userId ? `/api/posts/?user=${userId}` : `/api/posts`
const {
data,
error,
isLoading,
mutate
} = useSWR(url, fetcher)
return {
data,
error,
isLoading,
mutate
}
};

export default usePosts;

Add Form Component

Modify file components/Form.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
100
101
102
103
104
105
106
107
108
109
110
111
import axios from "axios";
import { useCallback, useState } from "react";
import toast from "react-hot-toast";

import useCurrentUser from "@/hooks/useCurrentUser";
import useRegisterModal from "@/hooks/useRegisterModal";
import Button from "./Button";
import Avatar from "./Avatar";

interface FromProps {
placeholder: string;
isComment?: boolean;
postId?: string;
}
const Form:React.FC<FromProps> = ({
placeholder,
isComment,
postId
}) => {
const registModel = useRegisterModal();
const loginModel = useRegisterModal();

const { data: currentUser } = useCurrentUser();
const { mutate: mutatePosts } = useCurrentUser();

const [body, setBody] = useState('');
const [isLoading, setIsLoading] = useState(false);

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

await axios.post('/api/posts/?user='+ currentUser.id , { body });

toast.success('Tweet created');

setBody('');
mutatePosts();
} catch(error) {
toast.error('Something went wrong');

} finally {
setIsLoading(false);
}
},[body, mutatePosts]);

return(
<div className="border-b-[1px] border-neutral-800 px-5 py-2">
{currentUser ? (
<div className="flex flex-row gap-4">
<div>
<Avatar userId={currentUser?.id} />
</div>
<div className="w-full">
<textarea
disabled={isLoading}
onChange={(e) => setBody(e.target.value)}
value={body}
className="
disabled:opacity-80
peer
resize-none
mt-3
w-full
bg-black
ring-0
outline-none
text-[20px]
placeholder-neutral-500
text-white
"
placeholder={placeholder}
></textarea>
<hr
className="
opacity-0
transition
peer-focus:opacity-100
h-[1px]
w-full
border-neutral-800
"
/>
<div className="mt-4 flex flex-row justify-end">
<Button
label="Tweet"
disabled={isLoading || !body}
onClick={onSubmit}
/>
</div>
</div>
</div>
) : (
<div className="py-8">
<h1 className="
text-white
text-2xl
mb-4
font-bold
">Welcome to Twitter</h1>
<div className="flex flex-row item-center justify-center gap-4">
<Button label="Login" onClick={loginModel.onOpen} />
<Button label="Register" onClick={registModel.onOpen} secondary />
</div>
</div>
)}
</div>
);
}

export default Form;

Add Form to Home Page

modify pages/index.tsx:

1
2
3
4
5
6
7
8
9
10
11
import Form from "@/components/Form";
import Header from "../components/Header";

export default function Home() {
return (
<>
<Header label="Home"/>
<Form placeholder="What's happening?"/>
</>
)
}

Demo

请我喝杯咖啡吧~

支付宝
微信