Skip to content

Commit b82e633

Browse files
authored
feat: api 주소 수정, 활동 현황 수정
1 parent 47ccade commit b82e633

2 files changed

Lines changed: 163 additions & 151 deletions

File tree

Lines changed: 162 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,191 @@
1-
import React from 'react'
1+
import React, { useEffect, useState } from 'react'
22
import { motion } from 'framer-motion'
33
import DasomLogo from '../../assets/images/dasomLogo.svg'
4-
import ActivityBar from '../../assets/images/activityBar.svg'
54
import { ActivityStatusProps, ActivitySection } from './types'
5+
import axios from 'axios'
6+
7+
interface ApiActivity {
8+
id: number
9+
monthDay: string
10+
title: string
11+
award: string | null
12+
}
13+
14+
interface ApiSection {
15+
id: number
16+
section: string
17+
activities: ApiActivity[]
18+
}
19+
20+
interface ApiYearData {
21+
year: number
22+
sections: ApiSection[]
23+
}
624

7-
// 페이드 인 및 위로 이동 애니메이션
825
const FadeInSection: React.FC<{ children: React.ReactNode }> = ({
926
children,
10-
}) => {
11-
return (
12-
<motion.div
13-
initial={{ opacity: 0, y: 20 }}
14-
whileInView={{ opacity: 1, y: 0 }}
15-
transition={{ duration: 0.8, ease: 'easeOut' }}
16-
viewport={{ once: false }}
17-
>
18-
{children}
19-
</motion.div>
20-
)
21-
}
27+
}) => (
28+
<motion.div
29+
initial={{ opacity: 0, y: 10 }}
30+
whileInView={{ opacity: 1, y: 0 }}
31+
transition={{ duration: 0.6, ease: 'easeOut' }}
32+
viewport={{ once: true, amount: 0.2 }}
33+
>
34+
{children}
35+
</motion.div>
36+
)
2237

