-
Notifications
You must be signed in to change notification settings - Fork 1
Feat: 홈화면에서 식물과 대화정도 있는 부분 추가 #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Walkthrough홈 화면 구성 요소 추가 및 헤더/버튼 확장: Swiper 기반 식물 진행, 주간 채팅 진행, HeaderWithIcon 도입, FullButton 색상 스킴 확장, 관련 유틸/타입/목업/스타일과 친구 목록 페이지 추가. (≤50단어) Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant HomePage as Home Page
participant Header as HeaderWithIcon / Header
participant PlantProgress as PlantProgress (Swiper)
participant PlantUtil as getPlantStatus
participant ChatProgress as ChatProgress
participant SortUtil as sortChatProgress
participant NavBar as Bottom NavBar
User->>HomePage: 홈 화면 요청
HomePage->>Header: 헤더 렌더 (알림 상태 표시)
Header-->>HomePage: 헤더 UI
HomePage->>PlantProgress: 식물 데이터 로드 및 슬라이드 렌더
PlantProgress->>PlantUtil: recentWateredTime로 상태 판정
PlantUtil-->>PlantProgress: 상태 반환
PlantProgress-->>HomePage: Swiper 슬라이드(버블, 버튼)
HomePage->>ChatProgress: 채팅 진행 데이터 로드
ChatProgress->>SortUtil: 정렬 수행
SortUtil-->>ChatProgress: 정렬된 목록
ChatProgress-->>HomePage: 프로그레스 바 목록 렌더
HomePage->>NavBar: 하단 네비게이션 렌더
NavBar-->>User: 네비게이션 응답
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/common/HeaderWithIcon.tsx (1)
25-28:router가 선언되지 않아 런타임 에러가 발생합니다.
pencilClick함수에서router.push를 호출하지만,useRouter()로router를 선언한 적이 없습니다. 또한 이 함수는 Line 48에서 사용되지 않고 인라인 함수가 대신 사용되고 있어 데드 코드입니다.의도에 따라 두 가지 수정 방안이 있습니다:
🔧 수정 방안 1: pencilClick 함수 사용 시
export const HeaderWithIcon = ({ title, havePencil = false, }: HeaderWithIconProps) => { + const router = useRouter(); const [isAlarmNew, setIsAlarmNew] = useState(true); const [isPencilClick, setIsPencilClick] = useState(false); const pencilClick = () => { setIsPencilClick(true); router.push("/shared-diary/upload"); }; // ... <PencilIcon className="h-6 w-6 cursor-pointer" - onClick={() => setIsPencilClick(true)} + onClick={pencilClick} />🔧 수정 방안 2: 네비게이션 불필요 시 데드 코드 제거
- import { useRouter } from "next/navigation"; - import { useState } from "react"; // ... export const HeaderWithIcon = ({ title, havePencil = false, }: HeaderWithIconProps) => { const [isAlarmNew, setIsAlarmNew] = useState(true); const [isPencilClick, setIsPencilClick] = useState(false); - const pencilClick = () => { - setIsPencilClick(true); - router.push("/shared-diary/upload"); - };
🤖 Fix all issues with AI agents
In `@src/components/home/Bubble.tsx`:
- Line 1: The Bubble.tsx file imports Image from "next/image" but never uses it;
remove the unused import statement (the "Image" import) from the top of the
Bubble component to clean up linter errors and unused-symbol warnings and ensure
no references to Image remain in the Bubble component or its helpers like the
Bubble component function.
In `@src/components/home/PlantProgress.tsx`:
- Line 34: Replace hard-coded status string literals passed to Bubble with the
imported enum/constant PlantWaterStatus; specifically change Bubble
status={"EMPTY"} and the other occurrences on the same file (lines noted in
review: around the usages at lines 56, 68, 86, 88-89) to use
PlantWaterStatus.EMPTY (or the appropriate PlantWaterStatus member) so all
Bubble(...) calls use the PlantWaterStatus constant instead of string literals.
- Around line 23-29: The Swiper is always using loop={true} which can cause DOM
churn or unexpected behaviour when there is one or zero slides; change the loop
prop to be conditional based on the number of plants (e.g., derive a boolean
like shouldLoop = plantLength > 1) and pass that boolean into the Swiper loop
prop inside the PlantProgress component so loop is only enabled when plantLength
> 1.
- Line 77: The JSX in PlantProgress.tsx uses the nonstandard Tailwind class
"z-99" (e.g., in the <p> with className including z-99 and another occurrence at
line 84); change those to the arbitrary value syntax "z-[99]" or alternatively
add a custom z-index token in your CSS theme (src/styles/globals.css `@theme`) and
reference that token, and update both occurrences (the className on the <p> and
the other instance at line 84) accordingly.
In `@src/styles/globals.css`:
- Around line 148-152: The box-shadow declaration contains invalid rgba() calls
without alpha; update the two occurrences of rgba(255, 255, 255) inside the
box-shadow to either rgb(255, 255, 255) or rgba(255, 255, 255, 1) so the CSS is
valid (i.e., change the top two inset color entries in the box-shadow to include
an alpha or use rgb()).
🧹 Nitpick comments (13)
src/utils/getPercentage.ts (1)
2-5: 엣지 케이스 처리 검토 권장.
part === 0조건은 수학적으로 불필요합니다 (0/total * 100 = 0). 또한 음수 값이나part > total인 경우의 동작을 고려해 보세요.♻️ 개선 제안
// 백분율 값 정수로 계산 export const getPercentage = (part: number, total: number): number => { - if (total === 0 || part === 0) return 0; - return Math.round((part / total) * 100); + if (total === 0) return 0; + const percentage = Math.round((part / total) * 100); + return Math.max(0, Math.min(100, percentage)); // 0-100 범위로 제한 };src/components/home/Header.tsx (1)
7-33: 전반적으로 LGTM!홈 헤더 컴포넌트가 잘 구현되어 있습니다. 몇 가지 개선 포인트가 있습니다:
- Line 27의
AlarmIcon에cursor-pointer가 적용되어 있지만 클릭 핸들러가 없어 사용자 경험에 혼란을 줄 수 있습니다.- Line 14-16의
FriendIcon도 클릭 가능해 보이지만 핸들러가 없습니다 (향후 친구 기능 추가 예정이라면 괜찮습니다).♻️ 접근성 개선 제안
<button className="relative cursor-pointer" onClick={() => setIsAlarmNew(false)} + aria-label="새 알림 확인" >src/components/common/FullButton.tsx (2)
20-27: 중첩 삼항 연산자 대신 객체 매핑 사용을 권장합니다.현재 중첩된 삼항 연산자는 가독성이 떨어지고,
text-button-sb가 모든 분기에서 중복됩니다. 또한 Line 40의<span>에도 동일한 클래스가 적용되어 이중 적용됩니다.♻️ 객체 매핑으로 리팩터링
+ const colorSchemeClasses = { + mint: "bg-mint-01", + orange: "bg-orange-00", + blue: "bg-blue-00", + } as const; + - const activeClass = - colorScheme === "mint" - ? "bg-mint-01 text-white text-button-sb" - : colorScheme === "orange" - ? "bg-orange-00 text-white text-button-sb" - : colorScheme === "blue" - ? "bg-blue-00 text-white text-button-sb" - : ""; + const activeClass = `${colorSchemeClasses[colorScheme]} text-white text-button-sb`;
39-41:text-button-sb클래스 중복 적용
activeClass와inactiveClass에 이미text-button-sb가 포함되어 있는데, Line 40의<span>에도 동일한 클래스가 적용되어 있습니다. 중복을 제거하세요.♻️ 중복 클래스 제거
<div className="flex h-[58px] items-center justify-center"> - <span className="text-button-sb">{children}</span> + <span>{children}</span> </div>src/components/home/ProgressBar.tsx (1)
1-17: LGTM - 단순하고 효과적인 구현입니다.한 가지 방어적 코딩 제안:
percentage값이 0-100 범위를 벗어날 경우를 대비하여 클램핑을 고려해 보세요.♻️ 방어적 코딩 제안
export const ProgressBar = ({ percentage, haveTodayChat, }: ProgressBarProps) => { + const clampedPercentage = Math.min(100, Math.max(0, percentage)); return ( <div className="bg-neutral-08 flex h-2 w-full rounded-sm"> <div className={`${haveTodayChat ? "bg-mint-02" : "bg-orange-01"} rounded-s-sm`} - style={{ width: `${percentage}%` }} + style={{ width: `${clampedPercentage}%` }} ></div> </div> ); };src/components/common/HeaderWithIcon.tsx (1)
8-8: 사용되지 않는 import
FriendIcon이 import되었지만 컴포넌트에서 사용되지 않습니다. 제거하거나, 향후 사용 예정이라면 TODO 주석을 추가하세요.♻️ 미사용 import 제거
import AlarmIcon from "@/assets/bell.svg"; -import FriendIcon from "@/assets/friend.svg"; import PencilIcon from "@/assets/pencil.svg";src/app/page.tsx (1)
19-21: NavBar 래퍼의 중복된 fixed 포지셔닝 확인 필요.
NavBar컴포넌트 내부에 이미fixed bottom-0 left-1/2 -translate-x-1/2가 적용되어 있습니다. 외부 래퍼 div에 추가로fixed bottom-0를 적용하면 예상치 못한 레이아웃 문제가 발생할 수 있습니다.래퍼를 제거하거나,
NavBar컴포넌트의 포지셔닝 방식을 통일하는 것을 권장합니다.♻️ 제안된 수정
<div className="pb-[119px]"> <ChatProgress /> </div> - <div className="fixed bottom-0 w-full max-w-[440px]"> - <NavBar /> - </div> + <NavBar /> </main>src/utils/getPlantStatus.ts (1)
3-5: 타입 정의와 유효하지 않은 날짜 처리 개선 필요
- 파라미터 타입이
string이지만, falsy 체크(!recentWateredTime)는null이나undefined를 처리하려는 의도로 보입니다. 타입을 명확히 하는 것이 좋습니다.- 유효하지 않은 날짜 문자열이 전달되면
NaN이 반환되어 예기치 않은 동작이 발생할 수 있습니다.♻️ 개선 제안
-export const getPlantStatus = (recentWateredTime: string) => { - if (!recentWateredTime) return PlantWaterStatus.EMPTY; - const wateredAt = new Date(recentWateredTime).getTime(); +export const getPlantStatus = (recentWateredTime: string | null | undefined) => { + if (!recentWateredTime) return PlantWaterStatus.EMPTY; + const wateredAt = new Date(recentWateredTime).getTime(); + if (Number.isNaN(wateredAt)) return PlantWaterStatus.EMPTY;src/components/home/ChatProgress.tsx (3)
10-11: 정렬 로직 메모이제이션 고려
sortChatProgress가 매 렌더링마다 호출됩니다. 데이터가 변경되지 않는 한 불필요한 재정렬을 방지하기 위해useMemo를 사용하는 것이 좋습니다.♻️ useMemo 적용 제안
+import { useMemo } from "react"; + export const ChatProgress = () => { - const sortedData = sortChatProgress(chatProgressData); + const sortedData = useMemo( + () => sortChatProgress(chatProgressData), + [chatProgressData] + );
19-61: 빈 데이터 상태 처리 누락
chatProgressData가 비어있을 경우 아무것도 렌더링되지 않습니다.PlantProgress컴포넌트처럼 빈 상태에 대한 UI를 추가하는 것이 좋습니다.♻️ 빈 상태 처리 예시
<div className="px-4 py-[10px]"> + {sortedData.length === 0 ? ( + <p className="text-neutral-05 text-center">이번 주 대화 기록이 없어요</p> + ) : ( {sortedData.map(data => { // ... existing code })} + )} </div>
24-30: 이미지 로딩 실패 시 fallback 처리 고려
profileImg가 유효하지 않거나 로딩에 실패할 경우 깨진 이미지가 표시될 수 있습니다. 기본 프로필 이미지나 placeholder를 고려해 보세요.src/components/home/Bubble.tsx (2)
16-30: switch문에 default case 또는 명시적 반환 타입 추가 권장현재 모든
PlantWaterStatus케이스를 처리하지만, 명시적 반환 타입이나 default case를 추가하면 타입 안전성이 향상됩니다. 예상치 못한 값이 전달될 경우undefined가 반환될 수 있습니다.♻️ 개선 제안
-export const Bubble = ({ status }: BubbleProps) => { +export const Bubble = ({ status }: BubbleProps): JSX.Element => { switch (status) { case PlantWaterStatus.EMPTY: { return <YellowCircle />; } case PlantWaterStatus.WATERED_RECENTLY: { return <GreenCircle />; } case PlantWaterStatus.WATERABLE: { return <BlueCircle />; } case PlantWaterStatus.WITHERED: { return <RedCircle />; } + default: { + const _exhaustiveCheck: never = status; + return <YellowCircle />; + } } };
3-6: 파일 명명 규칙 불일치
red_circle.svg는 언더스코어를 사용하지만, 다른 파일들은 하이픈을 사용합니다(blue-circle.svg,green-circle.svg,yellow-circle.svg). 일관성을 위해red-circle.svg로 변경하는 것을 권장합니다.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (8)
src/assets/bell.svgis excluded by!**/*.svgsrc/assets/clock.svgis excluded by!**/*.svgsrc/assets/friend.svgis excluded by!**/*.svgsrc/assets/home/blue-circle.svgis excluded by!**/*.svgsrc/assets/home/green-circle.svgis excluded by!**/*.svgsrc/assets/home/red_circle.svgis excluded by!**/*.svgsrc/assets/home/yellow-circle.svgis excluded by!**/*.svgyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (20)
package.jsonsrc/app/day-log/page.tsxsrc/app/page.tsxsrc/app/shared-diary/[id]/page.tsxsrc/components/common/FullButton.tsxsrc/components/common/HeaderWithIcon.tsxsrc/components/common/NavBar.tsxsrc/components/home/Bubble.tsxsrc/components/home/ChatProgress.tsxsrc/components/home/Header.tsxsrc/components/home/PlantProgress.tsxsrc/components/home/ProgressBar.tsxsrc/constants/plantStatus.tssrc/mock/chatProgress.jsonsrc/mock/plantProgress.jsonsrc/styles/globals.csssrc/types/chatProgress.type.tssrc/utils/getPercentage.tssrc/utils/getPlantStatus.tssrc/utils/sortChatProgress.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-02T13:08:01.441Z
Learnt from: lemoncurdyogurt
Repo: IT-Cotato/12th-SimTok-FE PR: 3
File: src/utils/formatPhone.ts:6-9
Timestamp: 2026-01-02T13:08:01.441Z
Learning: In phone number formatting/validation logic, enforce that Korean numbers are valid only as 10-digit landlines or 11-digit mobile numbers starting with 010. Do not perform strict intermediate-length formatting for 7–9 digits during input; assume intermediate values are not considered valid until they reach 10 or 11 digits. Implement or update validation to accept only 10 or 11 digits (with 010 prefix for mobiles) and, if formatting is needed during input, preserve user-friendly partial handling without emitting strict validation errors for intermediate states.
Applied to files:
src/utils/getPercentage.tssrc/utils/sortChatProgress.tssrc/utils/getPlantStatus.ts
🧬 Code graph analysis (9)
src/types/chatProgress.type.ts (1)
src/components/home/ChatProgress.tsx (1)
ChatProgress(10-65)
src/utils/sortChatProgress.ts (2)
src/components/home/ChatProgress.tsx (1)
ChatProgress(10-65)src/types/chatProgress.type.ts (1)
ChatProgress(1-8)
src/components/home/PlantProgress.tsx (5)
src/components/home/Bubble.tsx (1)
Bubble(16-31)src/components/dailyRecord/InfoMessage.tsx (1)
InfoMessage(5-19)src/components/common/FullButton.tsx (1)
FullButton(11-44)src/utils/getPlantStatus.ts (1)
getPlantStatus(3-13)src/constants/plantStatus.ts (2)
PLANT_BG_BY_STATUS(11-16)PlantWaterStatus(1-6)
src/app/day-log/page.tsx (1)
src/components/common/HeaderWithIcon.tsx (1)
HeaderWithIcon(18-59)
src/app/shared-diary/[id]/page.tsx (1)
src/components/common/HeaderWithIcon.tsx (1)
HeaderWithIcon(18-59)
src/components/home/ChatProgress.tsx (4)
src/types/chatProgress.type.ts (1)
ChatProgress(1-8)src/utils/sortChatProgress.ts (1)
sortChatProgress(3-14)src/utils/getPercentage.ts (1)
getPercentage(2-5)src/components/home/ProgressBar.tsx (1)
ProgressBar(5-17)
src/utils/getPlantStatus.ts (1)
src/constants/plantStatus.ts (1)
PlantWaterStatus(1-6)
src/components/home/Bubble.tsx (1)
src/constants/plantStatus.ts (2)
PlantWaterStatusType(8-9)PlantWaterStatus(1-6)
src/app/page.tsx (4)
src/components/home/Header.tsx (1)
Header(7-33)src/components/home/PlantProgress.tsx (1)
PlantProgress(18-105)src/components/home/ChatProgress.tsx (1)
ChatProgress(10-65)src/components/common/NavBar.tsx (1)
NavBar(8-31)
🔇 Additional comments (13)
src/mock/plantProgress.json (1)
1-32: LGTM!Mock 데이터 구조가 일관성 있게 잘 정의되어 있습니다. ISO 8601 날짜 형식을 사용하고 있어 파싱 및 처리에 용이합니다.
src/styles/globals.css (1)
86-124: LGTM!식물 상태별 그라디언트 유틸리티 클래스가 잘 정의되어 있습니다. 각 상태(blue, yellow, red, green)에 맞는 시각적 구분이 명확합니다.
src/components/common/NavBar.tsx (1)
21-25: LGTM!아이콘과 라벨 사이에
gap-[5px]를 추가하여 간격을 개선했습니다. TODO 주석으로 box-shadow 디자인 작업이 남아있음을 명확히 표시한 점도 좋습니다.package.json (1)
27-27: Swiper 12.0.3 버전은 유효하며 보안 이슈가 없습니다.버전 12.0.3은 npm 레지스트리에 존재하는 유효한 버전입니다. Swiper의 알려진 보안 취약점(CVE-2021-23370)은 6.5.1 이전 버전에만 영향을 미쳤으며 이미 패치되었으므로, 12.0.3에는 직접적인 보안 위협이 없습니다. PlantProgress 컴포넌트에서도 올바르게 사용 중입니다.
src/app/shared-diary/[id]/page.tsx (1)
23-27: LGTM!
HeaderWithIcon으로의 마이그레이션이 잘 적용되었습니다.justify-center추가로 레이아웃이 개선되었습니다.src/app/day-log/page.tsx (1)
1-1: LGTM!
HeaderWithIcon컴포넌트로의 변경이 올바르게 적용되었습니다.title과havePencilprops가 적절히 전달되고 있습니다.Also applies to: 15-15
src/mock/chatProgress.json (1)
1-82: LGTM!목업 데이터가
ChatProgress타입 정의와 일치하며, 개발 및 테스트 목적으로 적절하게 구성되어 있습니다.src/app/page.tsx (1)
7-18: LGTM!페이지 레이아웃 구조가 잘 구성되어 있습니다. Header, PlantProgress, ChatProgress 섹션이 적절하게 배치되었습니다.
src/utils/sortChatProgress.ts (1)
3-14: LGTM! 정렬 순서 의도 확인.정렬 로직이 올바르게 구현되어 있습니다:
hasTodayChat이false인 항목이 먼저 정렬됨 (PR 요구사항 "대화 안 한 사람 → 대화한 사람"과 일치)- 0으로 나누기 방지 처리 완료
- 원본 배열 변경 없이 복사본 정렬
현재 rate는 오름차순으로 정렬됩니다 (낮은 percentage가 먼저). 이것이 의도된 동작인지 확인해 주세요.
src/types/chatProgress.type.ts (1)
1-8: LGTM!타입 정의가 명확하고 목업 데이터 구조와 일치합니다. 관련 컴포넌트와 유틸리티에서 올바르게 사용되고 있습니다.
src/utils/getPlantStatus.ts (1)
7-12: LGTM!시간 차이 계산과 상태 임계값 로직이 PR 요구사항(24시간 이내: WATERED_RECENTLY, 24-48시간: WATERABLE, 48시간 이후: WITHERED)에 맞게 올바르게 구현되어 있습니다.
src/constants/plantStatus.ts (1)
1-16: LGTM!상수 정의가 깔끔하고
as const를 활용한 타입 안전성이 잘 구현되어 있습니다.PLANT_BG_BY_STATUS매핑이 모든 상태를 커버하고 있습니다.src/components/home/PlantProgress.tsx (1)
76-82: 조건부 로직 의도 확인 필요식물이 1개일 때 "원하는 식물을 골라보세요!" 메시지가 표시됩니다. 이미 식물을 키우고 있는 사용자에게 이 메시지가 적절한지 확인이 필요합니다. 식물명을 표시하거나 다른 메시지를 보여주는 것이 더 적절할 수 있습니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| @@ -0,0 +1,31 @@ | |||
| import Image from "next/image"; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
사용되지 않는 import 제거
Image가 next/image에서 import되었지만 컴포넌트에서 사용되지 않습니다.
♻️ 수정 제안
-import Image from "next/image";
-
import BlueCircle from "@/assets/home/blue-circle.svg";🤖 Prompt for AI Agents
In `@src/components/home/Bubble.tsx` at line 1, The Bubble.tsx file imports Image
from "next/image" but never uses it; remove the unused import statement (the
"Image" import) from the top of the Bubble component to clean up linter errors
and unused-symbol warnings and ensure no references to Image remain in the
Bubble component or its helpers like the Bubble component function.
| <Swiper | ||
| modules={[Keyboard]} | ||
| keyboard={{ enabled: true }} | ||
| loop={true} | ||
| spaceBetween={16} | ||
| slidesPerView={1} | ||
| > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cd /tmp && find . -type f -name "PlantProgress.tsx" 2>/dev/null | head -5Repository: IT-Cotato/12th-SimTok-FE
Length of output: 50
🏁 Script executed:
find . -type f -name "*.tsx" -o -name "*.ts" | grep -i plant | head -10Repository: IT-Cotato/12th-SimTok-FE
Length of output: 168
🏁 Script executed:
find . -type f -path "*components/home/PlantProgress.tsx"Repository: IT-Cotato/12th-SimTok-FE
Length of output: 107
🏁 Script executed:
cat -n ./src/components/home/PlantProgress.tsx | head -60Repository: IT-Cotato/12th-SimTok-FE
Length of output: 2535
🏁 Script executed:
wc -l ./src/components/home/PlantProgress.tsxRepository: IT-Cotato/12th-SimTok-FE
Length of output: 111
🏁 Script executed:
cat -n ./src/components/home/PlantProgress.tsx | sed -n '60,105p'Repository: IT-Cotato/12th-SimTok-FE
Length of output: 2267
단일 또는 소수의 슬라이드에서 loop 동작 비활성화 권장
loop={true}가 항상 활성화되어 있지만, 슬라이드가 1개 이하일 때(plantLength ≤ 1) Swiper의 loop 모드는 불필요한 DOM 조작을 발생시키고 예상치 못한 동작을 유발할 수 있습니다. 여러 개의 슬라이드가 있을 때만 loop를 활성화하는 것이 Swiper 모범 사례입니다.
♻️ 조건부 loop 적용
<Swiper
modules={[Keyboard]}
keyboard={{ enabled: true }}
- loop={true}
+ loop={plantLength > 1}
spaceBetween={16}
slidesPerView={1}
>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Swiper | |
| modules={[Keyboard]} | |
| keyboard={{ enabled: true }} | |
| loop={true} | |
| spaceBetween={16} | |
| slidesPerView={1} | |
| > | |
| <Swiper | |
| modules={[Keyboard]} | |
| keyboard={{ enabled: true }} | |
| loop={plantLength > 1} | |
| spaceBetween={16} | |
| slidesPerView={1} | |
| > |
🤖 Prompt for AI Agents
In `@src/components/home/PlantProgress.tsx` around lines 23 - 29, The Swiper is
always using loop={true} which can cause DOM churn or unexpected behaviour when
there is one or zero slides; change the loop prop to be conditional based on the
number of plants (e.g., derive a boolean like shouldLoop = plantLength > 1) and
pass that boolean into the Swiper loop prop inside the PlantProgress component
so loop is only enabled when plantLength > 1.
| <SwiperSlide> | ||
| <div className="bg-plant-yellow relative h-[551px] w-full overflow-hidden"> | ||
| <div className="flex h-full flex-col items-center justify-center px-4"> | ||
| <Bubble status={"EMPTY"} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
문자열 리터럴 대신 상수 사용 권장
"EMPTY" 문자열 대신 import된 PlantWaterStatus.EMPTY 상수를 사용하세요. 이 패턴이 lines 56, 68, 86, 88-89에도 적용됩니다.
♻️ 상수 사용으로 일관성 개선
- <Bubble status={"EMPTY"} />
+ <Bubble status={PlantWaterStatus.EMPTY} />Lines 68, 86, 88-89도 동일하게 수정:
- ? "오늘은 물주기를 완료했어요🥳"
+ {plantStatus === PlantWaterStatus.WATERED_RECENTLY
+ ? "오늘은 물주기를 완료했어요🥳"
- isActive={!(plantStatus === "WATERED_RECENTLY")}
+ isActive={plantStatus !== PlantWaterStatus.WATERED_RECENTLY}
- (plantStatus === "WATERABLE" && "blue") ||
- (plantStatus === "WITHERED" && "orange") ||
+ (plantStatus === PlantWaterStatus.WATERABLE && "blue") ||
+ (plantStatus === PlantWaterStatus.WITHERED && "orange") ||📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Bubble status={"EMPTY"} /> | |
| <Bubble status={PlantWaterStatus.EMPTY} /> |
🤖 Prompt for AI Agents
In `@src/components/home/PlantProgress.tsx` at line 34, Replace hard-coded status
string literals passed to Bubble with the imported enum/constant
PlantWaterStatus; specifically change Bubble status={"EMPTY"} and the other
occurrences on the same file (lines noted in review: around the usages at lines
56, 68, 86, 88-89) to use PlantWaterStatus.EMPTY (or the appropriate
PlantWaterStatus member) so all Bubble(...) calls use the PlantWaterStatus
constant instead of string literals.
| <div className="bg-blur absolute bottom-0 z-10 h-[329px] w-full max-w-[440px]" /> | ||
| <div className="absolute bottom-[84px] z-30 flex w-full items-center justify-center px-4 py-[10px]"> | ||
| {plantLength > 1 ? ( | ||
| <p className="text-h3 text-neutral-05 bg-glass-style z-99 rounded-2xl p-[10px]"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find Tailwind configuration files
find . -name "tailwind.config.*" -o -name "tailwind.config.js" -o -name "tailwind.config.ts" | head -20Repository: IT-Cotato/12th-SimTok-FE
Length of output: 50
🏁 Script executed:
# Search for z-99 usage and zIndex definitions
rg "z-99|zIndex" --type=js --type=ts --type=json -B 2 -A 2Repository: IT-Cotato/12th-SimTok-FE
Length of output: 1847
🏁 Script executed:
# Check PlantProgress.tsx context around lines 77 and 84
fd "PlantProgress.tsx" --exec head -90 {} \; | tail -25Repository: IT-Cotato/12th-SimTok-FE
Length of output: 1388
🏁 Script executed:
# Search for Tailwind configuration in all common locations
find . -type f \( -name "*.config.*" -o -name "postcss.config.*" \) 2>/dev/null | grep -E "(tailwind|postcss|next)"Repository: IT-Cotato/12th-SimTok-FE
Length of output: 105
🏁 Script executed:
# Check for Tailwind setup in package.json or tsconfig
rg "tailwind|zIndex" --type=json -A 3 -B 1 | head -50Repository: IT-Cotato/12th-SimTok-FE
Length of output: 511
🏁 Script executed:
# Look for any extend or theme configuration related to z-index
rg "extend.*theme|theme.*extend" --type=js --type=ts -A 10 | head -80Repository: IT-Cotato/12th-SimTok-FE
Length of output: 50
🏁 Script executed:
# Check postcss.config.mjs
cat postcss.config.mjsRepository: IT-Cotato/12th-SimTok-FE
Length of output: 161
🏁 Script executed:
# Look for CSS files that might define theme extensions
fd "\\.css$" | head -20Repository: IT-Cotato/12th-SimTok-FE
Length of output: 116
🏁 Script executed:
# Check for any CSS files with zIndex or theme definitions
rg "zIndex|--z-|extend" --type=css -B 2 -A 2Repository: IT-Cotato/12th-SimTok-FE
Length of output: 50
🏁 Script executed:
# Check globals.css
cat src/styles/globals.cssRepository: IT-Cotato/12th-SimTok-FE
Length of output: 3969
🏁 Script executed:
# Check typography.css
cat src/styles/typography.cssRepository: IT-Cotato/12th-SimTok-FE
Length of output: 2433
🏁 Script executed:
# Search for any theme or config definitions in all CSS files
rg "@theme|@layer|z-" --type=cssRepository: IT-Cotato/12th-SimTok-FE
Length of output: 176
Tailwind v4에서 정의되지 않은 z-index 클래스
z-99는 Tailwind v4의 표준 클래스가 아닙니다. 임의 값을 사용하려면 z-[99] 형식을 사용하거나, src/styles/globals.css의 @theme 블록에 --z-99 정의를 추가하세요. Line 84에도 동일한 이슈가 있습니다.
🤖 Prompt for AI Agents
In `@src/components/home/PlantProgress.tsx` at line 77, The JSX in
PlantProgress.tsx uses the nonstandard Tailwind class "z-99" (e.g., in the <p>
with className including z-99 and another occurrence at line 84); change those
to the arbitrary value syntax "z-[99]" or alternatively add a custom z-index
token in your CSS theme (src/styles/globals.css `@theme`) and reference that
token, and update both occurrences (the className on the <p> and the other
instance at line 84) accordingly.
| box-shadow: | ||
| inset 1px 1px 0 rgba(255, 255, 255), | ||
| inset -1px -1px 0 rgba(255, 255, 255), | ||
| inset 0 0 34px rgba(255, 255, 255, 0.55), | ||
| inset 0 6px 12px rgba(255, 255, 255, 0.12); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rgba() 구문 오류 수정 필요.
rgba(255, 255, 255)는 알파 값이 누락되어 유효하지 않은 CSS입니다. rgba()는 4개의 인자가 필요하거나, rgb()를 사용해야 합니다.
🐛 수정 제안
box-shadow:
- inset 1px 1px 0 rgba(255, 255, 255),
- inset -1px -1px 0 rgba(255, 255, 255),
+ inset 1px 1px 0 rgba(255, 255, 255, 1),
+ inset -1px -1px 0 rgba(255, 255, 255, 1),
inset 0 0 34px rgba(255, 255, 255, 0.55),
inset 0 6px 12px rgba(255, 255, 255, 0.12);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| box-shadow: | |
| inset 1px 1px 0 rgba(255, 255, 255), | |
| inset -1px -1px 0 rgba(255, 255, 255), | |
| inset 0 0 34px rgba(255, 255, 255, 0.55), | |
| inset 0 6px 12px rgba(255, 255, 255, 0.12); | |
| box-shadow: | |
| inset 1px 1px 0 rgba(255, 255, 255, 1), | |
| inset -1px -1px 0 rgba(255, 255, 255, 1), | |
| inset 0 0 34px rgba(255, 255, 255, 0.55), | |
| inset 0 6px 12px rgba(255, 255, 255, 0.12); |
🤖 Prompt for AI Agents
In `@src/styles/globals.css` around lines 148 - 152, The box-shadow declaration
contains invalid rgba() calls without alpha; update the two occurrences of
rgba(255, 255, 255) inside the box-shadow to either rgb(255, 255, 255) or
rgba(255, 255, 255, 1) so the CSS is valid (i.e., change the top two inset color
entries in the box-shadow to include an alpha or use rgb()).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/components/home/ChatProgress.tsx`:
- Around line 20-22: The Tailwind class on the EyesIcon is incomplete ("w-");
update the className on the EyesIcon component in ChatProgress.tsx to include a
valid width utility (for example replace "w- h-[29px]" with "w-6 h-[29px]" or
"w-[24px] h-[29px]") so the icon receives the intended width.
- Around line 30-36: The Tailwind size classes on the Image in ChatProgress.tsx
are invalid; update the Image component (props: src={data.profileImg},
alt={data.userName}, width={72}, height={72}) to either remove the h-18 w-18
classes from className or replace them with valid utilities like h-[72px]
w-[72px] (keeping rounded-2xl object-cover), and since data.profileImg uses
local paths, remove any unnecessary remotePatterns configuration from
next.config.js to avoid needless remote image rules.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
src/assets/hand-with-pen.svgis excluded by!**/*.svgsrc/assets/two-eyes.svgis excluded by!**/*.svg
📒 Files selected for processing (2)
src/assets/GalleryIcon.tsxsrc/components/home/ChatProgress.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/home/ChatProgress.tsx (4)
src/types/chatProgress.type.ts (1)
ChatProgress(1-8)src/utils/sortChatProgress.ts (1)
sortChatProgress(3-14)src/utils/getPercentage.ts (1)
getPercentage(2-5)src/components/home/ProgressBar.tsx (1)
ProgressBar(5-17)
🔇 Additional comments (5)
src/assets/GalleryIcon.tsx (3)
2-3: LGTM!SVG 아이콘 임포트가 정상적으로 추가되었습니다. 이모지를 SVG로 교체하는 것은 접근성과 일관성 측면에서 좋은 개선입니다.
9-10: 아이콘 크기가 컨테이너를 초과합니다.컨테이너 크기는
h-[15px] w-[15px]인데,EyesIcon의 너비가w-[18px]로 설정되어 있어 오버플로우가 발생합니다. 의도된 디자인이라면 무시해도 되지만, 그렇지 않다면 아이콘 크기를 컨테이너에 맞게 조정하거나overflow-hidden을 추가하는 것을 고려해 주세요.
12-13: LGTM!HandIcon 크기(13px)가 컨테이너(15px) 내에 적절하게 배치되어 있습니다.
src/components/home/ChatProgress.tsx (2)
1-11: LGTM!import 구조가 깔끔하게 정리되어 있습니다. SVG를 React 컴포넌트로, mock 데이터와 유틸리티 함수들을 적절히 분리하여 사용하고 있습니다.
26-67: LGTM!사용자 목록 렌더링 로직이 잘 구현되어 있습니다:
userId를 key로 사용하여 고유성 보장getPercentage유틸리티를 활용한 진행률 계산hasTodayChat상태에 따른 조건부 메시지 표시ProgressBar컴포넌트와의 연동이 적절함
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| <span> | ||
| <EyesIcon className="w- h-[29px]" /> | ||
| </span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
불완전한 Tailwind 클래스명 수정 필요.
w- 클래스가 불완전합니다. 값이 누락되어 너비가 적용되지 않습니다. 의도한 너비 값을 추가해주세요 (예: w-6, w-[24px] 등).
🔧 수정 제안
<span>
- <EyesIcon className="w- h-[29px]" />
+ <EyesIcon className="w-[29px] h-[29px]" />
</span>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <span> | |
| <EyesIcon className="w- h-[29px]" /> | |
| </span> | |
| <span> | |
| <EyesIcon className="w-[29px] h-[29px]" /> | |
| </span> |
🤖 Prompt for AI Agents
In `@src/components/home/ChatProgress.tsx` around lines 20 - 22, The Tailwind
class on the EyesIcon is incomplete ("w-"); update the className on the EyesIcon
component in ChatProgress.tsx to include a valid width utility (for example
replace "w- h-[29px]" with "w-6 h-[29px]" or "w-[24px] h-[29px]") so the icon
receives the intended width.
| <Image | ||
| src={data.profileImg} | ||
| alt={data.userName} | ||
| width={72} | ||
| height={72} | ||
| className="h-18 w-18 rounded-2xl object-cover" | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for next.config file and examine its content
fd "next\.config\.(js|ts|mjs)" --type f -x cat {}Repository: IT-Cotato/12th-SimTok-FE
Length of output: 634
🏁 Script executed:
#!/bin/bash
# Check for tailwind.config file
fd "tailwind\.config\.(js|ts)" --type f -x cat {}Repository: IT-Cotato/12th-SimTok-FE
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Check if mock data file exists and examine profileImg URLs
if [ -f "src/mock/chatProgress.json" ]; then
cat src/mock/chatProgress.json
elif [ -f "src/mocks/chatProgress.json" ]; then
cat src/mocks/chatProgress.json
else
echo "Mock file not found, searching for similar files..."
fd "chatProgress\|chat.*progress" --type f
fiRepository: IT-Cotato/12th-SimTok-FE
Length of output: 1557
🏁 Script executed:
#!/bin/bash
# Examine the ChatProgress.tsx component
fd "ChatProgress\.tsx" --type f -x cat {}Repository: IT-Cotato/12th-SimTok-FE
Length of output: 2520
🏁 Script executed:
#!/bin/bash
# Search for any h-18 or w-18 references in tailwind config or CSS
rg "h-18|w-18" --type js --type ts --type cssRepository: IT-Cotato/12th-SimTok-FE
Length of output: 167
🏁 Script executed:
#!/bin/bash
# Search for tailwind config in various locations and formats
find . -name "tailwind.config.*" -o -name "tailwind.css" -o -name "globals.css" 2>/dev/null | head -20Repository: IT-Cotato/12th-SimTok-FE
Length of output: 92
🏁 Script executed:
#!/bin/bash
# Check for any configuration files in root
ls -la | grep -E "tailwind|postcss"Repository: IT-Cotato/12th-SimTok-FE
Length of output: 138
🏁 Script executed:
#!/bin/bash
# Search for h-18 and w-18 definitions in CSS and config files
rg "h-18|w-18" --type css --type scssRepository: IT-Cotato/12th-SimTok-FE
Length of output: 96
🏁 Script executed:
#!/bin/bash
# Check if there's a custom theme extension in any config
rg "theme.*extend|spacing" --type js --type ts --max-count=50Repository: IT-Cotato/12th-SimTok-FE
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Check package.json to understand the tailwind setup
cat package.json | grep -A 10 -B 2 "tailwind"Repository: IT-Cotato/12th-SimTok-FE
Length of output: 562
🏁 Script executed:
#!/bin/bash
# Check globals.css for custom h-18 and w-18 definitions
cat src/styles/globals.cssRepository: IT-Cotato/12th-SimTok-FE
Length of output: 3969
🏁 Script executed:
#!/bin/bash
# Check postcss config
cat postcss.config.mjsRepository: IT-Cotato/12th-SimTok-FE
Length of output: 161
🏁 Script executed:
#!/bin/bash
# Check if there's any tailwind config in tsconfig or other places
find . -name "tsconfig.json" -o -name ".tailwindrc*" 2>/dev/nullRepository: IT-Cotato/12th-SimTok-FE
Length of output: 83
🏁 Script executed:
#!/bin/bash
# Search for any h- or w- class definitions in the entire codebase
rg "@layer|@apply|h-\[|w-\[|h-[0-9]|w-[0-9]" --type css --type js --type ts -A 2 | head -100Repository: IT-Cotato/12th-SimTok-FE
Length of output: 7858
Tailwind 클래스 h-18, w-18은 표준 클래스가 아니므로 수정 필요.
Image 컴포넌트에서 className="h-18 w-18 rounded-2xl object-cover"로 지정한 클래스는 Tailwind의 기본 spacing scale에 존재하지 않습니다. width={72}, height={72} props로 크기가 이미 제어되고 있으므로, h-[72px] w-[72px]으로 변경하거나 className에서 크기 관련 클래스를 제거하세요.
참고: data.profileImg는 mock 데이터에서 모두 로컬 경로(/images/1.jpg 등)이므로 next.config.js의 remotePatterns 설정은 필요하지 않습니다.
🤖 Prompt for AI Agents
In `@src/components/home/ChatProgress.tsx` around lines 30 - 36, The Tailwind size
classes on the Image in ChatProgress.tsx are invalid; update the Image component
(props: src={data.profileImg}, alt={data.userName}, width={72}, height={72}) to
either remove the h-18 w-18 classes from className or replace them with valid
utilities like h-[72px] w-[72px] (keeping rounded-2xl object-cover), and since
data.profileImg uses local paths, remove any unnecessary remotePatterns
configuration from next.config.js to avoid needless remote image rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@src/components/common/HeaderWithIcon.tsx`:
- Line 40: The span element in HeaderWithIcon.tsx uses an invalid Tailwind class
"bg-red-00" so the notification dot doesn't render; update the className on the
span (the notification dot in the HeaderWithIcon component) to use a valid
Tailwind background color such as "bg-red-500" (or another valid color class)
while keeping the positioning and sizing classes unchanged.
In `@src/components/friends/FrinedList.tsx`:
- Around line 1-4: The file name contains a typo: rename FrinedList.tsx to
FriendList.tsx and update any references/imports to use FriendList (e.g., import
FriendList from ".../FriendList") and ensure the component declaration/export
inside (component name, default export) is also corrected to FriendList so the
component name and filename match.
In `@src/components/home/Header.tsx`:
- Around line 29-31: The AlarmIcon rendering branch for isAlarmNew = false shows
a cursor-pointer but isn’t interactive; either remove the "cursor-pointer" class
from the non-interactive AlarmIcon or make it interactive to match the true
branch by wrapping the AlarmIcon in the same button element/handler used when
isAlarmNew is true (use the same onClick/navigation logic). Update the JSX
around isAlarmNew and the AlarmIcon to ensure visual affordance matches actual
behavior.
🧹 Nitpick comments (8)
src/components/common/HeaderWithIcon.tsx (2)
45-50: 접근성 개선: PencilIcon을 버튼으로 감싸세요.AlarmIcon과 달리 PencilIcon이 버튼 없이 직접 클릭 핸들러를 가지고 있습니다. 스크린 리더와 키보드 내비게이션을 위해 버튼으로 감싸는 것이 좋습니다.
♻️ 접근성 개선 제안
{havePencil && ( - <PencilIcon - className="h-6 w-6 cursor-pointer" - onClick={pencilClick} - /> + <button className="cursor-pointer" onClick={pencilClick}> + <PencilIcon className="h-6 w-6" /> + </button> )}
42-44: cursor-pointer가 있지만 클릭 핸들러가 없습니다.
isAlarmNew가 false일 때 AlarmIcon에cursor-pointer가 있지만 클릭 이벤트가 없어서 사용자에게 혼란을 줄 수 있습니다.♻️ 수정 제안
) : ( - <AlarmIcon className="h-6 w-6 cursor-pointer" /> + <AlarmIcon className="h-6 w-6" /> )}src/components/home/Header.tsx (1)
17-19: 아이콘 버튼에 접근성 속성 추가를 권장합니다.아이콘만 있는 버튼의 경우 스크린 리더 사용자를 위해
aria-label을 추가하는 것이 좋습니다. 또한 버튼 내부의cursor-pointer는 중복이므로 제거할 수 있습니다.♿ 접근성 개선 제안
- <button onClick={() => router.push("/friends")}> - <FriendIcon className="text-neutral-03 cursor-pointer" /> + <button onClick={() => router.push("/friends")} aria-label="친구 목록"> + <FriendIcon className="text-neutral-03" /> </button>AlarmIcon 버튼에도 동일하게 적용:
<button className="relative flex cursor-pointer items-center justify-center" onClick={() => setIsAlarmNew(false)} + aria-label="새 알림" > - <AlarmIcon className="text-neutral-03 h-6 w-6 cursor-pointer" /> + <AlarmIcon className="text-neutral-03 h-6 w-6" />src/components/friends/SearchField.tsx (1)
9-13: 접근성: input에 label이 필요합니다.스크린 리더 사용자를 위해
<label>을 추가하거나aria-label속성을 사용해주세요. 또한 input의 배경색이 부모와 다를 수 있으므로bg-transparent를 추가하는 것이 좋습니다.♻️ 개선 제안
<input type="text" placeholder="친구이름을 검색해보세요" - className="w-full focus:outline-none" - ></input> + aria-label="친구 검색" + className="w-full bg-transparent focus:outline-none" + />src/components/common/BackHeader.tsx (1)
49-52: subtext 버튼에 type과 onClick 핸들러가 필요합니다."편집하기" 같은 텍스트가 버튼으로 렌더링되지만, 클릭 시 동작이 정의되어 있지 않습니다.
onClickprop을 추가하거나, 동작이 없다면<span>으로 변경하는 것을 고려해주세요.♻️ onClick prop 추가 제안
interface HeaderProps { title: string; timeAgo?: string; menuIcon?: boolean; titleColor?: string; subtext?: string; + onSubtextClick?: () => void; }- {subtext && ( - <button className="text-h3 text-neutral-04 absolute top-1/2 right-4 -translate-y-1/2 cursor-pointer"> + {!menuIcon && subtext && ( + <button + type="button" + onClick={onSubtextClick} + className="text-h3 text-neutral-04 absolute top-1/2 right-4 -translate-y-1/2 cursor-pointer" + > {subtext} </button> )}src/app/friends/page.tsx (2)
14-16: SearchField에 가로 패딩이 필요합니다.
FriendList는 내부에px-4가 있지만,SearchField는 패딩 없이 렌더링되어 정렬이 맞지 않을 수 있습니다.♻️ 패딩 추가 제안
<div className="mt-[30.5px] flex flex-col gap-5"> - <SearchField /> + <div className="px-4"> + <SearchField /> + </div> <FriendList /> </div>
20-22: FAB 버튼에 접근성 속성과 클릭 핸들러가 필요합니다.
type="button",aria-label, 그리고onClick핸들러를 추가해주세요.♻️ 개선 제안
- <button className="bg-mint-01 mr-4 ml-auto flex h-[70px] w-[70px] items-center justify-center rounded-full shadow-[0_0_10px_0_rgba(0,0,0,0.10)]"> + <button + type="button" + aria-label="친구 추가" + onClick={() => {/* TODO: 친구 추가 로직 */}} + className="bg-mint-01 mr-4 ml-auto flex h-[70px] w-[70px] cursor-pointer items-center justify-center rounded-full shadow-[0_0_10px_0_rgba(0,0,0,0.10)]" + > <FriendAddIcon className="h-10 w-10 text-white" /> </button>src/components/friends/FrinedList.tsx (1)
5-27: 컴포넌트를 재사용 가능하도록 props를 통해 데이터를 받도록 개선해주세요.현재 목업 데이터를 직접 import하고 있어 다른 부분에서 재사용하기 어렵습니다. props 패턴으로 변경하면 재사용성을 높일 수 있습니다.
♻️ Props 패턴 제안
import Image from "next/image"; -import friendListData from "@/mock/friendList.json"; +interface Friend { + userId: string; + userName: string; + profileImg: string; +} -export const FriendList = () => { +interface FriendListProps { + friends: Friend[]; +} + +export const FriendList = ({ friends }: FriendListProps) => { return ( <section> <div className="flex gap-1 px-4"> <p className="text-sub1-r text-neutral-04">친구</p> - <p className="text-sub1-r text-neutral-04">{friendListData.length}</p> + <p className="text-sub1-r text-neutral-04">{friends.length}</p> </div> - {friendListData.map(friend => ( + {friends.map(friend => (
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
src/assets/mic-stroke.svgis excluded by!**/*.svgsrc/assets/person-plus.svgis excluded by!**/*.svgsrc/assets/search.svgis excluded by!**/*.svg
📒 Files selected for processing (7)
src/app/friends/page.tsxsrc/components/common/BackHeader.tsxsrc/components/common/HeaderWithIcon.tsxsrc/components/friends/FrinedList.tsxsrc/components/friends/SearchField.tsxsrc/components/home/Header.tsxsrc/mock/friendList.json
✅ Files skipped from review due to trivial changes (1)
- src/mock/friendList.json
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/friends/page.tsx (3)
src/components/common/BackHeader.tsx (1)
BackHeader(16-56)src/components/friends/SearchField.tsx (1)
SearchField(4-18)src/components/friends/FrinedList.tsx (1)
FriendList(5-28)
🔇 Additional comments (4)
src/components/common/HeaderWithIcon.tsx (2)
10-10: LGTM!import 경로가
dailyRecord로 변경되었으며, Next.js 16 및 React 19에 맞는 올바른 import 구조입니다.
12-20: LGTM!Props 인터페이스가 명확하게 정의되어 있고,
havePencil의 기본값이 적절하게 처리되었습니다.src/components/home/Header.tsx (2)
1-7: LGTM!import 구문이 적절하게 구성되어 있습니다. Next.js App Router에 맞게
next/navigation에서useRouter를 올바르게 가져오고 있습니다.
9-11: 알림 상태가 하드코딩되어 있습니다.현재
isAlarmNew가 항상true로 초기화되어 컴포넌트가 마운트될 때마다 알림이 새 것으로 표시됩니다. 향후 실제 API 연동 시 서버에서 알림 상태를 받아오도록 구현이 필요합니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| {menuIcon && ( | ||
| <div className="absolute top-1/2 right-4 -translate-y-1/2"> | ||
| <button className="absolute top-1/2 right-4 -translate-y-1/2"> | ||
| <ListIcon /> | ||
| </div> | ||
| </button> | ||
| )} | ||
| {subtext && ( | ||
| <button className="text-h3 text-neutral-04 absolute top-1/2 right-4 -translate-y-1/2 cursor-pointer"> | ||
| {subtext} | ||
| </button> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
menuIcon과 subtext가 동시에 전달될 경우 겹침 문제가 발생합니다.
두 요소 모두 absolute top-1/2 right-4에 렌더링되어 위치가 겹칩니다. 또한 menuIcon 버튼에 type="button" 속성과 onClick 핸들러가 없습니다.
🐛 개선 제안
{menuIcon && (
- <button className="absolute top-1/2 right-4 -translate-y-1/2">
+ <button
+ type="button"
+ className="absolute top-1/2 right-4 -translate-y-1/2 cursor-pointer"
+ >
<ListIcon />
</button>
)}
- {subtext && (
+ {!menuIcon && subtext && (
<button className="text-h3 text-neutral-04 absolute top-1/2 right-4 -translate-y-1/2 cursor-pointer">
{subtext}
</button>
)}또는 menuIcon과 subtext를 상호 배타적으로 사용하도록 props 설계를 검토해주세요.
| > | ||
| <AlarmIcon className="h-6 w-6 cursor-pointer" /> | ||
| <span className="bg-orange-00 absolute top-[3px] right-1 h-1 w-1 rounded-full" /> | ||
| <span className="bg-red-00 absolute top-[2px] left-[14px] h-[10px] w-[10px] rounded-full" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bg-red-00은 유효하지 않은 Tailwind 클래스입니다.
알림 점이 표시되지 않습니다. bg-red-500 또는 유효한 Tailwind 색상 클래스로 수정해야 합니다.
🐛 수정 제안
- <span className="bg-red-00 absolute top-[2px] left-[14px] h-[10px] w-[10px] rounded-full" />
+ <span className="absolute top-[2px] left-[14px] h-[10px] w-[10px] rounded-full bg-red-500" />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <span className="bg-red-00 absolute top-[2px] left-[14px] h-[10px] w-[10px] rounded-full" /> | |
| <span className="absolute top-[2px] left-[14px] h-[10px] w-[10px] rounded-full bg-red-500" /> |
🤖 Prompt for AI Agents
In `@src/components/common/HeaderWithIcon.tsx` at line 40, The span element in
HeaderWithIcon.tsx uses an invalid Tailwind class "bg-red-00" so the
notification dot doesn't render; update the className on the span (the
notification dot in the HeaderWithIcon component) to use a valid Tailwind
background color such as "bg-red-500" (or another valid color class) while
keeping the positioning and sizing classes unchanged.
| import Image from "next/image"; | ||
|
|
||
| import friendListData from "@/mock/friendList.json"; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
파일명 오타: "FrinedList" → "FriendList"
파일명 FrinedList.tsx에 오타가 있습니다. 컴포넌트명 FriendList와 일치하도록 FriendList.tsx로 수정해주세요.
#!/bin/bash
# 파일명 오타 확인
fd -t f "Frined" --exec echo "파일명 오타 발견: {}"🤖 Prompt for AI Agents
In `@src/components/friends/FrinedList.tsx` around lines 1 - 4, The file name
contains a typo: rename FrinedList.tsx to FriendList.tsx and update any
references/imports to use FriendList (e.g., import FriendList from
".../FriendList") and ensure the component declaration/export inside (component
name, default export) is also corrected to FriendList so the component name and
filename match.
| ) : ( | ||
| <AlarmIcon className="text-neutral-03 h-6 w-6 cursor-pointer" /> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isAlarmNew가 false일 때 AlarmIcon의 인터랙션 상태가 일관되지 않습니다.
isAlarmNew가 false일 때 AlarmIcon이 버튼으로 감싸져 있지 않지만 cursor-pointer 클래스가 적용되어 있어 사용자에게 클릭 가능한 것처럼 보입니다. 실제로는 클릭해도 아무 동작이 없어 UX 혼란을 줄 수 있습니다.
🛠️ 제안하는 수정 방안
) : (
- <AlarmIcon className="text-neutral-03 h-6 w-6 cursor-pointer" />
+ <button onClick={() => router.push("/alarms")}>
+ <AlarmIcon className="text-neutral-03 h-6 w-6" />
+ </button>
)}또는 알림 페이지 이동이 필요 없다면 cursor-pointer를 제거하세요:
- <AlarmIcon className="text-neutral-03 h-6 w-6 cursor-pointer" />
+ <AlarmIcon className="text-neutral-03 h-6 w-6" />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ) : ( | |
| <AlarmIcon className="text-neutral-03 h-6 w-6 cursor-pointer" /> | |
| )} | |
| ) : ( | |
| <AlarmIcon className="text-neutral-03 h-6 w-6" /> | |
| )} |
🤖 Prompt for AI Agents
In `@src/components/home/Header.tsx` around lines 29 - 31, The AlarmIcon rendering
branch for isAlarmNew = false shows a cursor-pointer but isn’t interactive;
either remove the "cursor-pointer" class from the non-interactive AlarmIcon or
make it interactive to match the true branch by wrapping the AlarmIcon in the
same button element/handler used when isAlarmNew is true (use the same
onClick/navigation logic). Update the JSX around isAlarmNew and the AlarmIcon to
ensure visual affordance matches actual behavior.
📢 전달사항
yarn add swiper추가해주세요!!🔥 작업 내용
🤔 추후 작업 사항
📸 작업 내역 스크린샷
2026-01-15.5.45.01.mov
🔗 이슈
Summary by CodeRabbit
릴리스 노트
새로운 기능
UI 개선
✏️ Tip: You can customize this high-level summary in your review settings.