Skip to content

Comments

Feat(재림): QA 반영 | 대시보드 랜딩 및 익스텐션 팝업 추가 수정#148

Merged
jllee000 merged 24 commits intodevelopfrom
feat/#109/jl-QA-2
Sep 22, 2025
Merged

Feat(재림): QA 반영 | 대시보드 랜딩 및 익스텐션 팝업 추가 수정#148
jllee000 merged 24 commits intodevelopfrom
feat/#109/jl-QA-2

Conversation

@jllee000
Copy link
Collaborator

@jllee000 jllee000 commented Sep 22, 2025

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

  1. 토스트 적용
  2. 리마인드 토글버튼 true 디폴트
  3. 메모 글자수 제한
  4. 카테고리 글자수 제한
  5. 대시보드 랜딩 도메인 수정

⭐ PR Point (To Reviewer)

📷 Screenshot

Summary by CodeRabbit

  • New Features

    • 편집 저장 시 토스트 알림 추가 후 1초 뒤 창 자동 종료.
    • 메모 입력 최대 글자 수를 100→500으로 확대.
    • 기본 알림(isRemindOn)을 ON으로 변경.
    • 카테고리 제목 최대 길이 제한을 20→10자로 축소(오류 메시지 반영).
  • Chores

@vercel
Copy link

vercel bot commented Sep 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
pinback-client-client Ready Ready Preview Comment Sep 22, 2025 10:35am
pinback-client-landing Ready Ready Preview Comment Sep 22, 2025 10:35am

@jllee000 jllee000 self-assigned this Sep 22, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 22, 2025

Walkthrough

이 PR은 여러 앱에 걸쳐 소규모 동작/검증/도메인 업데이트와 UI 토스트 추가를 포함합니다. 익스텐션 MainPop의 편집 저장 흐름에 토스트 표시와 지연 종료가 추가되었고, 카테고리 제목 길이 제한이 10자로 통일되었습니다. 일부 외부 링크가 www 도메인으로 변경되었으며 경미한 리팩터링/포매팅이 반영되었습니다.

Changes

Cohort / File(s) Summary
Edit 저장 흐름 + 토스트 추가 (Extension)
apps/extension/src/pages/MainPop.tsx
편집 저장 시 토스트 표시 후 1초 지연 창 닫기 추가, isRemindOn 기본값 true, 토스트 상태 추가, 메모 maxLength 100→500, 로고 링크 도메인 www로 변경, 로그 제거 및 관련 임포트 정리
카테고리 길이 제한 통일 (10자)
apps/client/src/shared/components/cardEditModal/CardEditModal.tsx, apps/extension/src/hooks/useCategoryManager.ts
categoryTitle 유효성 검증을 20자→10자로 축소, 에러 메시지 갱신; useCategoryManager는 options 초기화를 useEffect로 이동하는 구조 변경 및 문자열 포매팅 정리
온보딩 알람 UI 소폭 조정 (Client)
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx
포매팅 정리, select===3 분기에서 주 로직 처리 후 선택적 onClick() 추가 호출, TimePicker 표시/숨김 동작 유지
외부 도메인 URL 업데이트
apps/extension/src/App.tsx, apps/landing/src/components/FinalCTASection.tsx
외부 이동 URL을 https://www.pinback.today/ 경로로 변경(우클릭 이동 및 랜딩 CTA 온보딩 이동)

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as 사용자
  participant MainPop as MainPop(Extension)
  participant API as Backend API
  participant Toast as AutoDismissToast

  User->>MainPop: 편집 저장 클릭
  MainPop->>API: putArticle(saveData)
  API-->>MainPop: 200 OK
  MainPop->>Toast: 토스트 표시(set toastIsOpen = true)
  Note over MainPop,Toast: 성공 메시지 노출
  MainPop-->>User: 1초 후 window.close()
  alt 실패
    API-->>MainPop: 에러
    MainPop-->>User: 에러 처리(토스트 아님, 기존 흐름 유지)
  end
