Skip to content

Conversation

@lemoncurdyogurt
Copy link
Member

@lemoncurdyogurt lemoncurdyogurt commented Jan 15, 2026

📢 전달사항

yarn add swiper 추가해주세요!!

  • FullButton 컴포넌트 비활성화상태 디자인 변경돼서 수정해두었습니다.
  • 채팅 작업할 때 HeaderWithLogo컴포넌트 가져와서 알람만 있는 경우 구현해뒀으니 가져다 사용하면 좋을 것 같습니다.

🔥 작업 내용

  • 홈화면에서 스와이퍼 라이브러리 설치 후 슬라이더로 식물 물주기 현황들을 볼 수 있게 하였습니다.
  • 키보드 모듈도 추가해서 방향키로도 넘길 수 있습니다.
  • loop 설정도 해놔서 맨끝에서 우측방향으로 넘길경우 다시 처음으로 넘어옵니다
  • 식물명에서 글래스 스타일 선언해서 가져오는방식으로 하였습니다. 글래스 스타일 하는 경우 global.css에서 유틸리티 가져오면 됩니다.
  • 식물 물주고 나서 24시간 이내의 경우 물주기 완료 상태, 48시간 이내의 경우 물주기 가능 상태, 48시간 이후는 시들기 상태, 식물이 없는 경우엔 Empty상태로 선언하였습니다.
  • 대화상태 컴포넌트에서는 오늘 대화 여부에 따라 대화안한 사람 -> 대화한사람 순으로 order설정해놓았고, 그 내부에서는 대화목표 percentage에 따라서 정렬유틸 추가 해놓았습니다.

🤔 추후 작업 사항

  • 정원작업할 때 식물 다운받아서 추후에 추가할 예정입니다.
  • 친구목록
  • 정원 물주기 시간 카운트다운, 시든시간 카운트업
  • 친구 프로필 조회, 친구 삭제 (1/16금)
  • 친구추가 (1/17토)

📸 작업 내역 스크린샷

2026-01-15.5.45.01.mov
스크린샷 2026-01-15 오후 2 25 24 스크린샷 2026-01-15 오후 5 45 50 스크린샷 2026-01-15 오후 5 45 58 image

🔗 이슈

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 식물 관리 슬라이더 추가로 식물 상태 및 액션을 한눈에 확인 가능.
    • 채팅 진행률 대시보드 추가: 사용자별 주간 목표/진행 표시.
    • 친구 목록 페이지와 검색 필드, 친구 추가 버튼 추가.
    • 헤더에 아이콘·편집(연필) 옵션과 공유일기/하루기록 페이지 반영.
    • 진행률 바 및 상태 버블 컴포넌트 추가.
  • UI 개선

    • 버튼 색상 스킴(민트/오렌지/블루) 확장.
    • 네비게이션 간격 조정 및 새로운 그라데이션·글래스 스타일 적용.

✏️ Tip: You can customize this high-level summary in your review settings.

@lemoncurdyogurt lemoncurdyogurt added the feat 기능 추가 label Jan 15, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

Walkthrough

홈 화면 구성 요소 추가 및 헤더/버튼 확장: Swiper 기반 식물 진행, 주간 채팅 진행, HeaderWithIcon 도입, FullButton 색상 스킴 확장, 관련 유틸/타입/목업/스타일과 친구 목록 페이지 추가. (≤50단어)

Changes

