Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 로그인 구축으로 인한 인증 전략 변경 #837

Open
wants to merge 19 commits into
base: fe-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c4fa5b4
fix: 병합하면서 제대로 반영되지 않은 코드 수정
jinhokim98 Nov 21, 2024
64391f1
feat: 이벤트 정보 createdByGuest 필드 추가 반영
jinhokim98 Nov 21, 2024
bf04699
style: 게스트 로그인 페이지로 이름 변경
jinhokim98 Nov 21, 2024
13b80c3
feat: 게스트, 회원 관리 로그인 분리
jinhokim98 Nov 21, 2024
b643c8d
feat: 인증되지 않았을 때 fallback 새로운 url로 이동하도록 설정
jinhokim98 Nov 21, 2024
94fdfa7
feat: 인증 api 요청할 때 세션스토리지에 createdByGuest 저장
jinhokim98 Nov 21, 2024
5c07cf3
feat: 인증되지 않았을 때 이전 페이지 저장 후 로그인 페이지로 이동
jinhokim98 Nov 21, 2024
2f1ff3b
fix: location.pathname으로 navigate 값 수정
jinhokim98 Nov 21, 2024
e8e5e71
feat: 로그인에 성공했을 때 이전의 주소로 이동하는 기능 구현
jinhokim98 Nov 21, 2024
11e06a1
fix: StrictMode에서도 제대로 동작하도록 수정
jinhokim98 Nov 21, 2024
3171653
fix: 이벤트 베이스 url을 기반으로 라우트하는 방식으로 변경
jinhokim98 Nov 21, 2024
7210997
feat: 회원 생성 이벤트 로그인 화면 제작
jinhokim98 Nov 21, 2024
6014624
refactor: kakao redirect uri 변경으로 인한 카카오 로그인 로직 분리
jinhokim98 Nov 21, 2024
b4b2dba
fix: 함수 호출 실수 바로잡기
jinhokim98 Nov 21, 2024
4308e06
feat: 이벤트 전체정보 보장을 위해 useSuspenseQuery 사용
jinhokim98 Nov 21, 2024
8b44b26
style: suspense query를 사용함으로 ? 키워드 삭제
jinhokim98 Nov 21, 2024
03ce768
refactor: createByGuest로 상황에 맞는 navigate 하는 책임 useRequestPostAuthenti…
jinhokim98 Nov 25, 2024
68aeb04
refactor: previousUrl 이중부정구문 긍정으로 개선
jinhokim98 Nov 27, 2024
15f57d6
refactor: 카카오 계정 로그인 강조 길이 변경
jinhokim98 Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/src/components/Design/components/TopNav/NavItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {NavItemProps} from './NavItem.type';

import {useLocation, useNavigate} from 'react-router-dom';

import getDeletedLastPath from '@utils/getDeletedLastPath';
import getEventBaseUrl from '@utils/getEventBaseUrl';

import TextButton from '../TextButton/TextButton';

Expand All @@ -28,7 +28,7 @@ const NavItem = ({displayName, routePath, onHandleRouteInFunnel, noEmphasis = fa
navigate(-1);
break;
default:
navigate(`${getDeletedLastPath(location.pathname)}${routePath}`);
navigate(`/${getEventBaseUrl(location.pathname)}${routePath}`);
break;
}
};
Expand Down
3 changes: 3 additions & 0 deletions client/src/constants/routerUrls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ export const ROUTER_URLS = {
qrCode: `${EVENT_WITH_EVENT_ID}/qrcode`,
event: EVENT,
login: '/login',
guestEventLogin: `${EVENT_WITH_EVENT_ID}/admin/guest/login`,
memberEventLogin: `${EVENT_WITH_EVENT_ID}/admin/member/login`,
kakaoLoginRedirectUri: process.env.KAKAO_REDIRECT_URI,
};
2 changes: 2 additions & 0 deletions client/src/constants/sessionStorageKeys.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const SESSION_STORAGE_KEYS = {
closeAccountBannerByEventToken: (eventToken: string) => `closeAccountBanner-${eventToken}`,
closeDepositStateBannerByEventToken: (eventToken: string) => `closeDepositStateBanner-${eventToken}`,
createdByGuest: 'createdByGuest',
previousUrlForLogin: 'previousUrlForLogin',
} as const;

export default SESSION_STORAGE_KEYS;
4 changes: 2 additions & 2 deletions client/src/hooks/createEvent/useCreateGuestEventData.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {useState} from 'react';

