Skip to content

Commit 0b976b0

Browse files
authored
Merge pull request #643 from depromeet/develop
[v2.4.7] 배포용 PR
2 parents d4b57fb + a651584 commit 0b976b0

23 files changed

+533
-209
lines changed

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @wooBottle @wade3420 @junoshon @sumi-0011
1+
* @wooBottle @wade3420 @sumi-0011

public/assets/character/basic.png

1.01 MB
Loading

public/assets/character/flag.png

1.1 MB
Loading

public/assets/character/sad.png

1.05 MB
Loading

src/apis/auth.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface LoginResponse {
1818
accessToken: string;
1919
refreshToken: string;
2020
memberId?: number;
21+
landingStatus?: 'TO_MAIN' | 'TO_ONBOARDING';
2122
}
2223

2324
interface RegisterRequest {

src/app/auth/kakaoCallback/page.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useRouter, useSearchParams } from 'next/navigation';
55
import { useSocialLogin } from '@/apis/auth';
66
import Loading from '@/components/Loading';
77
import { AUTH_PROVIDER } from '@/constants/common';
8+
import { EVENT_LOG_CATEGORY, EVENT_LOG_NAME } from '@/constants/eventLog';
89
import { ROUTER } from '@/constants/router';
910
import { eventLogger } from '@/utils';
1011

@@ -32,7 +33,11 @@ export default function KakaoCallbackPage() {
3233
if (successData?.memberId) {
3334
eventLogger.identify(successData.memberId.toString());
3435
}
35-
36+
if (successData.landingStatus === 'TO_ONBOARDING') {
37+
eventLogger.logEvent(EVENT_LOG_CATEGORY.ONBOARDING, EVENT_LOG_NAME.ONBOARDING.SUCCESS_SIGNUP);
38+
router.push(ROUTER.ONBOARDING.HOME);
39+
return;
40+
}
3641
router.push(params.get('state') ?? ROUTER.HOME);
3742
},
3843
},

src/app/auth/login/page.tsx