23-
const ActivityStatus: React.FC<ActivityStatusProps> = ({
24-
year,
38+
const ActivityStatus: React.FC<ActivityStatusProps> = ({
39+
year,
2540
activityData: customActivityData,
26-
className = ''
41+
className = '',
2742
}) => {
28-
// 2024년도 기본 활동 데이터
29-
const defaultActivityData2024: ActivitySection[] = [
30-
{
31-
category: '코엑스 한국전자전',
32-
items: [
33-
{
34-
award: '장려상',
35-
subtitle: '2024 동양미래 EXPO',
36-
},
37-
],
38-
},
39-
{
40-
category: '외부 경진대회 / 전시회',
41-
items: [
42-
{
43-
award: '동상',
44-
subtitle: '교육장비 개발 및 아이디어 경진대회',
45-
},
46-
],
47-
},
48-
{
49-
category: '교내 경진대회',
50-
items: [
51-
{
52-
award: '최우수상',
53-
subtitle: '컴퓨터 공학부 경진대회',
54-
},
55-
],
56-
},
57-
{
58-
category: '세미나 실적',
59-
items: [
60-
{ title: '현직 백엔드 개발자 특강 - ', subtitle: '20명 대상' },
61-
{ title: '웹 개발 세미나 - ', subtitle: '10명 대상' },
62-
],
63-
},
64-
{
65-
category: '기타 활동',
66-
items: [
67-
{ title: '컴퓨터공학부 최초 해커톤 개최' },
68-
{ title: '전공동아리 내부 팀 프로젝트 발표회 개최' },
69-
{ title: 'DASOM MAKERS 스터디 및 홈페이지 제작' },
70-
{ title: '시험기간 간식 행사' },
71-
{ title: '할로윈 행사' },
72-
{ title: '동계, 하계 MT' },
73-
],
74-
},
75-
]
76-
77-
// 2025년도 기본 활동 데이터
78-
const defaultActivityData2025: ActivitySection[] = [
79-
{
80-
category: '신규 프로젝트',
81-
items: [
82-
{
83-
title: 'NFT 기반 타임캡슐 서비스 - ',
84-
subtitle: ' 기획, 디자인 및 시연',
85-
},
86-
],
87-
},
88-
{
89-
category: '세미나 및 워크샵',
90-
items: [
91-
{ title: '나의 커리어 디자인하기 - 나에게 맞는 회사 고민하기, 성장 전략은? ', subtitle: ' ' },
92-
],
93-
},
94-
{
95-
category: '대회 참가',
96-
items: [
97-
{
98-
award: '장려상 ',
99-
subtitle: '생성형 AI를 활용한 문제해결 해커톤',
100-
},
101-
],
102-
},
103-
{
104-
category: '2025년 기타 활동',
105-
items: [
106-
{ title: '스프링 부트, 팀 프로젝트 기획 개발 스터디 그룹 운영' },
107-
{ title: '컴퓨터공학부 + 시각디자인학부 협업 해커톤 개최' },
108-
{ title: '대학생 IT 연합동아리 DND, UMC 활동' },
109-
{ title: '오픈소스 프로젝트 기여 활동' },
110-
{ title: '2025년 동계 MT 계획' },
111-
{ title: '미니퀴즈 간식행사' },
112-
],
113-
},
114-
]
115-
116-
// 커스텀 데이터가 있으면 사용하고, 없으면 연도에 따른 기본 데이터 사용
117-
const data = customActivityData || (year === '2025' ? defaultActivityData2025 : defaultActivityData2024)
43+
const [apiData, setApiData] = useState<ActivitySection[]>([])
44+
const [loading, setLoading] = useState(true)
45+
46+
useEffect(() => {
47+
const fetchActivities = async () => {
48+
try {
49+
setLoading(true)
50+
51+
const response = await axios.get<ApiYearData[]>(
52+
'https://api.dmu-dasom.or.kr/api/activities'
53+
)
54+
55+
const result = response.data
56+
57+
const currentYearData = result.find(
58+
item => item.year === Number(year)
59+
)
60+
61+
if (!currentYearData) {
62+
setApiData([])
63+
return
64+
}
65+
66+
const transformed: ActivitySection[] =
67+
currentYearData.sections.map(section => ({
68+
category: section.section,
69+
items: section.activities.map(activity => ({
70+
title: activity.title,
71+
award: activity.award ?? undefined,
72+
subtitle: activity.monthDay
73+
? `(${activity.monthDay})`
74+
: undefined,
75+
})),
76+
}))
77+
78+
setApiData(transformed)
79+
} catch (error) {
80+
console.error('활동 데이터 불러오기 실패:', error)
81+
setApiData([])
82+
} finally {
83+
setLoading(false)
84+
}
85+
}
86+
87+
fetchActivities()
88+
}, [year])
89+
90+
const defaultActivityData2024: ActivitySection[] = []
91+
const defaultActivityData2025: ActivitySection[] = []
92+
93+
const data =
94+
customActivityData ||
95+
(apiData.length > 0
96+
? apiData
97+
: year === '2025'
98+
? defaultActivityData2025
99+
: defaultActivityData2024)
100+
101+
if (loading) {
102+
return <div className="text-white text-center py-10">Loading...</div>
103+
}
118104

119105
return (
120-
<FadeInSection>
121-
<div className={`max-w-[400px] bg-mainBlack p-4 rounded-xl text-white ${className}`}>
122-
<div className='flex items-center gap-2 mb-3'>
123-
<img src={DasomLogo} className='w-7 h-7' alt='Dasom Icon' />
106+
<FadeInSection key={year}>
107+
<div
108+
className={`max-w-[400px] bg-mainBlack p-4 rounded-xl text-white ${className}`}
109+
>
110+
{/* 헤더 */}
111+
<div className="flex items-center gap-2 mb-6">
112+
<img src={DasomLogo} className="w-7 h-7" alt="Dasom Icon" />
124113
<div>
125-
<div className='text-[16px] font-pretendardBold'>활동 현황</div>
126-
<div className='text-mainColor text-[13px] font-pretendardSemiBold'>
114+
<div className="text-[16px] font-pretendardBold">
115+
활동 현황
116+
</div>
117+
<div className="text-mainColor text-[13px] font-pretendardSemiBold">
127118
{year}
128119
</div>
129120
</div>
130121
</div>
131-
<div className='flex items-start gap-3'>
132-
<img
133-
src={ActivityBar}
134-
className='w-4 h-[300px] mt-1.5'
135-
alt='Activitybar'
136-
/>
137-
<div className='space-y-3'>
122+
123+
{/* 타임라인 */}
124+
<div className="relative">
125+
126+
<div className="space-y-6">
138127
{data.map((section, index) => (
139128
<FadeInSection key={index}>
140-
<div>
141-
<div className='text-white text-[12px] font-pretendardBold'>
142-
{section.category}
129+
<div className="flex gap-4 relative">
130+
131+
{/* 점 + 선 영역 */}
132+
<div className="relative w-6 flex justify-center">
133+
134+
{/* 세로 점선 (가운데 정렬) */}
135+
<div
136+
className="absolute top-0 bottom-0 left-1/2
137+
-translate-x-1/2
138+
border-l-2 border-dashed border-mainColor/40"
139+
/>
140+
141+
{/* 점 */}
142+
<span
143+
className="relative z-10 w-1.5 h-1.5 rounded-full bg-mainColor
144+
shadow-[0_0_10px_rgba(0,255,200,0.8)]"
145+
/>
146+
</div>
147+
148+
{/* 콘텐츠 */}
149+
<div className="flex-1">
150+
<div className="text-white text-[12px] font-pretendardBold mb-1">
151+
{section.category}
152+
</div>
153+
154+
<ul className="space-y-1">
155+
{section.items.map((activity, idx) => (
156+
<li
157+
key={idx}
158+
className="flex flex-wrap text-[10.5px] leading-tight"
159+
>
160+
{activity.award && (
161+
<span className="font-pretendardBold text-mainColor mr-1">
162+
{activity.award}
163+
</span>
164+
)}
165+
{activity.title && (
166+
<span className="font-pretendardRegular">
167+
{activity.title}
168+
</span>
169+
)}
170+
{activity.subtitle && (
171+
<span className="text-subGrey font-pretendardRegular ml-1">
172+
{activity.subtitle}
173+
</span>
174+
)}
175+
</li>
176+
))}
177+
</ul>
143178
</div>
144-
<ul className='space-y-1'>
145-
{section.items.map((activity, idx) => (
146-
<li
147-
key={idx}
148-
className='flex flex-wrap text-[10.5px] leading-tight'
149-
>
150-
{activity.title && (
151-
<span className='font-pretendardRegular'>
152-
{activity.title}
153-
</span>
154-
)}
155-
{activity.award && (
156-
<span className='font-pretendardBold text-mainColor mr-1'>
157-
{activity.award}
158-
</span>
159-
)}
160-
{activity.subtitle && (
161-
<span className='text-subGrey font-pretendardRegular'>
162-
{' '}
163-
{activity.subtitle}
164-
</span>
165-
)}
166-
</li>
167-
))}
168-
</ul>
179+
169180
</div>
170181
</FadeInSection>
171182
))}
172183
</div>
173184
</div>
185+
174186
</div>
175187
</FadeInSection>
176188
)
177189
}
178190

179-
export default ActivityStatus
191+
export default ActivityStatus

src/utils/apiClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getAccessToken, getRefreshToken, setTokens, removeTokens, removeAllToke
44
const API_BASE_URL =
55
(process.env.DASOM_BASE_URL as string) ||
66
(process.env.REACT_APP_API_BASE_URL as string) ||
7-
'https://dmu-dasom-api.or.kr/api'
7+
'https://api.dmu-dasom.or.kr/api/'
88

99
const apiClient = axios.create({
1010
baseURL: API_BASE_URL,

0 commit comments

Comments
 (0)