컴포넌트 / 파일(들) 요약
패키지 의존성
package.json
swiper ^12.0.3 의존성 추가
헤더 리팩토링
src/components/common/HeaderWithIcon.tsx
기존 Header → HeaderWithIcon으로 교체; title, havePencil props 및 연필 아이콘 조건부 렌더링 추가
페이지 변경
src/app/page.tsx, src/app/day-log/page.tsx, src/app/shared-diary/[id]/page.tsx
메인 페이지 레이아웃 재구성(헤더, PlantProgress, ChatProgress, 하단 Nav); day-logshared-diary에서 HeaderWithIcon 사용으로 교체
버튼 확장
src/components/common/FullButton.tsx
`colorScheme?: "mint"
네비게이션 UI
src/components/common/NavBar.tsx
아이콘-레이블 간 간격(gap-[5px]) 추가(레이아웃 스타일 변경)
홈 화면 컴포넌트
src/components/home/*
src/components/home/PlantProgress.tsx, src/components/home/ChatProgress.tsx, src/components/home/Header.tsx, src/components/home/ProgressBar.tsx, src/components/home/Bubble.tsx
홈 레이아웃 컴포넌트 추가: Swiper 기반 PlantProgress, ChatProgress(목업/정렬/ProgressBar), 상태 Bubble, 상단 Header(알림 상태 관리) 등
상수·타입
src/constants/plantStatus.ts, src/types/chatProgress.type.ts
식물 상태 열거형 및 상태→배경 매핑, ChatProgress 타입 추가
유틸리티
src/utils/*
src/utils/getPercentage.ts, src/utils/getPlantStatus.ts, src/utils/sortChatProgress.ts
백분율 계산, 최근 급수 시간 기반 식물 상태 판정, 채팅 진행도 정렬 함수 추가
모의 데이터
src/mock/*
src/mock/plantProgress.json, src/mock/chatProgress.json, src/mock/friendList.json
식물 진행·채팅 진행·친구 목록용 목업 데이터 추가
스타일
src/styles/globals.css
컬러 변수(--color-red-00, --color-blue-00) 및 .bg-plant-*, .bg-blur, .bg-glass-style 등 유틸 클래스/애니메이션 추가
아이콘 조정
src/assets/GalleryIcon.tsx
두 배지에 SVG 아이콘(EyesIcon, HandIcon) 적용 및 스타일 조정
친구 기능 페이지/컴포넌트
src/app/friends/page.tsx, src/components/friends/FrinedList.tsx, src/components/friends/SearchField.tsx
친구 목록 페이지 및 검색/목록 컴포넌트 추가

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: 네비게이션 응답
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • FEAT: 홈화면 #17: 홈 화면(식물 진행, 채팅 진행, 헤더 등) 기능 요구와 직접적으로 연관됨 — 본 PR이 해당 요구사항을 구현함.

Possibly related PRs

Poem

🐰 깡충깡충 인사할게,

스와이프 돌면 작은 화분 웃고,
채팅 바가 찰랑찰랑 빛나네,
버튼 누르면 숲이 살랑댄다,
오늘도 우리 앱에 새싹이 폈구나 🌱✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 홈화면에 식물과 대화정도 부분을 추가하는 주요 변경사항을 명확하게 요약하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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!

홈 헤더 컴포넌트가 잘 구현되어 있습니다. 몇 가지 개선 포인트가 있습니다:

  1. Line 27의 AlarmIconcursor-pointer가 적용되어 있지만 클릭 핸들러가 없어 사용자 경험에 혼란을 줄 수 있습니다.
  2. 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 클래스 중복 적용

activeClassinactiveClass에 이미 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: 타입 정의와 유효하지 않은 날짜 처리 개선 필요

  1. 파라미터 타입이 string이지만, falsy 체크(!recentWateredTime)는 null이나 undefined를 처리하려는 의도로 보입니다. 타입을 명확히 하는 것이 좋습니다.
  2. 유효하지 않은 날짜 문자열이 전달되면 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

📥 Commits

Reviewing files that changed from the base of the PR and between 314dd5a and e5e41be.

⛔ Files ignored due to path filters (8)
  • src/assets/bell.svg is excluded by !**/*.svg
  • src/assets/clock.svg is excluded by !**/*.svg
  • src/assets/friend.svg is excluded by !**/*.svg
  • src/assets/home/blue-circle.svg is excluded by !**/*.svg
  • src/assets/home/green-circle.svg is excluded by !**/*.svg
  • src/assets/home/red_circle.svg is excluded by !**/*.svg
  • src/assets/home/yellow-circle.svg is excluded by !**/*.svg
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (20)
  • package.json
  • src/app/day-log/page.tsx
  • src/app/page.tsx
  • src/app/shared-diary/[id]/page.tsx
  • src/components/common/FullButton.tsx
  • src/components/common/HeaderWithIcon.tsx
  • src/components/common/NavBar.tsx
  • src/components/home/Bubble.tsx
  • src/components/home/ChatProgress.tsx
  • src/components/home/Header.tsx
  • src/components/home/PlantProgress.tsx
  • src/components/home/ProgressBar.tsx
  • src/constants/plantStatus.ts
  • src/mock/chatProgress.json
  • src/mock/plantProgress.json
  • src/styles/globals.css
  • src/types/chatProgress.type.ts
  • src/utils/getPercentage.ts
  • src/utils/getPlantStatus.ts
  • src/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.ts
  • src/utils/sortChatProgress.ts
  • src/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 컴포넌트로의 변경이 올바르게 적용되었습니다. titlehavePencil props가 적절히 전달되고 있습니다.

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! 정렬 순서 의도 확인.

정렬 로직이 올바르게 구현되어 있습니다:

  • hasTodayChatfalse인 항목이 먼저 정렬됨 (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";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

사용되지 않는 import 제거

Imagenext/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.

Comment on lines +23 to +29
<Swiper
modules={[Keyboard]}
keyboard={{ enabled: true }}
loop={true}
spaceBetween={16}
slidesPerView={1}
>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -type f -name "PlantProgress.tsx" 2>/dev/null | head -5

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 50


🏁 Script executed:

find . -type f -name "*.tsx" -o -name "*.ts" | grep -i plant | head -10

Repository: 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 -60

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 2535


🏁 Script executed:

wc -l ./src/components/home/PlantProgress.tsx

Repository: 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.

Suggested change
<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"} />
Copy link

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.

Suggested change
<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]">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find Tailwind configuration files
find . -name "tailwind.config.*" -o -name "tailwind.config.js" -o -name "tailwind.config.ts" | head -20

Repository: 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 2

Repository: 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 -25

Repository: 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 -50

Repository: 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 -80

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 50


🏁 Script executed:

# Check postcss.config.mjs
cat postcss.config.mjs

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 161


🏁 Script executed:

# Look for CSS files that might define theme extensions
fd "\\.css$" | head -20

Repository: 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 2

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 50


🏁 Script executed:

# Check globals.css
cat src/styles/globals.css

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 3969


🏁 Script executed:

# Check typography.css
cat src/styles/typography.css

Repository: 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=css

Repository: 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.

Comment on lines +148 to +152
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);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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()).

Copy link

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between e5e41be and d007bd9.

⛔ Files ignored due to path filters (2)
  • src/assets/hand-with-pen.svg is excluded by !**/*.svg
  • src/assets/two-eyes.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • src/assets/GalleryIcon.tsx
  • src/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.

Comment on lines +20 to +22
<span>
<EyesIcon className="w- h-[29px]" />
</span>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

불완전한 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.

Suggested change
<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.

Comment on lines +30 to +36
<Image
src={data.profileImg}
alt={data.userName}
width={72}
height={72}
className="h-18 w-18 rounded-2xl object-cover"
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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
fi

Repository: 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 css

Repository: 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 -20

Repository: 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 scss

Repository: 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=50

Repository: 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.css

Repository: IT-Cotato/12th-SimTok-FE

Length of output: 3969


🏁 Script executed:

#!/bin/bash
# Check postcss config
cat postcss.config.mjs

Repository: 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/null

Repository: 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 -100

Repository: 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.jsremotePatterns 설정은 필요하지 않습니다.

🤖 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.

Copy link

@coderabbitai coderabbitai bot left a 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 핸들러가 필요합니다.

"편집하기" 같은 텍스트가 버튼으로 렌더링되지만, 클릭 시 동작이 정의되어 있지 않습니다. onClick prop을 추가하거나, 동작이 없다면 <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

📥 Commits

Reviewing files that changed from the base of the PR and between d007bd9 and b874903.

⛔ Files ignored due to path filters (3)
  • src/assets/mic-stroke.svg is excluded by !**/*.svg
  • src/assets/person-plus.svg is excluded by !**/*.svg
  • src/assets/search.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/app/friends/page.tsx
  • src/components/common/BackHeader.tsx
  • src/components/common/HeaderWithIcon.tsx
  • src/components/friends/FrinedList.tsx
  • src/components/friends/SearchField.tsx
  • src/components/home/Header.tsx
  • src/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.

Comment on lines 44 to 53
{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>
)}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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>
       )}

또는 menuIconsubtext를 상호 배타적으로 사용하도록 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" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

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.

Suggested change
<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.

Comment on lines +1 to +4
import Image from "next/image";

import friendListData from "@/mock/friendList.json";

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

파일명 오타: "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.

Comment on lines +29 to +31
) : (
<AlarmIcon className="text-neutral-03 h-6 w-6 cursor-pointer" />
)}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
) : (
<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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants