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

[YS-176] 회원가입 로직 리팩토링 (연구자) #23

Merged
merged 29 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bc002e0
[YS-176] chore: eslint fix
rbgksqkr Jan 19, 2025
19e2482
[YS-176] refactor: 유틸 함수 및 훅 파일 분리
rbgksqkr Jan 19, 2025
22c02be
[YS-176] refactor: funnel 컴포넌트 파일 분리
rbgksqkr Jan 19, 2025
34f9764
[YS-176] refactor: step 상수 분리
rbgksqkr Jan 19, 2025
ba13c1d
[YS-176] refactor: title 폰트 추가
rbgksqkr Jan 19, 2025
29211e6
[YS-176] design: 회원가입 성공 레이아웃 UI 수정
rbgksqkr Jan 19, 2025
538fe3d
[YS-176] feat: naver oauth 로그인 구현
rbgksqkr Jan 20, 2025
44e6176
[YS-176] refactor: 홈화면 API 응답값 수정 반영
rbgksqkr Jan 20, 2025
a7ca5cd
[YS-176] refactor: naver oauth state URL 인코딩하여 전달
rbgksqkr Jan 20, 2025
d55650c
[YS-176] refactor: 체크 상태에 따라 모두 동의 제어
rbgksqkr Jan 20, 2025
b93f55a
[YS-176] refactor: form 으로 관리되지 않는 form 타입 제거
rbgksqkr Jan 21, 2025
21f71be
[YS-176] feat: useFunnel 구현
rbgksqkr Jan 21, 2025
785c14c
[YS-176] refactor: useFunnel을 활용하여 선언적으로 Funnel 단계 관리
rbgksqkr Jan 21, 2025
b4e3252
[YS-176] refactor: JoinInput onBlur 이벤트 인자로 받기
rbgksqkr Jan 21, 2025
b068230
[YS-176] design: 버튼에 margin-bottom 추가
rbgksqkr Jan 21, 2025
f9b3d23
[YS-176] refactor: 폼으로 관리되던 상태를 state로 관리 (email)
rbgksqkr Jan 21, 2025
547588d
[YS-176] refactor: 체크 상태를 form이 아닌 상태로 관리
rbgksqkr Jan 21, 2025
963ab35
[YS-176] refactor: 각각의 상태를 컴포넌트의 역할에 맞는 위치로 개선
rbgksqkr Jan 21, 2025
2824436
[YS-176] refactor: 폼으로 관리되던 상태를 state로 관리 (info)
rbgksqkr Jan 21, 2025
a4c32fb
[YS-176] design: 여백이 맞지 않던 부분 수정
rbgksqkr Jan 21, 2025
e9394e2
[YS-176] fix: input blur 될 때마다 초기화되는 오류 제거
rbgksqkr Jan 21, 2025
e833358
[YS-176] fix: API 타입 수정 사항 반영
rbgksqkr Jan 21, 2025
3d851f6
[YS-176] fix: 매직 넘버 상수화
rbgksqkr Jan 21, 2025
588c50a
[YS-176] refactor: 디렉토리 구조 변경
rbgksqkr Jan 21, 2025
e243fe0
[YS-176] refactor: validation 제거 및 mode onBlur 추가
rbgksqkr Jan 23, 2025
6bcf857
[YS-176] refactor: 불필요한 import 제거
rbgksqkr Jan 23, 2025
231d972
[YS-176] refactor: 인증 번호 재전송 버튼 클릭 시 이메일 재전송 연결
rbgksqkr Jan 23, 2025
99d747d
[YS-176] refactor: 이메일 도메인 체크 유틸함수 개선
rbgksqkr Jan 23, 2025
7c8985d
[YS-176] refactor: provider util 함수 불필요한 허용 도메인 제거
rbgksqkr Jan 23, 2025
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
15 changes: 15 additions & 0 deletions src/apis/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,27 @@ export interface ResearcherResponse {
univName: string;
}

export interface NaverLoginParams {
code: string;
role: string;
state: string;
}

export const googleLogin = async (code: string, role: string) => {
const res = await API.post<LoginResponse>(API_URL.google(role), { authorizationCode: code });

return res.data;
};

export const naverLogin = async ({ code, role, state }: NaverLoginParams) => {
const res = await API.post<LoginResponse>(API_URL.naver(role), {
authorizationCode: code,
state,
});

return res.data;
};
Comment on lines +64 to +71
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리를 추가해주세요.

네이버 로그인 API 호출 시 발생할 수 있는 에러에 대한 처리가 필요합니다.

