Skip to content

Commit cac2f08

Browse files
authored
크루, 게스트 모집 상세 페이지 버튼 렌더링 로직 고도화 및 툴팁 기능 (#402)
* fix: api 명세 변경에 맞게 타입 수정 * feat: 게스트 모집 상세 페이지에 필요한 버튼 컴포넌트 구현 * feat: 게스트 모집 상세 페이지 스타일 수정 및 버튼 렌더링 로직 고도화 * fix: 게스트 모집 상세 페이지 게스트 버튼 로직 수정 * feat: 크루 상세 페이지 버튼 렌더링 로직 고도화 * chore: 크루 상세 페이지 TODO 작성 * feat: 크루 상세 페이지 툴팁 추가 * fix: 모집중 툴팁 렌더링 조건 수정
1 parent 0130f09 commit cac2f08

10 files changed

+315
-139
lines changed

src/pages/CrewsDetailPage/CrewsDetailPage.styles.ts

+12
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,15 @@ export const Crown = styled(CrownSvg)<{ isLeader: boolean }>`
8888
top: 0;
8989
right: 5px;
9090
`;
91+
92+
export const ToolTipWrapper = styled.div`
93+
background-color: white;
94+
padding: 0 2px;
95+
margin-top: 10px;
96+
position: absolute;
97+
top: 0;
98+
left: 0;
99+
color: ${({ theme }) => theme.PALETTE.RED_400};
100+
border: 1px solid ${({ theme }) => theme.PALETTE.RED_400};
101+
border-radius: 5px;
102+
`;

src/pages/CrewsDetailPage/CrewsDetailPage.tsx

+38-30
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ErrorBoundary } from 'react-error-boundary';
2-
import toast from 'react-hot-toast';
32
import { useNavigate, useParams } from 'react-router-dom';
43

54
import { Avatar } from '@components/Avatar';
@@ -9,7 +8,6 @@ import { Button } from '@components/shared/Button';
98
import { Flex } from '@components/shared/Flex';
109
import { Text } from '@components/shared/Text';
1110

12-
import { useCrewParticipateCreateMutation } from '@hooks/mutations/useCrewParticipateCreateMutation';
1311
import { useCrewDetailQuery } from '@hooks/queries/useCrewDetailQuery';
1412

1513
import { theme } from '@styles/theme';
@@ -34,9 +32,11 @@ import {
3432
PageContent,
3533
PageWrapper,
3634
ProfileImage,
35+
ToolTipWrapper,
3736
} from './CrewsDetailPage.styles';
3837
import { ParticipateButton } from './ParticipateButton';
3938

