Skip to content

Commit d65da82

Browse files
committed
feat(fe/fetch): swr
1 parent 61f7faa commit d65da82

File tree

13 files changed

+141
-87
lines changed

13 files changed

+141
-87
lines changed

spez-frontend/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"react-icons": "^5.3.0",
2020
"sharp": "^0.33.5",
2121
"suneditor": "^2.47.0",
22-
"suneditor-react": "^3.6.1"
22+
"suneditor-react": "^3.6.1",
23+
"swr": "^2.2.5"
2324
},
2425
"devDependencies": {
2526
"@types/jest": "^29.5.14",

spez-frontend/src/app/post/[id]/page.tsx

+17-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"use client"
2-
import svPost from "@/services/svPost";
3-
import svCmt from "@/services/svCmt";
2+
import {svPost} from "@/services/svPost";
43
import Link from "next/link";
54
import Comment from "@/components/Comment";
65
import Parser from 'html-react-parser'
@@ -9,37 +8,26 @@ import { getRelativeTime } from "@/utils/getRelativeTime";
98
import { GoTrash } from "react-icons/go";
109
import { IPost, IComment } from "@/types";
1110
import LikeButton from "@/components/LikeButton";
12-
import svLike from "@/services/svLike";
11+
// import svLike from "@/services/svLike";
1312
import { useEffect, useState } from "react";
13+
import usePost from "@/hooks/usePost";
14+
import useComments from "@/hooks/useComments";
15+
import useLikes from "@/hooks/useLikes";
1416
type Props = {
1517
params: { id: string };
1618
};
1719
export default function Post({ params }: Props) {
18-
const [info, setInfo] = useState<IPost>()
19-
const [likes, setLikes] = useState<number | null>(null)
20-
const [comment, setComments] = useState<IComment[] | undefined>()
2120
const id: string = params.id;
22-
const { getPost, delPost } = svPost();
23-
const {getComment} = svCmt();
24-
const {getLike} = svLike()
25-
useEffect(() => {
26-
async function fetching () {
27-
let res = await getPost(id);
28-
setInfo(res)
29-
res = await getLike(id);
30-
setLikes(res);
31-
res = await getComment(id);
32-
setComments(res);
33-
}
34-
fetching()
35-
}, [])
36-
const author_url = "/user/" + info?.author.id;
21+
const {post, isLoadingInfo} = usePost(id)
22+
const {Comments, isLoadingComments} = useComments(id)
23+
const {Likes, isLoadingLikes} = useLikes(id)
24+
const {delPost} = svPost()
25+
const author_url = "/user/" + post?.author.id;
3726
const handleDelPost = async () => {
3827
let token: string | null = null
3928
if (typeof window !== 'undefined')
4029
token = localStorage.getItem('jwt')
4130
await delPost(id, token);
42-
4331
}
4432
return (
4533
<>
@@ -48,22 +36,22 @@ export default function Post({ params }: Props) {
4836
<div className="pl-10 flex flex-row justify-between">
4937
<div className="w-auto">
5038

51-
<Link href={author_url} className="font-semibold"> {info?.author.username}</Link>
52-
{" "} { info?.created_at? getRelativeTime(info?.created_at) : null }
39+
<Link href={author_url} className="font-semibold"> {post?.author.username}</Link>
40+
{" "} { post?.created_at? getRelativeTime(post?.created_at) : null }
5341
</div>
5442
<button onClick={handleDelPost} className="mr-8 text-red-600 text-semibold"> <GoTrash /></button>
5543
</div>
56-
<div className="pl-2 text-2xl font-bold">{info?.title}</div>
57-
<div className="p-2">{ info?.content ? Parser(info?.content) : null}</div>
44+
<div className="pl-2 text-2xl font-bold">{post?.title}</div>
45+
<div className="p-2">{ post?.content ? Parser(post?.content) : null}</div>
5846
<div className="flex flex-row">
59-
<LikeButton initialLikes={likes} post_id={id} />
60-
<div className="w-auto mt-[0.35rem] ml-5 border-2 rounded-full px-2 border-black">Phản hồi: {comment?.length}</div>
47+
<LikeButton initialLikes={Likes} post_id={id} />
48+
<div className="w-auto mt-[0.35rem] ml-5 border-2 rounded-full px-2 border-black">Phản hồi: {Comments?.length}</div>
6149
</div>
6250
<CmtForm postId={id} />
6351
</div>
6452
<div className="border-2 border-slate-950 p-2 text-black rounded shadow h-full w-1/2 space-y-5">
6553
<a className="font-bold text-2xl">Bình Loạn</a>
66-
{comment?.map((element: IComment) => (
54+
{Comments?.map((element: IComment) => (
6755
<Comment
6856
key={element.id}
6957
id = {element.id}

spez-frontend/src/components/CmtForm.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@ import React, { useState } from "react";
33
// import dynamic from 'next/dynamic';
44
import SunEditor from "suneditor-react";
55
import "suneditor/dist/css/suneditor.min.css";
6-
import svCmt from "@/services/svCmt";
6+
import {svCmt} from "@/services/svCmt";
77
import { useRouter } from "next/navigation";
88

9-
// Dynamically import SunEditor to avoid SSR issues
10-
// const DynamicSunEditor = dynamic(() => import('suneditor-react'), {
11-
// ssr: false,
12-
// });
139

1410
type Props = {
1511
postId: string;

spez-frontend/src/components/NewsFeed.tsx

+5-12
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
11
"use client";
2-
import svPost from "@/services/svPost";
2+
// import svPost from "@/services/svPost";
33
import Post from "./Post";
44
import { IPost } from "@/types";
5-
import { useEffect, useState } from "react";
5+
// import { useEffect, useState } from "react";
6+
import usePosts from "@/hooks/usePosts";
67
export default function NewsFeed() {
7-
const [AllPost, setAllPost] = useState<IPost[] | null>();
8-
const { getAllPost } = svPost();
9-
useEffect(() => {
10-
async function fetching() {
11-
const res = await getAllPost();
12-
setAllPost(res);
13-
}
14-
fetching();
15-
});
8+
const {posts, isLoading} = usePosts()
169
return (
1710
<>
1811
<div className="w-full h-screen p-8">
1912
<div className=" flex flex-col items-center gap-8">
20-
{AllPost?.map((post: IPost) => (
13+
{posts?.map((post: IPost) => (
2114
<Post
2215
key={post.id}
2316
id={post.id}

spez-frontend/src/components/PostForm.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import React, { useState } from 'react';
44
import SunEditor from 'suneditor-react';
55
import 'suneditor/dist/css/suneditor.min.css';
66
import { useRouter } from 'next/navigation';
7-
import svPost from '@/services/svPost';
8-
// Dynamically import SunEditor to avoid SSR issues
9-
// const DynamicSunEditor = dynamic(() => import('suneditor-react'), {
10-
// ssr: false,
11-
// });
7+
import {svPost} from '@/services/svPost';
128

139
export default function PostForm () {
1410
const [content, setContent] = useState<string>('');
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import useSWR from "swr"
2+
import { getComments } from "@/services/svCmt"
3+
const useComments = (id: string) => {
4+
5+
const {data, isLoading } = useSWR(id, getComments)
6+
return {
7+
Comments: data,
8+
isLoadingComments: isLoading,
9+
// isErrored: error
10+
}
11+
}
12+
export default useComments;
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// import useSWR from "swr";
2+
// import { createPost } from "@/services/svPost";
3+
// interface Props {
4+
// title: string | null,
5+
// content: string | null,
6+
// token: string | null
7+
// }
8+
9+
// export const useCreatePost = <T> ({title, content, token}: Props) => {
10+
// const {data, isLoading} = useSWR<T> (title, content, token)
11+
// return{data, isLoading, createPost: (data: object) => createPost(title!, content!, token!, data)
12+
// }

spez-frontend/src/hooks/useLikes.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import useSWR from "swr";
2+
import { getLikes } from "@/services/svLike";
3+
4+
// interface Return
5+
const useLikes = (id: string) => {
6+
const { data, isLoading } = useSWR(id, getLikes);
7+
return {
8+
Likes: data,
9+
isLoadingLikes: isLoading,
10+
// isErrored: error
11+
};
12+
};
13+
export default useLikes;

spez-frontend/src/hooks/usePost.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import useSWR from "swr"
2+
import { getPost } from "@/services/svPost"
3+
4+
// interface Return
5+
const usePost = (id: string) => {
6+
7+
const {data, isLoading } = useSWR(id, getPost)
8+
return {
9+
post: data,
10+
isLoadingInfo: isLoading,
11+
// isErrored: error
12+
}
13+
}
14+
export default usePost;

spez-frontend/src/hooks/usePosts.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import useSWR from "swr"
2+
import { getAllPost } from "@/services/svPost"
3+
4+
// interface Return
5+
const usePosts = () => {
6+
7+
const {data, isLoading } = useSWR(" ", getAllPost)
8+
return {
9+
posts: data,
10+
isLoading,
11+
// isErrored: error
12+
}
13+
}
14+
export default usePosts;

spez-frontend/src/services/svCmt.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import axios from "axios";
22
import { BE_URI } from "@/utils/constants";
3-
export default function svCmt() {
4-
const API = {
5-
comments: BE_URI + "/posts/cmt/",
6-
};
3+
const API = {
4+
comments: BE_URI + "/posts/cmt/",
5+
};
6+
export const svCmt = () => {
77
async function getComment(id: string) {
88
const data = await axios.get(API.comments + id, {
99
headers: {
@@ -41,3 +41,5 @@ export default function svCmt() {
4141
createComment
4242
};
4343
}
44+
export const getComments = async(id: string) =>
45+
await axios.get(API.comments + id).then((res) => res.data)

spez-frontend/src/services/svLike.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import axios from "axios"
22
import { BE_URI } from "@/utils/constants"
3-
export default function svLike(){
4-
const API = {
5-
like: BE_URI + "/likes"
6-
}
3+
const API = {
4+
like: BE_URI + "/likes"
5+
}
6+
export const svLike = () => {
77
async function postLike(id: string, token: string | null) {
88
return await axios.post(API.like + "/" + id, {},{
99
headers: {
@@ -32,6 +32,8 @@ export default function svLike(){
3232
return {
3333
postLike,
3434
delLike,
35-
getLike,
3635
}
37-
}
36+
}
37+
export const getLikes = async (id: string) =>
38+
await axios.get(API.like + "/post/" + id)
39+
.then((res) => res.data)

spez-frontend/src/services/svPost.ts

+36-25
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { BE_URI } from "@/utils/constants";
22
import axios from "axios";
3-
export default function svPost() {
4-
const API = {
5-
all: BE_URI + "/posts",
6-
post: BE_URI + "/posts/",
7-
};
8-
async function createPost(title: string, content: string, token: string | null) {
3+
const API = {
4+
all: BE_URI + "/posts",
5+
post: BE_URI + "/posts/",
6+
};
7+
export const svPost = () => {
8+
async function createPost(
9+
title: string,
10+
content: string,
11+
token: string | null
12+
) {
913
await axios.post(
1014
API.post,
1115
{
@@ -20,22 +24,6 @@ export default function svPost() {
2024
}
2125
);
2226
}
23-
async function getAllPost() {
24-
const data = await axios.get(API.all + "/?skip=10", {
25-
headers: {
26-
accept: "application/json",
27-
},
28-
});
29-
return data.data;
30-
}
31-
async function getPost(id: string) {
32-
const data = await axios.get(API.post + id, {
33-
headers: {
34-
accept: "application/json",
35-
},
36-
});
37-
return data.data;
38-
}
3927
async function delPost(id: string, token: string | null) {
4028
const data = await axios.delete(API.post + id, {
4129
headers: {
@@ -46,9 +34,32 @@ export default function svPost() {
4634
return data.data;
4735
}
4836
return {
49-
getAllPost,
5037
getPost,
5138
delPost,
52-
createPost
39+
createPost,
5340
};
54-
}
41+
};
42+
export const createPost = async (
43+
title: string,
44+
content: string,
45+
token: string | null
46+
) => {
47+
await axios.post(
48+
API.post,
49+
{
50+
title: title,
51+
content: content,
52+
},
53+
{
54+
headers: {
55+
accept: "application/json",
56+
Authorization: `Bearer ${token}`,
57+
},
58+
}
59+
);
60+
};
61+
export const getPost = async (id: string) =>
62+
await axios.get(API.post + id).then((res) => res.data);
63+
64+
export const getAllPost = async () =>
65+
await axios.get(API.all + "/?skip=10").then((res) => res.data);

0 commit comments

Comments
 (0)