export const naverLogin = async ({ code, role, state }: NaverLoginParams) => {
+  try {
    const res = await API.post<LoginResponse>(API_URL.naver(role), {
      authorizationCode: code,
      state,
    });
    return res.data;
+  } catch (error) {
+    if (error instanceof Error) {
+      throw new Error(`네이버 로그인 실패: ${error.message}`);
+    }
+    throw new Error('네이버 로그인 중 알 수 없는 오류가 발생했습니다.');
+  }
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const naverLogin = async ({ code, role, state }: NaverLoginParams) => {
const res = await API.post<LoginResponse>(API_URL.naver(role), {
authorizationCode: code,
state,
});
return res.data;
};
export const naverLogin = async ({ code, role, state }: NaverLoginParams) => {
try {
const res = await API.post<LoginResponse>(API_URL.naver(role), {
authorizationCode: code,
state,
});
return res.data;
} catch (error) {
if (error instanceof Error) {
throw new Error(`네이버 로그인 실패: ${error.message}`);
}
throw new Error('네이버 로그인 중 알 수 없는 오류가 발생했습니다.');
}
};


export const sendUnivAuthCode = async (univEmail: string) => {
const res = await API.post<UnivAuthCodeResponse>(API_URL.send, { univEmail });

Expand Down
12 changes: 9 additions & 3 deletions src/apis/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { Area } from '@/app/home/home.types';
import { API_URL } from '@/constants/url';
import { Post } from '@/types/post';

type PostResponse = Post[];
interface PostResponse {
content: Post[];
isLast: boolean;
page: number;
size: number;
totalCount: number;
}
Comment on lines +7 to +13
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

응답 데이터 검증 로직 추가 필요

PostResponse 인터페이스가 추가되어 타입 안전성이 향상되었습니다. 하지만 실제 응답 데이터의 유효성 검증이 없습니다.

zod 스키마를 사용하여 런타임에서도 데이터 유효성을 검증하는 것을 추천드립니다:

import { z } from 'zod';

const PostResponseSchema = z.object({
  content: z.array(PostSchema),
  isLast: z.boolean(),
  page: z.number(),
  size: z.number(),
  totalCount: z.number()
});


export type AreaResponse = PostAreaResponse | PostSubAreaResponse;

Expand All @@ -24,7 +30,7 @@ interface PostArea {
}

export interface PostListParams {
recruitDone: boolean;
recruitStatus: 'ALL' | 'OPEN';
matchType?: 'ONLINE' | 'OFFLINE' | 'ALL';
gender?: '' | 'MALE' | 'FEMALE' | 'ALL';
age?: number;
Expand All @@ -34,7 +40,7 @@ export interface PostListParams {
count?: number;
}

export const fetchPostList = async (params: PostListParams) => {
export const fetchPostList = async (params: PostListParams = { recruitStatus: 'ALL' }) => {
const queryParams = new URLSearchParams();

Object.entries(params).forEach(([key, value]) => {
Expand Down
6 changes: 1 addition & 5 deletions src/app/home/components/PostCard/PostCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
} from './PostCard.styles';

import Icon from '@/components/Icon';
import theme from '@/styles/theme';
import { Post } from '@/types/post';

interface PostCardProps {
Expand All @@ -30,9 +29,6 @@ const PostCard = ({ post }: PostCardProps) => {
href={`/post/${post.postInfo.experimentPostId}`}
key={post.postInfo.experimentPostId}
css={postCardLayout}
style={{
backgroundColor: post.recruitDone ? theme.colors.field01 : theme.colors.field01,
}}
>
<div css={postHeader}>
<div css={postCardHeader}>
Expand All @@ -45,7 +41,7 @@ const PostCard = ({ post }: PostCardProps) => {
<h3 css={postTitle}>{post.postInfo.title}</h3>
</div>
<div>
{post.recruitDone ? (
{post.recruitStatus ? (
<div css={contactedPostTag}>
<span>모집 완료</span>
</div>
Expand Down
25 changes: 12 additions & 13 deletions src/app/home/components/PostContainer/PostContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { useState } from 'react';

import usePostListQuery from '../../hooks/usePostListQuery';
import PostCardList from '../PostCardList/PostCardList';
import FilterContainer from './FilterContainer/FilterContainer';
Expand All @@ -11,20 +12,16 @@ import {
postContainerTitle,
totalPostCount,
} from './PostContainer.styles';
import JoinCheckbox from '@/app/join/components/JoinCheckboxContainer/JoinCheckbox/JoinCheckbox';

import { PostListParams } from '@/apis/post';
import JoinCheckbox from '@/app/join/components/JoinEmailStep/JoinCheckboxContainer/JoinCheckbox/JoinCheckbox';

const PostContainer = () => {
const [filters, setFilters] = useState<PostListParams>({
matchType: 'ALL' as 'ALL' | 'ONLINE' | 'OFFLINE',
gender: '' as '' | 'ALL' | 'MALE' | 'FEMALE',
region: '',
areas: '',
age: 20,
recruitDone: false,
recruitStatus: 'ALL',
});

const { data: postList } = usePostListQuery(filters);
const { data } = usePostListQuery(filters);

const handleFilterChange = (key: string, value: string | number | boolean) => {
setFilters((prev) => ({
Expand All @@ -33,9 +30,11 @@ const PostContainer = () => {
}));
};

// TODO: 개선 필요.
const isRecruiting = filters.recruitStatus === 'OPEN';

const handleChange = () => {
handleFilterChange('recruitDone', !filters.recruitDone);
const toggleChecked = isRecruiting ? 'ALL' : 'OPEN';
handleFilterChange('recruitStatus', toggleChecked);
};

return (
Expand All @@ -45,14 +44,14 @@ const PostContainer = () => {
<FilterContainer handleFilterChange={handleFilterChange} />
<JoinCheckbox
label="모집 중인 공고만 보기"
isChecked={filters.recruitDone}
isChecked={isRecruiting}
onChange={handleChange}
isArrow={false}
/>
</div>
<div css={postCardContainer}>
<span css={totalPostCount}>총 {postList?.length}개</span>
<PostCardList postList={postList} />
<span css={totalPostCount}>총 {data?.content.length}개</span>
<PostCardList postList={data?.content} />
</div>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/app/home/hooks/usePostListQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { fetchPostList, PostListParams } from '@/apis/post';
import { QUERY_KEY } from '@/constants/queryKey';

const usePostListQuery = (params: PostListParams) => {
const { matchType, gender, age, region, areas, recruitDone } = params;
const { matchType, gender, age, region, areas, recruitStatus } = params;

return useQuery({
queryKey: [QUERY_KEY.post, matchType, gender, age, region, areas, recruitDone],
queryKey: [QUERY_KEY.post, matchType, gender, age, region, areas, recruitStatus],
queryFn: () => fetchPostList(params),
});
};
Expand Down
5 changes: 3 additions & 2 deletions src/app/home/hooks/useResearcherInfoQuery.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { getResearcherInfo } from '@/apis/login';
import { useQuery } from '@tanstack/react-query';

import { getResearcherInfo } from '@/apis/login';

export const useResearcherInfoQuery = () => {
const role = sessionStorage.getItem('role');
const userRole = role === 'RESEARCHER' ? 'researchers' : 'participants';

return useQuery({
queryKey: ['researcherInfo'],
queryFn: getResearcherInfo,
enabled: !!role,
enabled: !!userRole,
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

연구자 정보 쿼리 활성화 조건 수정 필요

현재 구현상 참여자 역할을 가진 사용자도 연구자 정보를 조회할 수 있습니다. 보안과 불필요한 API 호출을 방지하기 위해 다음과 같이 수정하는 것이 좋겠습니다:

-    enabled: !!userRole,
+    enabled: userRole === 'researchers',
🔗 Analysis chain

enabled 조건의 의도된 동작 여부를 확인해주세요.

userRole이 'participants'인 경우에도 쿼리가 활성화될 수 있습니다. 함수 이름이 useResearcherInfoQuery인 것을 고려할 때, 연구자 정보 조회는 연구자 역할을 가진 사용자에게만 제한되어야 할 것 같습니다.

다음과 같이 수정하는 것을 고려해보세요:

-    enabled: !!userRole,
+    enabled: userRole === 'researchers',
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find the complete implementation of useResearcherInfoQuery
echo "=== useResearcherInfoQuery Implementation ==="
ast-grep --pattern 'export function useResearcherInfoQuery($_) {
  $$$
}'

echo -e "\n=== useResearcherInfoQuery Hook Usage ==="
rg "useResearcherInfoQuery" -l

echo -e "\n=== Similar Query Hooks with Role Checks ==="
rg "enabled.*userRole" -A 2 -B 2

Length of output: 860


Script:

#!/bin/bash
echo "=== useResearcherInfoQuery.ts Content ==="
cat src/app/home/hooks/useResearcherInfoQuery.ts

echo -e "\n=== Header.tsx Usage ==="
cat src/components/Header/Header.tsx

echo -e "\n=== Role Type Definitions ==="
rg "type.*Role|enum.*Role|interface.*Role" -A 3 -B 1

echo -e "\n=== Role Constants or Utils ==="
rg "Role.*=.*['\"]researchers['\"]" -A 2 -B 2

Length of output: 2667

retry: 1,
});
};
121 changes: 0 additions & 121 deletions src/app/join/JoinEmailStep.tsx

This file was deleted.

66 changes: 0 additions & 66 deletions src/app/join/JoinInfoStep.tsx

This file was deleted.

Loading