import useSetEventNameStep from './useSetEventNameStep';
import {useSetNickNameStep} from './useSetNicknameStep';
import {useSetNicknameStep} from './useSetNicknameStep';

// 행사 생성 페이지에서 여러 스텝에 걸쳐 사용되는 상태를 선언해 내려주는 용도의 훅입니다.
const useCreateGuestEventData = () => {
const eventNameProps = useSetEventNameStep();
const nickNameProps = useSetNickNameStep();
const nickNameProps = useSetNicknameStep();
const [eventToken, setEventToken] = useState('');

return {
Expand Down
22 changes: 22 additions & 0 deletions client/src/hooks/queries/auth/useRequestPostAuthentication.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
import {useMutation} from '@tanstack/react-query';
import {useNavigate} from 'react-router-dom';

import {requestPostAuthentication} from '@apis/request/auth';

import {useAuthStore} from '@store/authStore';

import getEventIdByUrl from '@utils/getEventIdByUrl';
import SessionStorage from '@utils/SessionStorage';

import SESSION_STORAGE_KEYS from '@constants/sessionStorageKeys';

import useRequestGetEvent from '../event/useRequestGetEvent';

const useRequestPostAuthentication = () => {
const eventId = getEventIdByUrl();
const navigate = useNavigate();
const {updateAuth} = useAuthStore();

const {createdByGuest} = useRequestGetEvent();

const {mutate, ...rest} = useMutation({
mutationFn: () => requestPostAuthentication({eventId}),
onSuccess: () => updateAuth(true),
onError: () => {
if (!window.location.pathname.includes('/guest/login') && !window.location.pathname.includes('/member/login')) {
SessionStorage.set<string>(SESSION_STORAGE_KEYS.previousUrlForLogin, window.location.pathname);

const currentPath = window.location.pathname;

if (createdByGuest) {
navigate(`${currentPath}/guest/login`);
} else {
navigate(`${currentPath}/member/login`);
}
}
},
});

return {
Expand Down
14 changes: 13 additions & 1 deletion client/src/hooks/queries/auth/useRequestPostLogin.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import {useMutation} from '@tanstack/react-query';
import {useNavigate} from 'react-router-dom';

import {RequestPostToken, requestPostToken} from '@apis/request/auth';

import {useAuthStore} from '@store/authStore';

import getEventIdByUrl from '@utils/getEventIdByUrl';
import SessionStorage from '@utils/SessionStorage';

import SESSION_STORAGE_KEYS from '@constants/sessionStorageKeys';

const useRequestPostLogin = () => {
const eventId = getEventIdByUrl();
const {updateAuth} = useAuthStore();
const navigate = useNavigate();

const {mutate, ...rest} = useMutation({
mutationFn: ({password}: RequestPostToken) => requestPostToken({eventId, password}),
onSuccess: () => updateAuth(true),
onSuccess: () => {
const previousUrlForLogin = SessionStorage.get<string>(SESSION_STORAGE_KEYS.previousUrlForLogin);
if (previousUrlForLogin) {
SessionStorage.remove(SESSION_STORAGE_KEYS.previousUrlForLogin);
navigate(previousUrlForLogin, {replace: true});
}
updateAuth(true);
},
});

return {postLogin: mutate, ...rest};
Expand Down
11 changes: 6 additions & 5 deletions client/src/hooks/queries/event/useRequestGetEvent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useQuery} from '@tanstack/react-query';
import {useSuspenseQuery} from '@tanstack/react-query';

import {requestGetEvent} from '@apis/request/event';
import {WithErrorHandlingStrategy} from '@errors/RequestGetError';
Expand All @@ -10,15 +10,16 @@ import QUERY_KEYS from '@constants/queryKeys';
const useRequestGetEvent = ({...props}: WithErrorHandlingStrategy | null = {}) => {
const eventId = getEventIdByUrl();

const {data, ...rest} = useQuery({
const {data, ...rest} = useSuspenseQuery({
queryKey: [QUERY_KEYS.event],
queryFn: () => requestGetEvent({eventId, ...props}),
});

return {
eventName: data?.eventName ?? '',
bankName: data?.bankName ?? '',
accountNumber: data?.accountNumber ?? '',
eventName: data.eventName,
bankName: data.bankName,
accountNumber: data.accountNumber,
createdByGuest: data.createdByGuest,
...rest,
};
};
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/useAmplitude.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {EventName} from 'types/createEvent';
import {EventName} from 'types/serviceType';

import {useAmplitudeStore} from '@store/amplitudeStore';

Expand Down
3 changes: 2 additions & 1 deletion client/src/hooks/useEventPageLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import useRequestGetSteps from './queries/step/useRequestGetSteps';

const useEventPageLayout = () => {
const eventId = getEventIdByUrl();
const {eventName, bankName, accountNumber} = useRequestGetEvent();
const {eventName, bankName, accountNumber, createdByGuest} = useRequestGetEvent();
const {isAdmin} = useAuthStore();
const {totalExpenseAmount} = useTotalExpenseAmountStore();
const {members} = useRequestGetAllMembers();
Expand All @@ -20,6 +20,7 @@ const useEventPageLayout = () => {
eventName,
bankName,
accountNumber,
createdByGuest,
};

const eventSummary = {
Expand Down
38 changes: 9 additions & 29 deletions client/src/hooks/useLoginPage.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,37 @@
import {useEffect} from 'react';
import {useLocation, useNavigate} from 'react-router-dom';

import {useAuthStore} from '@store/authStore';
import {useNavigate} from 'react-router-dom';

import getKakaoRedirectUrl from '@utils/getKakaoRedirectUrl';
import SessionStorage from '@utils/SessionStorage';

import {ROUTER_URLS} from '@constants/routerUrls';
import SESSION_STORAGE_KEYS from '@constants/sessionStorageKeys';

import useRequestGetKakaoClientId from './queries/auth/useRequestGetKakaoClientId';
import useAmplitude from './useAmplitude';
import useRequestGetKakaoLogin from './queries/auth/useRequestGetKakaoLogin';

const useLoginPage = () => {
const navigate = useNavigate();
const location = useLocation();
const {trackStartCreateEvent} = useAmplitude();
const {updateAuth} = useAuthStore();
const {requestGetKakaoLogin} = useRequestGetKakaoLogin();

const {requestGetClientId} = useRequestGetKakaoClientId();

const goKakaoLogin = async () => {
const goKakaoLogin = async (previousUrl?: string) => {
const queryResult = await requestGetClientId();
const clientId = queryResult.data?.clientId;

if (typeof previousUrl !== 'undefined') {
SessionStorage.set<string>(SESSION_STORAGE_KEYS.previousUrlForLogin, previousUrl);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정말 별거 아닌 호기심입니다만.. previousUrl의 타입이 undefined가 아닐 때에만 세션 스토리지를 set하도록 해주셨잖아요. previousUrl === 'string'이 아닌 previousUrl !== 'undefined'로 해주신 이유가 궁금합니다!

previousUrl에는 타입이 string이나 undefined가 아니면 컴파일시에 타입 오류가 발생하기 때문에 해당 goKakaoLogin 함수가 실행되지 않을 것 같단 말이죠? 그래서 저라면 부정문 보다는 긍정문이 코드 이해에 더 좋을 것 같고, previousUrl은 무조건 string이어야 하기 때문에 if문 조건을 string으로 뒀을 것 같은데.. undefined로 하신 이유가 궁금합니다.

해당 질문은 정말 별거 아니고.. 저랑 다른 생각 구조(?)를 가지신 것 같아서 궁금해서 여쭤보는 겁니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파라미터를 넘길 때 previousUrl이 있는 경우가 있고 없는 경우가 있어서 undefined 체크를 했어요.
인증에 실패해서 돌아가야할 곳이 없는 경우를 체크하기 위해서였는데 "파라미터가 없지 않을 경우"에 실행한다 다시 생각해보니 어색하네요.

소하 의견대로 파리미터가 없을 경우 얼리리턴이나 파라미터가 있을 경우가 더 좋은 것 같아요

}

const link = `https://kauth.kakao.com/oauth/authorize?client_id=${clientId}&redirect_uri=${getKakaoRedirectUrl()}&response_type=code`;
window.location.href = link;
};

const goNonLoginCreateEvent = () => {
trackStartCreateEvent({login: false});
navigate(ROUTER_URLS.createEvent);
navigate(ROUTER_URLS.createGuestEvent);
};

useEffect(() => {
if (location.search === '') return;

const code = new URLSearchParams(location.search).get('code');

const kakaoLogin = async () => {
if (code) {
await requestGetKakaoLogin();
updateAuth(true);

// 추후에 업데이트 하는 로직 필요
trackStartCreateEvent({login: true});
navigate(ROUTER_URLS.createEvent);
}
};

kakaoLogin();
}, [location.search]);

return {goKakaoLogin, goNonLoginCreateEvent};
};

Expand Down
4 changes: 2 additions & 2 deletions client/src/hooks/useReportsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {useLocation, useNavigate, useOutletContext} from 'react-router-dom';

import {EventPageContextProps} from '@pages/EventPage/EventPageLayout';

import getDeletedLastPath from '@utils/getDeletedLastPath';
import getEventBaseUrl from '@utils/getEventBaseUrl';

import {useSearchReports} from './useSearchReports';
import toast from './useToast/toast';
Expand Down Expand Up @@ -37,7 +37,7 @@ const useReportsPage = () => {
eventToken,
};

navigate(`${getDeletedLastPath(location.pathname)}/${memberId}/send`, {state: sendInfo});
navigate(`/${getEventBaseUrl(location.pathname)}/${memberId}/send`, {state: sendInfo});
};

const onCopy = async (amount: number) => {
Expand Down
9 changes: 8 additions & 1 deletion client/src/mocks/handlers/authHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ import {MOCK_API_PREFIX} from '@mocks/mockEndpointPrefix';
export const authHandler = [
// POST /api/eventId/auth (requestPostAuthentication)
http.post(`${MOCK_API_PREFIX}${ADMIN_API_PREFIX}/:eventId/auth`, () => {
return new HttpResponse(null, {status: 200});
// return new HttpResponse(null, {status: 200});
return HttpResponse.json(
{
errorCode: 'TOKEN_NOT_FOUND',
message: '토큰이 존재하지 않습니다.',
},
{status: 401},
);
}),

http.get(`${MOCK_API_PREFIX}/api/login/kakao`, () => {
Expand Down
1 change: 1 addition & 0 deletions client/src/mocks/sharedState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export let eventData = {
eventName: '행동대장 야유회',
bankName: '',
accountNumber: '000000-01-121212',
createdByGuest: true,
};

export let memberData = {
Expand Down
4 changes: 2 additions & 2 deletions client/src/pages/AccountPage/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import useAccount from '@hooks/useAccount';

import {FixedButton, Flex, FunnelLayout, Input, MainLayout, Top, TopNav} from '@components/Design';

import getDeletedLastPath from '@utils/getDeletedLastPath';
import getEventBaseUrl from '@utils/getEventBaseUrl';

const Account = () => {
const navigate = useNavigate();
Expand All @@ -28,7 +28,7 @@ const Account = () => {

const enrollAccountAndNavigateAdmin = async () => {
await enrollAccount();
navigate(getDeletedLastPath(location.pathname));
navigate(`/${getEventBaseUrl(location.pathname)}/admin`);
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const CreateGuestEventFunnel = () => {
<Funnel.Step name="eventPassword">
<SetEventPasswordStep
moveToNextStep={moveToNextStep}
nickname={nickNameProps.nickName}
nickname={nickNameProps.nickname}
eventName={eventNameProps.eventName}
setEventToken={setEventToken}
/>
Expand Down
15 changes: 2 additions & 13 deletions client/src/pages/EventPage/AuthGate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,13 @@ import {useEffect} from 'react';

import useRequestPostAuthentication from '@hooks/queries/auth/useRequestPostAuthentication';

import {useAuthStore} from '@store/authStore';

type AuthGateProps = React.PropsWithChildren & {
fallback: React.ReactNode;
};

const AuthGate = ({children, fallback}: AuthGateProps) => {
const {isError, postAuthenticate} = useRequestPostAuthentication();
const {isAdmin} = useAuthStore();
const AuthGate = ({children}: React.PropsWithChildren) => {
const {postAuthenticate} = useRequestPostAuthentication();

useEffect(() => {
postAuthenticate();
}, [postAuthenticate]);

if (isError && !isAdmin) {
return fallback;
}

return children;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
import {css} from '@emotion/react';

import Top from '@components/Design/components/Top/Top';

import useEventLogin from '@hooks/useEventLogin';

import {FixedButton, Input} from '@HDesign/index';
import {FixedButton, FunnelLayout, Input} from '@HDesign/index';

import RULE from '@constants/rule';

const EventLoginPage = () => {
const GuestEventLogin = () => {
const {password, errorMessage, handleChange, canSubmit, submitPassword} = useEventLogin();

return (
<div
css={css`
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
`}
>
<FunnelLayout>
<Top>
<Top.Line
text={`행사 생성 시 설정한 ${RULE.maxEventPasswordLength}자리`}
Expand All @@ -41,8 +32,8 @@ const EventLoginPage = () => {
></Input>
<FixedButton disabled={!canSubmit}>관리 페이지로</FixedButton>
</form>
</div>
</FunnelLayout>
);
};

export default EventLoginPage;
export default GuestEventLogin;
Loading
Loading