|
3 | 3 | import { useEffect, useState } from 'react'; |
4 | 4 | import { toast } from 'react-toastify'; |
5 | 5 | import { useRouter } from 'next/navigation'; |
6 | | -import { Loader } from '@mantine/core'; |
7 | 6 | import { useDisclosure } from '@mantine/hooks'; |
8 | 7 | import { cancelCrew, joinCrew, leaveCrew } from '@/src/_apis/crew/crew-detail-apis'; |
9 | 8 | import { useUser } from '@/src/_queries/auth/user-queries'; |
10 | 9 | import { useGetCrewDetailQuery } from '@/src/_queries/crew/crew-detail-queries'; |
11 | 10 | import { ApiError } from '@/src/utils/api'; |
| 11 | +import Button from '@/src/components/common/input/button'; |
12 | 12 | import ConfirmCancelModal from '@/src/components/common/modal/confirm-cancel-modal'; |
| 13 | +import CrewDetailSkeleton from '@/src/components/common/skeleton/crew-detail-skeleton'; |
13 | 14 | import { User } from '@/src/types/auth'; |
14 | 15 | import DetailCrewPresenter from './detail-crew-presenter'; |
15 | 16 |
|
@@ -38,12 +39,8 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) { |
38 | 39 |
|
39 | 40 | useEffect(() => { |
40 | 41 | if (data) { |
41 | | - // confirmed 상태 계산 |
42 | | - if (data.participantCount !== undefined && data.totalCount !== undefined) { |
43 | | - setIsConfirmed(data.participantCount === data.totalCount); |
44 | | - } |
| 42 | + setIsConfirmed(data.participantCount === data.totalCount); |
45 | 43 |
|
46 | | - // Captain 및 멤버 여부 확인 (currentUserId 필요) |
47 | 44 | if (currentUserId) { |
48 | 45 | const captain = data.crewMembers.find((member) => member.captain); |
49 | 46 | const memberExists = data.crewMembers.some((member) => member.id === currentUserId); |
@@ -114,29 +111,35 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) { |
114 | 111 | }); |
115 | 112 | }; |
116 | 113 |
|
117 | | - // TODO: 로딩, 에러처리 추후 개선 |
118 | 114 | if (isLoading) { |
119 | | - return <Loader />; |
| 115 | + return <CrewDetailSkeleton />; |
120 | 116 | } |
121 | 117 |
|
122 | | - // TODO: 추후 404페이지로 이동시키기 |
123 | | - if (fetchError) { |
| 118 | + const renderErrorState = (message: string, actionLabel: string, action: () => void) => ( |
| 119 | + <div className="flex h-screen flex-col items-center justify-center"> |
| 120 | + <p className="mb-4 text-gray-500">{message} 😞</p> |
| 121 | + <Button className="btn-filled" onClick={action}> |
| 122 | + {actionLabel} |
| 123 | + </Button> |
| 124 | + </div> |
| 125 | + ); |
| 126 | + |
| 127 | + if (fetchError || !data) { |
124 | 128 | if (fetchError instanceof ApiError) { |
125 | | - try { |
126 | | - const errorData = JSON.parse(fetchError.message); |
127 | | - |
128 | | - if (errorData.status === 'NOT_FOUND') { |
129 | | - return <p>크루 정보를 찾을 수 없습니다</p>; |
130 | | - } |
131 | | - } catch (parseError) { |
132 | | - return <p>{`Error ${fetchError.message}`}</p>; |
| 129 | + if (fetchError.status === 404) { |
| 130 | + router.push('/404'); |
| 131 | + return null; |
133 | 132 | } |
| 133 | + toast.error(fetchError.message || '🚫 에러가 발생했습니다.'); |
| 134 | + } else if (fetchError) { |
| 135 | + toast.error('🚫 데이터 통신에 실패했습니다.'); |
134 | 136 | } |
135 | | - return <p>데이터 통신에 실패했습니다.</p>; |
136 | | - } |
137 | 137 |
|
138 | | - if (!data) { |
139 | | - return <p>데이터를 불러올 수 없습니다.</p>; |
| 138 | + const errorMessage = fetchError |
| 139 | + ? '데이터를 불러오는 데 실패했습니다.' |
| 140 | + : '데이터를 불러올 수 없습니다.'; |
| 141 | + |
| 142 | + return renderErrorState(errorMessage, '다시 시도', refetch); |
140 | 143 | } |
141 | 144 |
|
142 | 145 | return ( |
|
0 commit comments