From 23c60e870c1210234b45ee37e9a88920d125ddca Mon Sep 17 00:00:00 2001
From: yeji424
Date: Mon, 9 Feb 2026 16:45:53 +0900
Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=EB=A7=88=EC=BC=80=ED=8C=85=20?=
=?UTF-8?q?=EA=B0=95=EC=9D=98=20=EC=A0=95=EB=B3=B4=20=ED=95=98=EB=93=9C?=
=?UTF-8?q?=EC=BD=94=EB=94=A9=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EC=96=B4?=
=?UTF-8?q?=EB=93=9C=EB=AF=BC=20=EC=97=B0=EB=8F=99=20-=204=EA=B0=9C=20?=
=?UTF-8?q?=EC=9D=B4=ED=95=98=202=EA=B0=9C=EC=94=A9,=205=EA=B0=9C=20?=
=?UTF-8?q?=EC=9D=B4=EC=83=81=203=EA=B0=9C=EC=94=A9=20=EA=B0=80=EC=9A=B4?=
=?UTF-8?q?=EB=8D=B0=20=EC=A0=95=EB=A0=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/domain/admin/program/ChallengeLecture.tsx | 2 +-
.../challenge/ChallengeMarketingView.tsx | 4 +-
.../marketing-view/Differentiators.tsx | 202 +++++++++---------
.../MarketingDifferentiatorsSection.tsx | 83 +++----
4 files changed, 142 insertions(+), 149 deletions(-)
diff --git a/src/domain/admin/program/ChallengeLecture.tsx b/src/domain/admin/program/ChallengeLecture.tsx
index 23a9c8336..cd2a1b7e3 100644
--- a/src/domain/admin/program/ChallengeLecture.tsx
+++ b/src/domain/admin/program/ChallengeLecture.tsx
@@ -14,7 +14,7 @@ import { FaTrashCan } from 'react-icons/fa6';
const DEFAULT_LECTURE_COUNT = 3;
/** 강의 정보 등록 섹션을 노출할 챌린지 타입 (추가 타입은 이 배열에만 넣으면 됨) */
-const CHALLENGE_TYPES_WITH_LECTURES: ChallengeType[] = ['HR'];
+const CHALLENGE_TYPES_WITH_LECTURES: ChallengeType[] = ['HR', 'MARKETING'];
function createEmptyLecture() {
return {
diff --git a/src/domain/program/challenge/ChallengeMarketingView.tsx b/src/domain/program/challenge/ChallengeMarketingView.tsx
index fc53876d9..d9b8f7912 100644
--- a/src/domain/program/challenge/ChallengeMarketingView.tsx
+++ b/src/domain/program/challenge/ChallengeMarketingView.tsx
@@ -1,6 +1,6 @@
+import ChallengeIntroEditorContent from '@/domain/program/challenge/challenge-view/ChallengeIntroEditorContent';
import ChallengeRecruitmentInfoSection from '@/domain/program/challenge/challenge-view/ChallengeRecruitmentInfoSection';
import ChallengeTabNavigation from '@/domain/program/challenge/challenge-view/ChallengeTabNavigation';
-import ChallengeIntroEditorContent from '@/domain/program/challenge/challenge-view/ChallengeIntroEditorContent';
import MarketingCurriculumSection from '@/domain/program/challenge/marketing-view/MarketingCurriculumSection';
import MarketingDifferentiatorsSection from '@/domain/program/challenge/marketing-view/MarketingDifferentiatorsSection';
import MarketingPricingSection from '@/domain/program/challenge/marketing-view/MarketingPricingSection';
@@ -33,7 +33,7 @@ const ChallengeMarketingView = ({ challenge }: Props) => {
-
+
{
);
};
-/** 차별점 2 */
-const professionals = [
- {
- logo: 'class101.png',
- profile: 'profile2.png',
- week: '세미나(2월 3주차) & 피드백',
- company: '클래스 101',
- role: '콘텐츠 마케터',
- },
- {
- logo: 'nol.png',
- profile: 'profile3.png',
- week: '세미나(2월 4주차) & 피드백',
- company: '놀유니버스',
- role: '마케팅 전략',
- },
- {
- logo: 'cashnote.png',
- profile: 'profile5.png',
- week: '세미나(3월 1주차) & 피드백',
- company: '캐시노트',
- role: '그로스 마케터',
- },
- {
- logo: 'corpuniv.png',
- profile: 'profile4.png',
- week: '세미나(3월2주차) & 피드백',
- company: '대학내일',
- role: 'AE마케터',
- },
- // {
- // logo: 'innocean.png',
- // profile: 'profile1.png',
- // week: '피드백',
- // company: '이노션',
- // role: 'CRM 마케터',
- // },
-];
+/* 차별점 2 */
+type Lecture = NonNullable[number];
+
+type Professional = {
+ logo: string;
+ profile: string;
+ week: string;
+ company: string;
+ role: string;
+};
-export const ProfessionalsList = () => {
+const ProfessionalCard = ({ item }: { item: Professional }) => {
return (
-
-
- {professionals.slice(0, 2).map((item, index) => (
-
-
-

-

-
-
-
- {item.week}
-
-
- {item.company}
-
-
- {item.role}
-
-
-
- ))}
+
+
+

+
-
- {professionals.slice(2, 4).map((item, index) => (
-
-
-

-

-
-
-
- {item.week}
-
-
- {item.company}
-
-
- {item.role}
-
-
+
+
+ {item.week}
+
+
+ {item.company}
+
+
+ {item.role}
+
+
+
+ );
+};
+
+const mapLecturesToProfessionals = (
+ lectures?: ChallengeContent['lectures'],
+): Professional[] => {
+ if (!lectures || lectures.length === 0) {
+ return [];
+ }
+
+ // 강의 정보가 있는 경우, 강의 데이터를 우선 사용한다.
+ return lectures.map((lecture: Lecture) => ({
+ logo: lecture.companyLogo,
+ profile: lecture.mentorImage,
+ week: lecture.schedule,
+ // UI 구조상 회사명/역할 자리에 들어갈 텍스트가 필요하므로,
+ // 강의 주제를 회사명 자리, 멘토명을 역할 자리에 매핑한다.
+ company: lecture.topic || lecture.mentorName,
+ role: lecture.mentorName,
+ }));
+};
+
+export const ProfessionalsList = ({
+ lectures,
+}: {
+ lectures?: ChallengeContent['lectures'];
+}) => {
+ const professionals = mapLecturesToProfessionals(lectures);
+ const isThreeColumnLayout = professionals.length >= 5;
+
+ if (professionals.length === 0) {
+ return null;
+ }
+
+ if (isThreeColumnLayout) {
+ // 5개 이상
+ const rows: Professional[][] = [];
+ for (let i = 0; i < professionals.length; i += 3) {
+ rows.push(professionals.slice(i, i + 3));
+ }
+
+ return (
+
+ {rows.map((row, rowIndex) => (
+
+ {row.map((item, index) => (
+
+ ))}
))}
+ );
+ }
+
+ // 4개 이하
+ return (
+
+ {professionals.map((item, index) => (
+
+ ))}
);
};
diff --git a/src/domain/program/challenge/marketing-view/MarketingDifferentiatorsSection.tsx b/src/domain/program/challenge/marketing-view/MarketingDifferentiatorsSection.tsx
index b65692a0e..0cd9acb3c 100644
--- a/src/domain/program/challenge/marketing-view/MarketingDifferentiatorsSection.tsx
+++ b/src/domain/program/challenge/marketing-view/MarketingDifferentiatorsSection.tsx
@@ -1,3 +1,4 @@
+import { ChallengeContent } from '@/types/interface';
import { ReactNode } from 'react';
import MainTitle from '../ui/MainTitle';
import {
@@ -6,45 +7,6 @@ import {
ProfessionalsList,
} from './Differentiators';
-const differentiators = [
- {
- title: '마케팅 실무 역량 Class',
- description: (
- <>
- 신입 마케터가 가장 막히는 실무 툴,
단 3회
- 수업으로 한 번에 끝냅니다.
- >
- ),
- visualExplanation:
,
- },
- {
- title: (
- <>
- 모든 마케터의 현직자 특강부터
- 실시간 피드백까지
- >
- ),
- description: (
- <>
- 현직자와 직접 만나 질문하고, 피드백받고, 성장하는 4주
- 마케터가 되기 위해 필요한 경험, 역량, 프로젝트가
-
무엇인지 현직자 시선에서 알아가세요.
- >
- ),
- visualExplanation:
,
- },
- {
- title: (
- <>
- 4주 안에 서류 완성,
단 하나의 코스로 끝
- >
- ),
- description:
- '4주 안에 경험 정리, 자소서, 포트폴리오까지\n마케팅 직무에 꼭 맞는 서류를 한 번에 완성하세요.',
- visualExplanation:
,
- },
-];
-
const Badge = ({ index }: { index: number }) => {
return (
@@ -80,7 +42,48 @@ const Differentiator = ({
);
};
-const MarketingDifferentiatorsSection: React.FC = () => {
+const MarketingDifferentiatorsSection: React.FC<{
+ lectures?: ChallengeContent['lectures'];
+}> = ({ lectures }) => {
+ const differentiators = [
+ {
+ title: '마케팅 실무 역량 Class',
+ description: (
+ <>
+ 신입 마케터가 가장 막히는 실무 툴,
단 3회
+ 수업으로 한 번에 끝냅니다.
+ >
+ ),
+ visualExplanation:
,
+ },
+ {
+ title: (
+ <>
+ 모든 마케터의 현직자 특강부터
+ 실시간 피드백까지
+ >
+ ),
+ description: (
+ <>
+ 현직자와 직접 만나 질문하고, 피드백받고, 성장하는 4주
+ 마케터가 되기 위해 필요한 경험, 역량, 프로젝트가
+
무엇인지 현직자 시선에서 알아가세요.
+ >
+ ),
+ visualExplanation:
,
+ },
+ {
+ title: (
+ <>
+ 4주 안에 서류 완성,
단 하나의 코스로 끝
+ >
+ ),
+ description:
+ '4주 안에 경험 정리, 자소서, 포트폴리오까지\n마케팅 직무에 꼭 맞는 서류를 한 번에 완성하세요.',
+ visualExplanation:
,
+ },
+ ];
+
return (
{differentiators.map((item, index) => (
From 00dbde4ff4edb0dbb7935eca6a1c6e3d7f5a8b2d Mon Sep 17 00:00:00 2001
From: yeji424
Date: Mon, 9 Feb 2026 18:08:23 +0900
Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=EB=A7=88=EC=BC=80=ED=8C=85=20?=
=?UTF-8?q?=EC=A3=BC=EC=B0=A8=EB=B3=84=20=EC=BB=A4=EB=A6=AC=ED=81=98?=
=?UTF-8?q?=EB=9F=BC=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20=EC=A0=9C?=
=?UTF-8?q?=EA=B1=B0=20=EB=B0=8F=20=EC=96=B4=EB=93=9C=EB=AF=BC=20=EC=97=B0?=
=?UTF-8?q?=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../challenge/ChallengeMarketingView.tsx | 2 +-
.../marketing-view/CurriculumContent.tsx | 414 ++++++------------
.../challenge/marketing-view/Curriculums.tsx | 138 +++---
.../MarketingCurriculumSection.tsx | 11 +-
4 files changed, 221 insertions(+), 344 deletions(-)
diff --git a/src/domain/program/challenge/ChallengeMarketingView.tsx b/src/domain/program/challenge/ChallengeMarketingView.tsx
index d9b8f7912..0c5257a12 100644
--- a/src/domain/program/challenge/ChallengeMarketingView.tsx
+++ b/src/domain/program/challenge/ChallengeMarketingView.tsx
@@ -34,7 +34,7 @@ const ChallengeMarketingView = ({ challenge }: Props) => {
-
+
- 마케터 직무와 업무를 통해 지원서 작성 전략을 탐색합니다.
-
- ),
- },
- {
- date: '2/14',
- title: '현직자에게 듣는 합격하는 서류의 A-Z',
- content: (
-
- 현직 콘텐츠 마케터와 함께 콘텐츠 마케터에게
- 가장 필요한 경험과 역량을 살펴봅니다.
- >
- }
- />
- ),
- },
- {
- date: '2/17-20',
- title: '2회차 경험 정리',
- content: (
-
- 내 경험을 체계적으로 정리하여 장단점과 역량 키워드를 도출합니다.
-
- ),
- },
- {
- date: '2/18',
- title: '역량 더하기 | 렛츠커리어 LIVE 클래스',
- content: (
-
-
- 마케터 필수 Figma 사용 방법 A to Z
-
- }
- />
- ),
- },
- ],
- },
- {
- date: '2/21-27',
- title: '+ 놀유니버스 현직자 강연',
- detail: [
- {
- date: '2/21-2/23',
- title: '3회차 경험 분석',
- content: (
-
- 합격의 Key가 될 수 있는 경험을 분석하고{' '}
-
- 기업과 Fit한 요소를 파악합니다.
-
- ),
- },
- {
- date: '2/21',
- title: '현직자에게 듣는 합격하는 서류의 A-Z',
- content: (
-
- IT 스타트업 현직 마케터와 함께
- CRM 마케터에게 가장 필수적인 경험과 역량을 살펴봅니다.
- >
- }
- />
- ),
- },
- {
- date: '2/24-27',
- title: '4회차 컨셉 잡기',
- content: (
-
- 기업에 Fit한 나만의 컨셉을 확보하여 서류 요소의 기반을 완성합니다.
-
- ),
- },
- {
- date: '2/25',
- title: '역량 더하기 | 렛츠커리어 LIVE 클래스',
- content: (
-
-
- 데이터 역량 쌓는 방법. 인스타그램 계정, 메타 광고 운영
-
- }
- />
- ),
- },
- ],
- },
- {
- date: '2/28-3/6',
- title: '+ 캐시노트 현직자 강연',
- detail: [
- {
- date: '2/28-3/2',
- title: '5회차 이력서 작성',
- content: (
-
- 정리된 경험과 역량에 기반하여 눈에 띄는 이력서를 작성합니다.
-
- ),
- },
- {
- date: '2/28',
- title: '현직자에게 듣는 합격하는 서류의 A-Z',
- content: (
-
- 현직 마케터가 들려주는 그로스 마케팅의 A-Z,
-
합격하는 서류의 공통점을
- 소개합니다.
- >
- }
- />
- ),
- },
- {
- date: '3/3-6',
- title: '6회차 자기소개서 작성',
- content: (
-
- 이력서 컨셉에 기반하여 자기소개서의 공통 문항들을 완성합니다.
-
- ),
- },
- {
- date: '3/4',
- title: '역량 더하기 | 렛츠커리어 LIVE 클래스',
- content: (
-
-
- 데이터 역량 쌓는 방법. Google Analytics 실습
-
- }
- />
- ),
- },
- ],
- },
- {
- date: '3/7-13',
- title: '+ 대학내일 현직자 강연',
- detail: [
- {
- date: '3/7-9',
- title: '7회차 포트폴리오 기초',
- content: (
-
- 정리된 역량에 기반하여 포트폴리오 초안을 제작합니다.
-
- ),
- },
- {
- date: '3/7',
- title: '현직자에게 듣는 합격하는 서류의 A-Z',
- content: (
-
- 대학내일ES, 이런 포트폴리오를 기다려요.
-
- AE 취업을 위한 나만의 무기를 함께 찾아봅니다.
- >
- }
- />
- ),
- },
- {
- date: '3/10-13',
- title: '8회차 포트폴리오 완성',
- content: (
-
- 채용 담당자의 시선을 멈추게 하는 합격하는 포트폴리오를 완성합니다.
-
- ),
- },
- {
- date: '3/11',
- title: '역량 더하기 | 렛츠커리어 LIVE 클래스',
- content: (
-
-
- 렛츠커리어 CMO가 알려주는
- 2025 마케팅 합격 포트폴리오 트렌드
-
- }
- />
- ),
- },
- ],
- },
-];
+export interface WeekGroup {
+ week: string;
+ weekTitle: string;
+ startDate?: string;
+ endDate?: string;
+ items: ChallengeCurriculum[];
+}
function Description({ children }: { children: ReactNode }) {
return (
-
- {children}
-
+
);
}
function Highlight({
- companyImg,
- role,
- date,
+ contentImg,
+ contentHighlightColor,
description,
className,
}: {
- companyImg?: string;
- role?: string;
- date?: string;
+ contentImg?: string;
+ contentHighlightColor?: 'none' | 'gray' | 'accent';
description: ReactNode;
className?: string;
}) {
+ const hasHighlightColor =
+ contentHighlightColor && contentHighlightColor !== 'none';
+
+ const bgColorClass =
+ contentHighlightColor === 'gray'
+ ? 'bg-neutral-90'
+ : contentHighlightColor === 'accent'
+ ? 'bg-[#FFF0F4]'
+ : 'bg-transparent';
+
+ const textStyle = hasHighlightColor
+ ? 'text-xsmall16 font-semibold md:text-small18'
+ : 'text-xxsmall12 text-neutral-0 md:text-xsmall16';
+
+ const paddingClass = hasHighlightColor ? 'px-3 py-2.5' : '';
+
return (
- {role && (
-
-
+ {contentImg && (
+
-
- {role}
- {date}
-
-
- )}
-
+ )}
{description}
);
}
-const CurriculumContent = ({
- curriculum,
-}: {
- curriculum: (typeof curriculums)[0];
-}) => {
- const isLastItem = (index: number) => index === curriculum.detail.length - 1;
+export const CurriculumContent = ({ weekGroup }: { weekGroup: WeekGroup }) => {
+ const isLastItem = (index: number) => index === weekGroup.items.length - 1;
return (
-
-
- {title}
-
+ {title && (
+
+ {title}
+
+ )}
);
};
-const sidebarList = curriculums.map((item) => ({
- date: item.date,
- title: item.title,
-}));
-
-const ContentWithSidebar = () => {
- const [active, setActive] = useState(0);
-
- const activeContent = curriculums[active];
+function Curriculums({ curriculum, content }: CurriculumsProps) {
+ const isMobile = useMediaQuery('(max-width:768px)');
- return (
-
- {/* Sidebar */}
-
- {sidebarList.map((item, index) => (
- setActive(index)}
- />
- ))}
-
- {/* Content */}
-
-
-
-
+ const groupedByWeek = useMemo(
+ () => getCurriculumGroupedByWeek(curriculum, content),
+ [curriculum, content],
);
-};
-function Curriculums() {
- const isMobile = useMediaQuery('(max-width:768px)');
+ const sidebarListFromAdmin = groupedByWeek.map((group) => ({
+ date:
+ group.startDate && group.endDate
+ ? `${dayjs(group.startDate).format('M/D')}-${dayjs(group.endDate).format('M/D')}`
+ : '',
+ title: group.weekTitle,
+ }));
+
+ // 어드민 커리큘럼이 없으면 아무것도 렌더링하지 않음
+ if (groupedByWeek.length === 0) {
+ return null;
+ }
if (isMobile) {
return (
-
- {curriculums.map((item, index) => (
-
-
-
- ))}
+
+ {groupedByWeek.map((group, index) => {
+ const dateRange =
+ group.startDate && group.endDate
+ ? `${dayjs(group.startDate).format('M/D')}-${dayjs(group.endDate).format('M/D')}`
+ : '';
+
+ return (
+
+
+
+ );
+ })}
);
}
+ const ContentWithSidebar = () => {
+ const [active, setActive] = useState(0);
+ const activeGroup = groupedByWeek[active];
+
+ return (
+
+ {/* Sidebar */}
+
+ {sidebarListFromAdmin.map((item, index) => (
+ setActive(index)}
+ />
+ ))}
+
+ {/* Content */}
+
+
+
+
+ );
+ };
+
return
;
}
diff --git a/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx b/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx
index aa74f73d9..64f5c2d2b 100644
--- a/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx
+++ b/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx
@@ -1,10 +1,17 @@
import SectionHeader from '@/common/header/SectionHeader';
import SectionSubHeader from '@/common/header/SectionSubHeader';
+import { ChallengeContent } from '@/types/interface';
import React from 'react';
import MainTitle from '../ui/MainTitle';
import Curriculums from './Curriculums';
-const MarketingCurriculumSection: React.FC = () => {
+interface MarketingCurriculumSectionProps {
+ content?: ChallengeContent | null;
+}
+
+const MarketingCurriculumSection: React.FC
= ({
+ content,
+}) => {
return (
-
+
);
};
From 48b55220747a3cb00217711ee916eb7d762c71fd Mon Sep 17 00:00:00 2001
From: yeji424
Date: Mon, 9 Feb 2026 18:08:55 +0900
Subject: [PATCH 3/5] =?UTF-8?q?style:=20HR=20=EC=BB=A4=EB=A6=AC=ED=81=98?=
=?UTF-8?q?=EB=9F=BC=20=EB=82=B4=EC=9A=A9=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?=
=?UTF-8?q?+=20=EB=82=B4=EC=9A=A9=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20?=
=?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../challenge/hr-view/HrCurriculumContent.tsx | 26 +++++++------------
1 file changed, 10 insertions(+), 16 deletions(-)
diff --git a/src/domain/program/challenge/hr-view/HrCurriculumContent.tsx b/src/domain/program/challenge/hr-view/HrCurriculumContent.tsx
index 657aac5e4..3c777d379 100644
--- a/src/domain/program/challenge/hr-view/HrCurriculumContent.tsx
+++ b/src/domain/program/challenge/hr-view/HrCurriculumContent.tsx
@@ -1,7 +1,6 @@
import dayjs from '@/lib/dayjs';
import { twMerge } from '@/lib/twMerge';
import { ChallengeCurriculum } from '@/types/interface';
-import Image from 'next/image';
import { ReactNode } from 'react';
interface WeekGroup {
@@ -63,26 +62,21 @@ function Highlight({
className,
)}
>
-
+
{contentImg && (
-
)}
-
- {description}
-
-
+ {description}
+
);
}
From 0c8dc4722e5be66520bcb03e2ec086d19b87f02a Mon Sep 17 00:00:00 2001
From: yeji424
Date: Wed, 11 Feb 2026 18:08:18 +0900
Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20ContentWithSidebar=20=ED=95=A8?=
=?UTF-8?q?=EC=88=98=20=EC=99=B8=EB=B6=80=EB=A1=9C=20=EB=B6=84=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../challenge/hr-view/HrCurriculums.tsx | 79 +++++++++++-------
.../challenge/marketing-view/Curriculums.tsx | 80 ++++++++++++-------
2 files changed, 103 insertions(+), 56 deletions(-)
diff --git a/src/domain/program/challenge/hr-view/HrCurriculums.tsx b/src/domain/program/challenge/hr-view/HrCurriculums.tsx
index e41e98109..d19011944 100644
--- a/src/domain/program/challenge/hr-view/HrCurriculums.tsx
+++ b/src/domain/program/challenge/hr-view/HrCurriculums.tsx
@@ -107,6 +107,51 @@ const SidebarButton = ({
);
};
+interface DesktopHrCurriculumsProps {
+ groupedByWeek: WeekGroup[];
+ sidebarList: {
+ date: string;
+ title: string;
+ }[];
+}
+
+function DesktopHrCurriculums({
+ groupedByWeek,
+ sidebarList,
+}: DesktopHrCurriculumsProps) {
+ const [active, setActive] = useState(0);
+
+ const safeActiveIndex =
+ active >= 0 && active < groupedByWeek.length ? active : 0;
+ const activeGroup = groupedByWeek[safeActiveIndex];
+
+ if (!activeGroup) {
+ return null;
+ }
+
+ return (
+
+ {/* Sidebar */}
+
+ {sidebarList.map((item, index) => (
+ setActive(index)}
+ />
+ ))}
+
+ {/* Content */}
+
+
+
+
+ );
+}
+
function HrCurriculums({ curriculum, content }: HrCurriculumsProps) {
const isMobile = useMediaQuery('(max-width:768px)');
@@ -162,33 +207,6 @@ function HrCurriculums({ curriculum, content }: HrCurriculumsProps) {
title: group.weekTitle,
}));
- const ContentWithSidebar = () => {
- const [active, setActive] = useState(0);
- const activeGroup = groupedByWeek[active];
-
- return (
-
- {/* Sidebar */}
-
- {sidebarList.map((item, index) => (
- setActive(index)}
- />
- ))}
-
- {/* Content */}
-
-
-
-
- );
- };
-
if (isMobile) {
return (
@@ -212,7 +230,12 @@ function HrCurriculums({ curriculum, content }: HrCurriculumsProps) {
);
}
- return
;
+ return (
+
+ );
}
export default HrCurriculums;
diff --git a/src/domain/program/challenge/marketing-view/Curriculums.tsx b/src/domain/program/challenge/marketing-view/Curriculums.tsx
index 2f93b6d4b..5499bad37 100644
--- a/src/domain/program/challenge/marketing-view/Curriculums.tsx
+++ b/src/domain/program/challenge/marketing-view/Curriculums.tsx
@@ -8,6 +8,7 @@ import { ChevronDown, ChevronUp } from 'lucide-react';
import { ReactNode, useMemo, useState } from 'react';
import {
CurriculumContent,
+ WeekGroup,
getCurriculumGroupedByWeek,
} from './CurriculumContent';
@@ -102,6 +103,51 @@ const SidebarButton = ({
);
};
+interface DesktopCurriculumsProps {
+ groupedByWeek: WeekGroup[];
+ sidebarList: {
+ date: string;
+ title: string;
+ }[];
+}
+
+function DesktopCurriculums({
+ groupedByWeek,
+ sidebarList,
+}: DesktopCurriculumsProps) {
+ const [active, setActive] = useState(0);
+
+ const safeActiveIndex =
+ active >= 0 && active < groupedByWeek.length ? active : 0;
+ const activeGroup = groupedByWeek[safeActiveIndex];
+
+ if (!activeGroup) {
+ return null;
+ }
+
+ return (
+
+ {/* Sidebar */}
+
+ {sidebarList.map((item, index) => (
+ setActive(index)}
+ />
+ ))}
+
+ {/* Content */}
+
+
+
+
+ );
+}
+
function Curriculums({ curriculum, content }: CurriculumsProps) {
const isMobile = useMediaQuery('(max-width:768px)');
@@ -147,34 +193,12 @@ function Curriculums({ curriculum, content }: CurriculumsProps) {
);
}
- const ContentWithSidebar = () => {
- const [active, setActive] = useState(0);
- const activeGroup = groupedByWeek[active];
-
- return (
-
- {/* Sidebar */}
-
- {sidebarListFromAdmin.map((item, index) => (
- setActive(index)}
- />
- ))}
-
- {/* Content */}
-
-
-
-
- );
- };
-
- return
;
+ return (
+
+ );
}
export default Curriculums;
From ce77228a2d6d53070fb481221ab2c3df5554cf39 Mon Sep 17 00:00:00 2001
From: yeji424
Date: Sun, 15 Feb 2026 13:02:31 +0900
Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=EB=A7=88=EC=BC=80=ED=8C=85/HR=20?=
=?UTF-8?q?=EC=B1=8C=EB=A6=B0=EC=A7=80=20=EA=B0=95=EC=9D=98=EC=9E=90=20?=
=?UTF-8?q?=EC=88=98=20=EB=B0=8F=20=EA=B0=95=EC=9D=98=20=ED=9A=8C=EC=B0=A8?=
=?UTF-8?q?=20=EC=A0=95=EC=A0=81=20=E2=86=92=20=EA=B0=95=EC=9D=98=20?=
=?UTF-8?q?=EC=88=98=EB=A1=9C=20=EB=8F=99=EC=A0=81=20=ED=91=9C=EC=8B=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../challenge/ChallengeMarketingView.tsx | 1 +
.../hr-view/HrCurriculumCalendar.tsx | 11 ++-
.../hr-view/HrCurriculumPointsSection.tsx | 76 ++++++++++---------
.../challenge/hr-view/HrCurriculumSection.tsx | 16 ++--
.../MarketingChallengeCalendar.tsx | 13 +++-
.../MarketingCurriculumSection.tsx | 13 +++-
6 files changed, 78 insertions(+), 52 deletions(-)
diff --git a/src/domain/program/challenge/ChallengeMarketingView.tsx b/src/domain/program/challenge/ChallengeMarketingView.tsx
index 0c5257a12..0cf1b0b10 100644
--- a/src/domain/program/challenge/ChallengeMarketingView.tsx
+++ b/src/domain/program/challenge/ChallengeMarketingView.tsx
@@ -38,6 +38,7 @@ const ChallengeMarketingView = ({ challenge }: Props) => {
diff --git a/src/domain/program/challenge/hr-view/HrCurriculumCalendar.tsx b/src/domain/program/challenge/hr-view/HrCurriculumCalendar.tsx
index 8e1a91c00..17e6bcaf6 100644
--- a/src/domain/program/challenge/hr-view/HrCurriculumCalendar.tsx
+++ b/src/domain/program/challenge/hr-view/HrCurriculumCalendar.tsx
@@ -5,6 +5,7 @@ import { ReactNode } from 'react';
interface Props {
challenge: ChallengeIdPrimitive;
curriculumImage?: string;
+ lectureCount?: number;
}
interface CalendarItemProps {
@@ -53,7 +54,13 @@ const CalendarList = ({ children }: CalendarListProps) => {
);
};
-const HrCurriculumCalendar = ({ challenge, curriculumImage }: Props) => {
+const DEFAULT_LECTURE_COUNT = 4;
+
+const HrCurriculumCalendar = ({
+ challenge,
+ curriculumImage,
+ lectureCount = DEFAULT_LECTURE_COUNT,
+}: Props) => {
const calendarItems = [
{
number: 1,
@@ -70,7 +77,7 @@ const HrCurriculumCalendar = ({ challenge, curriculumImage }: Props) => {
{
number: 2,
bgColor: 'bg-[#FB923C]',
- title: '현직자 LIVE 세미나 4회',
+ title: `현직자 LIVE 세미나 ${lectureCount}회`,
description: (
채용, 리크루팅, HRD, People Analytics 등
diff --git a/src/domain/program/challenge/hr-view/HrCurriculumPointsSection.tsx b/src/domain/program/challenge/hr-view/HrCurriculumPointsSection.tsx
index 0cab2d274..48dfa4614 100644
--- a/src/domain/program/challenge/hr-view/HrCurriculumPointsSection.tsx
+++ b/src/domain/program/challenge/hr-view/HrCurriculumPointsSection.tsx
@@ -6,41 +6,45 @@ interface HrCurriculumPointsSectionProps {
content: ChallengeContent | null;
}
-const curriculumCards = [
- {
- title: 'HR 실무 역량 Class',
- description: (
- <>
- HR 직무에서 수행해야 하는 사전 과제,
-
- HR 관련 뉴스기사, 아티클 등 수집하는
-
- 스터디까지 지원해드려요
- >
- ),
- },
- {
- title: '현직자의 LIVE 세미나',
- description: (
- <>
- 4명의 HR 현직자 선배들이
-
- 어떻게 HR 커리어를 시작했는지,
-
그 이야기를 직접 들려드릴게요
- >
- ),
- },
- {
- title: '챌린지를 통한 서류 완성',
- description: (
- <>
- 채용 공고에 바로 지원이 가능하도록,
-
- 수준급의 서류를 무조건 완성해요
- >
- ),
- },
-];
+const DEFAULT_LECTURE_COUNT = 5;
+
+function getCurriculumCards(lectureCount: number) {
+ return [
+ {
+ title: 'HR 실무 역량 Class',
+ description: (
+ <>
+ HR 직무에서 수행해야 하는 사전 과제,
+
+ HR 관련 뉴스기사, 아티클 등 수집하는
+
+ 스터디까지 지원해드려요
+ >
+ ),
+ },
+ {
+ title: '현직자의 LIVE 세미나',
+ description: (
+ <>
+ {lectureCount}명의 HR 현직자 선배들이
+
+ 어떻게 HR 커리어를 시작했는지,
+
그 이야기를 직접 들려드릴게요
+ >
+ ),
+ },
+ {
+ title: '챌린지를 통한 서류 완성',
+ description: (
+ <>
+ 채용 공고에 바로 지원이 가능하도록,
+
+ 수준급의 서류를 무조건 완성해요
+ >
+ ),
+ },
+ ];
+}
const CurriculumCard = ({
title,
@@ -80,6 +84,8 @@ const HrCurriculumPointsSection: React.FC = ({
content,
}) => {
const weekText = content?.challengePoint?.weekText ?? '3주';
+ const lectureCount = content?.lectures?.length ?? DEFAULT_LECTURE_COUNT;
+ const curriculumCards = getCurriculumCards(lectureCount);
return (
diff --git a/src/domain/program/challenge/hr-view/HrCurriculumSection.tsx b/src/domain/program/challenge/hr-view/HrCurriculumSection.tsx
index 39ae4eb21..b4a72d10b 100644
--- a/src/domain/program/challenge/hr-view/HrCurriculumSection.tsx
+++ b/src/domain/program/challenge/hr-view/HrCurriculumSection.tsx
@@ -14,15 +14,12 @@ const HrCurriculumSection: React.FC = ({
challenge,
content,
}) => {
- if (
- !content ||
- !content.curriculum ||
- content.curriculum.length === 0
- ) {
+ if (!content || !content.curriculum || content.curriculum.length === 0) {
return null;
}
const weekText = content?.challengePoint?.weekText ?? '3주';
+ const lectureCount = content?.lectures?.length ?? 5;
return (
= ({
- 6회의 미션
+ 현직자 LIVE 세미나 4회와 함께
+ 6회의 미션
+ 현직자 LIVE 세미나{' '}
+ {lectureCount}회와 함께
만드는 밀도 있는 {weekText}간의 여정
@@ -42,13 +40,11 @@ const HrCurriculumSection: React.FC = ({
막연한 HR 관심에서 끝나지 않도록, 직무 탐색부터 경험 정리, 결과물
완성까지 함께합니다.
-
+
);
diff --git a/src/domain/program/challenge/marketing-view/MarketingChallengeCalendar.tsx b/src/domain/program/challenge/marketing-view/MarketingChallengeCalendar.tsx
index 7d04154ca..47f3de24b 100644
--- a/src/domain/program/challenge/marketing-view/MarketingChallengeCalendar.tsx
+++ b/src/domain/program/challenge/marketing-view/MarketingChallengeCalendar.tsx
@@ -4,9 +4,16 @@ import Image from 'next/image';
interface Props {
challenge: ChallengeIdPrimitive;
curriculumImage?: string;
+ lectureCount?: number;
}
-const ChallengeScheduleSection = ({ challenge, curriculumImage }: Props) => {
+const DEFAULT_LECTURE_COUNT = 4;
+
+const ChallengeScheduleSection = ({
+ challenge,
+ curriculumImage,
+ lectureCount = DEFAULT_LECTURE_COUNT,
+}: Props) => {
return (
@@ -56,7 +63,9 @@ const ChallengeScheduleSection = ({ challenge, curriculumImage }: Props) => {
3
- 현직자 세미나 4회
+
+ 현직자 세미나 {lectureCount}회
+
현직자 마케터의 세미나를
diff --git a/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx b/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx
index 64f5c2d2b..93e571fb3 100644
--- a/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx
+++ b/src/domain/program/challenge/marketing-view/MarketingCurriculumSection.tsx
@@ -9,9 +9,13 @@ interface MarketingCurriculumSectionProps {
content?: ChallengeContent | null;
}
+const DEFAULT_LECTURE_COUNT = 4;
+
const MarketingCurriculumSection: React.FC = ({
content,
}) => {
+ const lectureCount = content?.lectures?.length ?? DEFAULT_LECTURE_COUNT;
+
return (
= ({
- 실무 역량 Class 4회
+ 현직자 세미나
- 4회와 함께
+ 실무 역량 Class 4회
+ 현직자 세미나{' '}
+ {lectureCount}회와 함께
8회의 미션으로 만드는
@@ -35,7 +39,10 @@ const MarketingCurriculumSection: React.FC = ({
-
+
);
};