Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions apps/extension/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { useGetArticleDetail, useGetArticleSaved } from '@apis/query/queries';
import { useEffect, useState } from 'react';
import './App.css';
import DuplicatePop from './pages/DuplicatePop';
import MainPop from './pages/MainPop';
import { useState, useEffect } from 'react';
import { useGetArticleSaved } from '@apis/query/queries';
import { usePageMeta } from './hooks/usePageMeta';
import DuplicatePop from './pages/DuplicatePop';
import LogOutPop from './pages/LogOutPop';
import MainPop from './pages/MainPop';

const App = () => {
const { url } = usePageMeta();
const { data: isSaved } = useGetArticleSaved(url);
const { data: savedArticle } = useGetArticleSaved(url);
const articleId = savedArticle?.data?.id;
const { data: articleDetail } = useGetArticleDetail(articleId!);
Comment on lines +12 to +13
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

articleId 추출 및 사용 불일치

Line 12에서 savedArticle?.data?.id로 articleId를 추출하고, Line 42에서는 savedArticle?.data?.articleId를 로깅합니다. API 응답에서 올바른 필드가 무엇인지 확인하고 일관되게 사용해주세요.

또한 articleId! non-null assertion은 articleIdundefined일 때 타입 에러를 숨깁니다. useGetArticleDetail 훅 내부에서 enabled: !!articleId로 보호되어 있어 런타임에는 안전하지만, 명시적으로 처리하는 것이 좋습니다.

🐛 수정 제안
 const { data: savedArticle } = useGetArticleSaved(url);
-  const articleId = savedArticle?.data?.id;
-  const { data: articleDetail } = useGetArticleDetail(articleId!);
+  const articleId = savedArticle?.data?.articleId; // 또는 id - API 응답 확인 후 결정
+  const { data: articleDetail } = useGetArticleDetail(articleId);

useGetArticleDetail이 이미 articleId?: number를 받으므로 non-null assertion이 불필요합니다.

📝 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
const articleId = savedArticle?.data?.id;
const { data: articleDetail } = useGetArticleDetail(articleId!);
const articleId = savedArticle?.data?.articleId;
const { data: articleDetail } = useGetArticleDetail(articleId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension/src/App.tsx` around lines 12 - 13, The code inconsistently
reads savedArticle?.data?.id into articleId but logs
savedArticle?.data?.articleId — confirm which field the API returns (id or
articleId) and use that same property everywhere (update articleId extraction
and any logging to match); also remove the non-null assertion when calling
useGetArticleDetail (change useGetArticleDetail(articleId!) to
useGetArticleDetail(articleId)) since the hook already supports an optional
articleId and guards itself via enabled: !!articleId.


const [isDuplicatePop, setIsDuplicatePop] = useState(false);
const [mainPopType, setMainPopType] = useState<'add' | 'edit'>('add');
Expand All @@ -18,11 +21,13 @@ const App = () => {
setIsToken(!!result.token);
});
}, []);

// 이미 저장된 아티클이면 DuplicatePop 표시
useEffect(() => {
if (isSaved?.data) {
if (savedArticle?.data) {
setIsDuplicatePop(true);
}
}, [isSaved]);
}, [savedArticle]);

const handleDuplicateLeftClick = () => {
setIsDuplicatePop(false);
Expand All @@ -42,7 +47,7 @@ const App = () => {
onRightClick={handleDuplicateRightClick}
/>
) : (
<MainPop type={mainPopType} />
<MainPop type={mainPopType} savedData={articleDetail} />
Copy link
Copy Markdown

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
# Description: articleDetail 데이터 흐름 및 타입 확인

echo "=== MainPop savedData prop 타입 확인 ==="
rg -n "savedData\?:" apps/extension/src/pages/MainPop.tsx -A2

echo ""
echo "=== useGetArticleDetail 반환 타입 확인 ==="
rg -n "useGetArticleDetail" apps/extension/src/apis/query/queries.ts -A10

Repository: Pinback-Team/pinback-client

Length of output: 481


🏁 Script executed:

#!/bin/bash
echo "=== App.tsx의 useGetArticleDetail 사용 부분 ==="
rg -n "useGetArticleDetail\|articleDetail" apps/extension/src/App.tsx -B5 -A5

echo ""
echo "=== getArticleDetail 함수의 반환 타입 ==="
rg -n "getArticleDetail" apps/extension/src/apis/query/queries.ts -B2 -A8

echo ""
echo "=== ArticleResponse 타입 정의 확인 ==="
rg -n "type ArticleResponse\|interface ArticleResponse" apps/extension/src -A5

Repository: Pinback-Team/pinback-client

Length of output: 558


🏁 Script executed:

#!/bin/bash
echo "=== App.tsx 전체 내용 확인 ==="
cat -n apps/extension/src/App.tsx | head -80

echo ""
echo "=== ArticleResponse 타입 정의 위치 찾기 ==="
rg -l "ArticleResponse" apps/extension/src/

echo ""
echo "=== getArticleDetail 함수 정의 찾기 ==="
fd -e ts -e tsx apps/extension/src/apis | xargs rg -l "getArticleDetail"

Repository: Pinback-Team/pinback-client

Length of output: 3027


🏁 Script executed:

#!/bin/bash
echo "=== ArticleResponse 타입 정의 ==="
cat -n apps/extension/src/types/types.ts | head -100

echo ""
echo "=== getArticleDetail 및 useGetArticleDetail 전체 구현 ==="
sed -n '1,100p' apps/extension/src/apis/query/queries.ts | cat -n

Repository: Pinback-Team/pinback-client

Length of output: 2894


🏁 Script executed:

#!/bin/bash
echo "=== getArticleDetail 함수 정의 (axios.ts) ==="
rg -n "getArticleDetail" apps/extension/src/apis/axios.ts -B2 -A10

echo ""
echo "=== Axios 응답 타입 구조 ==="
rg -n "export.*getArticleDetail\|^export const getArticleDetail\|return.*getArticleDetail" apps/extension/src/apis/axios.ts -B5 -A15

Repository: Pinback-Team/pinback-client

Length of output: 335


articleDetail 타입과 로딩/에러 상태 처리 확인 필요

useGetArticleDetail에서 반환되는 data는 쿼리 완료 전 undefined이므로, articleDetail의 타입은 ArticleResponse | undefined입니다. 하지만 MainPopsavedData prop은 ArticleResponse | null을 기대합니다.

다음을 개선해주세요:

  • useGetArticleDetail에 명시적 반환 타입 추가
  • articleDetailundefined일 때의 처리 (로딩 상태 확인 및 조건부 렌더링)
  • 쿼리 실패 시 에러 상태 처리
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension/src/App.tsx` at line 53, useGetArticleDetail currently returns
data that can be undefined; update useGetArticleDetail to declare an explicit
return type (e.g., { data?: ArticleResponse; isLoading: boolean; isError:
boolean; error?: Error }) and ensure callers respect that shape; in the
component, check isLoading and isError from useGetArticleDetail and render a
loading indicator or error UI instead of passing undefined to MainPop, and only
pass savedData={articleDetail ?? null} (or conditionally render <MainPop /> when
articleDetail is available) so savedData matches MainPop's expected
ArticleResponse | null type.

)
) : (
<LogOutPop />
Expand Down
11 changes: 9 additions & 2 deletions apps/extension/src/apis/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ export const putArticle = async (
articleId: number,
data: PutArticleRequest
) => {
const response = await apiRequest.put(`/api/v1/articles/${articleId}`, data);
return response.data;
const response = await apiRequest.put(`/api/v1/articles/${articleId}`, {
...data,
});
return response;
Comment on lines +68 to +71
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

putArticle 반환값 일관성 문제

다른 API 함수들(postArticle, getArticleSaved 등)은 모두 response.data를 반환하지만, putArticleresponse 전체를 반환합니다. 이로 인해 호출 측에서 응답 데이터 접근 시 혼란이 발생할 수 있습니다.

또한 { ...data } 스프레드는 여기서 불필요합니다. Axios는 전달받은 객체를 직렬화하므로 원본이 변경되지 않습니다.

🐛 일관성 있는 반환값 수정 제안
 export const putArticle = async (
   articleId: number,
   data: PutArticleRequest
 ) => {
-  const response = await apiRequest.put(`/api/v1/articles/${articleId}`, {
-    ...data,
-  });
-  return response;
+  const response = await apiRequest.put(`/api/v1/articles/${articleId}`, data);
+  return response.data;
 };
📝 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
const response = await apiRequest.put(`/api/v1/articles/${articleId}`, {
...data,
});
return response;
const response = await apiRequest.put(`/api/v1/articles/${articleId}`, data);
return response.data;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension/src/apis/axios.ts` around lines 69 - 72, putArticle currently
returns the whole Axios response and spreads the payload, causing inconsistency
with other APIs; update putArticle to call
apiRequest.put(`/api/v1/articles/${articleId}`, data) (remove the unnecessary `{
...data }` spread) and return response.data to match postArticle/getArticleSaved
behavior so callers can access the payload uniformly.

};

export const getArticleDetail = async (articleId: number) => {
const response = await apiRequest.get(`/api/v3/articles/${articleId}`);
return response.data.data;
};
9 changes: 9 additions & 0 deletions apps/extension/src/apis/query/queries.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
getArticleDetail,
getArticleSaved,
getCategoriesExtension,
getRemindTime,
Expand Down Expand Up @@ -61,3 +62,11 @@ export const usePutArticle = () => {
}) => putArticle(articleId, data),
});
};

export const useGetArticleDetail = (articleId?: number) => {
return useQuery({
queryKey: ['articleDetail', articleId],
queryFn: () => getArticleDetail(articleId!),
enabled: !!articleId,
});
};
18 changes: 12 additions & 6 deletions apps/extension/src/pages/MainPop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import thumbImg from '@assets/extension_thumb.svg';
import { useCategoryManager } from '@hooks/useCategoryManager';
import { usePageMeta } from '@hooks/usePageMeta';
import { useSaveBookmark } from '@hooks/useSaveBookmarks';
import { Icon } from '@pinback/design-system/icons';
import {
AutoDismissToast,
Button,
Expand Down Expand Up @@ -111,7 +112,7 @@ const MainPop = ({ type, savedData }: MainPopProps) => {
categoryData?.data?.categories?.length
) {
setMemo(savedData.memo ?? '');
setIsArticleId(savedData.id ?? 0);
setIsArticleId(savedData.articleId ?? 0);

if (savedData.remindAt) {
const [rawDate, rawTime] = savedData.remindAt.split('T');
Expand All @@ -121,9 +122,10 @@ const MainPop = ({ type, savedData }: MainPopProps) => {
} else {
setIsRemindOn(false);
}

if (savedData.categoryResponse) {
setSelected(savedData.categoryResponse?.categoryId.toString());
setSelectedCategoryName(savedData.categoryResponse?.categoryName);
setSelected(savedData.categoryResponse.categoryId.toString());
setSelectedCategoryName(savedData.categoryResponse.categoryName);
}
}
}, [type, savedData, categoryData?.data?.categories?.length]);
Expand Down Expand Up @@ -243,7 +245,9 @@ const MainPop = ({ type, savedData }: MainPopProps) => {
},
{
onSuccess: () => {
window.close();
setTimeout(() => {
window.close();
}, 2000);
},
}
);
Expand All @@ -254,13 +258,15 @@ const MainPop = ({ type, savedData }: MainPopProps) => {
<div className="App">
<div className="relative flex h-[56.8rem] w-[31.2rem] items-center justify-center">
{toastIsOpen && (
<div className="absolute bottom-[5rem] left-1/2 -translate-x-1/2">
<div className="absolute bottom-[8rem] left-1/2 -translate-x-1/2">
<AutoDismissToast
duration={1000}
fadeMs={1000}
onClose={() => setToastIsOpen(false)}
>
<Toast text={`수정내용을 저장했어요`} />
<Toast text={`수정내용을 저장했어요`}>
<Icon name="check_circle" size={20} />
</Toast>
</AutoDismissToast>
</div>
)}
Expand Down
13 changes: 7 additions & 6 deletions apps/extension/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ export interface CategoryResponse {

export interface ArticleResponse {
id: number;
articleId: number;
url: string;
memo: string;
remindAt: string | null;
remindAt: string | null;
categoryResponse: CategoryResponse;
createdAt: string;
createdAt: string;
}

export interface Category {
categoryId: number;
categoryName: string;
categoryColor:string;
}
categoryId: number;
categoryName: string;
categoryColor: string;
}
10 changes: 7 additions & 3 deletions packages/design-system/src/components/toast/Toast.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { cn } from '../../lib/utils';

export interface ToastProps {
text: string;
text?: string;
children?: React.ReactNode;
}

export default function Toast({ text }: ToastProps) {
export default function Toast({ text, children }: ToastProps) {
return (
<div
role="alert"
Expand All @@ -15,7 +16,10 @@ export default function Toast({ text }: ToastProps) {
'common-shadow'
)}
>
<p className="caption2-sb whitespace-pre-line">{text}</p>
<div className="flex items-center gap-[0.4rem]">
{children}
{text && <p className="caption2-sb whitespace-nowrap">{text}</p>}
</div>
</div>
);
}
2 changes: 2 additions & 0 deletions packages/design-system/src/icons/iconNames.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
export const iconNames = [
'check_circle',
'chippi_profile',
'dotori',
'ext_home1',
Expand Down Expand Up @@ -28,6 +29,7 @@ export const iconNames = [
'logout_chippi.2512',
'main_header_logo',
'main_logo',
'notsave_circle',
'palms',
'saved',
'tooltip_1',
Expand Down
1 change: 1 addition & 0 deletions packages/design-system/src/icons/source/check_circle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/design-system/src/icons/source/notsave_circle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading