Skip to content

Commit 38cbcf8

Browse files
committed
파편화된 메타데이터 관리 포인트 최소화 및 통일 작업 진행
1 parent 70bd4b8 commit 38cbcf8

7 files changed

Lines changed: 272 additions & 228 deletions

File tree

src/data/constants.ts

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,61 @@
11
// 사이트 전반에서 공유하는 상수 및 레이블 매핑
22

33
// ─── 행사 종류 / 참여 대상 ───────────────────────────────────────────
4-
export const EVENT_KIND_LABEL = {
5-
regular: '정기',
6-
ongoing: '상시',
7-
} as const
4+
export type EventKind = 'regular' | 'ongoing'
5+
6+
export const EVENT_KIND: Record<EventKind, { label: string; desc: string }> = {
7+
regular: {
8+
label: '정기',
9+
desc: 'SSAFYnity를 대표하는 대규모 정기 행사예요.\n연 2회(상*하반기 1회씩), 50~100명 이상 규모로 진행되는 동문회의 정체성을 담은 행사입니다',
10+
},
11+
ongoing: {
12+
label: '상시',
13+
desc: '정회원을 위한 소규모 행사를 상시 운영합니다.\n더 자주, 더 가깝게 동문들과 만날 수 있는 자리입니다. 일부 공석에 대해 일반회원도 참여가능해요.',
14+
},
15+
}
816

9-
export type EventKind = keyof typeof EVENT_KIND_LABEL
17+
// label만 필요한 곳에서 사용
18+
export const EVENT_KIND_LABEL: { [K in EventKind]: string } = {
19+
regular: EVENT_KIND.regular.label,
20+
ongoing: EVENT_KIND.ongoing.label,
21+
}
1022

