Feature: 온보딩 페이지 퍼널 패턴 적용, api 연동(로그인 처리 완료)#14
Conversation
…ms-fullstack-devcourse/Comeet_FE into feature/api-onboarding-home
There was a problem hiding this comment.
Summary of Changes
Hello @Monixc, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
I've focused on building out the core onboarding experience for new users, integrating it deeply with our backend API. This involved creating a guided, multi-step process for profile creation, enhancing our data fetching strategy with React Query, and introducing location-based features. The changes also include significant refactoring of our API service layer and type definitions to ensure a robust and scalable foundation for future development.
Highlights
- New Onboarding Funnel: I've implemented a comprehensive multi-step onboarding flow using the
@use-funnel/react-router-domlibrary, allowing users to smoothly navigate through profile setup, technical interests, and additional information steps with proper state management and back navigation. - API Integration and Query Hooks Refactor: I've refactored our API integration by creating a dedicated
lib/apidirectory with separate modules for authentication, developers, posts, and tags. This improves code organization and maintainability. All data fetching now leverages@tanstack/react-querywith new custom hooks (useAuth,useLocationQuery,useTags) for efficient state management and caching. - Location Information Collection: A new feature has been added to collect user location information during onboarding, including reverse geocoding to display a human-readable address. This is crucial for connecting users with nearby developers.
- Dependency Updates and Type Standardization: I've updated the project's dependency management, adding
@use-funnel/react-router-domandreact-hot-toastfor enhanced UI/UX. Additionally, type definitions across the application have been standardized and organized into.types.tsfiles for improved clarity and consistency.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
이번 PR은 온보딩 퍼널 도입, API 연동 및 관련 타입 정의, 다수의 컴포넌트 리팩토링 등 많은 변경 사항을 포함하고 있습니다. 전반적으로 React Query를 활용한 데이터 페칭 로직 개선과 API 모듈화 등 코드 구조가 잘 개선되었습니다. 몇 가지 개선점을 제안합니다. useLocationQuery 훅의 타임아웃 설정이 사용자 경험에 영향을 줄 수 있어 조정을 제안하며, 온보딩 마지막 단계에서 데이터 불일치 및 예외 처리 관련 피드백을 추가했습니다. 또한, 프로젝트의 안정성을 위해 추가된 기능들에 대한 테스트 코드를 작성하는 것을 고려해보시는 것이 좋겠습니다.[^1]
| interestIds: data.interests, | ||
| ...(data.email && { email: data.email }), | ||
| ...(data.instagram && { instagram: data.instagram }), | ||
| ...(data.linkedin && { linkedIn: data.linkedin }), |
There was a problem hiding this comment.
| timeout: 300000, | ||
| maximumAge: 300000, |
There was a problem hiding this comment.
getCurrentPosition의 timeout과 maximumAge 값이 300000ms(5분)으로 설정되어 있습니다. 이 값은 너무 길어서 사용자 경험에 좋지 않은 영향을 줄 수 있습니다. 타임아웃이 너무 길면 사용자가 오래 기다려야 할 수 있고, maximumAge가 길면 오래된 위치 정보가 사용될 수 있습니다. 항상 새로운 위치 정보를 가져오도록 timeout을 30초 정도로 줄이고 maximumAge를 0으로 설정하는 것을 권장합니다.
| timeout: 300000, | |
| maximumAge: 300000, | |
| timeout: 30000, | |
| maximumAge: 0, |
| if ( | ||
| !data.nickname || | ||
| !data.age || | ||
| !data.experience || | ||
| !data.bio || | ||
| !data.location || | ||
| !data.position || | ||
| !data.techStack || | ||
| !data.interests | ||
| ) { | ||
| console.error("온보딩 데이터가 불완전합니다:", { | ||
| nickname: data.nickname, | ||
| age: data.age, | ||
| experience: data.experience, | ||
| bio: data.bio, | ||
| location: data.location, | ||
| position: data.position, | ||
| techStack: data.techStack, | ||
| interests: data.interests, | ||
| }); | ||
| return; | ||
| } |
There was a problem hiding this comment.
온보딩 데이터가 불완전할 경우, 콘솔에만 에러를 기록하고 사용자에게는 아무런 피드백을 주지 않아 사용자가 페이지에 갇히게 될 수 있습니다. 사용자에게 알림을 표시하고 온보딩 첫 단계로 돌려보내는 등 명확한 피드백을 제공하는 것이 좋습니다.
if (
!data.nickname ||
!data.age ||
!data.experience ||
!data.bio ||
!data.location ||
!data.position ||
!data.techStack ||
!data.interests
) {
console.error("온보딩 데이터가 불완전합니다:", {
nickname: data.nickname,
age: data.age,
experience: data.experience,
bio: data.bio,
location: data.location,
position: data.position,
techStack: data.techStack,
interests: data.interests,
});
alert("입력 정보가 완전하지 않습니다. 온보딩을 다시 시작합니다.");
navigate("/onboarding", { replace: true });
return;
}- board 상수가 아닌 api에서 동적으로 가져와서 사용
- 게시판 목록을 API에서 동적으로 가져오도록 변경 - 게시물 제출 시 유효성 검사 추가 - PostItem 및 RecruitItem 컴포넌트에 props를 통해 데이터 전달 방식으로 수정
|
/gemini review |
| location: { | ||
| lng: 127.0, | ||
| lat: 37.5, | ||
| }, | ||
| }), |
| if ( | ||
| !data.nickname || | ||
| !data.age || | ||
| !data.experience || | ||
| !data.bio || | ||
| !data.location || | ||
| !data.position || | ||
| !data.techStack || | ||
| !data.interests | ||
| ) { | ||
| console.error("온보딩 데이터가 불완전합니다:", { | ||
| nickname: data.nickname, | ||
| age: data.age, | ||
| experience: data.experience, | ||
| bio: data.bio, | ||
| location: data.location, | ||
| position: data.position, | ||
| techStack: data.techStack, | ||
| interests: data.interests, | ||
| }); | ||
| return; | ||
| } |
There was a problem hiding this comment.
온보딩 마지막 단계에서 회원가입 요청 시 필요한 데이터가 누락되었을 경우, 콘솔 에러만 출력하고 아무런 처리를 하지 않아 사용자가 아무런 피드백 없이 멈춘 화면에 있게 됩니다. 사용자에게 오류가 발생했음을 알리고, 로그인 페이지로 이동시키는 등의 예외 처리가 필요합니다.
if (
!data.nickname ||
!data.age ||
!data.experience ||
!data.bio ||
!data.location ||
!data.position ||
!data.techStack ||
!data.interests
) {
console.error("온보딩 데이터가 불완전합니다:", {
nickname: data.nickname,
age: data.age,
experience: data.experience,
bio: data.bio,
location: data.location,
position: data.position,
techStack: data.techStack,
interests: data.interests,
});
alert("온보딩 정보가 올바르지 않습니다. 다시 시도해주세요.");
navigate("/login", { replace: true });
return;
}| } else { | ||
| console.log(" 예상치 못한 응답:", result); | ||
| } |
There was a problem hiding this comment.
| type ProfileSetup = { | ||
| nickname?: string; | ||
| age?: number; | ||
| experience?: number; | ||
| bio?: string; | ||
| location?: { | ||
| lng: number; | ||
| lat: number; | ||
| }; | ||
| }; | ||
|
|
||
| type TechInterests = { | ||
| nickname: string; | ||
| age: number; | ||
| experience: number; | ||
| bio: string; | ||
| location: { | ||
| lng: number; | ||
| lat: number; | ||
| }; | ||
| position?: number; | ||
| techStack?: number[]; | ||
| interests?: number[]; | ||
| }; | ||
|
|
||
| type AdditionalInfo = { | ||
| nickname: string; | ||
| age: number; | ||
| experience: number; | ||
| bio: string; | ||
| location: { | ||
| lng: number; | ||
| lat: number; | ||
| }; | ||
| position: number; | ||
| techStack: number[]; | ||
| interests: number[]; | ||
| linkedin?: string; | ||
| email?: string; | ||
| instagram?: string; | ||
| blog?: string; | ||
| }; | ||
|
|
||
| type Complete = { | ||
| nickname: string; | ||
| age: number; | ||
| experience: number; | ||
| bio: string; | ||
| location: { | ||
| lng: number; | ||
| lat: number; | ||
| }; | ||
| position: number; | ||
| techStack: number[]; | ||
| interests: number[]; | ||
| linkedin?: string; | ||
| email?: string; | ||
| instagram?: string; | ||
| blog?: string; | ||
| }; | ||
|
|
||
| export interface OnboardingData { | ||
| nickname?: string; | ||
| age?: number; | ||
| experience?: number; | ||
| bio?: string; | ||
| location?: { | ||
| lng: number; | ||
| lat: number; | ||
| }; | ||
| position?: number; | ||
| techStack?: number[]; | ||
| interests?: number[]; | ||
| linkedin?: string; | ||
| email?: string; | ||
| instagram?: string; | ||
| blog?: string; | ||
| } |
There was a problem hiding this comment.
온보딩 각 단계의 컨텍스트 타입(ProfileSetup, TechInterests 등)이 다소 느슨하게 정의되어 있습니다. 예를 들어, TechInterests 단계에서는 ProfileSetup에서 입력받은 값들이 반드시 존재해야 하지만, 타입상으로는 여전히 optional로 되어 있습니다. 타입스크립트의 Required 유틸리티 타입과 타입 교차(&)를 사용하면 각 단계에서 사용 가능한 컨텍스트를 더 명확하고 안전하게 타이핑할 수 있습니다. 이는 '최대한 타입은 좁혀서 사용한다'는 프로젝트 스타일 가이드에도 부합합니다.1
예시:
type ProfileSetupData = { /* ... */ };
type TechInterestsData = { /* ... */ };
type TechInterestsContext = Required<ProfileSetupData> & TechInterestsData;
📌 PR 종류 (PR Type)
📝 요약 (Summary)
ex) 게시글 리스트 UI 개선 및 반응형 대응
온보딩 페이지 퍼널 적용, api 연동
🔍 상세 내용 (Describe your changes)
ex)
toss/@use-funnel적용geolocation api를 활용한 사용자 위치 수집Nominatim Reverse Geocoding으로 좌표 -> 주소 변환📸 스크린샷 (필수)
✅ 확인 사항 (CheckList)
💬 기타 참고사항 (Optional)
ex) 이 부분 로직이 좀 복잡해서 한번 더 확인 부탁드립니다 🙏