From 59ffb5370c9b907d697b22cd4541cb8c5aa18452 Mon Sep 17 00:00:00 2001 From: yeun38 Date: Sun, 28 Sep 2025 23:21:47 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20UI=EA=B5=AC=ED=98=84=EC=A4=91=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(nav)/study/[id]/page.tsx | 3 + app/(nav)/study/page.tsx | 141 +++++++++++++++++++++++++++ app/layout.tsx | 4 +- src/entities/study/ui/study-card.tsx | 93 ++++++++++++++++++ src/shared/icons/plus.svg | 3 + src/widgets/home/header.tsx | 19 ++-- src/widgets/home/sidebar.tsx | 2 +- 7 files changed, 253 insertions(+), 12 deletions(-) create mode 100644 app/(nav)/study/[id]/page.tsx create mode 100644 app/(nav)/study/page.tsx create mode 100644 src/entities/study/ui/study-card.tsx create mode 100644 src/shared/icons/plus.svg diff --git a/app/(nav)/study/[id]/page.tsx b/app/(nav)/study/[id]/page.tsx new file mode 100644 index 00000000..7addef93 --- /dev/null +++ b/app/(nav)/study/[id]/page.tsx @@ -0,0 +1,3 @@ +export default function StudyPage() { + return
Study Page
; +} diff --git a/app/(nav)/study/page.tsx b/app/(nav)/study/page.tsx new file mode 100644 index 00000000..73ce3539 --- /dev/null +++ b/app/(nav)/study/page.tsx @@ -0,0 +1,141 @@ +import React from 'react'; +import StudyCard, { GroupStudy } from '@/entities/study/ui/study-card'; +import Button from '@/shared/ui/button'; +import IconPlus from '@/shared/icons/plus.svg'; + +import Sidebar from '@/widgets/home/sidebar'; +const groupStudies: GroupStudy[] = [ + { + basicInfo: { + groupStudyId: 1, + type: 'frontend', + targetRole: 'junior', + maxMembers: 5, + experienceLevel: 'beginner', + method: 'online', + regularMeeting: '매주 화요일 8PM', + startDate: '2025-10-01', + durationWeeks: 6, + price: 50000, + status: 'recruiting', + createdAt: '2025-09-20T10:00:00Z', + updatedAt: '2025-09-25T12:30:00Z', + }, + simpleDetailInfo: { + title: 'React 입문 스터디', + summary: '기초부터 React를 배워보는 주니어 대상 스터디', + }, + }, + { + basicInfo: { + groupStudyId: 2, + type: 'backend', + targetRole: 'senior', + maxMembers: 8, + experienceLevel: 'intermediate', + method: 'offline', + regularMeeting: '매주 토요일 2PM', + startDate: '2025-11-05', + durationWeeks: 8, + price: 100000, + status: 'planned', + createdAt: '2025-09-22T09:00:00Z', + updatedAt: '2025-09-26T11:00:00Z', + }, + simpleDetailInfo: { + title: 'Spring Boot 중급 스터디', + summary: '실무 중심으로 스프링부트를 다뤄보는 스터디', + }, + }, + { + basicInfo: { + groupStudyId: 3, + type: 'fullstack', + targetRole: 'all', + maxMembers: 10, + experienceLevel: 'beginner', + method: 'hybrid', + regularMeeting: '격주 일요일 3PM', + startDate: '2025-12-01', + durationWeeks: 10, + price: 0, + status: 'recruiting', + createdAt: '2025-09-23T14:20:00Z', + updatedAt: '2025-09-27T15:40:00Z', + }, + simpleDetailInfo: { + title: '풀스택 웹 프로젝트 스터디', + summary: 'React + Node.js로 팀 프로젝트 경험 쌓기', + }, + }, + { + basicInfo: { + groupStudyId: 4, + type: 'ai', + targetRole: 'researcher', + maxMembers: 6, + experienceLevel: 'advanced', + method: 'online', + regularMeeting: '매주 수요일 9PM', + startDate: '2025-10-15', + durationWeeks: 12, + price: 200000, + status: 'in-progress', + createdAt: '2025-09-24T08:00:00Z', + updatedAt: '2025-09-28T09:30:00Z', + }, + simpleDetailInfo: { + title: '딥러닝 논문 스터디', + summary: '최신 AI 논문 리뷰와 구현을 목표로 하는 스터디', + }, + }, + { + basicInfo: { + groupStudyId: 5, + type: 'mobile', + targetRole: 'junior', + maxMembers: 4, + experienceLevel: 'beginner', + method: 'offline', + regularMeeting: '매주 금요일 7PM', + startDate: '2025-11-20', + durationWeeks: 5, + price: 30000, + status: 'recruiting', + createdAt: '2025-09-25T10:45:00Z', + updatedAt: '2025-09-27T18:00:00Z', + }, + simpleDetailInfo: { + title: 'Flutter 앱 개발 기초', + summary: 'Flutter로 간단한 앱을 함께 만들어보는 스터디', + }, + }, +]; + +export default function Study() { + return ( +
+
+
+ + 스터디 둘러보기 + + +
+
+ {groupStudies.map((study) => ( + + ))} +
+
+ +
+ ); +} diff --git a/app/layout.tsx b/app/layout.tsx index 7fda55f8..316d31fd 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -35,9 +35,9 @@ export default function RootLayout({
{/** 1400 + 48*2 패딩 양옆 48로 임의적용 */} -
+
-
{children}
+
{children}
diff --git a/src/entities/study/ui/study-card.tsx b/src/entities/study/ui/study-card.tsx new file mode 100644 index 00000000..d59a8a21 --- /dev/null +++ b/src/entities/study/ui/study-card.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import Badge from '@/shared/ui/badge'; + +export interface GroupStudy { + basicInfo: { + groupStudyId: number; // int64 + type: string; + targetRole: string; + maxMembers: number; // int32 + experienceLevel: string; + method: string; + regularMeeting: string; + startDate: string; // date + durationWeeks: number; // int32 + price: number; + status: string; + createdAt: string; // date-time + updatedAt: string; // date-time + }; + simpleDetailInfo: { + title: string; + summary: string; + }; +} + +export default function StudyCard(props: GroupStudy) { + const { basicInfo, simpleDetailInfo } = props; + + const basicInfoItems = [ + { + label: '유형', + value: + basicInfo.method === 'online' + ? '온라인' + : basicInfo.method === 'offline' + ? '오프라인' + : '혼합', + }, + { label: '주제', value: `${basicInfo.maxMembers}명` }, + { + label: '경력', + value: + basicInfo.experienceLevel === 'beginner' + ? '초급' + : basicInfo.experienceLevel === 'intermediate' + ? '중급' + : '고급', + }, + { label: '정기모임', value: `${basicInfo.durationWeeks}주` }, + { + label: '모집인원', + value: `/${basicInfo.maxMembers}`, + }, + { + label: '참가비', + value: + basicInfo.price === 0 + ? '무료' + : `${basicInfo.price.toLocaleString()}원`, + }, + ]; + + return ( +
+
+
+
+ + {simpleDetailInfo.title} + + 제로원 스터디 +
+

+ {simpleDetailInfo.summary} +

+
+
+ {basicInfoItems.map((item, idx) => ( +
+ + {item.label} + + + {item.value} + +
+ ))} +
+
+
img
+
+ ); +} diff --git a/src/shared/icons/plus.svg b/src/shared/icons/plus.svg new file mode 100644 index 00000000..897e8420 --- /dev/null +++ b/src/shared/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/widgets/home/header.tsx b/src/widgets/home/header.tsx index 122b4b48..fcd0b5d4 100644 --- a/src/widgets/home/header.tsx +++ b/src/widgets/home/header.tsx @@ -1,3 +1,5 @@ +import clsx from 'clsx'; +import Image from 'next/image'; import Link from 'next/link'; import { getUserProfileInServer } from '@/entities/user/api/get-user-profile.server'; import HeaderUserDropdown from '@/features/auth/ui/header-user-dropdown'; @@ -5,8 +7,6 @@ import LoginModal from '@/features/auth/ui/login-modal'; import { getServerCookie } from '@/shared/lib/server-cookie'; import { isNumeric } from '@/shared/lib/validation'; import Button from '@/shared/ui/button'; -import Image from 'next/image'; -import clsx from 'clsx'; export default async function Header() { const memberIdStr = await getServerCookie('memberId'); @@ -28,16 +28,16 @@ export default async function Header() { return (
- Logo + Logo Logo-title {/* 1차 MVP에선 사용하지 않아 제외 */} - {/* */} + {/* 알림 기능을 구현하지 못해 주석 처리 */} {/*
diff --git a/src/widgets/home/sidebar.tsx b/src/widgets/home/sidebar.tsx index 2c95571a..904d8d0f 100644 --- a/src/widgets/home/sidebar.tsx +++ b/src/widgets/home/sidebar.tsx @@ -14,7 +14,7 @@ export default async function Sidebar() { const userProfile = await getUserProfileInServer(memberId); return ( -