From 10a395d22eda74c8efbad7abd8ed07c0b44f0a95 Mon Sep 17 00:00:00 2001 From: Jeong Ha Seung <88266129+HA-SEUNG-JEONG@users.noreply.github.com> Date: Thu, 26 Feb 2026 08:54:50 +0900 Subject: [PATCH 01/12] =?UTF-8?q?fix:=20HTML=20=EC=9A=94=EC=86=8C=EC=97=90?= =?UTF-8?q?=20overflow-x-hidden=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20Toast=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EC=A0=95=EB=B3=B4=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(admin)/layout.tsx | 2 +- src/app/(landing)/layout.tsx | 2 +- src/app/(service)/insights/ui/blog-detail-page.tsx | 2 +- src/app/(service)/layout.tsx | 4 ++-- src/components/ui/toast.tsx | 6 ++++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app/(admin)/layout.tsx b/src/app/(admin)/layout.tsx index 29dd1c52..cddddc45 100644 --- a/src/app/(admin)/layout.tsx +++ b/src/app/(admin)/layout.tsx @@ -37,7 +37,7 @@ export default async function AdminLayout({ const initialAccessToken = await getServerCookie('accessToken'); return ( - +
{GTM_ID &&- 재량 평가는 최대 3회까지 가능하며, 각 평가별 5점씩 부여됩니다. + 재량 평가는 최대 {EVALUATION_COUNT}회까지 가능하며, 각 평가별 + 5점씩 부여됩니다.
+ {formState.errors.interviewPost.root.message} +
+ )} From b2445484c7868437a5a7a30a485a5e14422db353 Mon Sep 17 00:00:00 2001 From: Jeong Ha Seung <88266129+HA-SEUNG-JEONG@users.noreply.github.com> Date: Fri, 27 Feb 2026 02:40:56 +0900 Subject: [PATCH 08/12] =?UTF-8?q?fix:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EB=B0=8F=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=20=EC=A1=B0=ED=9A=8C=EC=88=98=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=B0=B0=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/card/study-card.tsx | 70 +++++++---- .../pages/group-study-detail-page.tsx | 11 +- .../pages/premium-study-detail-page.tsx | 13 +- .../section/group-study-info-section.tsx | 8 +- .../my-participating-studies-section.tsx | 4 +- src/components/summary/study-info-summary.tsx | 3 +- src/components/ui/study-active-ticker.tsx | 112 ++++++++---------- .../ui/study-card-countdown-badge.tsx | 31 ++++- .../my-page/ui/my-study-info-card.tsx | 6 +- .../study/group/api/group-study-types.ts | 10 +- .../study/group/const/group-study-const.ts | 1 + 11 files changed, 167 insertions(+), 102 deletions(-) diff --git a/src/components/card/study-card.tsx b/src/components/card/study-card.tsx index 8ca11cb8..6c8ff6af 100644 --- a/src/components/card/study-card.tsx +++ b/src/components/card/study-card.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Clock5, Users } from 'lucide-react'; +import { Clock5, Eye, Users } from 'lucide-react'; import Image from 'next/image'; import Link from 'next/link'; import { GroupStudyListItemDto } from '@/api/openapi'; @@ -45,12 +45,25 @@ interface StudyCardProps { study: GroupStudyListItemDto; href: string; onClick?: () => void; + viewCount?: number; } -export default function StudyCard({ study, href, onClick }: StudyCardProps) { +function formatCount(n: number): string { + if (n >= 1000) return `${(n / 1000).toFixed(1).replace(/\.0$/, '')}k`; + + return String(n); +} + +export default function StudyCard({ + study, + href, + onClick, + viewCount, +}: StudyCardProps) { const studyType = study.basicInfo?.type as StudyType; const badgeColor = studyType ? STUDY_TYPE_BADGE_COLORS[studyType] : 'default'; const price = study.basicInfo?.price ?? 0; + const isCompleted = study.basicInfo?.status === 'COMPLETED'; return ( {study.simpleDetailInfo?.thumbnail?.resizedImages?.[0] ?.resizedImageUrl ? ( -{studyDetail?.detailInfo.title} diff --git a/src/components/section/group-study-info-section.tsx b/src/components/section/group-study-info-section.tsx index 62b2ab24..a7598468 100644 --- a/src/components/section/group-study-info-section.tsx +++ b/src/components/section/group-study-info-section.tsx @@ -9,7 +9,6 @@ import UserAvatar from '@/components/ui/avatar'; import AvatarStack from '@/components/ui/avatar-stack'; import type { AvatarStackMember } from '@/components/ui/avatar-stack'; import Button from '@/components/ui/button'; -import StudyActiveTicker from '@/components/ui/study-active-ticker'; import UserProfileModal from '@/entities/user/ui/user-profile-modal'; import { CurriculumSummaryItem } from '@/features/study/group/api/group-study-types'; import { useApplicantsByStatusQuery } from '@/features/study/group/application/model/use-applicant-qeury'; @@ -147,12 +146,7 @@ export default function StudyInfoSection({
+ 지금{' '} + + {viewCount}명 + + 이 이 스터디를 보고 있어요. +
+ ), + }, + { + icon:+ + {approvedCount}명 + + 이 가입했고 현재{' '} + + {remaining}자리 + {' '} + 남았어요. +
+ ), + }, ]; - const [currentIndex, setCurrentIndex] = useState(0); - const [visible, setVisible] = useState(true); - useEffect(() => { const interval = setInterval(() => { - setVisible(false); - setTimeout(() => { - setCurrentIndex((prev) => (prev + 1) % messages.length); - setVisible(true); - }, 300); + setCurrentIndex((prev) => (prev + 1) % messages.length); }, 3000); return () => clearInterval(interval); }, [messages.length]); - const now = useNow(); - - const start = dayjs(startDate); - const diffMs = start.diff(now); - const state = getCountdownState(diffMs); - - const countdown = - state?.urgent === true - ? { text: state.label, color: state.textColorClass, pulse: state.pulse } - : null; - - const isPulse = remaining > 0 && remaining <= 3; - return ( -