Skip to content

Commit 48c7cf5

Browse files
authored
fix: 바뀐 명세 반영( 홈팝업 UX라이팅, subtitle 추가) (#2074)
* feat: 작업 궁합 레이아웃 변경 * feat: 내 작업 성향 조회 api 연결 * chore: 사용하지 않는 선언 제거 * chore: 홈팝업 라이팅 변경 * fix: 토스트 무한오픈 수정 * chore: 궁합 subtitle 색상 지정
1 parent 8dbe3d8 commit 48c7cf5

5 files changed

Lines changed: 136 additions & 34 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useQuery } from '@tanstack/react-query';
2+
import { z } from 'zod';
3+
4+
import { createEndpoint } from '@/api/typedAxios';
5+
6+
export const getMyWorkPreference = createEndpoint({
7+
request: {
8+
method: 'GET',
9+
url: 'api/v1/members/work-preference',
10+
},
11+
serverResponseScheme: z.object({
12+
workPreference: z.object({
13+
ideationStyle: z.union([z.literal('즉흥'), z.literal('숙고')]),
14+
workTime: z.union([z.literal('아침'), z.literal('밤')]),
15+
communicationStyle: z.union([z.literal('몰아서'), z.literal('나눠서')]),
16+
workPlace: z.union([z.literal('카공'), z.literal('집콕')]),
17+
feedbackStyle: z.union([z.literal('직설적'), z.literal('돌려서')]),
18+
}),
19+
}),
20+
});
21+
22+
export const useGetMyWorkPreference = () => {
23+
return useQuery({
24+
queryKey: ['getMyWorkPreference'],
25+
queryFn: () => getMyWorkPreference.request(),
26+
});
27+
};