39+
/** TODO 좌측 상단에 모집중, 내가 속한 크루, 내가 만든 크루 툴팁 보여주기 */
4040
export const CrewsDetailPage = () => {
4141
const { id } = useParams();
4242
if (id === undefined || isNaN(Number(id))) {
@@ -45,20 +45,16 @@ export const CrewsDetailPage = () => {
4545

4646
const loginInfo = useLoginInfoStore((state) => state.loginInfo);
4747
const { data: crew } = useCrewDetailQuery({ crewId: Number(id) });
48-
const { mutate: participateMutate } = useCrewParticipateCreateMutation();
48+
4949
const navigate = useNavigate();
5050
const handleClickMemberProfile = (id: number | string) =>
5151
navigate(PATH_NAME.GET_PROFILE_PATH(String(id)));
5252

53-
const renderManageButton =
54-
loginInfo !== null &&
55-
loginInfo.id !== null &&
56-
crew.leader.id === loginInfo.id;
57-
const renderParticipateButton =
58-
loginInfo !== null &&
59-
loginInfo.id !== null &&
60-
crew.leader.id !== loginInfo.id &&
61-
crew.members.every((member) => member.id !== loginInfo.id);
53+
const vacancy = crew.maxMemberCount - crew.memberCount > 0;
54+
const isMyCrew = crew.leader.id === loginInfo?.id;
55+
const isParticipant = crew.members.some(
56+
(member) => member.id === loginInfo?.id
57+
);
6258

6359
return (
6460
<PageWrapper>
@@ -77,6 +73,21 @@ export const CrewsDetailPage = () => {
7773
width={80}
7874
/>
7975
<Text>{crew.name}</Text>
76+
{isMyCrew && (
77+
<ToolTipWrapper>
78+
<Text>내가 만든 크루</Text>
79+
</ToolTipWrapper>
80+
)}
81+
{!isMyCrew && isParticipant && (
82+
<ToolTipWrapper>
83+
<Text>내가 속한 크루</Text>
84+
</ToolTipWrapper>
85+
)}
86+
{vacancy && !isMyCrew && !isParticipant && (
87+
<ToolTipWrapper>
88+
<Text>모집중</Text>
89+
</ToolTipWrapper>
90+
)}
8091
</CrewProfileInfo>
8192
<Text size={20} weight={700}>
8293
크루 소개
@@ -125,7 +136,7 @@ export const CrewsDetailPage = () => {
125136
</InfoItem>
126137
</Flex>
127138
<ButtonWrapper>
128-
{renderManageButton && (
139+
{isMyCrew && (
129140
<Button
130141
{...theme.BUTTON_PROPS.LARGE_RED_BUTTON_PROPS}
131142
height="50px"
@@ -137,28 +148,16 @@ export const CrewsDetailPage = () => {
137148
크루 관리
138149
</Button>
139150
)}
140-
{renderParticipateButton && (
141-
<ErrorBoundary
142-
fallback={<></>}
143-
onError={() => toast.error('크루 가입여부를 불러올 수 없습니다')}
144-
>
151+
{loginInfo && !isMyCrew && (
152+
<ErrorBoundary fallback={<></>}>
145153
<ParticipateButton
146-
memberId={Number(loginInfo.id)}
154+
loginId={loginInfo.id!}
147155
crewId={crew.id}
148-
onClick={() =>
149-
participateMutate(
150-
{ crewId: crew.id },
151-
{
152-
onSuccess: () => {
153-
toast('가입 신청되었습니다');
154-
},
155-
}
156-
)
157-
}
156+
vacancy={vacancy}
158157
/>
159158
</ErrorBoundary>
160159
)}
161-
{loginInfo === null && (
160+
{loginInfo === null && vacancy && (
162161
<Button
163162
{...theme.BUTTON_PROPS.LARGE_RED_BUTTON_PROPS}
164163
height="50px"
@@ -168,6 +167,15 @@ export const CrewsDetailPage = () => {
168167
로그인 후 가입 신청하기
169168
</Button>
170169
)}
170+
{loginInfo === null && !vacancy && (
171+
<Button
172+
{...theme.BUTTON_PROPS.LARGE_GRAY_OUTLINED_BUTTON_PROPS}
173+
height="50px"
174+
width="100%"
175+
>
176+
신청 마감
177+
</Button>
178+
)}
171179
</ButtonWrapper>
172180
</PageContent>
173181
</PageWrapper>
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,70 @@
1+
import toast from 'react-hot-toast';
2+
13
import { Button } from '@components/shared/Button';
24

5+
import { useCrewParticipateCreateMutation } from '@hooks/mutations/useCrewParticipateCreateMutation';
36
import { useCrewRegistrationStatusQuery } from '@hooks/queries/useCrewRegistrationStatusQuery';
47

58
import { theme } from '@styles/theme';
69

710
export const ParticipateButton = ({
8-
memberId,
11+
loginId,
912
crewId,
10-
onClick,
13+
vacancy,
1114
}: {
12-
memberId: number;
15+
loginId: number;
1316
crewId: number;
14-
onClick: VoidFunction;
17+
vacancy: boolean;
1518
}) => {
1619
const {
17-
data: { registrationStatus },
18-
} = useCrewRegistrationStatusQuery({ memberId, crewId });
20+
data: { memberRegistrationStatus },
21+
} = useCrewRegistrationStatusQuery({ memberId: loginId, crewId });
22+
const { mutate: participateMutate } = useCrewParticipateCreateMutation();
23+
24+
if (memberRegistrationStatus === '없음' && !vacancy) {
25+
return (
26+
<Button
27+
{...theme.BUTTON_PROPS.LARGE_GRAY_OUTLINED_BUTTON_PROPS}
28+
height="50px"
29+
width="100%"
30+
>
31+
신청 마감
32+
</Button>
33+
);
34+
}
1935

20-
if (registrationStatus) {
21-
return null;
36+
if (memberRegistrationStatus === '없음') {
37+
return (
38+
<Button
39+
{...theme.BUTTON_PROPS.LARGE_RED_BUTTON_PROPS}
40+
height="50px"
41+
width="100%"
42+
onClick={() =>
43+
participateMutate(
44+
{ crewId },
45+
{
46+
onSuccess: () => {
47+
toast('가입 신청되었습니다');
48+
},
49+
}
50+
)
51+
}
52+
>
53+
참여 신청하기
54+
</Button>
55+
);
2256
}
2357

24-
return (
58+
if (memberRegistrationStatus === '대기') {
2559
<Button
2660
{...theme.BUTTON_PROPS.LARGE_RED_BUTTON_PROPS}
2761
height="50px"
2862
width="100%"
29-
onClick={onClick}
63+
onClick={() => toast('준비중인 기능입니다')}
3064
>
31-
참여 신청하기
32-
</Button>
33-
);
65+
참여 취소하기
66+
</Button>;
67+
}
68+
69+
return null;
3470
};

src/pages/GamesDetailPage/GamesDetailPage.styles.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Text } from '@components/shared/Text';
55

66
export const TextContainer = styled.div`
77
display: flex;
8+
align-items: center;
89
gap: 5px;
910
`;
1011

0 commit comments

Comments
 (0)