From 3601137d9e2c21b019e2cea58ee296a64242f9d3 Mon Sep 17 00:00:00 2001 From: Eunji <129590633+bianbbc87@users.noreply.github.com> Date: Wed, 8 May 2024 04:11:42 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Feat=20-=20=EC=84=B8=EB=AF=B8?= =?UTF-8?q?=EB=82=98=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=85=B8=EC=85=98=20?= =?UTF-8?q?api=20=EC=97=B0=EA=B2=B0=20#44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.mjs | 4 ++ src/app/api/seminar/route.tsx | 59 +++++++++++++++++++ src/app/seminar/page.tsx | 18 +++--- .../seminar/header/SeminarHeader.tsx | 3 +- .../seminar/thumbnail/SeminarThumbnail.tsx | 10 +++- .../thumbnail/SeminarThumbnailList.tsx | 55 +++++++++-------- 6 files changed, 111 insertions(+), 38 deletions(-) create mode 100644 src/app/api/seminar/route.tsx diff --git a/next.config.mjs b/next.config.mjs index 6425efa..018fe49 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,10 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + // notion image doamin + images: { + domains: ['prod-files-secure.s3.us-west-2.amazonaws.com'], + }, webpack(config) { const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg'), diff --git a/src/app/api/seminar/route.tsx b/src/app/api/seminar/route.tsx new file mode 100644 index 0000000..bd6fa1f --- /dev/null +++ b/src/app/api/seminar/route.tsx @@ -0,0 +1,59 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); + +// seminar 데이터 query select, 오름차순 +async function querySeminarData(databaseId: string, tag: string): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + filter: { + property: 'Tags', + multi_select: { + contains: tag + } + }, + sorts: [ + { + property: 'Date', + direction: 'ascending' + } + ] + }); + + return response.results; + } catch (error) { + console.error('Error querying Notion database and fetching member data:', JSON.stringify(error)); + throw error; + } +} + +type Data = { + items?: any[]; + message: string; +}; + +export async function GET(req: NextRequest) { + const databaseId = process.env.NOTION_SEMINAR_DATABASE_ID || ''; + const tag = '🏕️ Camping Seminar'; + + try { + const data = await querySeminarData(databaseId, tag); + return new Response(JSON.stringify({ data, message: 'Success' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +} \ No newline at end of file diff --git a/src/app/seminar/page.tsx b/src/app/seminar/page.tsx index fede2de..001d04d 100644 --- a/src/app/seminar/page.tsx +++ b/src/app/seminar/page.tsx @@ -1,13 +1,14 @@ -'use client'; - import SeminarHeader from '@/components/seminar/header/SeminarHeader'; -import SeminarMenuBar from '@/components/seminar/menubar/SeminarMenuBar'; import SeminarThumbnailList from '@/components/seminar/thumbnail/SeminarThumbnailList'; import SeminarToggle from '@/components/seminar/toggle/SeminarToggle'; -import React, { useState } from 'react'; +import { refactorSeminarData } from '@/hooks/seminar/notionDataRefactor'; + +const SeminarPage = async () => { + // seminar 데이터 가져오기 + const seminarResponse = await fetch('http://localhost:3001/api/seminar'); + const seminarList = await seminarResponse.json(); -const SeminarPage = () => { - const [selectedCategory, setSelectedCategory] = useState('all'); + const seminars = refactorSeminarData(seminarList.data || []); return
@@ -18,11 +19,8 @@ const SeminarPage = () => { {/* toggle */} -{/* select button */} - - {/* seminar list */} - +
diff --git a/src/components/seminar/header/SeminarHeader.tsx b/src/components/seminar/header/SeminarHeader.tsx index 27a2878..e9c8b60 100644 --- a/src/components/seminar/header/SeminarHeader.tsx +++ b/src/components/seminar/header/SeminarHeader.tsx @@ -1,7 +1,8 @@ +'use client'; + import BannerImg from '@/svg/seminar/seminar_banner.svg'; import { motion } from 'framer-motion'; import Link from 'next/link'; -import { OpenSeminar } from '@/interfaces/seminar/openSeminar'; import { OPEN_SEMINAR_DATA } from '@/constants/seminar/openSeminarData'; /** diff --git a/src/components/seminar/thumbnail/SeminarThumbnail.tsx b/src/components/seminar/thumbnail/SeminarThumbnail.tsx index 5d127b3..f1fc73f 100644 --- a/src/components/seminar/thumbnail/SeminarThumbnail.tsx +++ b/src/components/seminar/thumbnail/SeminarThumbnail.tsx @@ -1,3 +1,4 @@ +import { SeminarMember } from '@/interfaces/seminar/seminarMember'; import { SeminarThumbnail } from '@/interfaces/seminar/seminarThumbnail'; import Image from 'next/image'; @@ -12,17 +13,20 @@ import Image from 'next/image'; * Renders the header component for the recruitment section. * @returns The rendered header component. */ -const SeminarThumbnailBox = ({ data }: { data: SeminarThumbnail }) => { +const SeminarThumbnailBox = ({ seminar }: { seminar: SeminarThumbnail }) => { return (
+
{`${data.presenter_name}'s_seminarimage`} +
); }; diff --git a/src/components/seminar/thumbnail/SeminarThumbnailList.tsx b/src/components/seminar/thumbnail/SeminarThumbnailList.tsx index 999025d..30b0f20 100644 --- a/src/components/seminar/thumbnail/SeminarThumbnailList.tsx +++ b/src/components/seminar/thumbnail/SeminarThumbnailList.tsx @@ -2,11 +2,12 @@ import React, { useState } from 'react'; import SeminarThumbnailBox from './SeminarThumbnail'; -import { SEMINAR_DATA } from '@/constants/seminar/seminarData'; import Link from 'next/link' import { motion } from 'framer-motion'; import { seminarCardVariants } from '@/constants/seminar/seminarCardVariants'; import SeminarPagination from './SeminarPagination'; +import { SeminarThumbnail } from '@/interfaces/seminar/seminarThumbnail'; +import SeminarMenuBar from '../menubar/SeminarMenuBar'; /** * @description @@ -22,12 +23,13 @@ import SeminarPagination from './SeminarPagination'; * @returns The rendered header component. */ -const SeminarThumbnailList = ({ selectedCategory }: { selectedCategory: string }) => { +const SeminarThumbnailList = ({ seminar }: { seminar:SeminarThumbnail[] }) => { const [currentPage, setCurrentPage] = useState(1); + const [selectedCategory, setSelectedCategory] = useState('all'); const itemsPerPage = 12; // 한 페이지당 표시할 항목 수 - + // topic으로 데이터 필터링 - const filteredData = selectedCategory !== "all" ? SEMINAR_DATA.filter(seminar => seminar.topic === selectedCategory) : SEMINAR_DATA; + const filteredData = selectedCategory !== "all" ? seminar.filter(seminar => seminar.topic === selectedCategory) : seminar; // 페이지네이션 const indexOfLastItem = currentPage * itemsPerPage; @@ -48,14 +50,18 @@ const SeminarThumbnailList = ({ selectedCategory }: { selectedCategory: string } return ( +
+ {/* select button */} + +
{/* 썸네일 리스트 */} {/* desktop인 경우 */}
- {currentItems.map((seminar) => ( + {currentItems.map((seminar:SeminarThumbnail, index:number) => ( - - - + + + ))}
{/*tablet, mobile인 경우 */}
- {filteredData.map((seminar) => ( + {filteredData.map((seminar:SeminarThumbnail, index:number) => ( + > - - + href={`/seminar/${seminar.id}`} + > + + ))}
@@ -110,6 +116,7 @@ const SeminarThumbnailList = ({ selectedCategory }: { selectedCategory: string } />
+
); }; export default SeminarThumbnailList;