11-
export const EVENT_AUDIENCE_LABEL = {
12-
open: '공개',
13-
members: '동문회',
14-
regular: '정회원',
15-
operator: '운영진',
23+
export const EVENT_AUDIENCE = {
24+
open: { label: '공개', desc: '동문 여부와 관계없이 누구나 참여할 수 있어요.' },
25+
members: { label: '동문회', desc: '동문회원이라면 누구나 참여할 수 있어요.' },
26+
regular: { label: '정회원', desc: '정회원만 참여할 수 있는 행사예요.' },
27+
operator: { label: '운영진', desc: '운영진만 참여하는 내부 행사예요.' },
1628
} as const
1729

18-
export type EventAudience = keyof typeof EVENT_AUDIENCE_LABEL
30+
export type EventAudience = keyof typeof EVENT_AUDIENCE
31+
32+
// label만 필요한 곳에서 사용
33+
export const EVENT_AUDIENCE_LABEL: { [K in EventAudience]: string } = {
34+
open: EVENT_AUDIENCE.open.label,
35+
members: EVENT_AUDIENCE.members.label,
36+
regular: EVENT_AUDIENCE.regular.label,
37+
operator: EVENT_AUDIENCE.operator.label,
38+
}
1939

2040
// ─── 행사 진행 방식 ──────────────────────────────────────────────────
2141
// 복수 선택 가능 (예: ['online', 'offline', 'recorded'])
22-
export const EVENT_FORMAT_LABEL = {
23-
online: '온라인',
24-
offline: '오프라인',
25-
recorded: '녹화제공',
42+
export const EVENT_FORMAT = {
43+
offline: { label: '오프라인', desc: '현장에 직접 방문하여 참여하는 행사예요.' },
44+
online: { label: '온라인', desc: '온라인으로 참여하는 행사예요. 참여 링크는 별도 안내돼요.' },
45+
recorded: { label: '녹화제공', desc: '참석하지 못해도 추후 녹화본을 제공해드려요.' },
2646
} as const
2747

28-
export type EventFormat = keyof typeof EVENT_FORMAT_LABEL
48+
export type EventFormat = keyof typeof EVENT_FORMAT
2949

3050
export const FORMAT_ORDER: EventFormat[] = ['offline', 'online', 'recorded']
3151

52+
// label만 필요한 곳에서 사용
53+
export const EVENT_FORMAT_LABEL: { [K in EventFormat]: string } = {
54+
offline: EVENT_FORMAT.offline.label,
55+
online: EVENT_FORMAT.online.label,
56+
recorded: EVENT_FORMAT.recorded.label,
57+
}
58+
3259
// ─── 행사 날짜 ──────────────────────────────────────────────────────
3360
// 날짜 범위 — 하루면 end 생략, 여러 날이면 end 기재
3461
export type EventDateRange = {

src/data/siteData.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,7 @@ export const siteData = {
140140

141141
// ─── 협력사 ────────────────────────────────────────────────────────
142142
// 상세 데이터는 src/data/partners/{slug}.ts 참조
143-
// type: '재정 후원' | '물품 후원' | '교육 지원' | '재능 기부'
144-
// status: '현재' | '이전'
145-
// 새 협력사 추가 시: 파일 생성 후 아래 배열에 slug 추가
146-
partnerSlugs: [
147-
'samsung',
148-
'multicampus',
149-
// 새 협력사 추가 시 여기에 slug 추가
150-
],
143+
// 새 협력사 추가 시: partners/{slug}.ts 생성 후 computed.ts의 allPartners에 추가
151144

152145
// ─── 멤버십 ────────────────────────────────────────────────────
153146
membership: {

src/lib/utils.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,59 @@
11
import { clsx, type ClassValue } from "clsx"
22
import { twMerge } from "tailwind-merge"
3-
import type { EventDateRange, RecruitDateRange } from "@/data/constants"
3+
import { MapPin, Monitor, Tv } from 'lucide-react'
4+
import type { EventDateRange, RecruitDateRange, EventFormat } from "@/data/constants"
5+
import type { Event as SiteEvent } from "@/data/computed"
46

57
export function cn(...inputs: ClassValue[]) {
68
return twMerge(clsx(inputs))
79
}
810

11+
// ─── 행사 상태 ────────────────────────────────────────────────────────
12+
export type EventStatus =
13+
| 'past'
14+
| 'today'
15+
| 'recruiting'
16+
| 'recruit-closed'
17+
| 'before-recruit'
18+
| 'no-recruit'
19+
| 'planning'
20+
21+
export const EVENT_STATUS_CONFIG: Record<EventStatus, { label: string; className: string }> = {
22+
'past': { label: '종료', className: 'bg-slate-100 text-slate-400' },
23+
'today': { label: '오늘 진행중', className: 'bg-blue-600 text-white' },
24+
'recruiting': { label: '접수 중', className: 'bg-emerald-500 text-white' },
25+
'recruit-closed': { label: '접수 마감', className: 'bg-slate-700 text-white' },
26+
'before-recruit': { label: '접수 예정', className: 'bg-amber-500 text-white' },
27+
'no-recruit': { label: '운영진', className: 'bg-slate-100 text-slate-500' },
28+
'planning': { label: '계획중', className: 'bg-slate-200 text-slate-500' },
29+
}
30+
31+
export function getEventStatus(event: SiteEvent): EventStatus {
32+
const today = new Date(); today.setHours(0, 0, 0, 0)
33+
const toDate = (s: string) => { const d = new Date(s); d.setHours(0, 0, 0, 0); return d }
34+
35+
const eventStart = toDate(event.eventDate.start)
36+
const eventEnd = toDate(event.eventDate.end ?? event.eventDate.start)
37+
38+
if (today > eventEnd) return 'past'
39+
if (today >= eventStart && today <= eventEnd) return 'today'
40+
if (!event.recruitDate) return event.audience === 'operator' ? 'no-recruit' : 'planning'
41+
42+
const recruitStart = toDate(event.recruitDate.start)
43+
const recruitEnd = toDate(event.recruitDate.end ?? event.recruitDate.start)
44+
45+
if (today < recruitStart) return 'before-recruit'
46+
if (today <= recruitEnd) return 'recruiting'
47+
return 'recruit-closed'
48+
}
49+
50+
// ─── 진행 방식 아이콘 ────────────────────────────────────────────────
51+
export const FORMAT_ICON: Record<EventFormat, typeof MapPin> = {
52+
offline: MapPin,
53+
online: Monitor,
54+
recorded: Tv,
55+
}
56+
957
// ─── 날짜 포매팅 ──────────────────────────────────────────────────────
1058
const DAY_KO = ['일', '월', '화', '수', '목', '금', '토'] as const
1159

0 commit comments

Comments
 (0)