src/components/matchmember/MatchContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const MatchContent = ({
5555
<Spacing size={24} />
5656
<LoggingClick eventKey='balancegame'>
5757
<Button size='lg' onClick={onNextStep}>
58-
5초만에 소울메이트 찾기
58+
앱잼 소울메이트 보러가기
5959
</Button>
6060
</LoggingClick>
6161
<CloseForTodayButton

src/components/matchmember/MemberCard.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,39 @@ import Text from '@/components/common/Text';
55
import ProfileIcon from 'public/icons/icon-profile.svg';
66
import ResizedImage from '@/components/common/ResizedImage';
77
import { useGetRecommendations } from '@/api/endpoint/members/getRecommendations';
8-
import { useState } from 'react';
9-
import { Skeleton } from '@sopt-makers/ui';
8+
import { useEffect, useState } from 'react';
9+
import { Skeleton, useToast } from '@sopt-makers/ui';
1010
import { playgroundLink } from '@/constants/links';
1111
import { useRouter } from 'next/router';
1212
import NonIcon from '@/public/icons/img/popup/member_match_search.svg';
1313
import useEventLogger from '@/components/eventLogger/hooks/useEventLogger';
1414
import { useRunOnce } from '@/hooks/useRunOnce';
15+
import axios from 'axios';
1516

1617
export const MemberCard = () => {
17-
const { data, isPending } = useGetRecommendations();
18+
const { data, isPending, isError, error } = useGetRecommendations();
1819
const [_isImageLoaded, setIsImageLoaded] = useState(false);
1920
const router = useRouter();
2021
const { logImpressionEvent } = useEventLogger();
22+
const { open: toastOpen } = useToast();
2123

2224
useRunOnce(() => {
2325
logImpressionEvent('feedCard', { screen: '기획경선 홈팝업' });
2426
}, []);
2527

28+
useEffect(() => {
29+
if (isError) {
30+
const status =
31+
axios.isAxiosError(error) && !!error.response && typeof error.response.status === 'number'
32+
? error.response.status
33+
: null;
34+
35+
const errorMessage =
36+
status === 400 ? `밸런스게임을 먼저 진행해주세요` : `데이터를 불러오는 중 오류가 발생했습니다.`;
37+
toastOpen({ icon: 'error', content: errorMessage });
38+
}
39+
}, [isError, error]);
40+
2641
if (isPending)
2742
return (
2843
<CardWrapper>

src/components/matchmember/constant.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,12 @@ export const convertAnswersToApiPayload = (answers: BalanceGameValue): WorkPrefe
6161

6262
return payload as WorkPreferenceType;
6363
};
64+
65+
export const convertWorkPreferenceToHashtags = (preference: WorkPreferenceType): string => {
66+
if (!preference) return '';
67+
68+
const tags = Object.values(preference);
69+
const hashtagString = tags.map((tag) => `#${tag}`).join(' ');
70+
71+
return hashtagString;
72+
};

src/components/members/main/MemberList/WorkPreferenceMatchedMemberList.tsx

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery';
1414
import MatchMemberModal from '@/components/matchmember/MatchMemberModal';
1515
import { useMatchMemberEvent } from '@/components/matchmember/hooks/useMatchMemberEvent';
1616
import useModalState from '@/components/common/Modal/useModalState';
17+
import { fonts } from '@sopt-makers/fonts';
18+
import { useGetMyWorkPreference } from '@/api/endpoint/members/getWorkPreference';
19+
import { convertWorkPreferenceToHashtags } from '@/components/matchmember/constant';
20+
21+
const MyPreferenceSubTitle = () => {
22+
const { data: myData, isLoading: myLoading } = useGetMyWorkPreference();
23+
24+
if (myLoading || !myData?.workPreference) return <></>;
25+
26+
const tags = convertWorkPreferenceToHashtags(myData.workPreference);
27+
28+
return <SubTitle>내 작업 스타일은 {tags}</SubTitle>;
29+
};
30+
1731
const WorkPreferenceMatchedMemberList = () => {
1832
const { data, isLoading } = useGetRecommendations();
1933
const isEmpty = data?.recommendations && data.recommendations.length === 0;
@@ -47,41 +61,44 @@ const WorkPreferenceMatchedMemberList = () => {
4761
return (
4862
<>
4963
<StyledContainer>
50-
<TitleWrapper>
51-
<Responsive only='desktop'>
52-
<Text typography='SUIT_20_B' color={colors.gray10}>
53-
나와 37기 사람들의 작업 궁합은?
54-
</Text>
55-
</Responsive>
56-
<Responsive only='mobile'>
57-
<Text typography='SUIT_16_B' color={colors.gray10}>
58-
나와 37기 사람들의 작업 궁합은?
59-
</Text>
60-
</Responsive>
61-
<RefreshIconWrapper>
62-
<button
63-
onClick={() => {
64-
queryClient.invalidateQueries({ queryKey: ['getRecommendations'] });
65-
}}
66-
>
67-
<RefreshIcon style={{ width: '24px', height: '24px', flexShrink: 0, cursor: 'pointer' }} />
68-
</button>
64+
<TitleContainer>
65+
<TitleWrapper>
66+
<Responsive only='desktop'>
67+
<Text typography='SUIT_24_B' color={colors.gray10}>
68+
나와 37기 사람들의 작업 궁합은?
69+
</Text>
70+
</Responsive>
6971
<Responsive only='mobile'>
70-
<MobileTooltipWrapper>
72+
<Text typography='SUIT_16_B' color={colors.gray10}>
73+
나와 37기 사람들의 작업 궁합은?
74+
</Text>
75+
</Responsive>
76+
<RefreshIconWrapper>
77+
<button
78+
onClick={() => {
79+
queryClient.invalidateQueries({ queryKey: ['getRecommendations'] });
80+
}}
81+
>
82+
<StyledRefreshIcon />
83+
</button>
84+
<Responsive only='mobile'>
85+
<MobileTooltipWrapper>
86+
<Text typography='SUIT_13_M' color={colors.gray50}>
87+
더 많은 멤버를 찾아보세요!
88+
</Text>
89+
</MobileTooltipWrapper>
90+
</Responsive>
91+
</RefreshIconWrapper>
92+
<Responsive only='desktop'>
93+
<TooltipWrapper>
7194
<Text typography='SUIT_13_M' color={colors.gray50}>
7295
더 많은 멤버를 찾아보세요!
7396
</Text>
74-
</MobileTooltipWrapper>
97+
</TooltipWrapper>
7598
</Responsive>
76-
</RefreshIconWrapper>
77-
<Responsive only='desktop'>
78-
<TooltipWrapper>
79-
<Text typography='SUIT_13_M' color={colors.gray50}>
80-
더 많은 멤버를 찾아보세요!
81-
</Text>
82-
</TooltipWrapper>
83-
</Responsive>
84-
</TitleWrapper>
99+
</TitleWrapper>
100+
<MyPreferenceSubTitle />
101+
</TitleContainer>
85102
{isEmpty ? (
86103
<EmptyStateWrapper>
87104
<WorkPreferenceMemberListWrapper isEmpty={isEmpty}>
@@ -100,6 +117,7 @@ const WorkPreferenceMatchedMemberList = () => {
100117
: '나의 작업 스타일을 5초만에 알아보고\n찰떡 케미 앱잼 멤버 확인해요!'}
101118
</Text>
102119

120+
{/* TODO: 작업선택 모달 오픈로직 추가 */}
103121
{!hasWorkPreference && (
104122
<Button variant='fill' theme='white' onClick={handleClickStartButton}>
105123
작업 스타일 선택하기
@@ -174,6 +192,17 @@ const TooltipWrapper = styled.div`
174192
content: '';
175193
}
176194
`;
195+
196+
const TitleContainer = styled.div`
197+
display: flex;
198+
flex-direction: column;
199+
gap: 6px;
200+
201+
@media ${MOBILE_MEDIA_QUERY} {
202+
gap: 2px;
203+
}
204+
`;
205+
177206
const TitleWrapper = styled.div`
178207
display: flex;
179208
gap: 8px;
@@ -243,4 +272,26 @@ const EmptyStateContent = styled.div`
243272
width: 100%;
244273
height: 100%;
245274
`;
275+
276+
const StyledRefreshIcon = styled(RefreshIcon)`
277+
flex-shrink: 0;
278+
cursor: pointer;
279+
width: 32px;
280+
height: 32px;
281+
282+
@media ${MOBILE_MEDIA_QUERY} {
283+
width: 24px;
284+
height: 24px;
285+
}
286+
`;
287+
288+
const SubTitle = styled.p`
289+
${fonts.TITLE_18_SB};
290+
291+
color: ${colors.gray200};
292+
293+
@media ${MOBILE_MEDIA_QUERY} {
294+
${fonts.BODY_13_M};
295+
}
296+
`;
246297
export default WorkPreferenceMatchedMemberList;

0 commit comments

Comments
 (0)