141 lines
4.8 KiB
TypeScript
141 lines
4.8 KiB
TypeScript
|
|
'use client'
|
||
|
|
import { useEffect, useState } from "react";
|
||
|
|
import NoticeModal from "@/app/components/ModelNotice";
|
||
|
|
import { MilkdownViewer } from "@/app/components/MilkdownViewer";
|
||
|
|
import { MilkdownProvider } from "@milkdown/react";
|
||
|
|
import { Crepe } from "@milkdown/crepe";
|
||
|
|
import { useRef } from "react";
|
||
|
|
|
||
|
|
export default function Page() {
|
||
|
|
const crepeRef = useRef<Crepe>(null!);
|
||
|
|
const [noticeList, setNoticeList] = useState<{
|
||
|
|
id: string;
|
||
|
|
title: string;
|
||
|
|
pubDate: Date;
|
||
|
|
content: string;
|
||
|
|
tag: string;
|
||
|
|
}[]>([]);
|
||
|
|
|
||
|
|
const [currentNotice, setCurrentNotice] = useState<{
|
||
|
|
id: string;
|
||
|
|
title: string;
|
||
|
|
content: string;
|
||
|
|
tag:string
|
||
|
|
pubDate: Date;
|
||
|
|
}>({
|
||
|
|
id: "",
|
||
|
|
tag: "",
|
||
|
|
title: "",
|
||
|
|
content: "",
|
||
|
|
pubDate: new Date("0"),
|
||
|
|
});
|
||
|
|
|
||
|
|
|
||
|
|
const [isNoticeModalOpen, setIsNoticeModalOpen] = useState(false);
|
||
|
|
|
||
|
|
const openHandler = (id: string) => {
|
||
|
|
const notice = noticeList.find((notice) => notice.id === id);
|
||
|
|
if (notice) {
|
||
|
|
setCurrentNotice({
|
||
|
|
id: notice.id,
|
||
|
|
title: notice.title,
|
||
|
|
content: notice.content,
|
||
|
|
tag: notice.tag,
|
||
|
|
pubDate: notice.pubDate,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
setIsNoticeModalOpen(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
const fetchNotices = async () => {
|
||
|
|
const response = await fetch('/api/notice');
|
||
|
|
const data = await response.json();
|
||
|
|
setNoticeList(data);
|
||
|
|
console.log(data);
|
||
|
|
}
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
fetchNotices();
|
||
|
|
}, []);
|
||
|
|
return (
|
||
|
|
<div className="bg-white h-full w-[100vw] lg:w-[calc(100vw-360px)]">
|
||
|
|
|
||
|
|
<div className="h-[calc(100%-80px)] max-w-[800px] mx-auto overflow-y-auto p-4 flex flex-col">
|
||
|
|
{noticeList.length === 0 ? (
|
||
|
|
<div className="text-center text-gray-500">게시글이 없습니다.</div>
|
||
|
|
) : (
|
||
|
|
noticeList.map((notice) => (
|
||
|
|
<div
|
||
|
|
key={notice.id}
|
||
|
|
className="h-[75px] border-[#d5d5d5] border-1 rounded-lg p-4 my-2 flex flex-row justify-between hover:border-[#F94B37] cursor-pointer min-w-[100px] shrink-0 basis-0 grow-0"
|
||
|
|
onClick={() => openHandler(notice.id)}
|
||
|
|
>
|
||
|
|
|
||
|
|
{/* 여기 min-w-0 추가해서 자식을 제한함 부모와 이 위치 관계 다시 확인 */}
|
||
|
|
<div className="flex flex-col justify-between min-w-0">
|
||
|
|
<div className="flex flex-row justify-start">
|
||
|
|
|
||
|
|
{
|
||
|
|
notice.tag === "중요" && (
|
||
|
|
<div className="mr-2 flex items-center justify-center">
|
||
|
|
<div className="w-[33px] h-[20px] bg-[#FEDBD7] text-[#F94B37] font-semibold text-xs rounded-lg text-center flex items-center justify-center">중요</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
<div className="text-normal font-semibold truncate">
|
||
|
|
{notice.title}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="text-xs text-[#848484]">
|
||
|
|
{notice.pubDate.toLocaleString('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false })}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-center">
|
||
|
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
|
|
<path d="M7.5 15L12.5 10L7.5 5" stroke="#848484" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||
|
|
</svg>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<NoticeModal isOpen={isNoticeModalOpen} onClose={() => setIsNoticeModalOpen(false)}>
|
||
|
|
<div className="flex flex-col h-full bg-white rounded-lg p-6">
|
||
|
|
<div className="flex justify-end mb-4">
|
||
|
|
<button
|
||
|
|
className="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600"
|
||
|
|
onClick={() => setIsNoticeModalOpen(false)}
|
||
|
|
>
|
||
|
|
닫기
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
<div className="flex flex-col border-b border-gray-200 pb-4 mb-4">
|
||
|
|
<h1 className="text-2xl font-bold text-gray-800">{currentNotice.title}</h1>
|
||
|
|
<p className="text-sm text-gray-400 mt-1">
|
||
|
|
{currentNotice.pubDate.toLocaleString('ko-KR', {
|
||
|
|
year: 'numeric',
|
||
|
|
month: '2-digit',
|
||
|
|
day: '2-digit',
|
||
|
|
hour: '2-digit',
|
||
|
|
minute: '2-digit',
|
||
|
|
hour12: false,
|
||
|
|
})}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 overflow-y-auto">
|
||
|
|
<MilkdownProvider>
|
||
|
|
<MilkdownViewer value={currentNotice.content} editorRef={crepeRef} />
|
||
|
|
</MilkdownProvider>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</NoticeModal>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|