Feat(extension): API 경로 수정 및 코드 정리#281
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
요약API 엔드포인트를 v1에서 v3로 업데이트하고, MainPop 컴포넌트에 API 쿼리 훅을 통합하여 카테고리 관리, 아티클 저장/편집 기능을 구현했습니다. 변경 사항
시퀀스 다이어그램sequenceDiagram
participant User as 사용자
participant UI as MainPop 컴포넌트
participant API as API 레이어
participant Server as 서버
User->>UI: 새 아티클 저장 요청 (카테고리, 메모, 시간)
activate UI
UI->>UI: 클라이언트 검증 (날짜/시간/카테고리)
alt 검증 성공
UI->>API: postArticle 호출 (카테고리, 메모, 시간)
activate API
API->>Server: POST /api/v3/articles
activate Server
Server-->>API: 저장 완료
deactivate Server
API-->>UI: 성공 응답
deactivate API
UI->>UI: useSaveBookmark 호출
UI->>User: 토스트 알림 (저장 완료)
else 검증 실패
UI->>User: 인라인 오류 메시지 표시
UI->>UI: 저장 버튼 비활성화
end
deactivate UI
sequenceDiagram
participant User as 사용자
participant UI as MainPop 컴포넌트
participant API as API 레이어
participant Server as 서버
User->>UI: 기존 아티클 편집 요청 (카테고리, 메모, 시간)
activate UI
UI->>UI: 클라이언트 검증
alt 검증 성공
UI->>API: putArticle 호출 (articleId, 수정 필드)
activate API
API->>Server: PUT /api/v3/articles/{id}
activate Server
Server-->>API: 업데이트 완료
deactivate Server
API-->>UI: 성공 응답
deactivate API
UI->>User: 토스트 알림 (편집 완료)
UI->>UI: 윈도우 닫기
else 검증 실패
UI->>User: 인라인 오류 메시지 표시
end
deactivate UI
예상 코드 리뷰 시간🎯 3 (Moderate) | ⏱️ ~20 분 관련 PR
제안된 라벨
제안된 리뷰어
시
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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 |
|
✅ Storybook chromatic 배포 확인: |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
apps/extension/src/pages/MainPop.tsx (5)
107-129:⚠️ Potential issue | 🔴 Critical수정 모드 초기화 조건에서 카테고리 의존성을 제거해주세요.
Line 111-112 조건 때문에 카테고리 목록을 불러오지 않으면 초기화 effect가 실행되지 않고, Line 230에서
articleId: 0으로 수정 요청이 나갈 수 있습니다.🔧 제안 수정안
- useEffect(() => { - if ( - type === 'edit' && - savedData && - categoryData?.data?.categories?.length - ) { + useEffect(() => { + if (type === 'edit' && savedData) { setMemo(savedData.memo ?? ''); setIsArticleId(savedData.id ?? 0); if (savedData.remindAt) { const [rawDate, rawTime] = savedData.remindAt.split('T'); @@ if (savedData.categoryResponse) { setSelected(savedData.categoryResponse?.categoryId.toString()); setSelectedCategoryName(savedData.categoryResponse?.categoryName); } } - }, [type, savedData, categoryData?.data?.categories?.length]); + }, [type, savedData]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/extension/src/pages/MainPop.tsx` around lines 107 - 129, The effect that initializes edit-mode state (the useEffect block referencing type === 'edit' and savedData) should not depend on categoryData?.data?.categories?.length; remove that dependency from the dependency array and only include type and savedData so the initialization always runs when entering edit mode or when savedData changes. Locate the useEffect that sets setMemo, setIsArticleId, setDate, setTime, setIsRemindOn, setSelected, and setSelectedCategoryName and update its dependency array to [type, savedData] (or equivalent) while leaving the internal logic unchanged.
178-208:⚠️ Potential issue | 🟠 Major저장 시점에 리마인드 입력값을 재검증해주세요.
현재 검증은 Line 158-166 입력 이벤트에서만 갱신됩니다. 사용자가 값을 건드리지 않으면 빈 값이 Line 207/238의
combineDateTime으로 전송될 수 있습니다.🔧 제안 수정안
const handleSave = async () => { const currentDate = date; const currentTime = time; + + if (isRemindOn) { + const nextDateError = validateDate(currentDate); + const nextTimeError = validateTime(currentTime); + setDateError(nextDateError); + setTimeError(nextTimeError); + if (nextDateError || nextTimeError) return; + } + if (!selected || parseInt(selected) === 0) { alert('카테고리를 선택해주세요!'); return; }Also applies to: 237-239
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/extension/src/pages/MainPop.tsx` around lines 178 - 208, handleSave is calling postArticle/postArticleUpdate and passing combineDateTime(saveData.date, saveData.time) without re-validating date/time at save time, so empty or stale values can be submitted if the user never touched the inputs; update handleSave to perform final validation when isRemindOn is true: ensure date and time are non-empty and valid (e.g., parseable/Date-check) before calling combineDateTime, and if invalid show the same alert/validation used on input change and abort save; apply the same final-check for the update branch (where postArticleUpdate is called) so both branches use validated date/time values (refer to handleSave, saveData, isRemindOn, combineDateTime, postArticle, postArticleUpdate).
227-247:⚠️ Potential issue | 🟠 Major성공 토스트를 API 성공 콜백에서만 열어주세요.
Line 227에서 먼저 토스트를 열어 실패 케이스에서도 “저장 완료” 메시지가 노출될 수 있습니다.
🔧 제안 수정안
} else { - setToastIsOpen(true); putArticle( { articleId: isArticleId, data: { @@ }, { onSuccess: () => { - window.close(); + setToastIsOpen(true); + setTimeout(() => window.close(), 1000); }, } ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/extension/src/pages/MainPop.tsx` around lines 227 - 247, The toast is being opened before the API call completes (setToastIsOpen(true) is invoked prior to putArticle), which can show a success message even on failure; remove the pre-call setToastIsOpen(true) and instead call setToastIsOpen(true) inside the putArticle onSuccess callback (the same block that calls window.close()), and optionally ensure onError/onFailure handlers do not open the toast; update references around putArticle, onSuccess, and setToastIsOpen to make this change.
168-170:⚠️ Potential issue | 🟠 Major리마인드 OFF 상태에서는 날짜/시간 에러로 저장이 막히지 않게 처리해주세요.
Line 365의
disabled조건이isRemindOn을 고려하지 않아, OFF로 전환해도 기존 에러 상태가 남으면 저장이 계속 비활성화됩니다.🔧 제안 수정안
const handleSwitchChange = (checked: boolean) => { setIsRemindOn(checked); + if (!checked) { + setDateError(''); + setTimeError(''); + } }; @@ <Button size="medium" onClick={handleSave} - disabled={isPopError || !!dateError || !!timeError} + disabled={isPopError || (isRemindOn && (!!dateError || !!timeError))} > 저장 </Button>Also applies to: 362-366
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/extension/src/pages/MainPop.tsx` around lines 168 - 170, The save button's disabled condition currently blocks saving based on date/time validation even when reminders are turned off; update the disabled expression used where the Save button is rendered (the JSX with the disabled prop around lines referenced) so that date/time error checks are only applied when isRemindOn is true (i.e., combine existing date/time error flags with isRemindOn). Ensure the change references the component state isRemindOn (and keep handleSwitchChange/setIsRemindOn as-is) so toggling the switch OFF bypasses the date/time validation and allows saving.
171-176:⚠️ Potential issue | 🟠 Major
getKSTISOString()은 현재 사용자의 로컬 타임존에 의존하며, KST 고정값을 반환하지 않습니다.현재 구현은
getTimezoneOffset()을 사용하여 로컬 타임존 오프셋을 계산하기 때문에, KST 사용자(UTC+9)에서만 올바른 결과를 반환합니다. UTC나 다른 타임존의 사용자가 동일한 UTC 시간을 입력하면 서로 다른 결과를 얻게 됩니다. KST 고정이 목적이라면 UTC 기준+9h로 하드코딩해야 합니다.function getKSTISOString() { - const now = new Date(); - const offset = now.getTimezoneOffset() * 60000; // UTC 기준 오프셋 (분 단위) - const kst = new Date(now.getTime() - offset); // UTC → KST 보정 - return kst.toISOString().slice(0, 19); // 밀리초, Z 제거 + const KST_OFFSET_MS = 9 * 60 * 60 * 1000; + return new Date(Date.now() + KST_OFFSET_MS).toISOString().slice(0, 19); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/extension/src/pages/MainPop.tsx` around lines 171 - 176, getKSTISOString currently uses the client's local timezone via getTimezoneOffset, so it only yields correct KST for users already in UTC+9; change it to compute KST deterministically by taking the current UTC time and adding a fixed +9 hours (e.g. now.getTime() + 9 * 60 * 60 * 1000) and then format to ISO (slice off milliseconds and trailing Z) so the function always returns KST regardless of the user's local timezone. Update the function name getKSTISOString to use this UTC+9 calculation and ensure the output remains YYYY-MM-DDTHH:MM:SS (no milliseconds or Z).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@apps/extension/src/pages/MainPop.tsx`:
- Around line 107-129: The effect that initializes edit-mode state (the
useEffect block referencing type === 'edit' and savedData) should not depend on
categoryData?.data?.categories?.length; remove that dependency from the
dependency array and only include type and savedData so the initialization
always runs when entering edit mode or when savedData changes. Locate the
useEffect that sets setMemo, setIsArticleId, setDate, setTime, setIsRemindOn,
setSelected, and setSelectedCategoryName and update its dependency array to
[type, savedData] (or equivalent) while leaving the internal logic unchanged.
- Around line 178-208: handleSave is calling postArticle/postArticleUpdate and
passing combineDateTime(saveData.date, saveData.time) without re-validating
date/time at save time, so empty or stale values can be submitted if the user
never touched the inputs; update handleSave to perform final validation when
isRemindOn is true: ensure date and time are non-empty and valid (e.g.,
parseable/Date-check) before calling combineDateTime, and if invalid show the
same alert/validation used on input change and abort save; apply the same
final-check for the update branch (where postArticleUpdate is called) so both
branches use validated date/time values (refer to handleSave, saveData,
isRemindOn, combineDateTime, postArticle, postArticleUpdate).
- Around line 227-247: The toast is being opened before the API call completes
(setToastIsOpen(true) is invoked prior to putArticle), which can show a success
message even on failure; remove the pre-call setToastIsOpen(true) and instead
call setToastIsOpen(true) inside the putArticle onSuccess callback (the same
block that calls window.close()), and optionally ensure onError/onFailure
handlers do not open the toast; update references around putArticle, onSuccess,
and setToastIsOpen to make this change.
- Around line 168-170: The save button's disabled condition currently blocks
saving based on date/time validation even when reminders are turned off; update
the disabled expression used where the Save button is rendered (the JSX with the
disabled prop around lines referenced) so that date/time error checks are only
applied when isRemindOn is true (i.e., combine existing date/time error flags
with isRemindOn). Ensure the change references the component state isRemindOn
(and keep handleSwitchChange/setIsRemindOn as-is) so toggling the switch OFF
bypasses the date/time validation and allows saving.
- Around line 171-176: getKSTISOString currently uses the client's local
timezone via getTimezoneOffset, so it only yields correct KST for users already
in UTC+9; change it to compute KST deterministically by taking the current UTC
time and adding a fixed +9 hours (e.g. now.getTime() + 9 * 60 * 60 * 1000) and
then format to ISO (slice off milliseconds and trailing Z) so the function
always returns KST regardless of the user's local timezone. Update the function
name getKSTISOString to use this UTC+9 calculation and ensure the output remains
YYYY-MM-DDTHH:MM:SS (no milliseconds or Z).
constantly-dev
left a comment
There was a problem hiding this comment.
아하 version만 업데이트 하면 되는거였군요~~ 굿입니다 👍
into feat/#280/extension-api-update
📌 Related Issues
📄 Tasks
⭐ PR Point (To Reviewer)
📷 Screenshot
Summary by CodeRabbit
릴리스 노트