Skip to content

Commit 8d9356b

Browse files
committed
fix(fe): fetch data + docker build
1 parent 11aec6c commit 8d9356b

File tree

7 files changed

+85
-67
lines changed

7 files changed

+85
-67
lines changed

spez-frontend/.babelrc

-4
This file was deleted.

spez-frontend/Dockerfile

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Use an official Node.js runtime as a parent image
2+
FROM node:20-alpine
3+
4+
# Set the working directory in the container
5+
WORKDIR /src/app
6+
7+
# Copy package.json and package-lock.json to the container
8+
COPY package*.json ./
9+
10+
# Install dependencies
11+
RUN npm install
12+
13+
# Copy the rest of the application code to the container
14+
COPY . .
15+
16+
# Build the Next.js app
17+
RUN npm run build
18+
19+
# Expose the port the app runs on
20+
EXPOSE 3000
21+
22+
# Start the Next.js application
23+
CMD ["npm", "run", "start"]
24+

spez-frontend/jest.config.js

-14
This file was deleted.

spez-frontend/package.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@
1010
"test": "jest"
1111
},
1212
"dependencies": {
13-
"@testing-library/jest-dom": "^6.6.3",
14-
"@testing-library/react": "^16.0.1",
1513
"axios": "^1.7.7",
1614
"html-react-parser": "^5.1.18",
17-
"jest": "^29.7.0",
1815
"js-cookie": "^3.0.5",
1916
"next": "14.2.15",
2017
"react": "^18",
2118
"react-dom": "^18",
2219
"react-icons": "^5.3.0",
20+
"sharp": "^0.33.5",
2321
"suneditor": "^2.47.0",
2422
"suneditor-react": "^3.6.1"
2523
},

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

+23-15
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,30 @@ import { GoTrash } from "react-icons/go";
1010
import { IPost, IComment } from "@/types";
1111
import LikeButton from "@/components/LikeButton";
1212
import svLike from "@/services/svLike";
13+
import { useEffect, useState } from "react";
1314
type Props = {
1415
params: { id: string };
1516
};
16-
// interface getILike{
17-
// like: number
18-
// }
19-
export default async function Post({ params }: Props) {
17+
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>()
2021
const id: string = params.id;
2122
const { getPost, delPost } = svPost();
2223
const {getComment} = svCmt();
2324
const {getLike} = svLike()
24-
const info: IPost = await getPost(id);
25-
const likes: number = await getLike(id);
26-
console.log(likes)
27-
const comment: IComment[] = await getComment(id);
28-
const author_url = "/user/" + info.author.id;
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;
2937
const handleDelPost = async () => {
3038
let token: string | null = null
3139
if (typeof window !== 'undefined')
@@ -40,22 +48,22 @@ export default async function Post({ params }: Props) {
4048
<div className="pl-10 flex flex-row justify-between">
4149
<div className="w-auto">
4250

43-
<Link href={author_url} className="font-semibold"> {info.author.username}</Link>
44-
{" "} {getRelativeTime(info.created_at)}
51+
<Link href={author_url} className="font-semibold"> {info?.author.username}</Link>
52+
{" "} { info?.created_at? getRelativeTime(info?.created_at) : null }
4553
</div>
4654
<button onClick={handleDelPost} className="mr-8 text-red-600 text-semibold"> <GoTrash /></button>
4755
</div>
48-
<div className="pl-2 text-2xl font-bold">{info.title}</div>
49-
<div className="p-2">{Parser(info.content)}</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>
5058
<div className="flex flex-row">
5159
<LikeButton initialLikes={likes} post_id={id} />
52-
<div className="w-auto mt-[0.35rem] ml-5 border-2 rounded-full px-2 border-black">Phản hồi: {comment.length}</div>
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>
5361
</div>
5462
<CmtForm postId={id} />
5563
</div>
5664
<div className="border-2 border-slate-950 p-2 text-black rounded shadow h-full w-1/2 space-y-5">
5765
<a className="font-bold text-2xl">Bình Loạn</a>
58-
{comment.map((element: IComment) => (
66+
{comment?.map((element: IComment) => (
5967
<Comment
6068
key={element.id}
6169
id = {element.id}

spez-frontend/src/components/LikeButton.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
// components/LikeButton.tsx
2+
"use client"
23
import React, { useState } from "react";
34
import Image from "next/image";
45
import EagleEmoji from "../../public/eagle_emoji.png";
56
import svLike from "@/services/svLike";
67
interface LikeButtonProps {
7-
initialLikes: number;
8+
initialLikes: number | null;
89
post_id: string
910
}
1011

1112
const LikeButton: React.FC<LikeButtonProps> = ({ initialLikes, post_id }) => {
12-
const [likes, setLikes] = useState<number>(initialLikes);
13+
const [likes, setLikes] = useState<number | null>(initialLikes);
1314
const [liked, setLiked] = useState(false);
1415
const {postLike, delLike} = svLike()
1516

@@ -21,7 +22,7 @@ const LikeButton: React.FC<LikeButtonProps> = ({ initialLikes, post_id }) => {
2122
const response = liked? await postLike(post_id, token) : await delLike(post_id, token);
2223
if (response.status == 201 || response.status == 204) {
2324
setLiked(!liked);
24-
setLikes((prev) => (liked ? prev - 1 : prev + 1));
25+
setLikes((prev) => (prev ? (liked? (prev - 1) : (prev + 1)) : null ))
2526
}
2627

2728
} catch (error) {
+33-28
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
1-
import svPost from "@/services/svPost"
1+
"use client";
2+
import svPost from "@/services/svPost";
23
import Post from "./Post";
34
import { IPost } from "@/types";
4-
export default async function NewsFeed() {
5-
const {getAllPost} = svPost();
6-
const AllPost = await getAllPost();
7-
return (
8-
<>
9-
<div className="w-full h-screen p-8">
10-
<div className=" flex flex-col items-center gap-8">
11-
12-
{
13-
AllPost?.map((post: IPost) => (
14-
<Post
15-
key={post.id}
16-
id = {post.id}
17-
title = {post.title}
18-
content = {post.content}
19-
author = {post.author}
20-
created_at = {post.created_at}
21-
updated_at= {post.updated_at}
22-
/>
23-
)
24-
)
25-
}
26-
</div>
27-
</div>
28-
</>
29-
)
30-
}
5+
import { useEffect, useState } from "react";
6+
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+
});
16+
return (
17+
<>
18+
<div className="w-full h-screen p-8">
19+
<div className=" flex flex-col items-center gap-8">
20+
{AllPost?.map((post: IPost) => (
21+
<Post
22+
key={post.id}
23+
id={post.id}
24+
title={post.title}
25+
content={post.content}
26+
author={post.author}
27+
created_at={post.created_at}
28+
updated_at={post.updated_at}
29+
/>
30+
))}
31+
</div>
32+
</div>
33+
</>
34+
);
35+
}

0 commit comments

Comments
 (0)