173 lines
5.3 KiB
TypeScript
173 lines
5.3 KiB
TypeScript
"use client";
|
|
|
|
import dayjs from "dayjs";
|
|
import Image from "next/image";
|
|
import { useEffect, useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
import { Button, Skeleton } from "@common/components";
|
|
import { AttachmentApi } from "@/entities/attachment";
|
|
import { PostApi } from "@/entities/post";
|
|
import {
|
|
useAlertStore,
|
|
useUserStore,
|
|
useMenuStore,
|
|
usePrompt,
|
|
} from "@/shared/lib";
|
|
import { ENDPOINT } from "@/shared/config";
|
|
import { PostAction } from "./post-action";
|
|
import { PostComment } from "./post-comment";
|
|
|
|
function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
|
|
const router = useRouter();
|
|
const { prompt } = usePrompt();
|
|
const { setMessage: alert } = useAlertStore((state) => state);
|
|
const { userInfo } = useUserStore((state) => state);
|
|
const { bbsInfo } = useMenuStore((state) => state);
|
|
|
|
const [filename, setFilename] = useState("");
|
|
|
|
const { data: postData } = useQuery({
|
|
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo],
|
|
queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
|
|
});
|
|
|
|
const { data: downloadResponse, isFetching } = useQuery({
|
|
queryKey: [ENDPOINT.ATTACH_SERVICE.DOWNLOAD, postData?.atflCd],
|
|
queryFn: () =>
|
|
AttachmentApi.downloadAttachmentByAtflCd(postData?.atflCd as string),
|
|
enabled: !!postData?.atflCd && bbsInfo?.bbsTypeCd !== "BBSIMAGE",
|
|
});
|
|
|
|
const { data: imageUrl, isLoading } = useQuery({
|
|
queryKey: [ENDPOINT.ATTACH_SERVICE.IMAGES, postData?.atflCd],
|
|
queryFn: () =>
|
|
AttachmentApi.getImageUrlByAtflCd(postData?.atflCd as string),
|
|
enabled: !!postData?.atflCd,
|
|
});
|
|
|
|
const { mutate: deletePost } = useMutation({
|
|
mutationFn: (pstPswd: string) => PostApi.deletePost(bbsId, pstNo, pstPswd),
|
|
onSuccess: () => {
|
|
alert("삭제되었습니다.", router.back);
|
|
},
|
|
});
|
|
|
|
const handleDelete = async () => {
|
|
let pstPswd = "";
|
|
if (userInfo?.userUnqId) {
|
|
pstPswd = userInfo?.userUnqId;
|
|
} else {
|
|
pstPswd = await prompt("비밀번호를 입력해주세요.");
|
|
}
|
|
deletePost(pstPswd);
|
|
};
|
|
|
|
const handleDownload = async () => {
|
|
if (!downloadResponse) return;
|
|
try {
|
|
const blob = new Blob([downloadResponse.data]);
|
|
const url = window.URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
|
|
link.href = url;
|
|
link.download = filename || "download";
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
|
|
window.URL.revokeObjectURL(url);
|
|
document.body.removeChild(link);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!downloadResponse) return;
|
|
try {
|
|
let filename = "";
|
|
const contentDisposition =
|
|
downloadResponse.headers["content-disposition"];
|
|
if (contentDisposition) {
|
|
const filenameMatch = contentDisposition.match(
|
|
/filename\*=UTF-8''([^;]+)/,
|
|
);
|
|
if (filenameMatch && filenameMatch[1]) {
|
|
filename = decodeURIComponent(filenameMatch[1]);
|
|
}
|
|
}
|
|
setFilename(filename);
|
|
} catch {
|
|
setFilename("");
|
|
}
|
|
}, [downloadResponse]);
|
|
|
|
return (
|
|
<>
|
|
<PostAction bbsId={bbsId} pstNo={pstNo} handleDelete={handleDelete}>
|
|
<div className="card card-border !p-8">
|
|
<h3 className="text-[2rem] font-bold text-foreground">
|
|
{postData?.pstTtl}
|
|
</h3>
|
|
<div className="card !m-0 !mt-8 bg-accent">
|
|
<ul className="flex gap-8 p-4 text-xl text-label">
|
|
<li>
|
|
작성자: <b>{postData?.wrtrNm}</b>
|
|
</li>
|
|
<li>
|
|
등록일: <b>{dayjs(postData?.regDt).format("YYYY-MM-DD")}</b>
|
|
</li>
|
|
<li>
|
|
조회수: <b>{postData?.inqNocs}</b>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<hr className="mt-8" />
|
|
{bbsInfo?.bbsTypeCd === "BBSIMAGE" && (
|
|
<div className="relative my-6 flex h-[75rem] w-[100rem]">
|
|
{isLoading && <Skeleton className="h-full w-full" />}
|
|
{imageUrl && (
|
|
<Image
|
|
src={imageUrl}
|
|
className="object-cover"
|
|
fill
|
|
alt="썸네일 이미지"
|
|
/>
|
|
)}
|
|
</div>
|
|
)}
|
|
<pre className="font-noto min-h-[40rem] whitespace-pre-wrap p-8 text-2xl tracking-tighter text-foreground">
|
|
{postData?.pstCn ?? ""}
|
|
</pre>
|
|
{isFetching ? (
|
|
<div className="p-8">
|
|
<Skeleton className="h-[2.5rem] w-[32rem]" />
|
|
</div>
|
|
) : (
|
|
filename && (
|
|
<>
|
|
<hr />
|
|
<div className="flex items-center gap-4 p-8">
|
|
<span className="font-bold text-label">첨부파일</span>
|
|
<Button
|
|
size="sm"
|
|
color="white"
|
|
className="flex w-fit items-center gap-2"
|
|
onClick={handleDownload}
|
|
>
|
|
<i className="diveicon di-download" />
|
|
<span>{filename}</span>
|
|
</Button>
|
|
</div>
|
|
</>
|
|
)
|
|
)}
|
|
</div>
|
|
</PostAction>
|
|
<PostComment bbsId={parseInt(bbsId)} pstNo={parseInt(pstNo)} />
|
|
</>
|
|
);
|
|
}
|
|
|
|
export { Post };
|