From 1ffe1edaef288736b10e302887409a0fcaf13106 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Sun, 5 Apr 2026 14:15:19 +0900 Subject: [PATCH 01/12] chore: update ampli interface --- packages/analytics/src/ampli/index.ts | 131 ++++++++++---------------- 1 file changed, 48 insertions(+), 83 deletions(-) diff --git a/packages/analytics/src/ampli/index.ts b/packages/analytics/src/ampli/index.ts index 012b4195..11a22fa0 100644 --- a/packages/analytics/src/ampli/index.ts +++ b/packages/analytics/src/ampli/index.ts @@ -55,7 +55,7 @@ export interface IdentifyProperties { job_role?: string; } -export interface ClickedReminderProperties { +export interface ClickedAlarmProperties { /** * 아티클 고유 ID (특정 아티클 재열람 확인 등) */ @@ -64,24 +64,20 @@ export interface ClickedReminderProperties { * 리마인드 아이디(보내고 클릭해졌는지 클릭률 계산 등) */ reminder_id?: string; - /** - * 리마인드 유형 - */ - reminder_type?: string; } -export interface ClickedSharedBookmarkProperties { +export interface ClickedReminderProperties { /** * 아티클 고유 ID (특정 아티클 재열람 확인 등) */ article_id?: string; /** - * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) + * 리마인드 아이디(보내고 클릭해졌는지 클릭률 계산 등) */ - category_id?: string; + reminder_id?: string; } -export interface OpenedSavedContentProperties { +export interface ClickedSharedBookmarkProperties { /** * 아티클 고유 ID (특정 아티클 재열람 확인 등) */ @@ -90,10 +86,6 @@ export interface OpenedSavedContentProperties { * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) */ category_id?: string; - /** - * 콘텐츠 유입 출처 - */ - source_type?: string; } export interface SavedArticleProperties { @@ -113,14 +105,6 @@ export interface SavedArticleProperties { * 저장 대상 페이지 도메인 */ page_domain?: string; - /** - * 저장 방식 - */ - save_method?: string; - /** - * 저장이 발생한 위치 - */ - save_source?: string; } export interface SavedSharedBookmarkProperties { @@ -129,17 +113,17 @@ export interface SavedSharedBookmarkProperties { */ article_id?: string; /** - * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) - */ - category_id?: string; - /** - * 저장이 발생한 위치 + * 콘텐츠 유입 출처 + * + * | Rule | Value | + * |---|---| + * | Enum Values | own, jobpin, remind | */ - save_source?: string; + bookmark_type?: "own" | "jobpin" | "remind"; /** - * 콘텐츠 유입 출처 + * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) */ - source_type?: string; + category_id?: string; } export interface TriggeredReminderProperties { @@ -151,10 +135,6 @@ export interface TriggeredReminderProperties { * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) */ category_id?: string; - /** - * 리마인드 유형 - */ - reminder_type?: string; } export interface ViewedSavedContentProperties { @@ -163,13 +143,17 @@ export interface ViewedSavedContentProperties { */ article_id?: string; /** - * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) + * 콘텐츠 유입 출처 + * + * | Rule | Value | + * |---|---| + * | Enum Values | own, jobpin, remind | */ - category_id?: string; + bookmark_type?: "own" | "jobpin" | "remind"; /** - * 콘텐츠 유입 출처 + * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) */ - source_type?: string; + category_id?: string; } export class Identify implements BaseEvent { @@ -182,31 +166,31 @@ export class Identify implements BaseEvent { } } -export class ClickedReminder implements BaseEvent { - event_type = 'Clicked_Reminder'; +export class ClickedAlarm implements BaseEvent { + event_type = 'Clicked_alarm'; constructor( - public event_properties?: ClickedReminderProperties, + public event_properties?: ClickedAlarmProperties, ) { this.event_properties = event_properties; } } -export class ClickedSharedBookmark implements BaseEvent { - event_type = 'Clicked_Shared_Bookmark'; +export class ClickedReminder implements BaseEvent { + event_type = 'Clicked_Reminder'; constructor( - public event_properties?: ClickedSharedBookmarkProperties, + public event_properties?: ClickedReminderProperties, ) { this.event_properties = event_properties; } } -export class OpenedSavedContent implements BaseEvent { - event_type = 'Opened_Saved_Content'; +export class ClickedSharedBookmark implements BaseEvent { + event_type = 'Clicked_Shared_Bookmark'; constructor( - public event_properties?: OpenedSavedContentProperties, + public event_properties?: ClickedSharedBookmarkProperties, ) { this.event_properties = event_properties; } @@ -252,10 +236,6 @@ export class ViewedSavedContent implements BaseEvent { } } -export class ViewedSharedBookmarkList implements BaseEvent { - event_type = 'Viewed_Shared_Bookmark_List'; -} - export type PromiseResult = { promise: Promise }; const getVoidPromiseResult = () => ({ promise: Promise.resolve() }); @@ -374,54 +354,54 @@ export class Ampli { } /** - * Clicked_Reminder + * Clicked_alarm * - * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Clicked_Reminder) + * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Clicked_alarm) * - * 사용자가 리마인드를 클릭했을 때 발생 + * 알림을 클릭했을 때 발생 * * @param properties The event's properties (e.g. article_id) * @param options Amplitude event options. */ - clickedReminder( - properties?: ClickedReminderProperties, + clickedAlarm( + properties?: ClickedAlarmProperties, options?: EventOptions, ) { - return this.track(new ClickedReminder(properties), options); + return this.track(new ClickedAlarm(properties), options); } /** - * Clicked_Shared_Bookmark + * Clicked_Reminder * - * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Clicked_Shared_Bookmark) + * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Clicked_Reminder) * - * 공유 북마크 카드를 클릭했을 때 발생 + * 대시보드 리마인드 카드를 클릭했을 때 발생 * * @param properties The event's properties (e.g. article_id) * @param options Amplitude event options. */ - clickedSharedBookmark( - properties?: ClickedSharedBookmarkProperties, + clickedReminder( + properties?: ClickedReminderProperties, options?: EventOptions, ) { - return this.track(new ClickedSharedBookmark(properties), options); + return this.track(new ClickedReminder(properties), options); } /** - * Opened_Saved_Content + * Clicked_Shared_Bookmark * - * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Opened_Saved_Content) + * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Clicked_Shared_Bookmark) * - * 저장한 콘텐츠를 다시 클릭해 열었을 때 발생 + * 공유 북마크 카드를 클릭했을 때 발생 * * @param properties The event's properties (e.g. article_id) * @param options Amplitude event options. */ - openedSavedContent( - properties?: OpenedSavedContentProperties, + clickedSharedBookmark( + properties?: ClickedSharedBookmarkProperties, options?: EventOptions, ) { - return this.track(new OpenedSavedContent(properties), options); + return this.track(new ClickedSharedBookmark(properties), options); } /** @@ -491,21 +471,6 @@ export class Ampli { ) { return this.track(new ViewedSavedContent(properties), options); } - - /** - * Viewed_Shared_Bookmark_List - * - * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Viewed_Shared_Bookmark_List) - * - * 공유 북마크 목록을 조회했을 때 발생 - * - * @param options Amplitude event options. - */ - viewedSharedBookmarkList( - options?: EventOptions, - ) { - return this.track(new ViewedSharedBookmarkList(), options); - } } export const ampli = new Ampli(); From 7743ebe63ec2717a4488b589f0749d79084635d2 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Sun, 5 Apr 2026 14:56:55 +0900 Subject: [PATCH 02/12] chore: update ampli interface --- packages/analytics/src/ampli/index.ts | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/analytics/src/ampli/index.ts b/packages/analytics/src/ampli/index.ts index 11a22fa0..54091bde 100644 --- a/packages/analytics/src/ampli/index.ts +++ b/packages/analytics/src/ampli/index.ts @@ -66,6 +66,17 @@ export interface ClickedAlarmProperties { reminder_id?: string; } +export interface ClickedMyBookmarkProperties { + /** + * 아티클 고유 ID (특정 아티클 재열람 확인 등) + */ + article_id?: string; + /** + * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) + */ + category_id?: string; +} + export interface ClickedReminderProperties { /** * 아티클 고유 ID (특정 아티클 재열람 확인 등) @@ -176,6 +187,16 @@ export class ClickedAlarm implements BaseEvent { } } +export class ClickedMyBookmark implements BaseEvent { + event_type = 'Clicked_My_Bookmark'; + + constructor( + public event_properties?: ClickedMyBookmarkProperties, + ) { + this.event_properties = event_properties; + } +} + export class ClickedReminder implements BaseEvent { event_type = 'Clicked_Reminder'; @@ -370,6 +391,23 @@ export class Ampli { return this.track(new ClickedAlarm(properties), options); } + /** + * Clicked_My_Bookmark + * + * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Clicked_My_Bookmark) + * + * 대시보드 나의 북마크 카드를 클릭했을 때 발생 (여기서 나의 북마크는 북마크 전체, 카테고리 등 전체를 포함함.) + * + * @param properties The event's properties (e.g. article_id) + * @param options Amplitude event options. + */ + clickedMyBookmark( + properties?: ClickedMyBookmarkProperties, + options?: EventOptions, + ) { + return this.track(new ClickedMyBookmark(properties), options); + } + /** * Clicked_Reminder * From 072946a343a7be4f3852434530bbf09f8465939b Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Sun, 5 Apr 2026 14:58:37 +0900 Subject: [PATCH 03/12] feat: connect Clicked_Shared_Bookmark, Clicked_Reminder, Clicked_My_Bookmark events --- apps/client/src/pages/jobPins/JobPins.tsx | 9 ++++++++- apps/client/src/pages/myBookmark/MyBookmark.tsx | 1 - .../components/myBookmarkContent/MyBookmarkContent.tsx | 9 +++++++-- apps/client/src/pages/remind/Remind.tsx | 4 ++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/client/src/pages/jobPins/JobPins.tsx b/apps/client/src/pages/jobPins/JobPins.tsx index 53c946c8..01b3e6d8 100644 --- a/apps/client/src/pages/jobPins/JobPins.tsx +++ b/apps/client/src/pages/jobPins/JobPins.tsx @@ -6,6 +6,7 @@ import JobPinsBottomNotice from '@pages/jobPins/components/JobPinsBottomNotice'; import MemoPopup from '@pages/jobPins/components/MemoPopup'; import { useJobPinsBottomNotice } from '@pages/jobPins/hooks/useJobPinsBottomNotice'; import Footer from '@pages/myBookmark/components/footer/Footer'; +import { analytics } from '@pinback/analytics'; import { Card } from '@pinback/design-system/ui'; import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll'; @@ -77,7 +78,13 @@ const JobPins = () => { category={article.category?.categoryName} categoryColor={article.category?.categoryColor} nickname={article.ownerName} - onClick={() => getJobPinDetail(article.articleId)} + onClick={() => { + analytics.track('Clicked_Shared_Bookmark', { + article_id: String(article.articleId), + category_id: String(article.category.categoryId), + }); + getJobPinDetail(article.articleId); + }} /> ); })} diff --git a/apps/client/src/pages/myBookmark/MyBookmark.tsx b/apps/client/src/pages/myBookmark/MyBookmark.tsx index f32efbc6..f2fe7dba 100644 --- a/apps/client/src/pages/myBookmark/MyBookmark.tsx +++ b/apps/client/src/pages/myBookmark/MyBookmark.tsx @@ -101,7 +101,6 @@ const MyBookmark = () => { onBadgeChange={setActiveBadge} updateToReadStatus={updateToReadStatus} openMenu={openMenu} - queryClient={queryClient} scrollContainerRef={scrollContainerRef} /> diff --git a/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx b/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx index 5378d387..fa25ca06 100644 --- a/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx +++ b/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx @@ -1,7 +1,9 @@ import NoArticles from '@pages/myBookmark/components/NoArticles/NoArticles'; import NoUnreadArticles from '@pages/myBookmark/components/noUnreadArticles/NoUnreadArticles'; import { useMyBookmarkContentData } from '@pages/myBookmark/hooks/useMyBookmarkContentData'; +import { analytics } from '@pinback/analytics'; import { Badge, Card } from '@pinback/design-system/ui'; +import { useQueryClient } from '@tanstack/react-query'; import { MutableRefObject } from 'react'; interface MyBookmarkContentProps { @@ -11,7 +13,6 @@ interface MyBookmarkContentProps { categoryId: string | null; updateToReadStatus: (id: number, options?: any) => void; openMenu: (id: number, anchor: HTMLElement) => void; - queryClient: any; scrollContainerRef: MutableRefObject; } @@ -22,9 +23,9 @@ const MyBookmarkContent = ({ categoryId, updateToReadStatus, openMenu, - queryClient, scrollContainerRef, }: MyBookmarkContentProps) => { + const queryClient = useQueryClient(); const { view, list, counts, pagination } = useMyBookmarkContentData({ activeBadge, category, @@ -83,6 +84,10 @@ const MyBookmarkContent = ({ } date={new Date(article.createdAt).toLocaleDateString('ko-KR')} onClick={() => { + analytics.track('Clicked_My_Bookmark', { + article_id: String(article.articleId), + category_id: article.category?.categoryId?.toString(), + }); window.open(article.url, '_blank'); updateToReadStatus(article.articleId, { onSuccess: () => { diff --git a/apps/client/src/pages/remind/Remind.tsx b/apps/client/src/pages/remind/Remind.tsx index de5e684d..93e125ab 100644 --- a/apps/client/src/pages/remind/Remind.tsx +++ b/apps/client/src/pages/remind/Remind.tsx @@ -1,4 +1,5 @@ import { useGetRemindArticles } from '@pages/remind/apis/queries'; +import { analytics } from '@pinback/analytics'; import NoReadArticles from '@pages/remind/components/noReadArticles/NoReadArticles'; import NoUnreadArticles from '@pages/remind/components/noUnreadArticles/NoUnreadArticles'; import { @@ -161,6 +162,9 @@ const Remind = () => { category={article.category.categoryName} categoryColor={article.category.categoryColor} onClick={() => { + analytics.track('Clicked_Reminder', { + article_id: String(article.articleId), + }); window.open(article.url, '_blank'); updateToReadStatus(article.articleId); }} From 82a398ca6d1754522fa1fb2f1b5e779560df4edc Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Sun, 5 Apr 2026 16:11:04 +0900 Subject: [PATCH 04/12] feat: connect Triggered_Reminder, Clicked_alarm events in service worker --- apps/client/public/firebase-messaging-sw.js | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/client/public/firebase-messaging-sw.js b/apps/client/public/firebase-messaging-sw.js index c5696972..e802dbd8 100644 --- a/apps/client/public/firebase-messaging-sw.js +++ b/apps/client/public/firebase-messaging-sw.js @@ -1,6 +1,25 @@ /* eslint-env serviceworker */ /* eslint-disable no-undef */ +const AMPLITUDE_API_KEY = 'bb48a29e445e2f350a1d23ad67f38d55'; + +const trackAmplitudeEvent = (eventType) => { + const isProd = self.location.hostname === 'pinback.today'; + if (!isProd) { + console.log('[Analytics] track', eventType); + return; + } + + fetch('https://api2.amplitude.com/2/httpapi', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + api_key: AMPLITUDE_API_KEY, + events: [{ device_id: 'serviceworker', event_type: eventType }], + }), + }).catch((err) => console.warn('[Amplitude] 이벤트 전송 실패', err)); +}; + const firebaseConfig = { apiKey: 'AIzaSyD3KM0IQ4Ro3Dd2fyAY8fnhE1bQ_NesrBc', authDomain: 'pinback-c55de.firebaseapp.com', @@ -35,6 +54,8 @@ firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); messaging.onBackgroundMessage((payload) => { + trackAmplitudeEvent('Triggered_Reminder'); + const url = payload.data?.url || 'https://pinback.today'; const notificationTitle = payload.notification?.title || 'pinback'; const notificationOptions = { @@ -50,6 +71,8 @@ messaging.onBackgroundMessage((payload) => { self.addEventListener('notificationclick', (event) => { const targetUrl = event.notification.data?.url || 'https://pinback.today'; + trackAmplitudeEvent('Clicked_alarm'); + fetch( `https://www.google-analytics.com/mp/collect?measurement_id=G-847ZNSCC3J&api_secret=1hei57fPTKyGX5Cw73rwgA`, { From b8e3dab40d860a5ecc45f1ae6ac423b4a7a06bcc Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Sun, 5 Apr 2026 16:42:41 +0900 Subject: [PATCH 05/12] feat: connect Saved_Article event on bookmark save --- apps/extension/src/pages/MainPop.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/extension/src/pages/MainPop.tsx b/apps/extension/src/pages/MainPop.tsx index 73bf8441..f975b9bf 100644 --- a/apps/extension/src/pages/MainPop.tsx +++ b/apps/extension/src/pages/MainPop.tsx @@ -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 { analytics } from '@pinback/analytics'; import { Icon } from '@pinback/design-system/icons'; import { AutoDismissToast, @@ -213,6 +214,12 @@ const MainPop = ({ type, savedData }: MainPopProps) => { }, { onSuccess: () => { + analytics.track('Saved_Article', { + // article_id: 응답 타입 미정의로 보류 + category_id: selected ?? undefined, + // is_first_save: 판단 불가로 보류 + page_domain: new URL(url).hostname, + }); save({ url, title, From b77fdcddd03efe9bfdbd362b5a20d77a069fa13b Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Mon, 6 Apr 2026 19:56:28 +0900 Subject: [PATCH 06/12] =?UTF-8?q?chore:=20ampli=20pull=20-=20Viewed=5FSave?= =?UTF-8?q?d=5FContent=EB=A5=BC=20Impression=5FSaved=5FContent=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- packages/analytics/src/ampli/index.ts | 92 +++++++++++++-------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/analytics/src/ampli/index.ts b/packages/analytics/src/ampli/index.ts index 54091bde..6c39f988 100644 --- a/packages/analytics/src/ampli/index.ts +++ b/packages/analytics/src/ampli/index.ts @@ -99,6 +99,25 @@ export interface ClickedSharedBookmarkProperties { category_id?: string; } +export interface ImpressionSavedContentProperties { + /** + * 아티클 고유 ID (특정 아티클 재열람 확인 등) + */ + article_id?: string; + /** + * 콘텐츠 유입 출처 + * + * | Rule | Value | + * |---|---| + * | Enum Values | own, jobpin, remind | + */ + bookmark_type?: "own" | "jobpin" | "remind"; + /** + * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) + */ + category_id?: string; +} + export interface SavedArticleProperties { /** * 아티클 고유 ID (특정 아티클 재열람 확인 등) @@ -148,25 +167,6 @@ export interface TriggeredReminderProperties { category_id?: string; } -export interface ViewedSavedContentProperties { - /** - * 아티클 고유 ID (특정 아티클 재열람 확인 등) - */ - article_id?: string; - /** - * 콘텐츠 유입 출처 - * - * | Rule | Value | - * |---|---| - * | Enum Values | own, jobpin, remind | - */ - bookmark_type?: "own" | "jobpin" | "remind"; - /** - * 카테고리 고유 ID (어디에 저장됐는지, 공유 여부 확인 등) - */ - category_id?: string; -} - export class Identify implements BaseEvent { event_type = amplitude.Types.SpecialEventType.IDENTIFY; @@ -217,6 +217,16 @@ export class ClickedSharedBookmark implements BaseEvent { } } +export class ImpressionSavedContent implements BaseEvent { + event_type = 'Impression_Saved_Content'; + + constructor( + public event_properties?: ImpressionSavedContentProperties, + ) { + this.event_properties = event_properties; + } +} + export class SavedArticle implements BaseEvent { event_type = 'Saved_Article'; @@ -247,16 +257,6 @@ export class TriggeredReminder implements BaseEvent { } } -export class ViewedSavedContent implements BaseEvent { - event_type = 'Viewed_Saved_Content'; - - constructor( - public event_properties?: ViewedSavedContentProperties, - ) { - this.event_properties = event_properties; - } -} - export type PromiseResult = { promise: Promise }; const getVoidPromiseResult = () => ({ promise: Promise.resolve() }); @@ -442,6 +442,23 @@ export class Ampli { return this.track(new ClickedSharedBookmark(properties), options); } + /** + * Impression_Saved_Content + * + * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Impression_Saved_Content) + * + * 저장한 콘텐츠 목록 또는 상세가 노출될 때 발생 + * + * @param properties The event's properties (e.g. article_id) + * @param options Amplitude event options. + */ + impressionSavedContent( + properties?: ImpressionSavedContentProperties, + options?: EventOptions, + ) { + return this.track(new ImpressionSavedContent(properties), options); + } + /** * Saved_Article * @@ -492,23 +509,6 @@ export class Ampli { ) { return this.track(new TriggeredReminder(properties), options); } - - /** - * Viewed_Saved_Content - * - * [View in Tracking Plan](https://data.amplitude.com/pinback/default/events/main/latest/Viewed_Saved_Content) - * - * 저장한 콘텐츠 목록 또는 상세가 노출될 때 발생 - * - * @param properties The event's properties (e.g. article_id) - * @param options Amplitude event options. - */ - viewedSavedContent( - properties?: ViewedSavedContentProperties, - options?: EventOptions, - ) { - return this.track(new ViewedSavedContent(properties), options); - } } export const ampli = new Ampli(); From 88e376be05bb2d5a68543aa9897dc53be59c3159 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Mon, 6 Apr 2026 19:56:36 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:=20analytics=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EC=97=90=EC=84=9C=20ampli=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20re-export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- packages/analytics/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/analytics/index.ts b/packages/analytics/index.ts index a5cd8f89..e940f80d 100644 --- a/packages/analytics/index.ts +++ b/packages/analytics/index.ts @@ -3,6 +3,7 @@ import { amplitudeProvider } from './src/providers/amplitude'; import { consoleProvider } from './src/providers/console'; export type { AnalyticsProvider, UserProperties } from './src/types'; +export type * from './src/ampli'; export { analytics }; interface InitAnalyticsOptions { From f2d7b56c0149f8999e6a5cb7272008cf83299131 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Mon, 6 Apr 2026 19:56:43 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat:=20=EC=B9=B4=EB=93=9C=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C=20=ED=8A=B8=EB=9E=98=ED=82=B9=EC=9A=A9=20AnalyticsCar?= =?UTF-8?q?dWrapper=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../AnalyticsCardWrapper.tsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx diff --git a/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx b/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx new file mode 100644 index 00000000..99cfa177 --- /dev/null +++ b/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx @@ -0,0 +1,30 @@ +import { + analytics, + type ImpressionSavedContentProperties, +} from '@pinback/analytics'; +import { useEffect } from 'react'; +import { useInView } from 'react-intersection-observer'; + +interface AnalyticsCardWrapperProps { + bookmarkType: ImpressionSavedContentProperties['bookmark_type']; + children: React.ReactNode; +} + +const AnalyticsCardWrapper = ({ + bookmarkType, + children, +}: AnalyticsCardWrapperProps) => { + const { ref, inView } = useInView({ threshold: 0.5, triggerOnce: true }); + + useEffect(() => { + if (inView) { + analytics.track('Impression_Saved_Content', { + bookmark_type: bookmarkType, + }); + } + }, [inView]); + + return
{children}
; +}; + +export default AnalyticsCardWrapper; From 5101d129806c4d8407418616282e56ba4794d02a Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Mon, 6 Apr 2026 19:56:48 +0900 Subject: [PATCH 09/12] =?UTF-8?q?feat:=20Remind,=20MyBookmark,=20JobPins?= =?UTF-8?q?=20=EC=B9=B4=EB=93=9C=EC=97=90=20Impression=5FSaved=5FContent?= =?UTF-8?q?=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- apps/client/src/pages/jobPins/JobPins.tsx | 38 +++---- .../myBookmarkContent/MyBookmarkContent.tsx | 100 +++++++++--------- apps/client/src/pages/remind/Remind.tsx | 45 ++++---- 3 files changed, 94 insertions(+), 89 deletions(-) diff --git a/apps/client/src/pages/jobPins/JobPins.tsx b/apps/client/src/pages/jobPins/JobPins.tsx index 01b3e6d8..8b075831 100644 --- a/apps/client/src/pages/jobPins/JobPins.tsx +++ b/apps/client/src/pages/jobPins/JobPins.tsx @@ -7,6 +7,7 @@ import MemoPopup from '@pages/jobPins/components/MemoPopup'; import { useJobPinsBottomNotice } from '@pages/jobPins/hooks/useJobPinsBottomNotice'; import Footer from '@pages/myBookmark/components/footer/Footer'; import { analytics } from '@pinback/analytics'; +import AnalyticsCardWrapper from '@shared/components/analyticsCardWrapper/AnalyticsCardWrapper'; import { Card } from '@pinback/design-system/ui'; import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll'; @@ -68,24 +69,25 @@ const JobPins = () => { const displayImageUrl = article.thumbnailUrl || undefined; return ( - { - analytics.track('Clicked_Shared_Bookmark', { - article_id: String(article.articleId), - category_id: String(article.category.categoryId), - }); - getJobPinDetail(article.articleId); - }} - /> + + { + analytics.track('Clicked_Shared_Bookmark', { + article_id: String(article.articleId), + category_id: String(article.category.categoryId), + }); + getJobPinDetail(article.articleId); + }} + /> + ); })} diff --git a/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx b/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx index fa25ca06..c960c6a1 100644 --- a/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx +++ b/apps/client/src/pages/myBookmark/components/myBookmarkContent/MyBookmarkContent.tsx @@ -3,8 +3,9 @@ import NoUnreadArticles from '@pages/myBookmark/components/noUnreadArticles/NoUn import { useMyBookmarkContentData } from '@pages/myBookmark/hooks/useMyBookmarkContentData'; import { analytics } from '@pinback/analytics'; import { Badge, Card } from '@pinback/design-system/ui'; +import AnalyticsCardWrapper from '@shared/components/analyticsCardWrapper/AnalyticsCardWrapper'; import { useQueryClient } from '@tanstack/react-query'; -import { MutableRefObject } from 'react'; +import { type MutableRefObject } from 'react'; interface MyBookmarkContentProps { activeBadge: 'all' | 'notRead'; @@ -66,54 +67,55 @@ const MyBookmarkContent = ({ className="scrollbar-hide mt-[2.6rem] flex h-screen flex-wrap content-start gap-[1.6rem] overflow-y-auto scroll-smooth" > {list.articles.map((article) => ( - { - analytics.track('Clicked_My_Bookmark', { - article_id: String(article.articleId), - category_id: article.category?.categoryId?.toString(), - }); - window.open(article.url, '_blank'); - updateToReadStatus(article.articleId, { - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: ['bookmarkArticles'], - }); - queryClient.invalidateQueries({ - queryKey: ['bookmarkArticlesCount'], - }); - queryClient.invalidateQueries({ - queryKey: ['categoryBookmarkArticlesCount'], - }); - queryClient.invalidateQueries({ - queryKey: ['categoryBookmarkArticles'], - }); - }, - onError: (error: any) => { - console.error(error); - }, - }); - }} - onOptionsClick={(e) => { - e.stopPropagation(); - openMenu(article.articleId, e.currentTarget); - }} - /> + + { + analytics.track('Clicked_My_Bookmark', { + article_id: String(article.articleId), + category_id: article.category?.categoryId?.toString(), + }); + window.open(article.url, '_blank'); + updateToReadStatus(article.articleId, { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: ['bookmarkArticles'], + }); + queryClient.invalidateQueries({ + queryKey: ['bookmarkArticlesCount'], + }); + queryClient.invalidateQueries({ + queryKey: ['categoryBookmarkArticlesCount'], + }); + queryClient.invalidateQueries({ + queryKey: ['categoryBookmarkArticles'], + }); + }, + onError: (error: any) => { + console.error(error); + }, + }); + }} + onOptionsClick={(e) => { + e.stopPropagation(); + openMenu(article.articleId, e.currentTarget); + }} + /> + ))}
{ const displayImageUrl = article.thumbnailUrl || undefined; return ( - { - analytics.track('Clicked_Reminder', { - article_id: String(article.articleId), - }); - window.open(article.url, '_blank'); - updateToReadStatus(article.articleId); - }} - onOptionsClick={(e) => { - e.stopPropagation(); - - openMenu(article.articleId, e.currentTarget); - }} - /> + + { + analytics.track('Clicked_Reminder', { + article_id: String(article.articleId), + }); + window.open(article.url, '_blank'); + updateToReadStatus(article.articleId); + }} + onOptionsClick={(e) => { + e.stopPropagation(); + openMenu(article.articleId, e.currentTarget); + }} + /> + ); })} From 586d248bb94de9c9f928ec5ec78fede9a207ab9f Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Mon, 6 Apr 2026 19:56:58 +0900 Subject: [PATCH 10/12] =?UTF-8?q?chore:=20consistent-type-imports=20ESLint?= =?UTF-8?q?=20=EB=A3=B0=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EC=8B=9C=20=EC=9E=90=EB=8F=99=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .vscode/settings.json | 2 +- packages/eslint-config/react-internal.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 97233c48..cd5ba4d5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,7 +12,7 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit", + "source.fixAll.eslint": "always", "source.organizeImports": "always" }, "tailwindCSS.suggestions": true, diff --git a/packages/eslint-config/react-internal.js b/packages/eslint-config/react-internal.js index 2226920d..4693f60b 100644 --- a/packages/eslint-config/react-internal.js +++ b/packages/eslint-config/react-internal.js @@ -34,6 +34,10 @@ const config = [ ...pluginReactHooks.configs.recommended.rules, // React scope no longer necessary with new JSX transform. 'react/react-in-jsx-scope': 'off', + '@typescript-eslint/consistent-type-imports': [ + 'error', + { prefer: 'type-imports', fixStyle: 'inline-type-imports' }, + ], }, }, ]; From 1c421613f6b7707c4dd6f36bfd4494fe58aa3b12 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Mon, 6 Apr 2026 19:58:38 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20consistent-type-imports=20?= =?UTF-8?q?=EB=A3=B0=20=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20AnalyticsCardWrapp?= =?UTF-8?q?er=20exhaustive-deps=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- apps/client/src/pages/jobPins/apis/axios.ts | 2 +- apps/client/src/pages/jobPins/apis/queries.ts | 4 +-- apps/client/src/pages/level/Level.tsx | 2 +- .../pages/level/components/LevelInfoCard.tsx | 2 +- .../src/pages/level/components/LevelScene.tsx | 4 +-- .../client/src/pages/myBookmark/apis/axios.ts | 6 ++-- .../src/pages/myBookmark/apis/queries.ts | 2 +- .../hooks/useMyBookmarkContentData.ts | 2 +- .../onBoarding/components/funnel/MainCard.tsx | 2 +- .../components/funnel/step/job/JobStep.tsx | 2 +- .../components/timePicker/TimePicker.tsx | 4 +-- .../onBoarding/hooks/useOnboardingFunnel.ts | 2 +- apps/client/src/shared/apis/axios.ts | 8 +++--- apps/client/src/shared/apis/queries.ts | 28 +++++++++---------- .../AnalyticsCardWrapper.tsx | 2 +- .../src/shared/components/balloon/Balloon.tsx | 2 +- .../cardEditModal/CardEditModal.tsx | 2 +- .../jobSelectionFunnel/step/job/JobStep.tsx | 2 +- .../components/sidebar/AccordionItem.tsx | 2 +- .../shared/components/sidebar/SideItem.tsx | 2 +- .../sidebar/hooks/useCategoryActions.ts | 4 +-- apps/client/src/shared/utils/fetchOgData.ts | 2 +- apps/client/src/shared/utils/treeLevel.ts | 4 +-- 23 files changed, 46 insertions(+), 46 deletions(-) diff --git a/apps/client/src/pages/jobPins/apis/axios.ts b/apps/client/src/pages/jobPins/apis/axios.ts index 292a3b53..85ccd5c2 100644 --- a/apps/client/src/pages/jobPins/apis/axios.ts +++ b/apps/client/src/pages/jobPins/apis/axios.ts @@ -1,4 +1,4 @@ -import { JobPinsResponse } from '@pages/jobPins/types/api'; +import { type JobPinsResponse } from '@pages/jobPins/types/api'; import apiRequest from '@shared/apis/setting/axiosInstance'; interface ApiResponse { diff --git a/apps/client/src/pages/jobPins/apis/queries.ts b/apps/client/src/pages/jobPins/apis/queries.ts index 533c6b91..90b162b6 100644 --- a/apps/client/src/pages/jobPins/apis/queries.ts +++ b/apps/client/src/pages/jobPins/apis/queries.ts @@ -1,9 +1,9 @@ -import { JobPinsResponse } from '@pages/jobPins/types/api'; +import { type JobPinsResponse } from '@pages/jobPins/types/api'; import { useInfiniteQuery, useMutation } from '@tanstack/react-query'; import { getJobPinsArticleDetail, getJobPinsArticles, - JobPinsDetailResponse, + type JobPinsDetailResponse, } from './axios'; const PAGE_SIZE = 20; diff --git a/apps/client/src/pages/level/Level.tsx b/apps/client/src/pages/level/Level.tsx index e33a9628..c38ee9e2 100644 --- a/apps/client/src/pages/level/Level.tsx +++ b/apps/client/src/pages/level/Level.tsx @@ -1,5 +1,5 @@ import LevelScene from '@pages/level/components/LevelScene'; -import { TreeLevel } from '@pages/level/types/treeLevelType'; +import { type TreeLevel } from '@pages/level/types/treeLevelType'; import { Icon } from '@pinback/design-system/icons'; import { Badge } from '@pinback/design-system/ui'; import { cn } from '@pinback/design-system/utils'; diff --git a/apps/client/src/pages/level/components/LevelInfoCard.tsx b/apps/client/src/pages/level/components/LevelInfoCard.tsx index ba48bc71..0909a2d6 100644 --- a/apps/client/src/pages/level/components/LevelInfoCard.tsx +++ b/apps/client/src/pages/level/components/LevelInfoCard.tsx @@ -1,4 +1,4 @@ -import { TREE_LEVEL_TABLE, TreeLevel } from '@pages/level/types/treeLevelType'; +import { TREE_LEVEL_TABLE, type TreeLevel } from '@pages/level/types/treeLevelType'; import { Level } from '@pinback/design-system/ui'; import { cn } from '@pinback/design-system/utils'; diff --git a/apps/client/src/pages/level/components/LevelScene.tsx b/apps/client/src/pages/level/components/LevelScene.tsx index bbc4ed73..a54f800e 100644 --- a/apps/client/src/pages/level/components/LevelScene.tsx +++ b/apps/client/src/pages/level/components/LevelScene.tsx @@ -1,6 +1,6 @@ import { cn } from '@pinback/design-system/utils'; -import { TreeLevel } from '@pages/level/types/treeLevelType'; -import { HTMLAttributes } from 'react'; +import { type TreeLevel } from '@pages/level/types/treeLevelType'; +import { type HTMLAttributes } from 'react'; import chippi_level1 from '../../../assets/Lv.1.webp'; import chippi_level2 from '../../../assets/Lv.2.webp'; diff --git a/apps/client/src/pages/myBookmark/apis/axios.ts b/apps/client/src/pages/myBookmark/apis/axios.ts index 9c799bc1..fdacc9aa 100644 --- a/apps/client/src/pages/myBookmark/apis/axios.ts +++ b/apps/client/src/pages/myBookmark/apis/axios.ts @@ -1,7 +1,7 @@ import { - BookmarkArticlesCountResponse, - BookmarkArticlesResponse, - CategoryBookmarkArticleResponse, + type BookmarkArticlesCountResponse, + type BookmarkArticlesResponse, + type CategoryBookmarkArticleResponse, } from '@pages/myBookmark/types/api'; import apiRequest from '@shared/apis/setting/axiosInstance'; diff --git a/apps/client/src/pages/myBookmark/apis/queries.ts b/apps/client/src/pages/myBookmark/apis/queries.ts index 4863f399..9dae387c 100644 --- a/apps/client/src/pages/myBookmark/apis/queries.ts +++ b/apps/client/src/pages/myBookmark/apis/queries.ts @@ -3,7 +3,7 @@ import { useSuspenseInfiniteQuery, useSuspenseQuery, } from '@tanstack/react-query'; -import { CategoryBookmarkArticleResponse } from '../types/api'; +import { type CategoryBookmarkArticleResponse } from '../types/api'; import { getBookmarkArticles, getBookmarkArticlesCount, diff --git a/apps/client/src/pages/myBookmark/hooks/useMyBookmarkContentData.ts b/apps/client/src/pages/myBookmark/hooks/useMyBookmarkContentData.ts index dcca585b..9dca99ce 100644 --- a/apps/client/src/pages/myBookmark/hooks/useMyBookmarkContentData.ts +++ b/apps/client/src/pages/myBookmark/hooks/useMyBookmarkContentData.ts @@ -5,7 +5,7 @@ import { useGetCategoryBookmarkArticlesCount, } from '@pages/myBookmark/apis/queries'; import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll'; -import { MutableRefObject } from 'react'; +import { type MutableRefObject } from 'react'; interface UseMyBookmarkContentDataParams { activeBadge: 'all' | 'notRead'; diff --git a/apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx b/apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx index 2769e7d9..bd2723ce 100644 --- a/apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx +++ b/apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx @@ -1,6 +1,6 @@ import { Step, - StepType, + type StepType, storySteps, } from '@pages/onBoarding/constants/onboardingSteps'; import { useOnboardingFunnel } from '@pages/onBoarding/hooks/useOnboardingFunnel'; diff --git a/apps/client/src/pages/onBoarding/components/funnel/step/job/JobStep.tsx b/apps/client/src/pages/onBoarding/components/funnel/step/job/JobStep.tsx index 146cd0ae..329ff8dd 100644 --- a/apps/client/src/pages/onBoarding/components/funnel/step/job/JobStep.tsx +++ b/apps/client/src/pages/onBoarding/components/funnel/step/job/JobStep.tsx @@ -2,7 +2,7 @@ import { Suspense } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import dotori from '/assets/onBoarding/icons/dotori.svg'; import { Checkbox } from '@pinback/design-system/ui'; -import { JobsResponse } from '@shared/types/api'; +import { type JobsResponse } from '@shared/types/api'; import JobCards from '@shared/components/jobSelectionFunnel/step/job/JobCards'; import JobCardsSkeleton from '@shared/components/jobSelectionFunnel/step/job/JobCardsSkeleton'; diff --git a/apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx b/apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx index 8e8fa091..7ecedac2 100644 --- a/apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx +++ b/apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx @@ -1,10 +1,10 @@ import { Button, WheelPicker, - WheelPickerOption, + type WheelPickerOption, WheelPickerWrapper, } from '@pinback/design-system/ui'; -import { MouseEventHandler, useState } from 'react'; +import { type MouseEventHandler, useState } from 'react'; const createArray = (length: number, add = 0): WheelPickerOption[] => Array.from({ length }, (_, i) => { diff --git a/apps/client/src/pages/onBoarding/hooks/useOnboardingFunnel.ts b/apps/client/src/pages/onBoarding/hooks/useOnboardingFunnel.ts index 8888ea84..90003542 100644 --- a/apps/client/src/pages/onBoarding/hooks/useOnboardingFunnel.ts +++ b/apps/client/src/pages/onBoarding/hooks/useOnboardingFunnel.ts @@ -2,7 +2,7 @@ import { AlarmsType } from '@constants/alarms'; import { Step, stepOrder, - StepType, + type StepType, } from '@pages/onBoarding/constants/onboardingSteps'; import { normalizeTime } from '@pages/onBoarding/utils/formatRemindTime'; import { registerServiceWorker } from '@pages/onBoarding/utils/registerServiceWorker'; diff --git a/apps/client/src/shared/apis/axios.ts b/apps/client/src/shared/apis/axios.ts index 7c45e215..d6dbb410 100644 --- a/apps/client/src/shared/apis/axios.ts +++ b/apps/client/src/shared/apis/axios.ts @@ -1,9 +1,9 @@ import apiRequest from '@shared/apis/setting/axiosInstance'; import { - AmplitudeUserPropertiesResponse, - EditArticleRequest, - HasJobResponse, - JobsResponse, + type AmplitudeUserPropertiesResponse, + type EditArticleRequest, + type HasJobResponse, + type JobsResponse, } from '@shared/types/api'; import { formatLocalDateTime } from '@shared/utils/formatDateTime'; diff --git a/apps/client/src/shared/apis/queries.ts b/apps/client/src/shared/apis/queries.ts index 8b6619f9..7498dbb3 100644 --- a/apps/client/src/shared/apis/queries.ts +++ b/apps/client/src/shared/apis/queries.ts @@ -12,36 +12,36 @@ import { getMyProfile, patchCategory, patchUserJob, - patchUserJobRequest, + type patchUserJobRequest, postCategory, postSignUp, - postSignUpRequest, + type postSignUpRequest, putArticleReadStatus, putEditArticle, } from '@shared/apis/axios'; import { - AcornsResponse, - AmplitudeUserPropertiesResponse, - ArticleDetailResponse, - ArticleReadStatusResponse, - CategoryDetailResponse, - DashboardCategoriesResponse, - EditArticleRequest, - HasJobResponse, - JobsResponse, + type AcornsResponse, + type AmplitudeUserPropertiesResponse, + type ArticleDetailResponse, + type ArticleReadStatusResponse, + type CategoryDetailResponse, + type DashboardCategoriesResponse, + type EditArticleRequest, + type HasJobResponse, + type JobsResponse, } from '@shared/types/api'; import { fetchOGData } from '@shared/utils/fetchOgData'; import { authStorage } from '@shared/utils/authStorage'; import { extensionBridge } from '@shared/utils/extensionBridge'; import { useMutation, - UseMutationResult, + type UseMutationResult, useQuery, useQueryClient, - UseQueryResult, + type UseQueryResult, useSuspenseQuery, } from '@tanstack/react-query'; -import { AxiosError } from 'axios'; +import { type AxiosError } from 'axios'; export const useGetDashboardCategories = (): UseQueryResult< DashboardCategoriesResponse, diff --git a/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx b/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx index 99cfa177..509aeab9 100644 --- a/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx +++ b/apps/client/src/shared/components/analyticsCardWrapper/AnalyticsCardWrapper.tsx @@ -22,7 +22,7 @@ const AnalyticsCardWrapper = ({ bookmark_type: bookmarkType, }); } - }, [inView]); + }, [inView, bookmarkType]); return
{children}
; }; diff --git a/apps/client/src/shared/components/balloon/Balloon.tsx b/apps/client/src/shared/components/balloon/Balloon.tsx index f50fd155..216e14dc 100644 --- a/apps/client/src/shared/components/balloon/Balloon.tsx +++ b/apps/client/src/shared/components/balloon/Balloon.tsx @@ -1,6 +1,6 @@ import { Icon } from '@pinback/design-system/icons'; import { cn } from '@pinback/design-system/utils'; -import { ReactNode } from 'react'; +import { type ReactNode } from 'react'; type BalloonVariant = 'gray' | 'main'; diff --git a/apps/client/src/shared/components/cardEditModal/CardEditModal.tsx b/apps/client/src/shared/components/cardEditModal/CardEditModal.tsx index 495794ce..ae523f6f 100644 --- a/apps/client/src/shared/components/cardEditModal/CardEditModal.tsx +++ b/apps/client/src/shared/components/cardEditModal/CardEditModal.tsx @@ -18,7 +18,7 @@ import { useGetDashboardCategories, usePutEditArticle, } from '@shared/apis/queries'; -import { ArticleDetailResponse, EditArticleRequest } from '@shared/types/api'; +import { type ArticleDetailResponse, type EditArticleRequest } from '@shared/types/api'; import { combineDateTime } from '@shared/utils/datetime'; import { updateDate, updateTime } from '@shared/utils/formatDateTime'; import { useQueryClient } from '@tanstack/react-query'; diff --git a/apps/client/src/shared/components/jobSelectionFunnel/step/job/JobStep.tsx b/apps/client/src/shared/components/jobSelectionFunnel/step/job/JobStep.tsx index ba67e8f9..e23acea7 100644 --- a/apps/client/src/shared/components/jobSelectionFunnel/step/job/JobStep.tsx +++ b/apps/client/src/shared/components/jobSelectionFunnel/step/job/JobStep.tsx @@ -1,7 +1,7 @@ import { Suspense } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { Checkbox } from '@pinback/design-system/ui'; -import { JobsResponse } from '@shared/types/api'; +import { type JobsResponse } from '@shared/types/api'; import JobCards from './JobCards'; import JobCardsSkeleton from './JobCardsSkeleton'; diff --git a/apps/client/src/shared/components/sidebar/AccordionItem.tsx b/apps/client/src/shared/components/sidebar/AccordionItem.tsx index c0696da4..e8e97649 100644 --- a/apps/client/src/shared/components/sidebar/AccordionItem.tsx +++ b/apps/client/src/shared/components/sidebar/AccordionItem.tsx @@ -1,7 +1,7 @@ import { useState, useId } from 'react'; import { cn } from '@pinback/design-system/utils'; import SideItem from './SideItem'; -import { IconToken } from './types/IconTokenType'; +import { type IconToken } from './types/IconTokenType'; interface AccordionItemProps extends Omit, 'children'> { diff --git a/apps/client/src/shared/components/sidebar/SideItem.tsx b/apps/client/src/shared/components/sidebar/SideItem.tsx index cd27430b..cba8a56a 100644 --- a/apps/client/src/shared/components/sidebar/SideItem.tsx +++ b/apps/client/src/shared/components/sidebar/SideItem.tsx @@ -1,6 +1,6 @@ import { Icon, type IconName } from '@pinback/design-system/icons'; import { cn } from '@pinback/design-system/utils'; -import { IconToken } from './types/IconTokenType'; +import { type IconToken } from './types/IconTokenType'; const ICON_MAP: Record = { clock: { on: 'ic_clock_active', off: 'ic_clock_disable' }, diff --git a/apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts b/apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts index 215e19d1..61bd1547 100644 --- a/apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts +++ b/apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts @@ -4,9 +4,9 @@ import { usePatchCategory, usePostCategory, } from '@shared/apis/queries'; -import { SidebarTab } from '@shared/hooks/useSidebarNav'; +import { type SidebarTab } from '@shared/hooks/useSidebarNav'; import { useQueryClient } from '@tanstack/react-query'; -import { Dispatch, SetStateAction, useState } from 'react'; +import { type Dispatch, type SetStateAction, useState } from 'react'; import { useNavigate } from 'react-router-dom'; interface CategoryActionsParams { diff --git a/apps/client/src/shared/utils/fetchOgData.ts b/apps/client/src/shared/utils/fetchOgData.ts index 94a599c5..a5841ab7 100644 --- a/apps/client/src/shared/utils/fetchOgData.ts +++ b/apps/client/src/shared/utils/fetchOgData.ts @@ -1,4 +1,4 @@ -import axios, { AxiosResponse } from 'axios'; +import axios, { type AxiosResponse } from 'axios'; export interface OGData { title: string; diff --git a/apps/client/src/shared/utils/treeLevel.ts b/apps/client/src/shared/utils/treeLevel.ts index 793f5d48..6af12256 100644 --- a/apps/client/src/shared/utils/treeLevel.ts +++ b/apps/client/src/shared/utils/treeLevel.ts @@ -1,7 +1,7 @@ import { TREE_LEVEL_TABLE, - TreeLevelResult, - TreeLevelRow, + type TreeLevelResult, + type TreeLevelRow, } from '@pages/level/types/treeLevelType'; function findLevelRow(count: number, rows: readonly TreeLevelRow[]) { From 06f757a59cd424dadf937a326e172d7c01d1540f Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Tue, 7 Apr 2026 11:08:53 +0900 Subject: [PATCH 12/12] =?UTF-8?q?chore:=20fallback=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/pages/jobPins/JobPins.tsx | 11 ++++++++--- apps/extension/src/pages/MainPop.tsx | 6 ++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/client/src/pages/jobPins/JobPins.tsx b/apps/client/src/pages/jobPins/JobPins.tsx index 8b075831..3a58ccca 100644 --- a/apps/client/src/pages/jobPins/JobPins.tsx +++ b/apps/client/src/pages/jobPins/JobPins.tsx @@ -7,8 +7,8 @@ import MemoPopup from '@pages/jobPins/components/MemoPopup'; import { useJobPinsBottomNotice } from '@pages/jobPins/hooks/useJobPinsBottomNotice'; import Footer from '@pages/myBookmark/components/footer/Footer'; import { analytics } from '@pinback/analytics'; -import AnalyticsCardWrapper from '@shared/components/analyticsCardWrapper/AnalyticsCardWrapper'; import { Card } from '@pinback/design-system/ui'; +import AnalyticsCardWrapper from '@shared/components/analyticsCardWrapper/AnalyticsCardWrapper'; import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll'; const JobPins = () => { @@ -69,7 +69,10 @@ const JobPins = () => { const displayImageUrl = article.thumbnailUrl || undefined; return ( - + { onClick={() => { analytics.track('Clicked_Shared_Bookmark', { article_id: String(article.articleId), - category_id: String(article.category.categoryId), + category_id: article.category + ? String(article.category.categoryId) + : undefined, }); getJobPinDetail(article.articleId); }} diff --git a/apps/extension/src/pages/MainPop.tsx b/apps/extension/src/pages/MainPop.tsx index f975b9bf..0642c1cf 100644 --- a/apps/extension/src/pages/MainPop.tsx +++ b/apps/extension/src/pages/MainPop.tsx @@ -23,7 +23,7 @@ import { validateDate, validateTime, } from '@pinback/design-system/ui'; -import { ArticleResponse } from '@shared-types/types'; +import { type ArticleResponse } from '@shared-types/types'; import Header from '@shared/components/Header'; import { combineDateTime, @@ -218,7 +218,9 @@ const MainPop = ({ type, savedData }: MainPopProps) => { // article_id: 응답 타입 미정의로 보류 category_id: selected ?? undefined, // is_first_save: 판단 불가로 보류 - page_domain: new URL(url).hostname, + page_domain: URL.canParse(url) + ? new URL(url).hostname + : undefined, }); save({ url,