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 - 마케터 필수 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 - 데이터 역량 쌓는 방법. 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} -

+
+

+ {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 ( -
    - {curriculum.detail.map((item, index) => ( -
  • -
    - {item.date} -

    {item.title}

    -
    - {item.content} - {!isLastItem(index) && ( -
    - )} -
  • - ))} +
      + {weekGroup.items.map((item, index) => { + const dateRange = `${dayjs(item.startDate).format('M/D')}-${dayjs(item.endDate).format('M/D')}`; + const hasHighlight = + item.contentHighlightColor && item.contentHighlightColor !== 'none'; + const hasContentImg = !!item.contentImg; + + return ( +
    • +
      + {dateRange && {dateRange}} +

      + {item.session} {item.title} +

      +
      + {hasHighlight || hasContentImg ? ( + + ) : ( + {item.content} + )} + {!isLastItem(index) && ( +
      + )} +
    • + ); + })}
    ); }; -export default CurriculumContent; +export const getCurriculumGroupedByWeek = ( + curriculum: ChallengeCurriculum[] | undefined, + content?: ChallengeContent, +): WeekGroup[] => { + if (!curriculum || curriculum.length === 0) { + return []; + } + + if (!content?.useWeekSettings || !content.weekTitles?.length) { + return [ + { + week: '', + weekTitle: '', + startDate: '', + endDate: '', + items: curriculum, + }, + ]; + } + + const weekMap = new Map(); + + content.weekTitles.forEach((weekTitle) => { + weekMap.set(weekTitle.week, { + week: weekTitle.week, + weekTitle: weekTitle.weekTitle, + startDate: weekTitle.startDate, + endDate: weekTitle.endDate, + items: [], + }); + }); + + curriculum.forEach((item) => { + if (item.week && weekMap.has(item.week)) { + weekMap.get(item.week)!.items.push(item); + } else { + const firstWeek = Array.from(weekMap.values())[0]; + if (firstWeek) { + firstWeek.items.push(item); + } + } + }); + + return Array.from(weekMap.values()); +}; diff --git a/src/domain/program/challenge/marketing-view/Curriculums.tsx b/src/domain/program/challenge/marketing-view/Curriculums.tsx index 79547606e..2f93b6d4b 100644 --- a/src/domain/program/challenge/marketing-view/Curriculums.tsx +++ b/src/domain/program/challenge/marketing-view/Curriculums.tsx @@ -1,18 +1,30 @@ 'use client'; +import dayjs from '@/lib/dayjs'; import { twMerge } from '@/lib/twMerge'; +import { ChallengeContent, ChallengeCurriculum } from '@/types/interface'; import { useMediaQuery } from '@mui/material'; import { ChevronDown, ChevronUp } from 'lucide-react'; -import { ReactNode, useState } from 'react'; -import CurriculumContent, { curriculums } from './CurriculumContent'; +import { ReactNode, useMemo, useState } from 'react'; +import { + CurriculumContent, + getCurriculumGroupedByWeek, +} from './CurriculumContent'; + +interface CurriculumsProps { + curriculum?: ChallengeCurriculum[]; + content?: ChallengeContent; +} const Dropdown = ({ index, title, + date, children, }: { index: number; title: string; + date?: string; children: ReactNode; }) => { const [isOpen, setIsOpen] = useState( @@ -27,7 +39,7 @@ const Dropdown = ({ >
    WEEK {index + 1} - {title} + {date ? {date} : {title}}
    {isOpen ? ( @@ -77,69 +89,91 @@ const SidebarButton = ({ WEEK {index + 1} {date}
-

- {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 = ({
- +
); };