Skip to content

Commit 2cda148

Browse files
authored
Merge pull request #94 from 100-hours-a-week/feature/resume
feat: 이력서 검색 및 필터링
2 parents 76e9819 + 237d0b1 commit 2cda148

File tree

6 files changed

+255
-41
lines changed

6 files changed

+255
-41
lines changed

src/app/api/endpoints/resumes.js

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,37 @@ import { mutatingClient } from '../mutatingClient';
33
import { streamAPI } from '../streamingClient';
44
import { API_CONFIG } from '../config';
55

6-
export const fetchResumes = async ({ page = 0, size = 10 } = {}) => {
6+
/**
7+
* Fetch resumes with cursor-based pagination
8+
* @param {Object} params
9+
* @param {string | null} params.next - Cursor for next page ("updatedAt|id" format)
10+
* @param {number} params.size - Page size (default: 10, max: 49)
11+
* @param {string} params.keyword - Resume name search (1-30 chars, optional)
12+
* @param {string} params.sortedBy - Sort order: UPDATED_DESC (default) | UPDATED_ASC
13+
* @returns {Promise<{data: Array, before: null, next: string | null}>}
14+
*/
15+
export const fetchResumes = async ({
16+
next = null,
17+
size = 10,
18+
keyword = undefined,
19+
sortedBy = 'UPDATED_DESC',
20+
} = {}) => {
21+
const params = { size, sortedBy };
22+
23+
// Only add optional params if they have values
24+
if (next) {
25+
params.next = next;
26+
}
27+
if (keyword && keyword.trim()) {
28+
params.keyword = keyword.trim();
29+
}
30+
731
const response = await apiClient.get(API_CONFIG.ENDPOINTS.RESUMES, {
8-
params: { page, size },
32+
params,
933
});
10-
const data = response.data.data;
11-
return {
12-
...data,
13-
content: data?.items || data?.content || [],
14-
};
34+
35+
// Response structure: { code, message, data: { data: [], before: null, next: string | null } }
36+
return response.data.data;
1537
};
1638

1739
export const createResume = async (request) => {

src/app/components/features/ChatRoomListSheet.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ export function ChatRoomListSheet() {
7676
const [isSending, setIsSending] = useState(false);
7777

7878
const messages = useMemo(() => {
79-
const rawMessages =
80-
messagesData?.pages?.flatMap((page) => page.chats) || [];
79+
const rawMessages = messagesData?.pages?.flatMap((page) => page.data) || [];
8180

8281
// Deduplicate by message ID (defensive against backend pagination overlaps)
8382
const uniqueMessages = Array.from(

src/app/constants/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ export const REPO_SORT_OPTIONS = {
9797
name: '이름 순',
9898
};
9999

100+
// Resume Sort Options
101+
// ========================================
102+
103+
export const RESUME_SORT_OPTIONS = {
104+
UPDATED_DESC: 'UPDATED_DESC',
105+
UPDATED_ASC: 'UPDATED_ASC',
106+
};
107+
108+
export const RESUME_SORT_LABELS = {
109+
[RESUME_SORT_OPTIONS.UPDATED_DESC]: '최근 업데이트 순',
110+
[RESUME_SORT_OPTIONS.UPDATED_ASC]: '오래된 순',
111+
};
112+
100113
// Upload Constants
101114
// ========================================
102115

src/app/hooks/queries/useResumeQueries.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* React Query hooks for fetching resume data
44
*/
55

6-
import { useQuery } from '@tanstack/react-query';
6+
import { useQuery, useInfiniteQuery } from '@tanstack/react-query';
77
import {
88
fetchResumes,
99
fetchResumeById,
@@ -21,10 +21,33 @@ export const resumeKeys = {
2121
detail: (id) => [...resumeKeys.details(), id],
2222
};
2323

24-
export function useResumes({ page = 0, size = 10 } = {}) {
25-
return useQuery({
26-
queryKey: ['resumes', { page, size }],
27-
queryFn: () => fetchResumes({ page, size }),
24+
/**
25+
* Fetch resumes with infinite scroll (cursor-based pagination)
26+
* Supports search and sort functionality
27+
* @param {Object} params
28+
* @param {number} params.size - Page size (default: 10)
29+
* @param {string} params.keyword - Search keyword (optional, 1-30 chars)
30+
* @param {string} params.sortedBy - Sort order: UPDATED_DESC (default) | UPDATED_ASC
31+
* @returns {import('@tanstack/react-query').UseInfiniteQueryResult}
32+
*/
33+
export function useResumes({
34+
size = 10,
35+
keyword = '',
36+
sortedBy = 'UPDATED_DESC',
37+
} = {}) {
38+
return useInfiniteQuery({
39+
queryKey: ['resumes', 'list', { size, keyword: keyword.trim(), sortedBy }],
40+
queryFn: ({ pageParam = null }) =>
41+
fetchResumes({
42+
next: pageParam,
43+
size,
44+
keyword: keyword.trim() || undefined,
45+
sortedBy,
46+
}),
47+
getNextPageParam: (lastPage) => lastPage.next || undefined,
48+
initialPageParam: null,
49+
staleTime: 0,
50+
gcTime: 1000 * 60 * 5,
2851
});
2952
}
3053

src/app/hooks/useChatWebSocket.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export function useChatWebSocket(chatroomId) {
4242
const lastPage = pages[pages.length - 1];
4343
pages[pages.length - 1] = {
4444
...lastPage,
45-
chats: [...lastPage.chats, newMsg],
45+
data: [...lastPage.data, newMsg],
4646
};
4747
return { ...oldData, pages };
4848
}

0 commit comments

Comments
 (0)