+11-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useSocialLogin, useUpdateMemberFcmToken } from '@/apis/auth';
77
// import Button from '@/components/Button/Button';
88
import ButtonSocialLogin from '@/components/ButtonSocialLogin/ButtonSocialLogin';
99
import { AUTH_PROVIDER, WINDOW_CUSTOM_EVENT } from '@/constants/common';
10+
import { EVENT_LOG_CATEGORY, EVENT_LOG_NAME } from '@/constants/eventLog';
1011
import { NATIVE_CUSTOM_EVENTS } from '@/constants/nativeCustomEvent';
1112
import { ROUTER } from '@/constants/router';
1213
import { eventLogger } from '@/utils';
@@ -35,9 +36,6 @@ export default function LoginPage() {
3536
const { mutate: updateMemberFcmTokenMutate } = useUpdateMemberFcmToken();
3637
const search = useSearchParams();
3738
const redirectUrl = search.get('redirect') ?? ROUTER.HOME;
38-
// const onClickGuest = () => {
39-
// router.push(ROUTER.GUEST.MISSION.NEW);
40-
// };
4139

4240
const onClickAppleLogin = () => {
4341
if (isWebView()) {
@@ -81,6 +79,11 @@ export default function LoginPage() {
8179
if (data?.memberId) {
8280
eventLogger.identify(data.memberId.toString());
8381
}
82+
if (data.landingStatus === 'TO_ONBOARDING') {
83+
eventLogger.logEvent(EVENT_LOG_CATEGORY.ONBOARDING, EVENT_LOG_NAME.ONBOARDING.SUCCESS_SIGNUP);
84+
router.push(ROUTER.ONBOARDING.HOME);
85+
return;
86+
}
8487
router.push(redirectUrl);
8588
},
8689
},
@@ -103,6 +106,11 @@ export default function LoginPage() {
103106
updateMemberFcmTokenMutate({ fcmToken: event.detail.data.deviceToken });
104107
}
105108
// 지금 당장은 필요없지만 나중을 위해 작동하도록 한다
109+
if (data.landingStatus === 'TO_ONBOARDING') {
110+
eventLogger.logEvent(EVENT_LOG_CATEGORY.ONBOARDING, EVENT_LOG_NAME.ONBOARDING.SUCCESS_SIGNUP);
111+
router.push(ROUTER.ONBOARDING.HOME);
112+
return;
113+
}
106114
router.push(redirectUrl);
107115
},
108116
onError: () => {

src/app/mission/new/MissionRegistration.tsx

-96
This file was deleted.

src/app/mission/new/page.tsx

+105-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,114 @@
1-
import MissionRegistration from '@/app/mission/new/MissionRegistration';
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { type MissionCategory, type MissionVisibility } from '@/apis/schema/mission';
5+
import useCreateMissionMutation from '@/app/mission/new/useCreateMissionMutation';
26
import Header from '@/components/Header/Header';
7+
import Input from '@/components/Input/Input';
8+
import { type DropdownValueType } from '@/components/Input/Input.types';
9+
import { useSnackBar } from '@/components/SnackBar/SnackBarProvider';
10+
import { MISSION_CATEGORY_LIST, PUBLIC_SETTING_LIST } from '@/constants/mission';
11+
import { flex } from '@/styled-system/patterns';
312
import { css } from '@styled-system/css';
413

514
export default function MissionNewPage() {
15+
const { triggerSnackBar } = useSnackBar();
16+
17+
const [missionTitleInput, setMissionTitleInput] = useState('');
18+
const [missionContentInput, setMissionContentInput] = useState('');
19+
const [missionCategory, setMissionCategory] = useState<DropdownValueType<MissionCategory> | null>(null);
20+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
21+
const [missionPublicSetting, setMissionPublicSetting] = useState<DropdownValueType<MissionVisibility>>(
22+
PUBLIC_SETTING_LIST[1],
23+
);
24+
25+
const isSubmitButtonDisabled = !missionTitleInput || !missionCategory;
26+
27+
const { mutate } = useCreateMissionMutation();
28+
// 미션 명
29+
const handleMissionTitleInput = (value: string) => {
30+
setMissionTitleInput(value);
31+
};
32+
// 미션 내용
33+
const handleMissionContentInput = (value: string) => {
34+
setMissionContentInput(value);
35+
};
36+
37+
const handleSubmit = () => {
38+
if (!missionCategory) {
39+
triggerSnackBar({
40+
message: '미션 제목을 입력해주세요.',
41+
});
42+
return;
43+
}
44+
45+
mutate({
46+
name: missionTitleInput,
47+
content: missionContentInput,
48+
category: missionCategory.value,
49+
visibility: missionPublicSetting.value,
50+
});
51+
};
652
return (
753
<main className={mainWrapperCss}>
8-
<Header title={'미션 등록'} rightAction="none" />
54+
<Header
55+
title={'미션 생성'}
56+
rightAction="text-button"
57+
rightButtonText="등록"
58+
rightButtonProps={{ disabled: isSubmitButtonDisabled, onClick: handleSubmit }}
59+
/>
960
<div className={containerCss}>
1061
<h1 className={mainTitleCss}>
11-
하루 <strong>10분</strong> 2주 동안
62+
하루 <strong>10분씩</strong> 2주 동안
1263
<br />
1364
어떤 일에 투자하고 싶은가요?
1465
</h1>
15-
<MissionRegistration />
66+
<section className={sectionCss}>
67+
<Input
68+
type="text"
69+
placeholder="미션명 입력"
70+
name="미션명"
71+
required
72+
maxLength={20}
73+
value={missionTitleInput}
74+
onChange={handleMissionTitleInput}
75+
/>
76+
<Input
77+
type="text"
78+
placeholder="미션 내용 입력"
79+
name="미션내용"
80+
maxLength={30}
81+
value={missionContentInput}
82+
onChange={handleMissionContentInput}
83+
/>
84+
85+
{/* 카테고리 */}
86+
<Input
87+
variant="drop-down"
88+
title="카테고리"
89+
required
90+
list={MISSION_CATEGORY_LIST}
91+
placeholder="카테고리 선택"
92+
selected={missionCategory}
93+
onSelect={(item) => setMissionCategory(item)}
94+
/>
95+
{/* TODO: 이후에 삭제 - 미션 기간, 알림 설정 Input 생기며 리스트 여백 수정 */}
96+
<hr
97+
className={css({
98+
height: '12px',
99+
opacity: 0,
100+
})}
101+
/>
102+
103+
{/* 공개설정 */}
104+
<Input
105+
variant="drop-down"
106+
title="공개설정"
107+
list={PUBLIC_SETTING_LIST}
108+
selected={missionPublicSetting}
109+
onSelect={(item) => setMissionPublicSetting(item)}
110+
/>
111+
</section>
16112
</div>
17113
</main>
18114
);
@@ -46,3 +142,8 @@ const mainTitleCss = css({
46142
textStyle: 'title2',
47143
},
48144
});
145+
146+
const sectionCss = flex({
147+
flexDirection: 'column',
148+
gap: '12px',
149+
});
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React from 'react';
2+
import Button from '@/components/Button/Button';
3+
import Thumbnail from '@/components/Thumbnail/Thumbnail';
4+
import { css } from '@styled-system/css';
5+
6+
interface RecommendFollowItemProps {
7+
id: number;
8+
nickname: string;
9+
profileImageUrl: string | null;
10+
tags: string[];
11+
onChangeFollow: (id: number) => void;
12+
isFollowing: boolean;
13+
}
14+
15+
function RecommendFollowItem({
16+
profileImageUrl,
17+
nickname,
18+
tags,
19+
onChangeFollow,
20+
isFollowing,
21+
id,
22+
}: RecommendFollowItemProps) {
23+
const handleFollow = () => {
24+
onChangeFollow(id);
25+
};
26+
27+
return (
28+
<div className={followItemWrapperCss}>
29+
<div className={leftWrapperCss}>
30+
<Thumbnail size={'h36'} variant={'filled'} url={profileImageUrl} />
31+
<div>
32+
<p className={nicknameCss}>{nickname}</p>
33+
<ul className={tagListCss}>
34+
{tags.map((tag, index) => (
35+
<li className={tagCss} key={index}>
36+
{tag}
37+
</li>
38+
))}
39+
</ul>
40+
</div>
41+
</div>
42+
<Button onClick={handleFollow} size={'small'} variant={isFollowing ? 'secondary' : 'primary'}>
43+
{isFollowing ? '팔로우' : '팔로잉'}
44+
</Button>
45+
</div>
46+
);
47+
}
48+
49+
export default React.memo(RecommendFollowItem);
50+
51+
const leftWrapperCss = css({
52+
display: 'flex',
53+
alignItems: 'center',
54+
gap: '12px',
55+
});
56+
57+
const nicknameCss = css({
58+
textStyle: 'subtitle4',
59+
color: 'text.secondary',
60+
});
61+
const tagListCss = css({
62+
display: 'flex',
63+
gap: '6px',
64+
});
65+
66+
const tagCss = css({
67+
textStyle: 'body6',
68+
color: 'text.tertiary',
69+
});
70+
71+
const followItemWrapperCss = css({
72+
display: 'flex',
73+
justifyContent: 'space-between',
74+
75+
width: '100%',
76+
padding: '8px',
77+
});

0 commit comments

Comments
 (0)