Loading
sequenceDiagram
  autonumber
  actor User as 사용자
  participant AlarmBox as AlarmBox
  participant Parent as 부모 컴포넌트
  participant TimePicker as TimePicker

  User->>AlarmBox: 클릭(select===3)
  AlarmBox->>TimePicker: 표시
  User->>TimePicker: 시간 선택
  TimePicker-->>AlarmBox: 시간 값
  AlarmBox->>AlarmBox: 시간 포맷/상태 업데이트
  AlarmBox->>TimePicker: 숨김
  opt 선택적 후처리
    AlarmBox->>Parent: onClick() 호출(있을 경우)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🛠️ Feature, 재림, frontend

Suggested reviewers

  • constantly-dev
  • jjangminii

Poem

퐁당-퐁당, 토스트가 반짝!
저장하면 살짝 쉬고 창은 쓱- 닫히네.
카테고리는 열 글자, 딱- 맞춰 춤을 춘다.
www 길 따라 토끼는 링크를 건너고,
알람 시곗바늘 톡— 시간은 제 자리로. 🐇⏰

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning 본 PR은 #147의 주요 요구사항을 대체로 구현하고 있습니다: 토스트 추가 및 표시 로직(MainPop.tsx), 리마인드 토글 기본값 true 적용, 메모 입력 maxlength 적용(100→500), 카테고리 제목 길이 제한 20→10 적용(CardEditModal.tsx 및 useCategoryManager.ts), 그리고 대시보드/익스텐션 도메인 수정이 반영되었습니다. 반면 linked_issues에 포함된 #25(Progress 컴포넌트 구현)는 이 PR의 변경 내역에 포함되어 있지 않아 해당 이슈의 요구사항은 충족되지 않습니다. 따라서 이 PR은 #147 관련 목표에는 부합하나 #25는 별도 조치가 필요합니다. 해결안: linked_issues 목록에서 #25를 제거하거나 #25를 구현하는 별도 PR을 열고 이 PR의 설명에 연관 이슈(#147)만 명확히 표기하여 의도를 분리하세요.
Out of Scope Changes Check ⚠️ Warning 검토 결과 대부분 변경은 #147의 요구사항(토스트, 리마인드 기본값, 글자수 제한, 도메인 수정)에 부합하지만 apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx에 있는 온보딩 관련 변경(선택값 select===3일 때 추가적인 onClick 호출 도입)은 PR 목적과 명시된 작업 목록에 포함되어 있지 않아 범위 외 변경으로 보입니다. 또한 일부 포맷·따옴표 변경 등은 무해하지만 동작을 바꿀 수 있는 파일은 분리하는 것이 안전합니다. 범위 외 변경이 섞여 있으면 리뷰와 롤백 난이도가 올라갑니다. 해결안: 온보딩(AlarmBox.tsx) 관련 변경을 이 PR에서 분리하거나 PR 설명에 해당 변경 사유와 테스트 결과를 명시하고 관련 이슈를 링크해 주세요; 불필요하면 변경을 제거하고 별도 PR로 제출하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed PR 제목 "Feat(재림): QA 반영
Description Check ✅ Passed PR 설명은 레포 템플릿 구조를 따르고 있으며 Related Issues에 "close #147"와 Tasks 항목(토스트 적용, 리마인드 기본값, 메모/카테고리 글자수 제한, 도메인 수정)을 명확히 기재해 주요 요구사항을 담고 있습니다. PR Point와 Screenshot 섹션은 비어있지만 템플릿상 선택적 항목으로 판단되어 전반적으로 설명은 충분히 완결적입니다. 추가로 테스트/검증 방법이나 스크린샷을 첨부하면 리뷰어 이해에 더 도움이 됩니다.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#109/jl-QA-2

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

@github-actions github-actions bot added the feat 기능 개발하라 개발 달려라 달려 label Sep 22, 2025
@jllee000 jllee000 added the fix 버그 수정하라 러브버그 label Sep 22, 2025
@github-actions github-actions bot requested a review from jjangminii September 22, 2025 10:35
@github-actions
Copy link

✅ Storybook chromatic 배포 확인:
🐿️ storybook

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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/client/src/shared/components/cardEditModal/CardEditModal.tsx (1)

80-98: 리마인드 저장 시 날짜/시간 에러 미차단

