Files
frontend/apps/common/features/src/widgets/post/model/grid-view-table-columns.tsx
T

179 lines
5.4 KiB
TypeScript

import dayjs from "dayjs";
import Image from "next/image";
import type { ColumnDef } from "@tanstack/react-table";
import { Badge, Checkbox, Skeleton, cn } 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 type { BbsType } from "@/shared/store/menu-store";
declare module "@tanstack/react-table" {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface TableMeta<TData> {
bbsTypeCd?: BbsType;
}
}
export const createColumns = (
thumbRefs: React.MutableRefObject<Map<number, string>>,
): ColumnDef<Post>[] => [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={table.getIsAllPageRowsSelected()}
onClick={(e) => e.stopPropagation()}
onCheckedChange={(checked) =>
table.toggleAllPageRowsSelected(!!checked)
}
className="h-4 w-4 rounded border-gray-300"
/>
),
cell: ({ row, table }) => {
const { atflCd, pstNo, pstTtl, inqNocs, rgtrNm, regDt } = row.original;
const bbsTypeCd = table.options.meta?.bbsTypeCd;
if (bbsTypeCd === "BBSIMAGE") {
return (
<div className="flex flex-col gap-4">
<div className="flex items-center gap-2">
<Checkbox
checked={row.getIsSelected()}
onClick={(e) => e.stopPropagation()}
onCheckedChange={(checked) => row.toggleSelected(!!checked)}
className="h-4 w-4 rounded border-gray-300"
/>
{inqNocs >= 100 && <Badge color="red">HOT</Badge>}
{dayjs().diff(dayjs(row.original.regDt), "hour") < 24 && (
<Badge color="blue">NEW</Badge>
)}
<span className="text-[1.6rem] font-bold text-label">
{pstTtl}
</span>
</div>
<ThumbImage
atflCd={atflCd}
pstNo={pstNo}
thumbRefs={thumbRefs}
bbsTypeCd={bbsTypeCd}
/>
<div className="flex flex-col">
<span className="text-[1.4rem] font-bold text-label">
{rgtrNm}
</span>
<span className="text-[1.2rem] text-label">
{dayjs(regDt).format("YYYY-MM-DD")}
</span>
</div>
</div>
);
}
if (bbsTypeCd === "BBSMOVIE") {
return (
<div className="-m-4">
<ThumbImage
atflCd={atflCd}
pstNo={pstNo}
thumbRefs={thumbRefs}
bbsTypeCd={bbsTypeCd}
classes={{
image: "object-cover",
}}
/>
<div className="p-4">
<div className="flex flex-col gap-4">
<div className="flex items-center gap-2">
<Checkbox
checked={row.getIsSelected()}
onClick={(e) => e.stopPropagation()}
onCheckedChange={(checked) => row.toggleSelected(!!checked)}
className="h-4 w-4 rounded border-gray-300"
/>
{inqNocs >= 100 && <Badge color="red">HOT</Badge>}
{dayjs().diff(dayjs(regDt), "hour") < 24 && (
<Badge color="blue">NEW</Badge>
)}
<span className="text-[1.6rem] font-bold text-label">
{pstTtl}
</span>
</div>
<div className="flex flex-col">
<span className="text-[1.4rem] font-bold text-label">
{rgtrNm}
</span>
<span className="text-[1.2rem] text-label">
{dayjs(regDt).format("YYYY-MM-DD")}
</span>
</div>
</div>
</div>
</div>
);
}
},
},
];
type ThumbImageProps = {
atflCd: string;
pstNo: number;
thumbRefs: React.MutableRefObject<Map<number, string>>;
bbsTypeCd?: string;
classes?: {
image?: string;
};
};
const ThumbImage = ({
atflCd,
pstNo,
thumbRefs,
bbsTypeCd,
classes,
}: ThumbImageProps) => {
const prevImage = thumbRefs.current.get(pstNo);
const { data: imageUrl, isLoading } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.IMAGES, atflCd],
queryFn: () => {
if (bbsTypeCd === "BBSIMAGE") {
return AttachmentApi.getImageUrlByAtflCd(atflCd);
} else if (bbsTypeCd === "BBSMOVIE") {
return AttachmentApi.getMovieThumbnailUrlByAtflCd(atflCd);
}
},
select: (url) => {
if (url) thumbRefs.current.set(pstNo, url);
return url;
},
enabled: !prevImage && !!atflCd,
});
if (isLoading)
return (
<div className="h-[16rem] w-full">
<Skeleton className="h-full w-full" />
</div>
);
if (imageUrl)
return (
<div className="relative flex h-[16rem] w-full items-center justify-center">
<Image
src={imageUrl}
className={cn("object-contain", classes?.image)}
fill
alt="썸네일 이미지"
/>
</div>
);
return (
<div className="flex h-[16rem] w-full items-center justify-center rounded-sm border border-border bg-background">
<i className="diveicon di-image text-3xl" />
</div>
);
};