Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(firebase 게시글 불러오기) #26

Merged
merged 4 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/pages/Main/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logo from "../../assets/logo.png";

export default function Main() {
return (
<div>
Expand Down
162 changes: 52 additions & 110 deletions src/pages/Notice/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import {
container,
titleText,
mid,
notice,
noticeList,
noticeContentWrapper,
noticeContent,
noticeTitle,
noticeContainer,
searchbar,
searchContainer,
Expand All @@ -16,107 +14,55 @@ import {
newBadge,
pageButton,
activePageButton,
emptyListAlert,
} from "./notice.css.ts"; // 스타일 가져오기

// NoticeItem 타입 정의: 제목은 string, 콘텐츠는 JSX.Element로 지정
interface NoticeItem {
id: number;
title: string;
content: string;
detail: string;
}

// 임시 데이터 예시
const noticeData: NoticeItem[] = [
{
id: 1,
title: "2024 강원대학교 백령대동제 개최 안내",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 2,
title: "2024 강원대학교 백령대동제 개최 안내",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 3,
title: "랄랄라 신규 게시물",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 4,
title: "2024 강원대학교 백령대동제 개최 안내",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 5,
title: "랄랄라 신규 게시물",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 6,
title: "2024 강원대학교 백령대동제 개최 안내",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 7,
title: "랄랄라 신규 게시물",
content: "This 강원대 the content for notice 1.",
detail: "여기는 세부내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 8,
title: "2024 강원대학교 백령대동제 개최 안내",
content: "This 강원대 the content for notice 1.",
detail: "여기는 룰루입니다. Notice 1에 대한 정보가 더 있습니다.",
},
{
id: 9,
title: "랄랄라 신규 게시물",
content: "This 강원대 the content for notice 1.",
detail: "여기는 부스내용입니다. Notice 1에 대한 정보가 더 있습니다.",
},
// 나머지 공지사항 추가
];
import { getNoticeList } from "../../shared/firebase/noticeService"; // Firebase에서 getNoticeList 가져오기
import { NoticeDto } from "../../shared/types/notice"; // NoticeDto 타입 정의

function Notice() {
const [query, setQuery] = useState<string>(""); // 검색어의 타입을 string으로 지정
const [notices, setNotices] = useState<NoticeDto[]>([]); // 공지사항 목록 상태
const [loading, setLoading] = useState<boolean>(true); // 로딩 상태 관리
const [query, setQuery] = useState<string>(""); // 검색어 상태
const [currentPage, setCurrentPage] = useState<number>(1); // 현재 페이지 상태
const [expandedNotices, setExpandedNotices] = useState<number[]>([]); // 확장된 공지 ID들을 관리
const itemsPerPage = 6;
const [expandedNoticeId, setExpandedNoticeId] = useState<string | null>(null); // 확장된 공지 ID를 관리
const itemsPerPage = 6; // 페이지당 항목 수

// Firebase에서 공지사항 데이터를 가져오는 함수
const fetchNotices = async () => {
try {
const noticeList = await getNoticeList(); // Firebase에서 데이터 가져오기
setNotices(noticeList); // 데이터를 상태에 저장
setLoading(false); // 로딩 완료
} catch (error) {
console.error("Error fetching notices:", error);
setLoading(false); // 에러가 발생해도 로딩 완료로 변경
}
};

// 가장 최근 게시물의 ID 찾기 (ID가 제일 큰 것이 최신 게시물이라고 가정)
const mostRecentNoticeId = Math.max(...noticeData.map((notice) => notice.id));
// 컴포넌트가 처음 렌더링될 때 Firebase에서 데이터를 가져옴
useEffect(() => {
fetchNotices();
}, []);

// 검색어 입력 시 상태 업데이트
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
setQuery(event.target.value);
setCurrentPage(1);
setCurrentPage(1); // 검색 시 첫 페이지로 이동
};

// downbtn 클릭 시 상세 내용을 보여주는 로직
const toggleNotice = (id: number) => {
setExpandedNotices((prev) =>
prev.includes(id) ? prev.filter((noticeId) => noticeId !== id) : [...prev, id],
);
// 공지사항 토글 로직 (한 게시글만 확장되도록 수정)
const toggleNotice = (id: string) => {
setExpandedNoticeId((prevId) => (prevId === id ? null : id)); // 같은 게시글 클릭 시 축소, 다른 게시글 클릭 시 확장
};

// 필터링 로직
const filteredNotices = noticeData
.filter((noticeItem) => {
const searchText = query.toLowerCase();
return (
noticeItem.title.toLowerCase().includes(searchText) ||
noticeItem.detail.toLowerCase().includes(searchText)
);
})
.reverse(); // 공지사항을 내림차순으로 정렬 (마지막 공지사항이 제일 위로 오게)
// 필터링된 공지사항 목록 (검색어 적용 및 내림차순 정렬)
const filteredNotices = notices.filter((noticeItem) => {
const searchText = query.toLowerCase();
return (
noticeItem.title.toLowerCase().includes(searchText) ||
noticeItem.contents.toLowerCase().includes(searchText)
);
});

// 현재 페이지에 맞는 데이터 추출
const indexOfLastItem = currentPage * itemsPerPage;
Expand All @@ -129,11 +75,13 @@ function Notice() {
// 페이지 변경 함수
const paginate = (pageNumber: number) => setCurrentPage(pageNumber);

// 로딩 중일 때 로딩 메시지 표시
if (loading) {
return <div>Loading...</div>;
}

return (
<div>
<div className={container}>
<p className={titleText}>공지사항</p>
</div>
<div className={mid}>
<div className={searchContainer}>
<input
Expand All @@ -145,39 +93,35 @@ function Notice() {
/>
</div>

{/* noticeList 렌더링 */}
{/* 공지사항 목록 렌더링 */}
<div className={noticeList}>
{filteredNotices.length === 0 ? (
<p style={{ textAlign: "center", color: "white", fontSize: "18px" }}>
해당하는 게시글이 없어요!
</p>
<p className={emptyListAlert}>해당하는 게시글이 없어요!</p>
) : (
currentNotices.map((noticeItem, index) => (
<div className={noticeContainer} key={noticeItem.id}>
<div className={notice}>
{/* 번호와 제목 표시 */}
<div style={{ display: "flex", alignItems: "center" }}>
<p className={noticeNumber}>{index + 1 + (currentPage - 1) * itemsPerPage}</p>
{/* 가장 최근 게시물에만 'New' 표시 */}
{noticeItem.id === mostRecentNoticeId && <span className={newBadge}>New</span>}
{/* 공지사항의 renewal이 true일 경우 'New' 배지를 표시 */}
{noticeItem.renewal && <span className={newBadge}>New</span>}
</div>

<div className={noticeContentWrapper}>
<p className={noticeContent}>{noticeItem.title}</p>
<p className={noticeTitle}>{noticeItem.title}</p>
</div>

{/* downbtn을 클릭하면 토글 */}
<button onClick={() => toggleNotice(noticeItem.id)} className={arrowButton}>
<span className="material-symbols-outlined">
{expandedNotices.includes(noticeItem.id)
? "arrow_drop_up"
: "arrow_drop_down"}
{expandedNoticeId === noticeItem.id ? "arrow_drop_up" : "arrow_drop_down"}
</span>
</button>
</div>

{/* 상세 내용 표시 - 확장 시만 보여줌 */}
{expandedNotices.includes(noticeItem.id) && (
<div className={noticeDetail}>{noticeItem.detail}</div>
{expandedNoticeId === noticeItem.id && (
<div className={noticeDetail}>{noticeItem.contents}</div>
)}
</div>
))
Expand All @@ -199,8 +143,6 @@ function Notice() {
</div>
)}
</div>

<div className={container}></div>
</div>
);
}
Expand Down
32 changes: 13 additions & 19 deletions src/pages/Notice/notice.css.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { style } from "@vanilla-extract/css";
import { vars } from "../../shared/styles/vars.css";

export const titleText = style({
fontSize: 20,
fontWeight: 600,
color: "white",
marginTop: 60,
});
// 검색 필드와 버튼을 감싸는 컨테이너
// 검색 필드를 감싸는 컨테이너
export const searchContainer = style({
display: "flex",
alignItems: "center",
Expand All @@ -33,14 +27,6 @@ export const searchbar = style({
fontWeight: 500,
});

// 상단의 빨간 컨테이너
export const container = style({
width: "100%",
height: 110,
display: "flex",
justifyContent: "center",
});

// 중간에 검색창을 배치하는 컨테이너
export const mid = style({
position: "relative",
Expand Down Expand Up @@ -99,25 +85,33 @@ export const noticeContentWrapper = style({
marginLeft: 10,
});

export const noticeContent = style({
display: "inline-block", // 텍스트가 한 줄로 스크롤되도록 설정
whiteSpace: "nowrap", // 텍스트를 한 줄로 유지
export const noticeTitle = style({
display: "inline-block",
whiteSpace: "nowrap",
fontSize: 16,
fontWeight: 500,
color: "black",
margin: 5,
});

export const noticeDetail = style({
whiteSpace: "pre-wrap",
overflow: "hidden",
maxHeight: "500px", // 최대 높이를 설정
backgroundColor: "rgba(255,255,255,0.6)", // 배경색
padding: "10px",
marginTop: -12,
marginBottom: 5,
width: "90%",
});

//검색한 키워드가 없을 경우 뜨는 글귀
export const emptyListAlert = style({
color: "white",
fontSize: 18,
fontWeight: 700,
textAlign: "center",
});

//새 게시물에 뜨는 new 태그
export const newBadge = style({
marginLeft: "10px",
Expand Down
7 changes: 0 additions & 7 deletions src/pages/QnA/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useState } from "react";
import {
container,
titleText,
mid,
qna,
qnaList,
Expand Down Expand Up @@ -103,9 +101,6 @@ function QnA() {

return (
<div>
<div className={container}>
<p className={titleText}>FAQ</p>
</div>
<div className={mid}>
<div className={subTitleContainer}>
<p className={subTitleText}>자주 하는 질문</p>
Expand Down Expand Up @@ -164,8 +159,6 @@ function QnA() {
</div>
)}
</div>

<div className={container}></div>
</div>
);
}
Expand Down
15 changes: 0 additions & 15 deletions src/pages/QnA/qna.css.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { style } from "@vanilla-extract/css";
import { vars } from "../../shared/styles/vars.css";

export const titleText = style({
fontSize: 30,
fontWeight: 500,
color: "white",
marginTop: 60,
});

export const subTitleContainer = style({
marginBottom: 20,
position: "absolute",
Expand All @@ -23,14 +16,6 @@ export const subTitleText = style({
fontFamily: vars.font.pyeongChangBold,
});

// 상단의 빨간 컨테이너
export const container = style({
width: "100%",
height: 110,
display: "flex",
justifyContent: "center",
});

// 중간에 검색창을 배치하는 컨테이너
export const mid = style({
position: "relative",
Expand Down
2 changes: 1 addition & 1 deletion src/shared/styles/vars.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const pyeongChangLight = fontFace({

export const vars = createGlobalTheme("#root", {
color: {
blue1: "#CFCECE",
blue1: "#0781CD",
blue2: "#029FD7",
blue3: "#C9CEE1",
green1: "#04D1C3",
Expand Down