-
Notifications
You must be signed in to change notification settings - Fork 1
main 최신화 #329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
main 최신화 #329
Changes from all commits
3231a6f
77ca42c
51942e1
5ce8179
26f434f
8ddd238
6db5199
aa75ae4
20ed63b
1ca5136
741705a
90e583d
389a7ba
1cc5147
468a8ce
66160db
c6bcc5d
8adbe1b
a65ea8a
818aacf
846e600
b8636e1
dfc4d90
0bf7309
0816e8f
6083557
a7b6014
0655de2
d443399
8f29d09
58bef9e
dfc3cdd
d66eba3
183fde1
7eede88
19532f1
148ff0d
e304657
acc82ca
76d83ca
e6ff5d5
10ff0f2
b711b81
3d44700
664c05c
782ea92
e80b6dd
10c5250
5fabd17
caf32cb
f2a15e5
c6a4c53
241c526
03eadb5
cca7d76
c59cdba
a5bb523
5adb27c
b5e3a4a
abf1952
e14c43a
6e1325c
108ed15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,4 +4,4 @@ | |
| . "$(dirname "$0")/_/husky.sh" | ||
|
|
||
| echo "✅ Lint-staged 시작..." | ||
| yarn lint-staged | ||
| npx lint-staged | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| declare global { | ||
| interface Window { | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| amplitude: any; | ||
| } | ||
| } | ||
|
|
||
| export {}; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,11 +18,25 @@ const FloatingButton = () => { | |
| }, 2500); | ||
| }; | ||
|
|
||
| const handleFloatingButtonClick = () => { | ||
| // Amplitude 이벤트 - 플로팅 버튼 클릭 | ||
| if (typeof window !== 'undefined' && 'amplitude' in window && window.amplitude) { | ||
| (window as any).amplitude.track('todo_create', { | ||
| source_method: 'floating', | ||
| source_page: window.location.pathname, | ||
| timestamp: new Date().toISOString(), | ||
| }); | ||
| console.log('Amplitude event sent: todo_create_start (floating)'); | ||
| } | ||
|
|
||
| setIsModal(true); | ||
| }; | ||
|
Comment on lines
+21
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 버튼 내부 중첩 onClick으로 닫기 불가 + ESLint(any) 발생 텍스트 div(onClick)와 버튼(onClick)이 중첩되어 클릭 시 항상 최종적으로 열림(setIsModal(true))으로 귀결됩니다. 또한 - const handleFloatingButtonClick = () => {
- // Amplitude 이벤트 - 플로팅 버튼 클릭
- if (typeof window !== 'undefined' && 'amplitude' in window && window.amplitude) {
- (window as any).amplitude.track('todo_create', {
- source_method: 'floating',
- source_page: window.location.pathname,
- timestamp: new Date().toISOString(),
- });
- console.log('Amplitude event sent: todo_create_start (floating)');
- }
-
- setIsModal(true);
- };
+ const handleFloatingButtonClick = () => {
+ const opening = !isModal;
+ if (opening && typeof window !== 'undefined' && window.amplitude) {
+ window.amplitude.track('todo_create', {
+ source_method: 'floating',
+ source_page: window.location.pathname,
+ timestamp: new Date().toISOString(),
+ });
+ console.log('Amplitude event sent: todo_create (floating)');
+ }
+ setIsModal((prev) => !prev);
+ };
@@
- <button
+ <button
+ type="button"
className="fixed bottom-[50px] right-[80px] flex h-[102px] items-center gap-[10px] rounded-[28px] bg-purple-500 px-[30px] shadow-shadow4 transition-colors hover:bg-purple-600"
onClick={handleFloatingButtonClick}
>
- <div
- className="cursor-pointer text-white font-T02-B"
- onClick={() => setIsModal(false)}
- >
+ <div className="cursor-pointer text-white font-T02-B">
{isModal ? '할일 추가 닫기' : '바로 할일 추가'}
</div>Also applies to: 37-37, 41-46 🧰 Tools🪛 ESLint[error] 24-24: Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any) 🤖 Prompt for AI Agents |
||
|
|
||
| return ( | ||
| <div> | ||
| <button | ||
| className="fixed bottom-[50px] right-[80px] flex h-[102px] items-center gap-[10px] rounded-[28px] bg-purple-500 px-[30px] shadow-shadow4 transition-colors hover:bg-purple-600" | ||
| onClick={() => setIsModal(true)} | ||
| onClick={handleFloatingButtonClick} | ||
| > | ||
| <div | ||
| className="cursor-pointer text-white font-T02-B" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| interface TagProps { | ||
| context: string; | ||
| fontClass?: string; | ||
| width?: string; | ||
| height?: string; | ||
| } | ||
|
|
||
| const Tag = ({ | ||
| context, | ||
| fontClass = 'font-T05-SB', | ||
| width = 'w-auto', | ||
| height = 'h-auto', | ||
| }: TagProps) => { | ||
| return ( | ||
| <div | ||
| className={`flex items-center justify-center rounded-[10px] bg-purple-100 p-2 text-purple-500 ${fontClass} ${width} ${height}`} | ||
| > | ||
| {context} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Tag; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,10 @@ import { ReactTagManager } from 'react-gtm-ts'; | |
| import { useAddTodoMutation } from '@hook/todo/useAddTodoMutation'; | ||
| import Fire from '@assets/icons/fire.svg?react'; | ||
| import Reset from '@assets/icons/reset.svg?react'; | ||
| import { | ||
| useFloatingPopular, | ||
| useNoLoginFloatingPopular, | ||
| } from '@hook/floating/useFloatingPopular'; | ||
|
|
||
| interface FloatingModalProps { | ||
| onClose: () => void; | ||
|
|
@@ -22,6 +26,27 @@ const FloatingModal = ({ onClose, onAddTask }: FloatingModalProps) => { | |
|
|
||
| const { mutate } = useAddTodoMutation(); | ||
| const { data: hasJob, isLoading } = useMdTodoQuery(); | ||
| const { | ||
| data: hot, | ||
| isLoading: loadingLogin, | ||
| refetch: refetchLogin, | ||
| } = useFloatingPopular({ | ||
| enabled: isLoggedIn, | ||
| queryKey: [], | ||
| }); | ||
|
Comment on lines
+33
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 중요: 옵션으로 queryKey를 덮어써 캐시 키가 비어 충돌합니다 useFloatingPopular/useNoLoginFloatingPopular 내부에서 queryKey를 지정한 뒤 } = useFloatingPopular({
enabled: isLoggedIn,
- queryKey: [],
});
...
} = useNoLoginFloatingPopular({
enabled: !isLoggedIn,
- queryKey: [],
});Also applies to: 42-45 🤖 Prompt for AI Agents |
||
|
|
||
| const { | ||
| data: hotGuest, | ||
| isLoading: loadingGuest, | ||
| refetch: refetchGuest, | ||
| } = useNoLoginFloatingPopular({ | ||
| enabled: !isLoggedIn, | ||
| queryKey: [], | ||
| }); | ||
|
|
||
| const hotList = isLoggedIn ? hot : hotGuest; | ||
| const isHotLoading = isLoggedIn ? loadingLogin : loadingGuest; | ||
| const refreshHot = isLoggedIn ? refetchLogin : refetchGuest; | ||
|
|
||
| const hasNoJob = | ||
| isLoggedIn && | ||
|
|
@@ -34,6 +59,17 @@ const FloatingModal = ({ onClose, onAddTask }: FloatingModalProps) => { | |
| const handleSubmit = () => { | ||
| if (!isLoggedIn || !taskText.trim() || hasNoJob) return; | ||
|
|
||
| // Amplitude 이벤트 - 할일 추가 시도 | ||
| if (window.amplitude) { | ||
| window.amplitude.track('todo_create', { | ||
| source_method: 'floating', | ||
| source_page: location.pathname, | ||
| todo_length: taskText.trim().length, | ||
| timestamp: new Date().toISOString(), | ||
| }); | ||
| console.log('Amplitude event sent: todo_create_attempt'); | ||
| } | ||
|
|
||
| mutate( | ||
| { | ||
| todoTitle: taskText, | ||
|
|
@@ -61,20 +97,29 @@ const FloatingModal = ({ onClose, onAddTask }: FloatingModalProps) => { | |
| <div className="text-black font-T03-B">바로 할일 추가</div> | ||
| </div> | ||
|
|
||
| <div className="mt-[22px] flex w-full flex-row items-center rounded-[8px] bg-gray-100 p-3"> | ||
| <div className="flex flex-row items-center gap-[6px]"> | ||
| <Fire /> | ||
| <div className="text-gray-900 font-B03-SB"> 인기</div> | ||
| </div> | ||
| <div className="mt-[22px] w-full rounded-[8px] bg-gray-100 p-3"> | ||
| <div className="flex items-center"> | ||
| <div className="flex shrink-0 items-center gap-[6px]"> | ||
| <Fire /> | ||
| <span className="text-gray-900 font-B03-SB">인기</span> | ||
| </div> | ||
|
|
||
| <div className="mx-[10px] h-4 w-[1px] bg-gray-400" /> | ||
| <div className="mx-[10px] h-4 w-[1px] shrink-0 bg-gray-400" /> | ||
|
|
||
| <div className="text-gray-600 font-B03-M"> | ||
| 요양보호사 카페 주소 검색하고 가입하기 | ||
| </div> | ||
| <div className="min-w-0 flex-1"> | ||
| <span className="block truncate text-gray-600 font-B03-M"> | ||
| {isHotLoading | ||
| ? '인기 목록을 불러오는 중입니다...' | ||
| : (hotList?.title ?? '인기데이터가 없습니다')} | ||
| </span> | ||
| </div> | ||
|
|
||
| <div className="ml-[83px] cursor-pointer"> | ||
| <Reset /> | ||
| <div | ||
| className="shrink-0 cursor-pointer" | ||
| onClick={() => refreshHot()} | ||
| > | ||
| <Reset /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,79 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import api from '@hook/api'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useInfiniteQuery } from '@tanstack/react-query'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface CommunityItem { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| level: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| imageUrl?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dDay?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| saveCount: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isSaved: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface CommunityGetTodoResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: CommunityItem[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| number: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| first: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| last: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| empty: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| numberOfElements: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageable: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageNumber: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sort: { empty: boolean; sorted: boolean; unsorted: boolean }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type BaseParams = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobName: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| level: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sort: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fetchCommunityPage = async ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| level, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sort, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| page, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: BaseParams & { page: number }): Promise<CommunityGetTodoResponse> => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const token = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof window !== 'undefined' ? localStorage.getItem('accessToken') : null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const res = await api.get('/v1/community/todos', { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| params: { jobName, level, sort, page, size }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(token ? { headers: { Authorization: `Bearer ${token}` } } : {}), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const result = res.data?.data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: result.content, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| number: result.number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size: result.size, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| first: result.first, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| last: result.last, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| empty: result.empty, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| numberOfElements: result.numberOfElements, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageable: { pageNumber: result.pageable?.pageNumber ?? page }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sort: result.sort, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 런타임 형태 검증과 방어적 체크 부재 — 응답 파싱 추가 제안 result가 null/shape 변경 시 NPE 위험이 있습니다. Zod 파싱과 명시적 에러를 추가하세요. 원하시면 해당 스키마를 별도 파일로 분리해 드리겠습니다. import api from '@hook/api';
+import { z } from 'zod';
@@
- const res = await api.get('/v1/community/todos', {
+ const res = await api.get('/v1/community/todos', {
params: { jobName, level, sort, page, size },
...(token ? { headers: { Authorization: `Bearer ${token}` } } : {}),
});
- const result = res.data?.data;
-
- return {
- content: result.content,
- number: result.number,
- size: result.size,
- first: result.first,
- last: result.last,
- empty: result.empty,
- numberOfElements: result.numberOfElements,
- pageable: { pageNumber: result.pageable?.pageNumber ?? page },
- sort: result.sort,
- };
+ const result = res.data?.data;
+ if (!result) {
+ throw new Error('Invalid response: data is missing');
+ }
+
+ const CommunityItemSchema = z
+ .object({
+ id: z.number().int().positive(),
+ name: z.string(),
+ level: z.string(),
+ imageUrl: z.string().url().or(z.literal('')).optional(),
+ dDay: z.string().optional(),
+ description: z.string(),
+ saveCount: z.number().int().nonnegative(),
+ isSaved: z.boolean(),
+ })
+ .passthrough();
+
+ const CommunityGetTodoResponseSchema = z
+ .object({
+ content: z.array(CommunityItemSchema),
+ number: z.number().int().nonnegative(),
+ size: z.number().int().positive(),
+ first: z.boolean(),
+ last: z.boolean(),
+ empty: z.boolean(),
+ numberOfElements: z.number().int().nonnegative(),
+ pageable: z.object({ pageNumber: z.number().int().nonnegative() }).partial(),
+ sort: z.object({ empty: z.boolean(), sorted: z.boolean(), unsorted: z.boolean() }),
+ })
+ .passthrough();
+
+ const parsed = CommunityGetTodoResponseSchema.parse(result);
+ return {
+ ...parsed,
+ pageable: { pageNumber: parsed.pageable?.pageNumber ?? page },
+ };📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const useCommunityGetTodo = (params: BaseParams) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return useInfiniteQuery({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryKey: ['CommunityGetTodo', params], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| initialPageParam: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryFn: ({ pageParam }) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetchCommunityPage({ ...params, page: pageParam as number }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getNextPageParam: (lastPage) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (lastPage.last) return undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return lastPage.number + 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retry: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { useQuery } from '@tanstack/react-query'; | ||
| import api from '@hook/api'; | ||
|
|
||
| export const useGetCommunityQuery = () => { | ||
| const isLoggedIn = | ||
| typeof window !== 'undefined' && !!localStorage.getItem('accessToken'); | ||
|
|
||
| return useQuery({ | ||
| queryKey: ['community', isLoggedIn], | ||
| queryFn: async () => { | ||
|
Comment on lines
+8
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent ❓ Verification inconclusivequeryKey에 로그인 여부만 포함 → 계정 전환 캐시 오염 가능성 동일한 “로그인 상태(true)”에서 계정을 바꾸면 key가 동일해 캐시 재사용됩니다. 사용자 식별자(예: userId) 또는 토큰 버전 키를 포함해 주세요. 토큰 원문 자체는 포함하지 마세요. 예) queryKey에 userId 포함 필수 queryKey: ['community', { authed: !!token, userId }]🤖 Prompt for AI Agents |
||
| const token = | ||
| typeof window !== 'undefined' | ||
| ? localStorage.getItem('accessToken') | ||
| : null; | ||
|
|
||
| const res = await api.get( | ||
| '/v1/community/job', | ||
| token ? { headers: { Authorization: `Bearer ${token}` } } : undefined | ||
| ); | ||
|
|
||
| return res.data; | ||
| }, | ||
| staleTime: 1000 * 60 * 5, | ||
| refetchOnWindowFocus: false, | ||
| }); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
기본 배경색 제거로 인한 UI 회귀 가능성 점검
이제 className을 넘기지 않으면 선이 보이지 않을 수 있습니다. 사용처 중 className 미지정 사례를 확인해 주세요.
원한다면 기본 색을 얇게 유지하고, 명시 시 오버라이드하는 방안도 있습니다.
🏁 Script executed:
Length of output: 100
rg 명령이
tsx파일 타입을 인식하지 못해 검색이 실패한 것으로 보입니다. glob 패턴을 사용해.ts/.tsx파일을 대상으로 다시 검색합니다.🏁 Script executed:
Length of output: 1549
Divider 컴포넌트 기본 색상 설정 필수
<Divider />가 투명 선으로 렌더링되어 보이지 않습니다. 다음 5곳에서 확인 필요:📝 Committable suggestion
🤖 Prompt for AI Agents