feat: 동영상 게시글 상세 작업

This commit is contained in:
2025-05-14 17:37:14 +09:00
parent b0235808f8
commit 1069197d62
7 changed files with 75 additions and 42 deletions
@@ -52,7 +52,15 @@ export class AttachmentApiService implements AttachmentService {
return URL.createObjectURL(blob);
}
public async getMovieThumbnailUrl(atflId: string): Promise<string> {
public async getStreamVideoUrlByAtflId(atflId: string): Promise<string> {
const response = await fetch(
`${ENDPOINT.ATTACH_SERVICE.STREAM_VIDEO}/${atflId}`,
);
const blob = await response.blob();
return URL.createObjectURL(blob);
}
public async getMovieThumbnailUrlByAtflId(atflId: string): Promise<string> {
const response = await fetch(
`${ENDPOINT.ATTACH_SERVICE.MOVIE_THUMBNAIL}/${atflId}`,
);
@@ -60,6 +68,14 @@ export class AttachmentApiService implements AttachmentService {
return URL.createObjectURL(blob);
}
public async getMovieThumbnailUrlByAtflCd(atflCd: string): Promise<string> {
const response = await fetch(
`${ENDPOINT.ATTACH_SERVICE.MOVIE_THUMBNAIL}/atflCd/${atflCd}`,
);
const blob = await response.blob();
return URL.createObjectURL(blob);
}
public async downloadAttachmentByAtflCd(
atflCd: string,
): Promise<AxiosResponse> {
@@ -40,6 +40,8 @@ export interface AttachmentService {
deleteAttachmentByAtflCd: (atflCd: string) => Promise<void>;
getImageUrlByAtflId: (atflId: string) => Promise<string>;
getImageUrlByAtflCd: (atflCd: string) => Promise<string>;
getMovieThumbnailUrl: (atflId: string) => Promise<string>;
getStreamVideoUrlByAtflId: (atflId: string) => Promise<string>;
getMovieThumbnailUrlByAtflId: (atflId: string) => Promise<string>;
getMovieThumbnailUrlByAtflCd: (atflCd: string) => Promise<string>;
downloadAttachmentByAtflCd: (atflCd: string) => Promise<AxiosResponse>;
}
+1
View File
@@ -10,6 +10,7 @@ export const ENDPOINT = {
MOVIE_THUMBNAIL: "/attach-service/api/v1/movie/thumbnail",
ATTACHMENTS: "/attach-service/api/v1/atfl/attachments",
DOWNLOAD: "/attach-service/api/v1/atflcd/download",
STREAM_VIDEO: "/attach-service/api/v1/stream/video",
},
USER_SERVICE: {
LOGIN: "/user-service/login",
@@ -2,10 +2,11 @@ import dayjs from "dayjs";
import Image from "next/image";
import type { ColumnDef } from "@tanstack/react-table";
import { Badge, Checkbox, Skeleton } from "@common/components";
import { AttachmentApi } from "@/entities/attachment";
import type { Post } from "@/entities/post";
import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
import { AttachmentApi } from "@/entities/attachment";
import { useMenuStore } from "@/shared/lib";
export const createColumns = (
thumbRefs: React.MutableRefObject<Map<number, string>>,
@@ -81,9 +82,17 @@ type ThumbImageProps = {
const ThumbImage = ({ atflCd, pstNo, thumbRefs }: ThumbImageProps) => {
const prevImage = thumbRefs.current.get(pstNo);
const { bbsInfo } = useMenuStore((state) => state);
const { data: imageUrl, isLoading } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.IMAGES, atflCd],
queryFn: () => AttachmentApi.getImageUrlByAtflCd(atflCd),
queryFn: () => {
if (bbsInfo?.bbsTypeCd === "BBSIMAGE") {
return AttachmentApi.getImageUrlByAtflCd(atflCd);
} else if (bbsInfo?.bbsTypeCd === "BBSMOVIE") {
return AttachmentApi.getMovieThumbnailUrlByAtflCd(atflCd);
}
},
select: (url) => {
if (url) thumbRefs.current.set(pstNo, url);
return url;
+17 -36
View File
@@ -23,12 +23,11 @@ import {
Skeleton,
} from "@common/components";
import { PostApi, type Post, type PostParams } from "@/entities/post";
import type { BoardType } from "@/entities/board";
import { ENDPOINT } from "@/shared/config";
import { useMenuStore, useUserStore } from "@/shared/lib";
import { GridViewDataTable } from "@/shared/ui/grid-view-data-table";
import { columns } from "../model/post-table-columns";
import { createColumns } from "../model/grid-view-table-columns";
import { columns as tableColumns } from "../model/post-table-columns";
import { createColumns as createGridViewColumns } from "../model/grid-view-table-columns";
function PostPage({ bbsId }: { bbsId: string }) {
const router = useRouter();
@@ -36,7 +35,7 @@ function PostPage({ bbsId }: { bbsId: string }) {
const { confirm } = useConfirm();
const { userInfo } = useUserStore((state) => state);
const { bbsInfo, pageMenuAuthority } = useMenuStore((state) => state);
const bbsType = bbsInfo?.bbsTypeCd as BoardType;
const thumbRefs = useRef<Map<number, string>>(new Map());
const [postParams, setPostParams] = useState<PostParams>({
keywordType: "title",
@@ -48,8 +47,6 @@ function PostPage({ bbsId }: { bbsId: string }) {
});
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const thumbRefs = useRef<Map<number, string>>(new Map());
const { data: upndFixPostList } = useQuery({
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, bbsInfo],
queryFn: () =>
@@ -62,10 +59,7 @@ function PostPage({ bbsId }: { bbsId: string }) {
...post,
isUpndFixPost: post.upndFixYn === "Y",
}));
return {
...data,
content: newContent,
};
return { ...data, content: newContent };
},
enabled: bbsInfo?.upndFixUseYn === "Y",
});
@@ -85,9 +79,14 @@ function PostPage({ bbsId }: { bbsId: string }) {
enabled: false,
});
const isGridViewPage =
bbsInfo?.bbsTypeCd === "BBSIMAGE" || bbsInfo?.bbsTypeCd === "BBSMOVIE";
const table = useReactTable({
data: [...(upndFixPostList?.content ?? []), ...(postList?.content ?? [])],
columns,
data: isGridViewPage
? (postList?.content ?? [])
: [...(upndFixPostList?.content ?? []), ...(postList?.content ?? [])],
columns: isGridViewPage ? createGridViewColumns(thumbRefs) : tableColumns,
state: { pagination, rowSelection },
rowCount: postList?.totalElements ?? 0,
manualPagination: true,
@@ -97,17 +96,7 @@ function PostPage({ bbsId }: { bbsId: string }) {
onRowSelectionChange: setRowSelection,
});
const gridViewTable = useReactTable({
data: postList?.content ?? [],
columns: createColumns(thumbRefs),
state: { pagination, rowSelection },
rowCount: postList?.totalElements ?? 0,
manualPagination: true,
enableMultiRowSelection: true,
getCoreRowModel: getCoreRowModel(),
onPaginationChange: setPagination,
onRowSelectionChange: setRowSelection,
});
const DataTableComponent = isGridViewPage ? GridViewDataTable : DataTable;
const onPostDelete = async () => {
const selectedPosts = table
@@ -211,19 +200,11 @@ function PostPage({ bbsId }: { bbsId: string }) {
</div>
<div className="card !m-[1.2rem] h-full overflow-auto !p-0">
{isFetched ? (
bbsType === "BBSIMAGE" || bbsType === "BBSMOVIE" ? (
<GridViewDataTable
table={gridViewTable}
onRowClick={handleRowClick}
viewPagination
/>
) : (
<DataTable
table={table}
onRowClick={handleRowClick}
viewPagination
/>
)
<DataTableComponent
table={table}
onRowClick={handleRowClick}
viewPagination
/>
) : (
<Skeleton className="h-[36rem] w-full" />
)}
+25 -1
View File
@@ -36,7 +36,10 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
queryKey: [ENDPOINT.ATTACH_SERVICE.DOWNLOAD, postData?.atflCd],
queryFn: () =>
AttachmentApi.downloadAttachmentByAtflCd(postData?.atflCd as string),
enabled: !!postData?.atflCd && bbsInfo?.bbsTypeCd !== "BBSIMAGE",
enabled:
!!postData?.atflCd &&
bbsInfo?.bbsTypeCd !== "BBSIMAGE" &&
bbsInfo?.bbsTypeCd !== "BBSMOVIE",
});
const { data: imageUrl, isLoading } = useQuery({
@@ -46,6 +49,22 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
enabled: !!postData?.atflCd,
});
const { data: videoAttachment } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, postData?.atflCd],
queryFn: () => AttachmentApi.getAttachmentsInfo(postData?.atflCd as string),
select: (data) => data[0],
enabled: !!postData?.atflCd && bbsInfo?.bbsTypeCd === "BBSMOVIE",
});
const { data: videoUrl } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.STREAM_VIDEO, videoAttachment?.atflId],
queryFn: () =>
AttachmentApi.getStreamVideoUrlByAtflId(
videoAttachment?.atflId as string,
),
enabled: !!videoAttachment?.atflId,
});
const { mutate: deletePost } = useMutation({
mutationFn: (pstPswd: string) => PostApi.deletePost(bbsId, pstNo, pstPswd),
onSuccess: () => {
@@ -142,6 +161,11 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
)}
</>
)}
{bbsInfo?.bbsTypeCd === "BBSMOVIE" && (
<div className="relative my-6 flex h-[56.25rem] w-[100rem]">
<video src={videoUrl} controls className="object-contain" />
</div>
)}
<pre className="font-noto min-h-[40rem] whitespace-pre-wrap p-8 text-2xl tracking-tighter text-foreground">
{postData?.pstCn ?? ""}
</pre>
@@ -50,7 +50,7 @@ function WithPreviewFileUploader<T extends PostFormData | PostUpdateFormData>({
imageUrl = await AttachmentApi.getImageUrlByAtflId(atflId);
}
if (bbsInfo?.bbsTypeCd === "BBSMOVIE") {
imageUrl = await AttachmentApi.getMovieThumbnailUrl(atflId);
imageUrl = await AttachmentApi.getMovieThumbnailUrlByAtflId(atflId);
}
setThumbnailUrl(imageUrl);
}