-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 탠스택 쿼리 툴킷 설정 * refactor: 인덱스 적용 및 파일 삭제 * refactor: 바뀐 타입 적용 * refactor: 게더링 외 파일에서 바뀐 타입 적용 * feat: 게더링 작성 훅 * feat: 게더링 디테일 훅 * feat: 게더링 리스트 훅 * feat: 커스텀 인피니트 쿼리 희정 버전 반영 * feat: 바뀐 타입 적용 * refactor: 게더링 카드의 버튼 눌렀을 때 카드 눌리는 현상 수정 * feat: 게더링 리스트 페이지 훅 연결 * feat: 게더링 api 타입 정리 * feat: 도메인 연결 * style: 작성 버튼 스타일 수정 * style: 게더링 작성 페이지 스타일 수정 * style: 게더링 태그 인풋 스타일 수정 * refactor: 쓸모 없는 내용 삭제 * style: 게더링 작성 페이지 스타일 수정 * feat: 게더링 디테일 페이지 유저 정보 유저 스토어 연동 * feat: 게더링 리스트 페이지 사이드바 필터링 연동 * refactor: personnel 타입 수정 * reafactor: 게더링 디테일 페이지 뒤로가기 버튼 추가 * refactor: 게더링 리스트 똑같은 페이지 반복되는 오류 수정 * feat: 게더링 디테일 페이지 api 연동 * feat: 게더링 리스트 필터링 기능 구현 * feat: 포트폴리오 리스트 페이지 api 연동 및 구현 * fix: 머지 충돌에러 수정 * fix: 게더링 리스트 payload 오류 수정 * feat: 게더링 리스트 * feat: 게더링 수정 기능 * feat: 게더링 삭제 기능 훅 * feat: 게더링 모집완료 기능 훅 * feat: 게더링 수정, 삭제, 모집완료 기능 적용 * fix: 데이트피커 타입 오류 수정 * feat: 메인 포트폴리오 리스트 위젯 구현 * fix: a 태크로 변경 * refactor: 로더 추가 * fix: 배포 오류 수정 * feat: 포폴 조회수 증가 연동
- Loading branch information
Showing
76 changed files
with
2,247 additions
and
691 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,62 @@ | ||
import type { GatheringDetailResponse } from '../model/gathering.dto'; | ||
import type { GatheringPageResponse, GatheringListParams } from '../model/dto/gathering.dto'; | ||
import type { | ||
GatheringItemDto, | ||
GatheringSortType, | ||
GatheringPeriod, | ||
GatheringPosition, | ||
} from '../model/gathering.dto'; | ||
GatheringDetailResponse, | ||
CreateGatheringRequest, | ||
CreateGatheringResponse, | ||
GatheringLikeResponse, | ||
} from '../model/dto/request.dto'; | ||
|
||
import api from '@/shared/api/baseApi'; | ||
|
||
interface GetGatheringsParams { | ||
sort?: GatheringSortType; | ||
period?: GatheringPeriod; | ||
position?: GatheringPosition; | ||
status?: '모집중' | '모집완료'; | ||
size?: number; | ||
gatheringId?: number; | ||
} | ||
export const gatheringApi = { | ||
getGatherings: async (params: GatheringListParams): Promise<GatheringPageResponse> => { | ||
// params를 URLSearchParams로 변환 | ||
const queryString = new URLSearchParams(); | ||
|
||
interface GetGatheringsParams { | ||
sort?: GatheringSortType; | ||
period?: GatheringPeriod; | ||
position?: GatheringPosition; | ||
status?: '모집중' | '모집완료'; | ||
size?: number; | ||
nextLikeId?: number; | ||
} | ||
Object.entries(params).forEach(([key, value]) => { | ||
if (value !== undefined && value !== 'undefined') { | ||
if (key === 'positions' && Array.isArray(value)) { | ||
value.forEach(pos => { | ||
queryString.append('positions', pos); | ||
}); | ||
} else { | ||
queryString.append(key, value.toString()); | ||
} | ||
} | ||
}); | ||
|
||
interface GatheringListResponse { | ||
data: { | ||
content: GatheringItemDto[]; | ||
hasNext: boolean; | ||
nextLikeId: number; | ||
}; | ||
timeStamp: string; | ||
} | ||
|
||
export const getGatheringList = { | ||
getGatherings: async (params: GetGatheringsParams): Promise<GatheringListResponse> => { | ||
const { data } = await api.get<GatheringListResponse>('/gathering', { params }); | ||
const { data } = await api.get<GatheringPageResponse>(`/gathering?${queryString.toString()}`); | ||
return data; | ||
}, | ||
}; | ||
interface GatheringDetailApi { | ||
getGatheringById: (id: string) => Promise<GatheringDetailResponse>; | ||
} | ||
|
||
export const gatheringDetailApi: GatheringDetailApi = { | ||
getGatheringById: async (id: string) => { | ||
getGatheringDetail: async (id: string): Promise<GatheringDetailResponse> => { | ||
const { data } = await api.get<GatheringDetailResponse>(`/gathering/${id}`); | ||
return data; | ||
}, | ||
|
||
create: async (requestData: CreateGatheringRequest): Promise<CreateGatheringResponse> => { | ||
const { data } = await api.post<CreateGatheringResponse>('/gathering', { | ||
...requestData, | ||
gatheringImages: [], | ||
}); | ||
return data; | ||
}, | ||
update: async ( | ||
gatheringId: string, | ||
data: CreateGatheringRequest, | ||
): Promise<CreateGatheringResponse> => { | ||
const response = await api.put<CreateGatheringResponse>(`/gathering/${gatheringId}`, data); | ||
return response.data; | ||
}, | ||
|
||
toggleLike: async (gatheringId: string): Promise<GatheringLikeResponse> => { | ||
const { data } = await api.post<GatheringLikeResponse>(`/gathering/${gatheringId}/like`); | ||
return data; | ||
}, | ||
deleteGathering: async (gatheringId: string): Promise<void> => { | ||
await api.delete(`/gathering/${gatheringId}`); | ||
}, | ||
completeGathering: async (gatheringId: string): Promise<void> => { | ||
await api.patch(`/gathering/${gatheringId}`); | ||
}, | ||
}; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export * from './useCompleteGathering'; | ||
export * from './useCreateGathering'; | ||
export * from './useDeleteGathering'; | ||
export * from './useGatheringDetail'; | ||
export * from './useGatheringLike'; | ||
export * from './useInfiniteGatheringId'; | ||
export * from './useUpdateGathering'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
|
||
import { gatheringApi } from '../../api/gathering.api'; | ||
|
||
interface UseCompleteGatheringProps { | ||
onSuccess?: () => void; | ||
onError?: (error: unknown) => void; | ||
} | ||
|
||
export const useCompleteGathering = ({ onSuccess, onError }: UseCompleteGatheringProps = {}) => { | ||
const queryClient = useQueryClient(); | ||
|
||
return useMutation({ | ||
mutationFn: (gatheringId: string) => gatheringApi.completeGathering(gatheringId), | ||
|
||
onSuccess: async () => { | ||
// 관련 쿼리 무효화 | ||
await queryClient.invalidateQueries({ queryKey: ['/gatheringDetail'] }); | ||
onSuccess?.(); | ||
}, | ||
|
||
onError, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import type { AxiosError } from 'axios'; | ||
import { useNavigate } from 'react-router-dom'; | ||
|
||
import { gatheringApi } from '../../api/gathering.api'; | ||
import type { CreateGatheringRequest, CreateGatheringResponse } from '../../model/dto/request.dto'; | ||
|
||
export const useCreateGathering = () => { | ||
const queryClient = useQueryClient(); | ||
const navigate = useNavigate(); | ||
|
||
return useMutation<CreateGatheringResponse, AxiosError, CreateGatheringRequest>({ | ||
mutationFn: gatheringApi.create, | ||
onSuccess: async response => { | ||
try { | ||
await queryClient.invalidateQueries({ queryKey: ['gathering'] }); | ||
|
||
const gatheringId = response.data?.gatheringId; | ||
if (gatheringId) { | ||
navigate(`/gathering/${gatheringId}`); | ||
} else { | ||
console.error('No gathering ID in response'); | ||
alert('게더링이 생성되었으나 상세 페이지로 이동할 수 없습니다.'); | ||
} | ||
} catch (error) { | ||
console.error('게더링 생성 후 처리 중 오류 발생:', error); | ||
alert('게더링은 생성되었으나 추가 처리 중 오류가 발생했습니다.'); | ||
} | ||
}, | ||
onError: (error: AxiosError) => { | ||
if (error.response?.status === 401) { | ||
alert('로그인이 필요합니다.'); | ||
navigate('/login'); | ||
} else if (error.response?.status === 403) { | ||
alert('권한이 부족합니다. 다시 로그인해주세요.'); | ||
navigate('/login'); | ||
} else if (error.response?.status === 400) { | ||
alert('입력하신 정보를 다시 확인해주세요.'); | ||
} else { | ||
console.error('게더링 생성 실패:', error); | ||
alert('게더링 생성에 실패했습니다. 잠시 후 다시 시도해주세요.'); | ||
} | ||
}, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import { useNavigate } from 'react-router-dom'; | ||
|
||
import { gatheringApi } from '../../api/gathering.api'; | ||
|
||
interface UseDeleteGatheringProps { | ||
onSuccess?: () => void; | ||
onError?: (error: unknown) => void; | ||
} | ||
|
||
export const useDeleteGathering = ({ onSuccess, onError }: UseDeleteGatheringProps = {}) => { | ||
const queryClient = useQueryClient(); | ||
const navigate = useNavigate(); | ||
|
||
return useMutation({ | ||
mutationFn: (gatheringId: string) => gatheringApi.deleteGathering(gatheringId), | ||
onSuccess: async () => { | ||
// 캐시 무효화 | ||
await queryClient.invalidateQueries({ queryKey: ['/gatheringDetail'] }); | ||
// 성공 콜백 | ||
onSuccess?.(); | ||
// 목록 페이지로 이동 | ||
navigate('/gathering'); | ||
}, | ||
onError, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { useQuery } from '@tanstack/react-query'; | ||
import type { AxiosError } from 'axios'; | ||
|
||
import { gatheringApi } from '../../api/gathering.api'; | ||
import type { GatheringDetailResponse } from '../../model/dto/request.dto'; | ||
|
||
export const useGatheringDetail = (gatheringId: string) => { | ||
return useQuery<GatheringDetailResponse, AxiosError>({ | ||
queryKey: ['/gatheringDetail',gatheringId], | ||
queryFn: () => gatheringApi.getGatheringDetail(gatheringId), | ||
enabled: !!gatheringId, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
|
||
import { gatheringApi } from '../../api/gathering.api'; | ||
import type { GatheringLikeResponse, GatheringDetailResponse } from '../../model/dto/request.dto'; | ||
|
||
interface UseGatheringLikeProps { | ||
gatheringId: string; | ||
onSuccess?: (response: GatheringLikeResponse) => void; | ||
onError?: (error: unknown) => void; | ||
} | ||
|
||
interface MutationContext { | ||
previousDetail: GatheringDetailResponse | undefined; | ||
} | ||
|
||
export const useGatheringLike = ({ gatheringId, onSuccess, onError }: UseGatheringLikeProps) => { | ||
const queryClient = useQueryClient(); | ||
|
||
return useMutation<GatheringLikeResponse, Error, void, MutationContext>({ | ||
mutationFn: () => gatheringApi.toggleLike(gatheringId), | ||
|
||
onMutate: async () => { | ||
await queryClient.cancelQueries({ | ||
queryKey: ['/gatheringDetail', gatheringId], | ||
}); | ||
|
||
const previousDetail = queryClient.getQueryData<GatheringDetailResponse>([ | ||
'/gatheringDetail', | ||
gatheringId, | ||
]); | ||
|
||
console.log('이전 상태:', previousDetail); | ||
return { previousDetail }; | ||
}, | ||
|
||
onSuccess: response => { | ||
console.log('좋아요 API 응답:', response); | ||
|
||
const currentDetail = queryClient.getQueryData<GatheringDetailResponse>([ | ||
'/gatheringDetail', | ||
gatheringId, | ||
]); | ||
|
||
if (currentDetail?.data) { | ||
const newLikeCounts = response.data | ||
? currentDetail.data.likeCounts + 1 | ||
: Math.max(0, currentDetail.data.likeCounts - 1); | ||
|
||
queryClient.setQueryData<GatheringDetailResponse>(['/gatheringDetail', gatheringId], { | ||
...currentDetail, | ||
data: { | ||
...currentDetail.data, | ||
likeCounts: newLikeCounts, | ||
}, | ||
}); | ||
|
||
console.log('캐시 업데이트 완료, 새로운 좋아요 수:', newLikeCounts); | ||
} | ||
|
||
onSuccess?.(response); | ||
}, | ||
|
||
onError: (error, _, context) => { | ||
console.log('에러 발생:', error); | ||
|
||
if (context?.previousDetail) { | ||
queryClient.setQueryData(['/gatheringDetail', gatheringId], context.previousDetail); | ||
} | ||
onError?.(error); | ||
}, | ||
}); | ||
}; |
Oops, something went wrong.
9d07a47
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.
⚡ Lighthouse report for http://localhost:3000/
Detailed Metrics