Skip to content

Commit fbcb1ef

Browse files
committed
feature login flow on app
1 parent 90536af commit fbcb1ef

File tree

16 files changed

+256
-56
lines changed

16 files changed

+256
-56
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
"prepare": "husky",
1111
"graph": "nx run-many --target=build --graph",
1212
"storybook": "nx storybook @ahhachul/storybook",
13+
"dev:app": "yarn workspace ahhachul.com start",
1314
"dev:one-app": "yarn workspace @ahhachul/one-app dev",
1415
"test:one-app": "yarn workspace @ahhachul/one-app test",
1516
"dev:mocking": "yarn workspace @ahhachul/one-app dev:mocking",
1617
"server:mocking": "yarn workspace @ahhachul/one-app server:mocking",
18+
"build:app": "nx build ahhachul.com",
1719
"build:one-app": "nx build @ahhachul/one-app",
1820
"build:all": "nx run-many --target=build --all",
19-
"build:app": "nx build ahhachul.com",
2021
"start:one-app": "yarn workspace @ahhachul/one-app start"
2122
},
2223
"lint-staged": {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { SignIn } from 'pages/sign-in/ui/Page/Page';
22
import { SetupNickname } from 'pages/sign-in/ui/Page/SetupNickname';
3+
import { SignInCallback } from 'pages/sign-in/ui/Page/SignInCallback';
34

45
export const signInLayers = {
56
SignIn,
7+
SignInCallback,
68
SetupNickname,
7-
// LostDetail,
8-
// LostEditor,
99
};

services/ahhachul.com/src/app/stackflow/plugins/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ const stackflowPlugin = [
2020
historySyncPlugin({
2121
routes: {
2222
// sign-in pages
23-
SignIn: PATH.authentication.signIn.home,
24-
SetupNickname: PATH.authentication.signIn.setting.nickname,
23+
SignIn: PATH.authentication.login.home,
24+
SignInCallback: PATH.authentication.login.callback,
25+
SetupNickname: PATH.authentication.login.setting.nickname,
2526

2627
// main pages
2728
Home: PATH.home,

services/ahhachul.com/src/entities/app-authentications/api/index.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface APIRedirectUrlResponse {
1717
redirectUrl: string;
1818
}
1919

20-
const getRedirectUrl = (params: APIRedirectUrlParams) =>
20+
export const getRedirectUrl = (params: APIRedirectUrlParams) =>
2121
base.get<IResponse<APIRedirectUrlResponse>>(
2222
`${routes.auth}/redirect-url?${queryString.stringify(params)}`,
2323
);
@@ -48,23 +48,17 @@ interface APISocialSignInResponse extends IToken {
4848
isNeedAdditionalUserInfo: boolean;
4949
}
5050

51-
const login = (body: APISocialSignInParams) =>
51+
export const requestLogin = (body: APISocialSignInParams) =>
5252
base.post<IResponse<APISocialSignInResponse>>(`${routes.auth}/login`, body);
5353

5454
export const useLogin = () => {
5555
const setToken = useAuthStore((state) => state.setToken);
5656

5757
return useMutation({
58-
mutationFn: login,
58+
mutationFn: requestLogin,
5959
onSuccess({
6060
data: {
61-
result: {
62-
accessToken,
63-
refreshToken,
64-
accessTokenExpiresIn,
65-
refreshTokenExpiresIn,
66-
isNeedAdditionalUserInfo,
67-
},
61+
result: { accessToken, refreshToken, isNeedAdditionalUserInfo },
6862
},
6963
}) {
7064
if (isNeedAdditionalUserInfo) {
@@ -75,8 +69,6 @@ export const useLogin = () => {
7569
setToken({
7670
accessToken,
7771
refreshToken,
78-
accessTokenExpiresIn,
79-
refreshTokenExpiresIn,
8072
});
8173
},
8274
onError(err) {

services/ahhachul.com/src/entities/app-authentications/model/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,4 @@ export interface IToken {
1414
accessToken: string;
1515
/** 리프레시 토큰 */
1616
refreshToken: string;
17-
/** 액세스 토큰 만료 시간 */
18-
accessTokenExpiresIn: number;
19-
/** 리프레시 토큰 만료 시간 */
20-
refreshTokenExpiresIn: number;
2117
}

services/ahhachul.com/src/entities/app-authentications/slice/index.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { persist } from 'zustand/middleware';
33
import { type IToken } from 'entities/app-authentications/model';
44

55
interface IAuthStore {
6-
state: Nullable<IToken>;
6+
auth: Nullable<IToken>;
77
}
88

99
export const useAuthStore = create(
@@ -13,9 +13,9 @@ export const useAuthStore = create(
1313
}
1414
>(
1515
(set) => ({
16-
state: null,
17-
setToken: (state: Nullable<IToken>) => {
18-
set({ state });
16+
auth: null,
17+
setToken: (auth: Nullable<IToken>) => {
18+
set({ auth });
1919
},
2020
}),
2121
{
@@ -39,3 +39,15 @@ export const useSocialLoginModal = create<
3939
active,
4040
})),
4141
}));
42+
43+
interface TemporaryAuthState {
44+
auth: Nullable<IToken>;
45+
setTempAuth: (authData: IToken) => void;
46+
reset: () => void;
47+
}
48+
49+
export const useTemporaryAuthStore = create<TemporaryAuthState>((set) => ({
50+
auth: null,
51+
setTempAuth: (authData: IToken) => set({ auth: authData }),
52+
reset: () => set({ auth: null }),
53+
}));
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import cssUtils from 'shared/utils.css';
3+
4+
const SVG = `
5+
<svg
6+
width="18"
7+
height="18"
8+
viewBox="0 0 18 18"
9+
fill="none"
10+
xmlns="http://www.w3.org/2000/svg"
11+
>
12+
<path
13+
d="M12.8015 0C12.8434 0 12.8853 0 12.9295 0C13.0323 1.26946 12.5477 2.218 11.9589 2.90489C11.381 3.58705 10.5898 4.24865 9.31008 4.14827C9.22471 2.89699 9.71004 2.0188 10.2981 1.33348C10.8435 0.694803 11.8435 0.126472 12.8015 0Z"
14+
fill="black"
15+
/>
16+
<path
17+
d="M16.6754 13.2123C16.6754 13.225 16.6754 13.236 16.6754 13.2479C16.3158 14.3371 15.8028 15.2706 15.1768 16.137C14.6053 16.9235 13.9049 17.9819 12.6544 17.9819C11.5739 17.9819 10.8562 17.2871 9.74875 17.2681C8.57731 17.2491 7.9331 17.8491 6.86204 18.0001C6.73952 18.0001 6.617 18.0001 6.49685 18.0001C5.71036 17.8862 5.07563 17.2634 4.61322 16.7021C3.2497 15.0438 2.19603 12.9017 2 10.1604C2 9.89164 2 9.62368 2 9.35493C2.083 7.39304 3.03628 5.79792 4.30336 5.02486C4.97208 4.61383 5.89137 4.26366 6.915 4.42017C7.3537 4.48815 7.80188 4.63833 8.19473 4.78694C8.56704 4.93001 9.03261 5.18374 9.47368 5.1703C9.77247 5.16161 10.0697 5.00589 10.3708 4.89602C11.253 4.57747 12.1177 4.21228 13.2575 4.38381C14.6274 4.5909 15.5996 5.19955 16.2004 6.1386C15.0416 6.87609 14.1255 7.98746 14.282 9.88532C14.4211 11.6093 15.4234 12.6179 16.6754 13.2123Z"
18+
fill="black"
19+
/>
20+
</svg>
21+
`;
22+
23+
export const AppleIcon = () => (
24+
<div
25+
css={[cssUtils.flexCenterCenter]}
26+
dangerouslySetInnerHTML={{ __html: SVG }}
27+
/>
28+
);

services/ahhachul.com/src/entities/app-authentications/ui/SocialLogin.tsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@ import styled from '@emotion/styled';
33
import { motion } from 'framer-motion';
44
import { fadeInAndUpVariants } from 'shared/lib/config/animation/framer-motion';
55

6-
import { useFlow } from 'app/stackflow';
7-
import { useGetSignInRedirectUrl } from '../api';
6+
import { getRedirectUrl } from '../api';
87
import { KakaoIcon } from '../static/icons/kakao';
98
import { GoogleIcon } from '../static/icons/google';
9+
import type { ISocialSignInType } from '../model';
10+
import { AppleIcon } from '../static/icons/apple';
1011

1112
export const SocialLogin = () => {
12-
const { push } = useFlow();
13-
const urls = useGetSignInRedirectUrl();
14-
console.log('urls:', urls);
15-
16-
const clickLogin = () => push('SetupNickname', {});
13+
const clickLogin = async (loginType: ISocialSignInType) => {
14+
try {
15+
const res = await getRedirectUrl({ providerType: loginType });
16+
window.location.assign(res.data.result.redirectUrl);
17+
} catch (error) {
18+
alert('로그인 정보를 불러오는데 실패했어요. (unknown)');
19+
}
20+
};
1721

1822
return (
1923
<SocialGroup
@@ -22,14 +26,18 @@ export const SocialLogin = () => {
2226
initial="initial"
2327
variants={fadeInAndUpVariants(0.3)}
2428
>
25-
<KakaoLogin onClick={clickLogin}>
26-
<KakaoIcon />
27-
<span>Kakao로 계속하기</span>
28-
</KakaoLogin>
29-
<GoogleLogin onClick={clickLogin}>
29+
<GoogleLogin onClick={() => clickLogin('GOOGLE')}>
3030
<GoogleIcon />
3131
<span>Google로 계속하기</span>
3232
</GoogleLogin>
33+
<GoogleLogin onClick={() => clickLogin('APPLE')}>
34+
<AppleIcon />
35+
<span>Apple로 계속하기</span>
36+
</GoogleLogin>
37+
<KakaoLogin onClick={() => clickLogin('KAKAO')}>
38+
<KakaoIcon />
39+
<span>Kakao로 계속하기</span>
40+
</KakaoLogin>
3341
</SocialGroup>
3442
);
3543
};
Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,29 @@
1+
import axios from 'axios';
2+
import { IToken } from 'entities/app-authentications';
13
import { type IResponse } from 'entities/with-server';
2-
import { base, routes, useAuthMutation } from 'shared/api';
4+
import { base, routes, useAuthMutation, useAuthQuery } from 'shared/api';
5+
6+
export const GET_USER_INFO_QUERY_KEY = ['USER', 'INFO'];
37

48
interface APICheckNicknameParams {
59
nickname: string;
610
}
711
interface APINicknameResponse {
812
available: boolean;
913
}
14+
interface APIUpdateUserResponse {
15+
nickname: string;
16+
gender: string | null;
17+
ageRange: string | null;
18+
}
19+
20+
interface APIUserInfoResponse {
21+
memberId: number;
22+
nickname: string;
23+
email: string | null;
24+
gender: string | null;
25+
ageRange: string | null;
26+
}
1027

1128
const checkNickname = (body: APICheckNicknameParams) =>
1229
base.post<IResponse<APINicknameResponse>>(
@@ -15,3 +32,43 @@ const checkNickname = (body: APICheckNicknameParams) =>
1532
);
1633
export const useCheckNickName = () =>
1734
useAuthMutation({ mutationFn: checkNickname });
35+
36+
export const updateUser = async (data: { nickname: string; auth: IToken }) => {
37+
try {
38+
const accessToken = data.auth.accessToken;
39+
const res = await axios.patch<APIUpdateUserResponse>(
40+
`${process.env.REACT_APP_BASE_URL}/members`,
41+
{ nickname: data.nickname },
42+
{
43+
headers: {
44+
Authorization: `Bearer ${accessToken}`,
45+
},
46+
},
47+
);
48+
49+
return res.data;
50+
} catch (error) {
51+
if (axios.isAxiosError(error)) {
52+
throw new Error(
53+
`Update user failed: ${error.response?.data?.message || error.message}`,
54+
);
55+
} else {
56+
console.error('Unexpected error during user update:', error);
57+
throw new Error('An unexpected error occurred during user update.');
58+
}
59+
}
60+
};
61+
62+
const getUserInfo = () =>
63+
base.post<IResponse<APIUserInfoResponse>>(routes.users);
64+
65+
export const useGetUserInfo = (auth: Nullable<IToken>) =>
66+
useAuthQuery({
67+
queryFn: getUserInfo,
68+
queryKey: GET_USER_INFO_QUERY_KEY,
69+
options: {
70+
enabled: !!auth,
71+
staleTime: 10 * 60 * 1000,
72+
select: (res) => res.data.result,
73+
},
74+
});

services/ahhachul.com/src/features/users/ui/CheerUpPhrase/CheerUpPhrase.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import React, { type HTMLAttributes } from 'react';
22
import { getRandomPhrase } from 'features/users/lib/getRandomPhrase';
33
import * as styles from './CheerUpPhrase.css';
4+
import { useGetUserInfo } from 'features/users/api';
5+
import { useAuthStore } from 'entities/app-authentications/slice';
46

57
interface CTAFlowsProps extends HTMLAttributes<HTMLHeadingElement> {}
68

79
const phrase = getRandomPhrase();
810
export const CheerUpPhrase = ({ ...props }: CTAFlowsProps) => {
9-
let username = '이효범';
11+
const { auth } = useAuthStore();
12+
const { data: userInfo } = useGetUserInfo(auth);
13+
const username = userInfo?.nickname || '아하철';
1014

1115
return (
1216
<h1 css={styles.cheerUpPhrase} {...props}>

0 commit comments

Comments
 (0)