ํ๊ธฐ
์ข์์ ๊ธฐ๋ฅ์ ๊ตฌํํ์๋ค.
UI์์ ํ์์ ๋ฐฑ์๋์ ์ข์์ ๊ธฐ๋ฅ์ ๊ฐ์ง ๊ฒ์ ๋ฐ๋ก ๋ถ๋ฆฌํ์ฌ ๊ตฌํ์ด ๋์ด์๋ค. ํจ๊ป ์๋ฒ ์ก์ ๊ณผ ์ฐ๋ํ๋ ์๊ฐ๋ ์ค๋๊ฑธ๋ฆฌ๋ ๊ฒ์ ์๊ฒ ๋์๋ค. ๊ทธ๋์ ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ๋ฐ์์ ์ฃผ๊ธฐ๋ก ํ๋ค.
ํํํ Thread ๊ฐ์ฒด๋ฅผ ๋ถ๋ฌ์์ ์ข์์ ํํฉ์ ๋ ๋๋งํ๋ค.
import React, { useEffect, useState } from "react";
import { HeartIcon, MessageCircle, RepeatIcon, SendIcon } from "lucide-react";
import { threadLike } from "@/actions/thread/ThreadLike";
import { ThreadType } from "@/type/ThreadType";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
interface ThreadFooterProps {
thread: ThreadType;
}
const ThreadFooter = ({ thread }: ThreadFooterProps) => {
const [likeNumber, setLikeNumber] = useState(thread?.likes | 0);
const [iLike, setILike] = useState(thread?.iLike);
const onClick = () => {
const action = async () => {
await threadLike(thread?.id);
};
action().then();
if (iLike) {
toast.error("์ข์์ ์ทจ์");
setILike(false);
setLikeNumber((thread.likes -= 1));
}
if (!iLike) {
toast.success("์ข์์");
setILike(true);
setLikeNumber((thread.likes += 1));
}
};
useEffect(() => {
if (thread) {
setILike(thread?.iLike);
setLikeNumber(thread?.likes);
}
}, [thread]);
return (
<div className={"flex select-none items-center"}>
<Button
variant={"ghost"}
onClick={onClick}
className={"flex items-center gap-2"}
>
<HeartIcon fill={iLike ? "red" : "none"} />
<div>{likeNumber}</div>
</Button>
<Button variant={"ghost"} className={"flex items-center gap-2"}>
<MessageCircle />
<div>00</div>
</Button>
<Button variant={"ghost"} className={"flex items-center gap-2"}>
<RepeatIcon />
</Button>
<Button variant={"ghost"} className={"flex items-center gap-2"}>
<SendIcon />
</Button>
</div>
);
};
export default ThreadFooter;
threadLike ํจ์์ ์๋ ๋ก์ง์ด๋ค ํ๋์์ ๊ธฐ์กด ๋ด๊ฐ ์ข์์๋ฅผ ํ ์ํ์ธ์ง ์ฒดํฌ๋ฅผ ํ๋ค.
"use server";
import db from "@/lib/db";
import { currentUser } from "@/lib/auth";
export const threadLike = async (threadId: string) => {
const user = await currentUser();
// ์ด๋ฏธ ์ข์์๋ฅผ ๋๋ ๋์ง ํ์ธ
const existingLike = await db.threadLike.findFirst({
where: {
threadId: threadId,
userId: user?.id,
},
});
// ์ด๋ฏธ ์ข์์๋ฅผ ๋๋ ๋ค๋ฉด, ์ข์์ ์ญ์ ๋ฐ ์ทจ์
if (existingLike != null) {
await db.threadLike.delete({
where: {
id: existingLike.id,
},
});
await db.thread.update({
where: {
id: threadId,
},
data: {
likes: {
decrement: 1,
},
},
});
return { dislike: "์ข์์ ์ทจ์" };
}
// ์ข์์ ์์ฑ ๋ฐ ์ฆ๊ฐ
if (existingLike == null) {
await db.threadLike.create({
data: {
threadId: threadId,
userId: user?.id as string,
},
});
// ํด๋น ์ค๋ ๋์ ์ข์์ ์๋ฅผ ์ฆ๊ฐ
await db.thread.update({
where: {
id: threadId,
},
data: {
likes: {
increment: 1,
},
},
});
const activity = await db.activity.create({
data: {
title: "์ข์์",
content: "์ข์์๋ฅผ ๋๋ ์ต๋๋ค.",
},
});
await db.activityUser.create({
data: {
userId: user?.id as string,
activityId: activity.id,
},
});
return { like: "์ข์์" };
}
return { error: "์๋ฒ ์๋ฌ" };
};
์ฌ์ดํธ
https://richable.cyber-luna.com
์์ค์ฝ๋
https://github.com/TwoIceFIsh/richable-web-server