dateError/timeError가 존재해도 remindTime을 생성해 저장 시도합니다. 서버 에러/누락 데이터 가능성이 있습니다.

저장 전에 에러/빈값을 차단하세요:

 const saveData = () => {
   if (!prevData?.id) {
     console.error('Article ID is missing, cannot save.');
     setToastIsOpen(true);
     return;
   }
-  const remindTime =
-    isRemindOn && date && time ? buildUtcIso(date, time) : null;
+  if (isRemindOn) {
+    if (dateError || timeError || !date || !time) {
+      setToastIsOpen(true);
+      return;
+    }
+  }
+  const remindTime = isRemindOn ? buildUtcIso(date, time) : null;

Also applies to: 219-233

apps/extension/src/pages/MainPop.tsx (1)

216-233: API 성공 확인 전에 토스트/창 닫힘 발생 — 성공 콜백으로 이동 필요

현재 putArticle 호출 직후 토스트 표시 및 1초 후 window.close()가 실행되어, 실패해도 성공처럼 보일 수 있습니다. 성공/실패 콜백으로 분기하고, 닫기 타이밍도 토스트 표시 타이밍과 동기화하세요.

권장 diff:

-      setToastIsOpen(true);
-      putArticle({
-        articleId: isArticleId,
-        data: {
-          categoryId: saveData.selectedCategory
-            ? parseInt(saveData.selectedCategory)
-            : 0,
-          memo: saveData.memo,
-          now: new Date().toISOString(),
-          remindTime: isRemindOn
-            ? combineDateTime(saveData.date ?? '', saveData.time ?? '')
-            : null,
-        },
-      });
-      setTimeout(() => {
-        window.close();
-      }, 1000);
+      putArticle(
+        {
+          articleId: isArticleId,
+          data: {
+            categoryId: saveData.selectedCategory
+              ? parseInt(saveData.selectedCategory)
+              : 0,
+            memo: saveData.memo,
+            now: new Date().toISOString(),
+            remindTime: isRemindOn
+              ? combineDateTime(saveData.date ?? '', saveData.time ?? '')
+              : null,
+          },
+        },
+        {
+          onSuccess: () => {
+            setToastIsOpen(true);
+            // 토스트 duration(1000) + fadeMs(1000)과 동기화
+            setTimeout(() => window.close(), 2000);
+          },
+          onError: () => {
+            alert('저장에 실패했어요. 잠시 후 다시 시도해주세요.');
+          },
+        }
+      );

추가 권장: 저장 직전 날짜/시간 유효성 재검증(에러 시 early-return)을 넣어 서버에 잘못된 값이 전달되지 않도록 하세요.

🧹 Nitpick comments (15)
apps/client/src/shared/components/cardEditModal/CardEditModal.tsx (3)

58-61: 카테고리 제목 길이 검증: 공백 처리 및 에러 상태 초기화 제안

  • trim() 없이 길이만 체크하면 공백만 입력해도 통과합니다.
  • 성공 시 에러 상태와 메시지를 즉시 해제하는 편이 UX에 좋습니다.

다음처럼 보완 제안드립니다:

 const saveCategory = () => {
-  if (categoryTitle.length > 10) {
-    setIsPopError(true);
-    setErrorTxt('10자 이내로 작성해주세요');
-  } else {
-    setIsPopupOpen(false);
-  }
+  const title = categoryTitle.trim();
+  if (title.length === 0) {
+    setIsPopError(true);
+    setErrorTxt('제목을 입력해주세요');
+    return;
+  }
+  if (title.length > 10) {
+    setIsPopError(true);
+    setErrorTxt('10자 이내로 작성해주세요');
+    return;
+  }
+  setIsPopError(false);
+  setErrorTxt('');
+  setIsPopupOpen(false);
 }

90-97: categoryId의 -1 폴백 전송은 위험

선택 불일치 시 -1을 전송하면 4xx/서버 오류를 유발할 수 있습니다. 저장 차단 또는 null 전송 정책 확인이 필요합니다.

예시:

-  categoryId:
-    category?.categories.find((cat) => cat.name === selectedCategory)?.id ?? -1,
+  const selected = category?.categories.find((cat) => cat.name === selectedCategory);
+  if (!selected) {
+    setToastIsOpen(true);
+    return;
+  }
+  categoryId: selected.id,

Also applies to: 93-94


234-235: 구식 TODO 제거

이미 저장 API 연동과 실패 토스트가 구현되어 TODO는 불필요합니다.

-{/* TODO: onClick 추후  저장 api 연결후 실패/성공 연결 */}
 <Button onClick={saveData}>저장하기</Button>
apps/extension/src/hooks/useCategoryManager.ts (7)

28-31: 카테고리 제목 검증: 공백/빈값 처리 및 메시지 보완

현재 길이만 검사합니다. 공백만 입력/빈 문자열 허용 가능성이 있습니다.

- if (categoryTitle.length > 10) {
-   setIsPopError(true);
-   setErrorTxt('10자 이내로 작성해주세요');
-   return;
- }
+ const title = categoryTitle.trim();
+ if (title.length === 0) {
+   setIsPopError(true);
+   setErrorTxt('제목을 입력해주세요');
+   return;
+ }
+ if (title.length > 10) {
+   setIsPopError(true);
+   setErrorTxt('10자 이내로 작성해주세요');
+   return;
+ }

27-56: 중복/예약어 방지 및 서버 호출에 정규화된 제목 사용

  • 기존 카테고리 중복명 방지 필요.
  • 기본 카테고리 “안 읽은 정보”는 생성 금지(과거 학습 맥락).
  • 서버엔 trim()된 제목 전송.
- postCategories(
-   { categoryName: categoryTitle },
+ // 중복/예약어 체크
+ if (options.includes(title)) {
+   setIsPopError(true);
+   setErrorTxt('이미 존재하는 카테고리예요');
+   return;
+ }
+ if (title === '안 읽은 정보') {
+   setIsPopError(true);
+   setErrorTxt('기본 카테고리 이름은 사용할 수 없어요');
+   return;
+ }
+
+ postCategories(
+   { categoryName: title },
    {
      onSuccess: (res) => {
        const newCategory: Category = {
          categoryId: res.data.categoryId,
-         categoryName: categoryTitle,
+         categoryName: title,
          categoryColor: res.data.categoryColor ?? '#000000',
        };
        setOptions((prev) => [...prev, newCategory.categoryName]);

49-52: 훅 내부 alert 사용 지양: UI 제어 역전

훅은 사이드 이펙트 UI를 직접 띄우지 않는 것이 좋습니다. 에러 상태를 노출하고, 토스트는 상위 컴포넌트에서 처리하세요.

- alert(
-   err.response?.data?.message ??
-     '카테고리 추가 중 오류가 발생했어요 😢'
- );
+ setIsPopError(true);
+ setErrorTxt(err.response?.data?.message ?? '카테고리 추가 중 오류가 발생했어요 😢');

17-19: options 초기화 중복 패턴 단순화

초기 useState에서 categoryData를 읽고, 다시 useEffect에서 세팅합니다. 하나로 줄이면 깔끔합니다.

- const [options, setOptions] = useState<string[]>(
-   categoryData?.data?.categories?.map((c: Category) => c.categoryName) ?? []
- );
+ const [options, setOptions] = useState<string[]>([]);
  useEffect(() => {
    if (categoryData?.data?.categories) {
      setOptions(categoryData.data.categories.map((c) => c.categoryName));
    }
  }, [categoryData]);

Also applies to: 21-25


21-25: 기본 카테고리 포함 보장

“안 읽은 정보”를 옵션 첫 항목으로 보장하십시오(삭제 불가/생성 금지).

  useEffect(() => {
    if (categoryData?.data?.categories) {
-     setOptions(categoryData.data.categories.map((c) => c.categoryName));
+     const names = categoryData.data.categories.map((c) => c.categoryName);
+     const base = '안 읽은 정보';
+     const merged = names.includes(base) ? names : [base, ...names];
+     setOptions(merged);
    }
  }, [categoryData]);

37-47: 카테고리 추가 후 쿼리 무효화/동기화 권장

로컬 options만 갱신하면 다른 구독 지점과 불일치할 수 있습니다. categoriesExtension 쿼리를 무효화하거나 setQueryData로 동기화하세요.

 import { AxiosError } from 'axios';
+import { useQueryClient } from '@tanstack/react-query';
 ...
 export const useCategoryManager = () => {
+  const queryClient = useQueryClient();
 ...
   postCategories(
     { categoryName: title },
     {
       onSuccess: (res) => {
         const newCategory: Category = {
           categoryId: res.data.categoryId,
           categoryName: title,
           categoryColor: res.data.categoryColor ?? '#000000',
         };
         setOptions((prev) => [...prev, newCategory.categoryName]);
+        queryClient.invalidateQueries({ queryKey: ['categoriesExtension'] });

59-62: 입력 변화 시 에러 상태 자동 해제

길이 제한 내로 수정되면 에러 표시를 자동 해제하면 좋습니다.

 const resetPopup = () => {
   setCategoryTitle('');
   setIsPopError(false);
   setErrorTxt('');
 };
+
+useEffect(() => {
+  if (categoryTitle.trim().length <= 10) {
+    setIsPopError(false);
+    setErrorTxt('');
+  }
+}, [categoryTitle]);
apps/landing/src/components/FinalCTASection.tsx (2)

26-27: 네비게이션 처리: a 링크 사용 검토

내비게이션만 수행한다면 버튼 onClick 보다는 시맨틱한 a 링크가 적합합니다. 디자인 시스템 Button이 asChild를 지원한다면 다음 형태를 권장합니다: <Button asChild><a href="https://www.pinback.today/onboarding">…</a></Button>.


22-22: 주석 오타 수정(가독성)

'랜딩페이디' → '랜딩페이지'.

적용 diff:

-          {/* TODO : 랜딩페이디 크롬스토어 설치페이지로 링크 추후 수정 필요! */}
+          {/* TODO : 랜딩페이지 크롬스토어 설치 페이지로 링크 추후 수정 필요! */}
apps/extension/src/pages/MainPop.tsx (1)

277-278: 도메인 하드코딩 중복 — 상수화 권장

App.tsx와 동일 도메인을 반복 사용 중입니다. const PINBACK_WEB_ORIGIN = 'https://www.pinback.today' 등으로 공통화하면 유지보수성이 향상됩니다.

apps/extension/src/App.tsx (1)

26-28: PINBACK 도메인 상수화(PINBACK_WEB_ORIGIN) 적용 및 레거시 참조 교체

앱 코드의 하드코딩 도메인을 상수로 추출하고 레포 전역의 레거시(https://pinback.today)를 www 포함 표준(origin)으로 통일하세요.

  • 변경 대상: apps/extension/src/App.tsx (lines 26–28 — handleDuplicateRightClick) — 'https://www.pinback.today/' → PINBACK_WEB_ORIGIN 상수로 대체.
  • 추가 발견된 레거시 참조(교체 필요):
    • apps/landing/index.html — line 19 (meta og:url), line 22 (meta og:image)
    • apps/client/index.html — line 19 (meta og:url), line 22 (meta og:image)
  • 참고: 실행하신 스크립트에서 인용부호 오류로 일부 검사가 실패했습니다. 누락 가능성이 있으니 재검증 명령(인용 이스케이프 포함)으로 전체 검색 권장:
    rg -nP "https?://(?:www.)?pinback.today[^\s\"']*"
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (1)

76-85: TimePicker 렌더 조건 단순화 및 결합도 축소 제안

select === 3 && isDisabled에 종속시키면 실제 의도(3번 카드 클릭 시 항상 열기)와 어긋날 수 있습니다. showPicker만으로 제어하고, 외부 스타일 상태(isDisabled)와 독립시키는 편이 UX/테스트 측면에서 유리합니다.

권장 구조 예시:

{select === 3 && (
  <>
    {!!AlarmsType[2].time && (
      <p className="caption2-m text-font-gray-3">{AlarmsType[2].time}</p>
    )}
    {showPicker && (
      <TimePicker
        onSave={getTimePicker}
        onCancel={() => setShowPicker(false)}
        onClick={(e) => e.stopPropagation()}
      />
    )}
  </>
)}

추가 확인: TimePickeronClick prop을 실제로 수용하는지 타입 정의를 확인해 주세요(필요 시 래퍼 div로 이벤트 중단).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30f052a and b3cbad5.

⛔ Files ignored due to path filters (6)
  • packages/design-system/src/icons/source/chippi_profile.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/tooltip_1.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/tooltip_2.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/tooltip_3.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/tooltip_4.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/tooltip_5.svg is excluded by !**/*.svg
📒 Files selected for processing (6)
  • apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (2 hunks)
  • apps/client/src/shared/components/cardEditModal/CardEditModal.tsx (1 hunks)
  • apps/extension/src/App.tsx (1 hunks)
  • apps/extension/src/hooks/useCategoryManager.ts (3 hunks)
  • apps/extension/src/pages/MainPop.tsx (6 hunks)
  • apps/landing/src/components/FinalCTASection.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-15T20:00:13.756Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#80
File: apps/client/src/shared/components/ui/modalPop/ModalPop.tsx:36-41
Timestamp: 2025-07-15T20:00:13.756Z
Learning: In apps/client/src/shared/components/ui/modalPop/ModalPop.tsx, the InfoBox component uses hardcoded values for title, location, and icon URL as temporary test data. These should be replaced with dynamic data from props when implementing actual functionality and should be marked with TODO comments for future changes.

Applied to files:

  • apps/landing/src/components/FinalCTASection.tsx
  • apps/extension/src/pages/MainPop.tsx
📚 Learning: 2025-07-17T09:18:13.818Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#102
File: apps/extension/src/components/modalPop/ModalPop.tsx:166-172
Timestamp: 2025-07-17T09:18:13.818Z
Learning: In apps/extension/src/components/modalPop/ModalPop.tsx, the categories array should include "안 읽은 정보" (Unread Information) as the first default category that cannot be deleted. This default category is used consistently across the client-side dashboard and should be protected from deletion in the extension as well.

Applied to files:

  • apps/extension/src/hooks/useCategoryManager.ts
🧬 Code graph analysis (3)
apps/extension/src/pages/MainPop.tsx (2)
packages/design-system/src/components/toast/hooks/uesFadeOut.tsx (1)
  • AutoDismissToast (12-49)
packages/design-system/src/components/toast/Toast.tsx (1)
  • Toast (7-21)
apps/extension/src/hooks/useCategoryManager.ts (3)
apps/extension/src/apis/query/queries.ts (2)
  • useGetCategoriesExtension (36-44)
  • usePostCategories (28-32)
apps/extension/src/apis/axios.ts (1)
  • postCategories (35-38)
apps/extension/src/types/types.ts (1)
  • Category (16-20)
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (2)
apps/client/src/constants/alarms.ts (1)
  • AlarmsType (11-15)
apps/client/src/pages/onBoarding/utils/formatRemindTime.ts (1)
  • normalizeTime (1-26)
🔇 Additional comments (10)
apps/client/src/shared/components/cardEditModal/CardEditModal.tsx (3)

41-41: 리마인드 토글 기본값 요구사항 확인 필요

PR 목표(“리마인드 토글버튼 true 디폴트”)와 현재 기본값(false)이 상이합니다. 이 컴포넌트에도 적용 대상인지 확인 부탁드립니다.

필요 시:

-const [isRemindOn, setIsRemindOn] = useState(false);
+const [isRemindOn, setIsRemindOn] = useState(true);

151-167: “카테고리 추가하기” 팝업 오픈 트리거 확인

isPopupOpen을 true로 만드는 경로가 보이지 않습니다. Dropdown의 “추가하기”가 팝업을 여는 콜백을 제공한다면 연결이 필요합니다.

디자인시스템 API에 따라(예: onAddClick) 다음과 같이 연결해 주세요:

 <Dropdown
   options={category?.categories.map((category) => category.name) || []}
   selectedValue={selectedCategory}
   onChange={(value) => setSelectedCategory(value)}
   placeholder="선택해주세요"
   addItemLabel="추가하기"
+  onAddClick={() => setIsPopupOpen(true)}
 />

Also applies to: 188-196


200-207: 메모 글자 수 제한 합의 범위 확인

maxLength={500} 적용됐습니다. 확정된 한도(예: 300/500/1000 등)와 앱 전역 일관성 확인 부탁드립니다.

apps/extension/src/hooks/useCategoryManager.ts (1)

41-42: 기본 색상 확인 필요

'#000000' 폴백이 디자인시스템/서버 기본과 일치하는지 확인해 주세요. 상이하면 DS 토큰(예: --gray-900) 또는 서버 기본으로 맞추는 게 안전합니다.

apps/extension/src/pages/MainPop.tsx (4)

11-13: 토스트 컴포넌트 도입 LGTM

디자인시스템 Toast/AutoDismissToast 활용 적절합니다.


88-91: 리마인드 기본값 true 전환 OK

PR 목표(“리마인드 토글버튼 true 디폴트”)와 일치합니다. 편집 모드 분기에서도 savedData에 따라 값이 덮이는지 확인만 부탁드립니다.


239-249: 토스트 페이드아웃과 창 닫기 타이밍 싱크

AutoDismissToast가 duration=1000, fadeMs=1000이므로 토스트는 총 2초 후 사라집니다. 위 수정대로 창 닫기를 2초로 맞추면 시각적 컷오프가 사라집니다. 별도 변경 없으면 OK.


309-309: 메모 글자수 제한 500자 적용 OK. 백엔드 제약과 메시지 동기화 확인

서버/스키마가 500자를 허용하는지와 오류 메시지(i18n 포함)가 제한과 일치하는지 확인해 주세요.

apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (2)

46-46: 표시 조건 불일치로 TimePicker가 열리지 않을 수 있음 — 검증 필요

File: apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx
Lines: 46-46

여기서 setShowPicker(true)로 강제하지만 렌더 조건은 select === 3 && isDisabledisDisabled === false면 TimePicker가 열리지 않습니다. 동작을 일치시키세요.

빠른 수정 제안:

-          setShowPicker(true);
+          setShowPicker(isDisabled);

또는 렌더 조건에서 isDisabled를 제거하고 showPicker만으로 제어(권장). isDisabled의 의미(선택됨/비활성화)를 상위 사용처에서 확인하세요.

검증 스크립트(원래 스크립트가 "unrecognized file type: tsx" 오류로 출력 없음 — 아래로 재실행):

#!/bin/bash
rg -nP -C3 '<AlarmBox\b' -g '**/*.{tsx,jsx,ts,js}'

71-73: 중요 — normalizeTime이 영문 AM/PM(H:MM)만 파싱하므로 '오전/오후'·'시' 표기가 들어가면 NaN이 표시됩니다.

  • 원인: apps/client/src/pages/onBoarding/utils/formatRemindTime.ts의 정규식이 /(AM|PM)\s?(\d{1,2}):(\d{1,2})/i 으로 한국어 '오전/오후'나 '9시' 등을 처리하지 않음.
  • 조치(우선순위 제안):
    1. 권장 — AlarmBox의 getTimePicker에서 저장 포맷을 24시간 'HH:MM'으로 변경해 저장(파일: apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx, getTimePicker 부분).
    2. 또는 normalizeTime에 '오전/오후'와 '시' 포맷 파싱 로직 추가(파일: apps/client/src/pages/onBoarding/utils/formatRemindTime.ts).
    3. 또는 normalizeTime 호출 전 입력 검증 후 파싱 실패 시 원본 문자열을 그대로 표시하는 폴백 추가(표시: AlarmBox.tsx lines 70–73, API 전송 전: MainCard.tsx lines 139–141).
  • 확인 필요: TimePicker가 반환하는 meridiem 값이 'AM'/'PM'인지 '오전'/'오후'인지 확인해 주세요 (확인 불가 시 파싱 확장 권장).

Comment on lines +27 to +40
const getTimePicker = ({
hour,
minute,
meridiem,
}: {
hour: string;
minute: string;
meridiem: string;
}) => {
const formatted = `${meridiem} ${hour}:${minute}`;
AlarmsType[2].time = formatted;
setShowPicker(false);
// 이거 나중에 api 연결때 쓸려고 표시한거.. 그떄 지우겠듬여 console.log('저장된 사용자 알람:', AlarmsType[2].time);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

전역 상수(AlarmsType) 직접 변이 및 시간 포맷 불일치

  • import된 상수(AlarmsType)를 컴포넌트에서 직접 수정하면 예측 불가한 사이드이펙트/렌더 불일치가 납니다.
  • 저장은 "AM/PM hh:mm" 포맷, 표시(1·2번 카드)는 "오전/오후 N시"로 혼재되어 있어 일관성이 없습니다.
  • meridiem이 '오전/오후'로 들어오면 normalizeTime의 정규식(AM|PM)과 안 맞아 NaN 위험이 있습니다.

최소 수정으로는 저장 시 24시간 포맷으로 정규화하여 넣어주세요(AM/PM 미지정 시 '오전/오후' 매핑). 주석 로그는 제거 권장.

아래 diff를 적용하면 파싱 실패를 방지하며 표시도 단순화됩니다.

   }) => {
-    const formatted = `${meridiem} ${hour}:${minute}`;
-    AlarmsType[2].time = formatted;
-    setShowPicker(false);
-    // 이거 나중에 api 연결때 쓸려고 표시한거.. 그떄 지우겠듬여 console.log('저장된 사용자 알람:', AlarmsType[2].time);
+    // AM/PM 미정규 표기(오전/오후) 대응 후 24h 포맷으로 저장
+    const merMap: Record<string, string> = { 오전: 'AM', 오후: 'PM' };
+    const mer = merMap[meridiem] ?? meridiem;
+    const normalized = normalizeTime(`${mer} ${hour}:${minute}`);
+    AlarmsType[2].time = normalized;
+    setShowPicker(false);
   };

추가로 권장(선택): 전역 상수 변이 대신 로컬 상태로 관리하세요.

// (26행 인접) 추가
const [customTime, setCustomTime] = useState<string>('');

// 저장 시
const normalized = normalizeTime(`${mer} ${hour}:${minute}`);
setCustomTime(normalized);

또한 하드코딩 인덱스(2)는 상수로 추출해 의미를 드러내면 안전합니다(e.g., const CUSTOM_ALARM_INDEX = 2).
검증: 레포 전체에서 AlarmsType[2] 사용이 더 있는지 확인해 주세요.


🏁 Script executed:

#!/bin/bash
rg -nP -C2 'AlarmsType\[2\]\.time'

Length of output: 1394


중요: AlarmsType 전역 직접 변경 금지 및 시간 포맷 정규화 필요

검증: apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx — 37행(할당), 70–73행(표시)에서 AlarmsType[2].time 사용 확인.

  • 전역 상수(AlarmsType)를 컴포넌트에서 직접 변경하고 있음 → 즉시 중단. 로컬 state(setState)나 상위 콜백/액션으로 값 저장하도록 변경.
  • meridiem이 '오전'/'오후'로 들어올 수 있어 normalizeTime이 기대하는 'AM'/'PM'과 불일치해 파싱 실패 가능. 저장 전에 '오전'→'AM', '오후'→'PM' 매핑 후 normalizeTime에 전달하여 24시간 포맷으로 정규화해 저장.
  • 하드코딩 인덱스(2)는 상수로 추출: const CUSTOM_ALARM_INDEX = 2.
  • 디버그용 주석·console.log 삭제.
🤖 Prompt for AI Agents
In apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx around lines
27–40 (and note AlarmsType[2].time is read at 70–73), stop mutating the global
AlarmsType directly; instead store the selected time in local component state or
call an onChange/onSave callback to propagate it upward. Replace the hardcoded
index with a constant like const CUSTOM_ALARM_INDEX = 2 and use that when
referring to the custom alarm externally (via the callback), not by assigning
into AlarmsType. Before saving, normalize meridiem by mapping '오전'→'AM' and
'오후'→'PM', pass the mapped meridiem plus hour/minute into your existing
normalizeTime utility to get a 24-hour string, and save that result via
state/callback. Remove the debug comment and console.log line entirely.

@jllee000 jllee000 merged commit 9fcd4c3 into develop Sep 22, 2025
11 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려 fix 버그 수정하라 러브버그

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 대시보드 랜딩 도메인 수정 및 추가 익스텐션 수정

1 participant