diff --git a/next.config.mjs b/next.config.mjs index cc44ed7..1f85e95 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,7 +1,9 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + // notion image doamin + images: { domains: ['prod-files-secure.s3.us-west-2.amazonaws.com'], }, diff --git a/package-lock.json b/package-lock.json index 218707f..4784d42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "gdsc-dgu", "version": "0.1.0", "dependencies": { + "@notionhq/client": "^2.2.15", "clsx": "^2.1.0", "framer-motion": "^11.1.7", "next": "14.1.3", @@ -2427,6 +2428,18 @@ "node": ">= 8" } }, + "node_modules/@notionhq/client": { + "version": "2.2.15", + "resolved": "https://registry.npmjs.org/@notionhq/client/-/client-2.2.15.tgz", + "integrity": "sha512-XhdSY/4B1D34tSco/GION+23GMjaS9S2zszcqYkMHo8RcWInymF6L1x+Gk7EmHdrSxNFva2WM8orhC4BwQCwgw==", + "dependencies": { + "@types/node-fetch": "^2.5.10", + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2727,11 +2740,19 @@ "version": "20.11.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.26.tgz", "integrity": "sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", @@ -3197,6 +3218,11 @@ "has-symbols": "^1.0.3" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.18", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", @@ -3552,6 +3578,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -3790,6 +3827,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -4673,6 +4718,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -5728,6 +5786,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5880,6 +5957,25 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -7285,6 +7381,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -7448,8 +7549,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -7536,6 +7636,20 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/public/images/project_img.png b/public/images/default_member.png similarity index 100% rename from public/images/project_img.png rename to public/images/default_member.png diff --git a/public/images/default_project.png b/public/images/default_project.png new file mode 100644 index 0000000..17bd67d Binary files /dev/null and b/public/images/default_project.png differ diff --git a/src/app/api/member/route.tsx b/src/app/api/member/route.tsx index b002fd9..5db7534 100644 --- a/src/app/api/member/route.tsx +++ b/src/app/api/member/route.tsx @@ -5,38 +5,25 @@ const notion = new Client({ auth: process.env.NOTION_SECRET_KEY, }); -// seminar id를 가진 member 불러오기 -async function queryMemberData(databaseId: string, seminarId: string): Promise { + +async function queryAllMemberData(): Promise { try { const response = await notion.databases.query({ - database_id: databaseId, - filter: { - property: 'Seminars', - relation: { - contains: seminarId - } - }, + database_id: process.env.NOTION_MEMBER_DATABASE_ID || '', }); - return response.results; } catch (error) { - console.error('Error querying Notion database and fetching member data:', JSON.stringify(error)); + console.error(JSON.stringify(error)); + throw error; } } -type Data = { - items?: any[]; - message: string; -}; export async function GET(req: NextRequest) { - const url = new URL(req.url); - const seminarId = url.searchParams.get('seminarId') || ''; // 쿼리 파라미터에서 세미나 ID 가져오기 - const databaseId = process.env.NOTION_MEMBER_DATABASE_ID || ''; - try { - const data = await queryMemberData(databaseId, seminarId); + const data = await queryAllMemberData(); + return new Response(JSON.stringify({ data, message: 'Success' }), { status: 200, headers: { @@ -44,11 +31,16 @@ export async function GET(req: NextRequest) { }, }); } catch (error) { - return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { - status: 500, - headers: { - 'Content-Type': 'application/json', + + 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/api/project/all/route.tsx b/src/app/api/project/all/route.tsx new file mode 100644 index 0000000..b73f4f0 --- /dev/null +++ b/src/app/api/project/all/route.tsx @@ -0,0 +1,47 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); +const databaseId = process.env.NOTION_PROJECT_DATABASE_ID || ''; + +async function queryAllProjectData(): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + sorts: [ + { + property: 'Date', + direction: 'ascending', + }, + ], + }); + return response.results; + } catch (error) { + console.error(JSON.stringify(error)); + throw error; + } +} + +export async function GET(req: NextRequest) { + try { + const data = await queryAllProjectData(); + 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', + }, + }, + ); + } +} diff --git a/src/app/api/project/route.tsx b/src/app/api/project/route.tsx new file mode 100644 index 0000000..fd6e7be --- /dev/null +++ b/src/app/api/project/route.tsx @@ -0,0 +1,66 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); +const databaseId = process.env.NOTION_PROJECT_DATABASE_ID || ''; + +async function queryAllProjectData(type: string): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + filter: { + property: 'type', + multi_select: { + contains: type, + }, + }, + sorts: [ + { + property: 'Date', + direction: 'ascending', + }, + ], + }); + return response.results; + } catch (error) { + console.error(JSON.stringify(error)); + throw error; + } +} + +export async function GET(req: NextRequest) { + const url = new URL(req.url); + const type = url.searchParams.get('type'); + + if (!type) { + return new Response(JSON.stringify({ message: 'Type is required' }), { + status: 400, + headers: { + 'Content-Type': 'application/json', + }, + }); + } + + try { + const data = await queryAllProjectData(type); + + 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', + }, + }, + ); + } +} diff --git a/src/app/project/[id]/page.tsx b/src/app/project/[id]/page.tsx index 887d962..c188e90 100644 --- a/src/app/project/[id]/page.tsx +++ b/src/app/project/[id]/page.tsx @@ -1,16 +1,38 @@ -'use client'; - +import NotFoundPage from '@/app/not-found'; import ProjectContent from '@/components/project/content/ProjectContent'; import ProjectIntroduction from '@/components/project/introduction/ProjectIntroduction'; -import { PROJECTS } from '@/constants/project/projects'; -import { ProjectData } from '@/interfaces/project/projectData'; +import { + refactorMemberListData, + refactorProjectData, +} from '@/hooks/project/notionProjectDataRefactor'; import React from 'react'; -const ProjectDetailPage = ({ params }: { params: { id: string } }) => { - const projectData: ProjectData = PROJECTS.find( - (project) => project.id === Number(params.id), +const ProjectDetailPage = async ({ params }: { params: { id: string } }) => { + // 프로젝트 데이터 불러오기 + const projectResponse = await fetch( + `${process.env.SERVER_HOST}/api/project/all`, + ); + const projectList = await projectResponse.json(); + + const findProjectData = projectList?.data.find( + (project: any) => project.id === params.id, )!; + if (!findProjectData) { + // 찾을 수 없는 프로젝트인 경우! + return ; + } + + // 멤버 데이터 불러오기 + const memberResponse = await fetch(`${process.env.SERVER_HOST}/api/member`); + + const memberList = await memberResponse.json(); + + const projectData = refactorProjectData( + findProjectData, + refactorMemberListData(memberList?.data || []), + ); + return (
{/* -----------------------------------------------*/} diff --git a/src/app/project/page.tsx b/src/app/project/page.tsx index 3f2839b..05d1ee4 100644 --- a/src/app/project/page.tsx +++ b/src/app/project/page.tsx @@ -1,13 +1,24 @@ import ProjectHeader from '@/components/project/header/ProjectHeader'; import ProjectDesktopList from '@/components/project/list/ProjectDesktopList'; import ProjectMobileList from '@/components/project/list/ProjectMobileList'; +import { refactorProjectListData } from '@/hooks/project/notionProjectDataRefactor'; import React from 'react'; export const metadata = { title: 'Project', }; -const ProjectPage = () => { +const ProjectPage = async () => { + let projectData = []; + + // 목록 데이터 불러오기 + const type = 'WITHU'; + const projectResponse = await fetch( + `${process.env.SERVER_HOST}/api/project?type=${type}`, + ); + const projectList = await projectResponse.json(); + projectData = refactorProjectListData(projectList?.data || []); + return (
{/* -----------------------------------------------*/} @@ -18,13 +29,13 @@ const ProjectPage = () => { {/* -------프로젝트 리스트 (페이지네이션) ----------------*/} {/* -----------------------------------------------*/}
- +
{/* -----------------------------------------------*/} {/* -------프로젝트 리스트 (무한 스크롤 ) ----------------*/} {/* -----------------------------------------------*/}
- +
); diff --git a/src/app/solutionChallenge/page.tsx b/src/app/solutionChallenge/page.tsx index d9c0320..16bc6eb 100644 --- a/src/app/solutionChallenge/page.tsx +++ b/src/app/solutionChallenge/page.tsx @@ -1,14 +1,25 @@ -import ProjectList from '@/components/project/list/ProjectDesktopList'; import SolutionChallengeHeader from '@/components/sollutionChallenge/header/SolutionChallengeHeader'; import SolutionChallengeList from '@/components/sollutionChallenge/list/SolutionChallengeList'; -import SolutionChallengeTab from '@/components/sollutionChallenge/tab/SolutionChallengeTab'; +import { refactorProjectListData } from '@/hooks/project/notionProjectDataRefactor'; import React from 'react'; export const metadata = { title: 'SolutionChallenge', }; -const SolutionChallengePage = () => { +const SolutionChallengePage = async () => { + let solutionChallengeData = []; + + // 목록 데이터 불러오기 + const type = 'Solution Challenge'; + const solutionChallengeResponse = await fetch( + `${process.env.SERVER_HOST}/api/project?type=${type}`, + ); + const solutionChallengeList = await solutionChallengeResponse.json(); + solutionChallengeData = refactorProjectListData( + solutionChallengeList?.data || [], + ); + return (
{/* -----------------------------------------------*/} @@ -18,7 +29,7 @@ const SolutionChallengePage = () => { {/* -----------------------------------------------*/} {/* ------------------ 프로젝트 리스트 ----------------*/} {/* -----------------------------------------------*/} - +
); }; diff --git a/src/components/project/card/ProjectCard.tsx b/src/components/project/card/ProjectCard.tsx index bce8f40..479c078 100644 --- a/src/components/project/card/ProjectCard.tsx +++ b/src/components/project/card/ProjectCard.tsx @@ -1,8 +1,8 @@ -import ProjectImg from '@/images/project_img.png'; import { ProjectData } from '@/interfaces/project/projectData'; import Link from 'next/link'; import { motion } from 'framer-motion'; import { slideUpVariants } from '@/constants/project/slideUpVariants'; +import Image from 'next/image'; /** * @description @@ -28,21 +28,21 @@ const ProjectCard = ({ project }: { project: ProjectData }) => { variants={slideUpVariants} style={{ transformOrigin: '10% 60%' }} > - -
+ 프로젝트 사진
+ priority + />
-
{project.title}
+
{project?.title}
- {project.introduce} + {project?.introduce}
-
{project.feature}
+
{project?.feature}
diff --git a/src/components/project/content/ProjectContent.tsx b/src/components/project/content/ProjectContent.tsx index 0cbf3a9..c9765f7 100644 --- a/src/components/project/content/ProjectContent.tsx +++ b/src/components/project/content/ProjectContent.tsx @@ -1,3 +1,5 @@ +'use client'; + import { ProjectData } from '@/interfaces/project/projectData'; import ProjectToggle from './ProjectToggle'; import { slideUpVariants } from '@/constants/project/slideUpVariants'; @@ -28,10 +30,10 @@ const ProjectContent = ({ projectData }: { projectData: ProjectData }) => { className="w-full pb-[7.5rem] mx-auto" > -
+ {/*
노션 내용 크롤링
{projectData?.content}
-
+
*/} ); diff --git a/src/components/project/content/ProjectMember.tsx b/src/components/project/content/ProjectMember.tsx index 65c6ffe..4887284 100644 --- a/src/components/project/content/ProjectMember.tsx +++ b/src/components/project/content/ProjectMember.tsx @@ -1,4 +1,3 @@ -import ProfileImg from '@/images/project_img.png'; import { ProjectMemberData } from '@/interfaces/project/projectMemberData'; /** @@ -19,8 +18,10 @@ const ProjectMember = ({ member }: { member: ProjectMemberData }) => { return (
profile
diff --git a/src/components/project/content/ProjectToggle.tsx b/src/components/project/content/ProjectToggle.tsx index 2afd635..c27dcaf 100644 --- a/src/components/project/content/ProjectToggle.tsx +++ b/src/components/project/content/ProjectToggle.tsx @@ -33,11 +33,12 @@ const ProjectToggle = ({ teamData }: { teamData: ProjectMemberData[] }) => {
-
+
{teamData.length > 0 && teamData.map((member) => ( ))} +
); diff --git a/src/components/project/introduction/ProjectIntroduction.tsx b/src/components/project/introduction/ProjectIntroduction.tsx index ecd7d2c..ffd3ed8 100644 --- a/src/components/project/introduction/ProjectIntroduction.tsx +++ b/src/components/project/introduction/ProjectIntroduction.tsx @@ -3,12 +3,12 @@ import GithubIcon from '@/svg/icons/project/githubIcon.svg'; import YoutubeIcon from '@/svg/icons/project/youtubeIcon.svg'; import FileIcon from '@/svg/icons/project/fileIcon.svg'; -import ProjectImg from '@/images/project_img.png'; import Image from 'next/image'; import { ProjectData } from '@/interfaces/project/projectData'; import ProjectIntroductionBand from './ProjectIntroductionBand'; import { motion } from 'framer-motion'; import { slideUpVariants } from '@/constants/project/slideUpVariants'; +import Link from 'next/link'; /** * @description @@ -29,8 +29,10 @@ const ProjectIntroduction = ({ projectData }: { projectData: ProjectData }) => {
프로젝트 프로필 { className="flex flex-col justify-end my-3" >
- - - + {projectData?.github && ( + + + + )} + {/* */} + {projectData?.youtube && ( + + + + )}
{projectData?.title}
{projectData?.introduce}
diff --git a/src/components/project/introduction/ProjectIntroductionBand.tsx b/src/components/project/introduction/ProjectIntroductionBand.tsx index 3914ceb..7ea9ae3 100644 --- a/src/components/project/introduction/ProjectIntroductionBand.tsx +++ b/src/components/project/introduction/ProjectIntroductionBand.tsx @@ -33,7 +33,7 @@ const ProjectIntroductionBand = ({ className="w-full flex flex-col items-center my-16 bg-mono_900" >
-
서비스가 어디서 시작됐는지, 서비스의 띠지
+
{projectData?.performance}
diff --git a/src/components/project/list/ProjectDesktopList.tsx b/src/components/project/list/ProjectDesktopList.tsx index 37de15b..69007b9 100644 --- a/src/components/project/list/ProjectDesktopList.tsx +++ b/src/components/project/list/ProjectDesktopList.tsx @@ -3,7 +3,6 @@ import { useEffect, useState } from 'react'; import ProjectCard from '../card/ProjectCard'; import { ProjectData } from '@/interfaces/project/projectData'; -import { PROJECTS } from '@/constants/project/projects'; import ProjectPagination from '../pagination/ProjectPagination'; /** @@ -18,13 +17,17 @@ import ProjectPagination from '../pagination/ProjectPagination'; * @returns The rendered list component. */ -const ProjectDesktopList = () => { +const ProjectDesktopList = ({ + projectData, +}: { + projectData: ProjectData[]; +}) => { const [currentPage, setCurrentPage] = useState(1); const [projects, setProjects] = useState([]); - const itemsPerPage = 10; + const itemsPerPage = 9; const pageNum = []; - for (let i = 1; i <= Math.ceil(PROJECTS.length / itemsPerPage); i++) { + for (let i = 1; i <= Math.ceil(projectData.length / itemsPerPage); i++) { pageNum.push(i); } @@ -32,7 +35,7 @@ const ProjectDesktopList = () => { // 페이지 갱신 const startItemIndex = (page - 1) * itemsPerPage; const endItemIndex = startItemIndex + itemsPerPage; - setProjects(PROJECTS.slice(startItemIndex, endItemIndex)); + setProjects(projectData.slice(startItemIndex, endItemIndex)); setCurrentPage(page); }; @@ -42,7 +45,7 @@ const ProjectDesktopList = () => { return (
-
+
{projects.map((project) => ( ))} diff --git a/src/components/project/list/ProjectMobileList.tsx b/src/components/project/list/ProjectMobileList.tsx index ec91443..d45a673 100644 --- a/src/components/project/list/ProjectMobileList.tsx +++ b/src/components/project/list/ProjectMobileList.tsx @@ -1,9 +1,7 @@ 'use client'; -import { useState } from 'react'; import ProjectCard from '../card/ProjectCard'; import { ProjectData } from '@/interfaces/project/projectData'; -import { PROJECTS } from '@/constants/project/projects'; /** * @description @@ -17,13 +15,11 @@ import { PROJECTS } from '@/constants/project/projects'; * @returns The rendered list component. */ -const ProjectMobileList = () => { - const [projects, setProjects] = useState(PROJECTS); - +const ProjectMobileList = ({ projectData }: { projectData: ProjectData[] }) => { return (
- {projects.map((project) => ( + {projectData.map((project) => ( ))}
diff --git a/src/components/sollutionChallenge/header/SolutionChallengeHeader.tsx b/src/components/sollutionChallenge/header/SolutionChallengeHeader.tsx index e5ae19a..de1999a 100644 --- a/src/components/sollutionChallenge/header/SolutionChallengeHeader.tsx +++ b/src/components/sollutionChallenge/header/SolutionChallengeHeader.tsx @@ -32,8 +32,8 @@ const SolutionChallengeHeader = () => { backgroundBlendMode: 'multiply', }} > -
- +
+
{ +const SolutionChallengeList = ({ + solutionChallengeData, +}: { + solutionChallengeData: ProjectData[]; +}) => { const [selectedYear, setSelectedYear] = useState('2024'); const [projects, setProjects] = useState([]); const changeSelectedYear = (year: string) => { - setProjects(PROJECTS.filter((project) => project.date === year)); + // 년도 필터링 추후에 추가하기 + // setProjects( + // solutionChallengeData.filter((project) => project.date === year), + // ); + setProjects(solutionChallengeData); setSelectedYear(year); }; @@ -40,7 +47,7 @@ const SolutionChallengeList = () => { selectedYear={selectedYear} changeSelectedYear={changeSelectedYear} /> -
+
{projects.map((project) => ( ))} diff --git a/src/components/sollutionChallenge/tab/SolutionChallengeTab.tsx b/src/components/sollutionChallenge/tab/SolutionChallengeTab.tsx index 527d119..b7a52b8 100644 --- a/src/components/sollutionChallenge/tab/SolutionChallengeTab.tsx +++ b/src/components/sollutionChallenge/tab/SolutionChallengeTab.tsx @@ -24,7 +24,7 @@ const SolutionChallengeTab = ({ selectedYear: string; changeSelectedYear: (year: string) => void; }) => { - const yearData: string[] = ['2024', '2023', '2022', '2021', '2020']; + const yearData: string[] = ['2024']; const motionRef = useRef(null); const isInView = useInView(motionRef, { once: true }); diff --git a/src/hooks/project/notionProjectDataRefactor.ts b/src/hooks/project/notionProjectDataRefactor.ts new file mode 100644 index 0000000..8a0399a --- /dev/null +++ b/src/hooks/project/notionProjectDataRefactor.ts @@ -0,0 +1,54 @@ +import { ProjectData } from '@/interfaces/project/projectData'; +import ProjectImg from '@/images/default_project.png'; +import MemberImg from '@/images/default_member.png'; +import { ProjectMemberData } from '@/interfaces/project/projectMemberData'; + +// 프로젝트 목록 데이터 +export function refactorProjectListData(items: any[]): ProjectData[] { + return items.map((item) => ({ + id: item.id ?? '', + title: item?.properties?.Idea?.title[0]?.plain_text ?? '', + introduce: + item?.properties['소개 (150자 이내)']?.rich_text[0]?.plain_text ?? '', + image: item?.cover?.file?.url ?? ProjectImg.src, + feature: '', + performance: '', + team: [], + content: '', + date: '', + // 유튜브, 깃허브 링크도 추가하기 + })); +} + +// 프로젝트 디테일 데이터 +export function refactorProjectData(item: any, memberList: any[]): ProjectData { + return { + id: item.id ?? '', + title: item?.properties?.Idea?.title[0]?.plain_text ?? '', + introduce: + item?.properties['소개 (150자 이내)']?.rich_text[0]?.plain_text ?? '', + image: item?.cover?.file?.url ?? ProjectImg.src, + feature: '', + performance: '', + team: item?.properties?.Members?.relation.map((item: any) => + memberList.find((member) => member.id === item.id), + ), + content: '', + date: '', + youtube: + item?.properties['유튜브 링크']?.rich_text[0]?.plain_text ?? undefined, + github: + item?.properties['깃허브 링크']?.rich_text[0]?.plain_text ?? undefined, + }; +} + +// 멤버 목록 데이터 +export function refactorMemberListData(items: any[]): ProjectMemberData[] { + return items.map((item) => ({ + id: item.id ?? '', + name: item?.properties['이름']?.title[0]?.plain_text ?? '', + role: item.properties.Part?.multi_select[0]?.name ?? '', + seminar: '', + image: MemberImg.src, // 프로필 이미지도 추가하기 + })); +} diff --git a/src/interfaces/project/projectData.ts b/src/interfaces/project/projectData.ts index 0593026..22c8394 100644 --- a/src/interfaces/project/projectData.ts +++ b/src/interfaces/project/projectData.ts @@ -10,4 +10,6 @@ export interface ProjectData { team: ProjectMemberData[]; content: string; date: string; // 일단은 연도값만 넣기 + youtube?: string; + github?: string; } diff --git a/src/interfaces/project/projectMemberData.ts b/src/interfaces/project/projectMemberData.ts index 307bb5a..d71cbad 100644 --- a/src/interfaces/project/projectMemberData.ts +++ b/src/interfaces/project/projectMemberData.ts @@ -3,4 +3,5 @@ export interface ProjectMemberData { name: string; role: string; seminar: string; + image: string; }