-
Notifications
You must be signed in to change notification settings - Fork 0
[Feat] user 엔드포인트 API 연결 #175
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
Changes from 8 commits
211bdb6
e2f077c
9b2b305
76e9f79
f0b6908
0aa8047
0652ddd
6adfb79
cea998b
3278739
7770581
97b6691
3ed8765
4c285c6
7034542
5210af3
b917018
d84d2b5
6439f28
cdcd943
87a91a7
12200b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,46 +1,58 @@ | ||||||||||||||||||||||
| import { api } from '@/api/core'; | ||||||||||||||||||||||
| import { | ||||||||||||||||||||||
| Availability, | ||||||||||||||||||||||
| FollowParams, | ||||||||||||||||||||||
| GetEmailAvailabilityParams, | ||||||||||||||||||||||
| GetNickNameAvailabilityParams, | ||||||||||||||||||||||
| GetUserParams, | ||||||||||||||||||||||
| UpdateMePayload, | ||||||||||||||||||||||
| UpdateMyImagePayload, | ||||||||||||||||||||||
| UpdateMyNotiParams, | ||||||||||||||||||||||
| UpdateMyProfileImagePayload, | ||||||||||||||||||||||
| User, | ||||||||||||||||||||||
| } from '@/types/service/user'; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| export const userServiceRemote = () => ({ | ||||||||||||||||||||||
| // 2. 프로필 편집 | ||||||||||||||||||||||
| // 1. 사용자 팔로우 | ||||||||||||||||||||||
| followUser: async (payload: FollowParams) => { | ||||||||||||||||||||||
| return api.post<void>(`/follows/${payload.followNickname}`); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 2. 유저 프로필 변경 | ||||||||||||||||||||||
| updateMe: async (payload: UpdateMePayload) => { | ||||||||||||||||||||||
| return api.patch<User>('/users', payload); | ||||||||||||||||||||||
| return api.patch<User>('/users/profile', payload); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 3. 프로필 이미지 편집 | ||||||||||||||||||||||
| updateMyImage: async (payload: UpdateMyImagePayload) => { | ||||||||||||||||||||||
| return api.patch<User>(`/users/profile-image`, payload); | ||||||||||||||||||||||
| // 3. 프로필 이미지 변경 | ||||||||||||||||||||||
| updateMyProfileImage: async (payload: UpdateMyProfileImagePayload) => { | ||||||||||||||||||||||
| const formData = new FormData(); | ||||||||||||||||||||||
| formData.append('file', payload.file); | ||||||||||||||||||||||
| return api.patch<User>(`/users/profile-image`, formData); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 4. 알림 설정 변경 | ||||||||||||||||||||||
| updatMyNotification: async (payload: UpdateMyNotiParams) => { | ||||||||||||||||||||||
| return api.patch<User>(`/users/notification/${payload.isNotificationEnabled}`); | ||||||||||||||||||||||
| updatMyNotification: async (params: UpdateMyNotiParams) => { | ||||||||||||||||||||||
| return api.patch<User>( | ||||||||||||||||||||||
| `/users/notification?isNotificationEnabled=${params.isNotificationEnabled}`, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 5. 사용자 단건 조회 | ||||||||||||||||||||||
| // 5. 유저 프로필 조회 | ||||||||||||||||||||||
| getUser: async (payload: GetUserParams) => { | ||||||||||||||||||||||
| return api.get<User>(`/users/${payload.userId}`); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 1. 사용자 팔로우 | ||||||||||||||||||||||
| followUser: async (payload: FollowParams) => { | ||||||||||||||||||||||
| return api.post<void>(`/follows/${payload.followNickname}`); | ||||||||||||||||||||||
| // 6. 닉네임 중복 검사 | ||||||||||||||||||||||
| getNicknameAvailability: async (params: GetNickNameAvailabilityParams) => { | ||||||||||||||||||||||
| return api.get<Availability>(`/users/nickname/availability?nickname=${params.nickName}`); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
Comment on lines
47
to
52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's examine the file structure and the endpoint in question
cat -n src/api/service/user-service/index.ts | head -60Repository: WeGo-Together/WeGo_FrontEnd Length of output: 2141 🏁 Script executed: # Search for API endpoint definitions or tests that might show the correct parameter name
rg "nickname.*availability" -i -A 3 -B 3Repository: WeGo-Together/WeGo_FrontEnd Length of output: 1298 🏁 Script executed: # Look for similar endpoints to understand the pattern used in the codebase
rg "api\.get.*params:" -A 2 -B 2Repository: WeGo-Together/WeGo_FrontEnd Length of output: 53 🏁 Script executed: # Check if there's any API documentation or backend endpoint definition
find . -type f \( -name "*api*" -o -name "*spec*" -o -name "*swagger*" -o -name "*openapi*" \) | grep -E "\.(ts|js|md|json|yaml|yml)$" | head -20Repository: WeGo-Together/WeGo_FrontEnd Length of output: 53 🏁 Script executed: # Look for tests related to this endpoint
rg "getNicknameAvailability" -A 5 -B 2Repository: WeGo-Together/WeGo_FrontEnd Length of output: 661 🏁 Script executed: # Check the axios configuration to understand default behavior with params
rg "api\.get|axios.*get" -A 2 | head -40Repository: WeGo-Together/WeGo_FrontEnd Length of output: 1314 🏁 Script executed: # Look for test files or actual usage of getNicknameAvailability
rg "getNicknameAvailability" -A 5 -B 2Repository: WeGo-Together/WeGo_FrontEnd Length of output: 661 🏁 Script executed: # Check the axios/api core configuration
cat -n src/api/core/index.ts 2>/dev/null || find src/api/core -type f -name "*.ts" | head -5Repository: WeGo-Together/WeGo_FrontEnd Length of output: 3597 🏁 Script executed: # Look for backend API documentation or OpenAPI spec
find . -type f \( -name "*.md" -o -name "*.json" -o -name "*.yaml" -o -name "*.yml" \) | xargs grep -l "nickname.*availability" 2>/dev/null | head -5Repository: WeGo-Together/WeGo_FrontEnd Length of output: 53 🏁 Script executed: # Check if there's environment/config that might specify API endpoint details
find . -type f \( -name ".env*" -o -name "config*" -o -name "*api*config*" \) | head -10Repository: WeGo-Together/WeGo_FrontEnd Length of output: 84 🏁 Script executed: # Look for any comments or documentation about the nickname endpoint
rg "nickname" -B 2 -A 2 | grep -E "(api|endpoint|param|query)" | head -20Repository: WeGo-Together/WeGo_FrontEnd Length of output: 709 🏁 Script executed: # Look for any integration tests or E2E tests that use this endpoint
find . -type f -name "*.test.*" -o -name "*.spec.*" | xargs grep -l "getNicknameAvailability\|nickname.*availability" 2>/dev/nullRepository: WeGo-Together/WeGo_FrontEnd Length of output: 55 🏁 Script executed: # Check if there's a backend repository reference or API spec
cat README.md 2>/dev/null | grep -i "api\|backend\|backend-repo" | head -10Repository: WeGo-Together/WeGo_FrontEnd Length of output: 410 🏁 Script executed: # Search for actual usage of these functions to see if they work with special characters
rg "getNicknameAvailability|getEmailAvailability" -A 3 -B 3 | head -30Repository: WeGo-Together/WeGo_FrontEnd Length of output: 909 Missing URL encoding for query parameters. The nickname query parameter is not URL-encoded. Nicknames containing spaces or special characters (e.g., "John Doe", "user@123") will cause malformed URLs and request failures. The // 6. 닉네임 중복 검사
getNicknameAvailability: async (params: GetNickNameAvailabilityParams) => {
- return api.get<Availability>(`/users/nickname/availability?nickname=${params.nickName}`);
+ return api.get<Availability>('/users/nickname/availability', {
+ params: { nickname: params.nickName },
+ });
},Note: The same issue affects the 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 7. 이메일 중복 검사 | ||||||||||||||||||||||
| getEmailAvailability: async (params: GetEmailAvailabilityParams) => { | ||||||||||||||||||||||
| return api.get<Availability>(`/users/email/availability?email=${params.email}`); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 6. 사용자 언팔로우 | ||||||||||||||||||||||
| // 8. 사용자 언팔로우 | ||||||||||||||||||||||
| unfollowUser: async (payload: FollowParams) => { | ||||||||||||||||||||||
| return api.delete<void>(`/follows/${payload.followNickname}`); | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 7. 회원탈퇴 | ||||||||||||||||||||||
| deleteMe: async () => api.delete<User>(`/users`), | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // 8. 사용자 프로필 이미지 변경 | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export { ImageField } from './image-field'; | ||
| export { MBTIField } from './mbti-field'; | ||
| export { MessageField } from './message-field'; | ||
| export { NickNameField } from './nickname-field'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,12 +9,11 @@ import { | |
| ModalTitle, | ||
| useModal, | ||
| } from '@/components/ui'; | ||
| import { User } from '@/types/service/user'; | ||
| import { useUpdateUser } from '@/hooks/use-user'; | ||
| import { useUserImageUpdate } from '@/hooks/use-user/use-user-image-update'; | ||
| import { UpdateMePayload, User } from '@/types/service/user'; | ||
|
|
||
| import ImageField from '../profile-edit-fields/image-field'; | ||
| import { MBTIField } from '../profile-edit-fields/mbti-field'; | ||
| import { MessageField } from '../profile-edit-fields/message-field'; | ||
| import { NickNameField } from '../profile-edit-fields/nickname-field'; | ||
| import { ImageField, MBTIField, MessageField, NickNameField } from '../profile-edit-fields'; | ||
|
|
||
| interface Props { | ||
| user: User; | ||
|
|
@@ -25,21 +24,40 @@ export const ProfileEditModal = ({ user }: Props) => { | |
|
|
||
| const { close } = useModal(); | ||
|
|
||
| const { mutateAsync: updateUser, isPending: isUserInfoPending } = useUpdateUser(); | ||
| const { mutateAsync: updateUserImage, isPending: isUserImagePending } = useUserImageUpdate(); | ||
|
|
||
| const form = useForm({ | ||
| defaultValues: { | ||
| profileImage: { | ||
| [image]: null, | ||
| } as ImageRecord, | ||
| profileImage: { [image]: null } as ImageRecord, | ||
| nickName, | ||
| profileMessage, | ||
| mbti, | ||
| }, | ||
| onSubmit: async ({ value }) => { | ||
| console.log(value); | ||
| const { profileImage, nickName, profileMessage, mbti } = value; | ||
|
|
||
| // 프로필 항목 업데이트 조건 체크 | ||
| const nextProfileInfo: UpdateMePayload = { | ||
| ...(user.nickName !== value.nickName && { nickName }), | ||
| ...(user.profileMessage !== value.profileMessage && { profileMessage }), | ||
| ...(user.mbti !== value.mbti && { mbti }), | ||
| }; | ||
| if (Object.values(nextProfileInfo).length > 0) { | ||
| await updateUser(nextProfileInfo); | ||
| } | ||
|
|
||
| // 이미지 업데이트 조건 체크 | ||
| const imageFileObject = Object.values(profileImage)[0]; | ||
| if (imageFileObject) { | ||
| await updateUserImage({ file: imageFileObject }); | ||
| } | ||
| close(); | ||
| }, | ||
|
Comment on lines
46
to
82
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for failed mutations. If either onSubmit: async ({ value }) => {
const { profileImage, nickName, profileMessage, mbti } = value;
// 프로필 항목 업데이트 조건 체크
const nextProfileInfo: UpdateMePayload = {
...(user.nickName !== value.nickName && { nickName }),
...(user.profileMessage !== value.profileMessage && { profileMessage }),
...(user.mbti !== value.mbti && { mbti }),
};
- if (Object.values(nextProfileInfo).length > 0) {
- await updateUser(nextProfileInfo);
- }
-
- // 이미지 업데이트 조건 체크
- const imageFileObject = Object.values(profileImage)[0];
- if (imageFileObject) {
- await updateUserImage({ file: imageFileObject });
+ try {
+ if (Object.keys(nextProfileInfo).length > 0) {
+ await updateUser(nextProfileInfo);
+ }
+
+ // 이미지 업데이트 조건 체크
+ const imageFileObject = Object.values(profileImage)[0];
+ if (imageFileObject) {
+ await updateUserImage({ file: imageFileObject });
+ }
+ close();
+ } catch (error) {
+ // Consider showing a toast notification here
+ console.error('프로필 업데이트 실패:', error);
}
- close();
},🤖 Prompt for AI Agents |
||
| }); | ||
|
|
||
| const isPending = isUserInfoPending || isUserImagePending; | ||
|
|
||
| return ( | ||
| <ModalContent className='max-w-82.5'> | ||
| <ModalTitle>프로필 수정</ModalTitle> | ||
|
|
@@ -61,7 +79,9 @@ export const ProfileEditModal = ({ user }: Props) => { | |
| <Button variant='tertiary' onClick={close}> | ||
| 취소 | ||
| </Button> | ||
| <Button type='submit'>수정하기</Button> | ||
| <Button disabled={isPending} type='submit'> | ||
| {isPending ? '수정 중...' : '수정하기'} | ||
| </Button> | ||
| </div> | ||
| </form> | ||
| </ModalContent> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| 'use client'; | ||
|
|
||
| import Image, { ImageProps } from 'next/image'; | ||
|
|
||
| import { useEffect, useState } from 'react'; | ||
|
|
||
| interface ImageWithFallbackProps extends Omit<ImageProps, 'src' | 'onError'> { | ||
| src: string; | ||
| fallbackSrc?: string; | ||
| } | ||
|
|
||
| export const ImageWithFallback = ({ | ||
| src, | ||
| fallbackSrc = 'https://plus.unsplash.com/premium_photo-1738592736106-a17b897c0ab1?q=80&w=1934&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', | ||
| ...rest | ||
| }: ImageWithFallbackProps) => { | ||
|
Comment on lines
+12
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a local fallback image instead of an external URL. The default Consider using a local placeholder image: export const ImageWithFallback = ({
src,
- fallbackSrc = 'https://plus.unsplash.com/premium_photo-1738592736106-a17b897c0ab1?q=80&w=1934&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
+ fallbackSrc = '/images/default-profile.png',
...rest
}: ImageWithFallbackProps) => {
🤖 Prompt for AI Agents |
||
| const [error, setError] = useState(false); | ||
|
|
||
| useEffect(() => { | ||
| // eslint-disable-next-line react-hooks/set-state-in-effect | ||
| setError(false); | ||
| }, [src]); | ||
|
|
||
| const imgSrc = error || !src || src === 'null' ? fallbackSrc : src; | ||
|
|
||
| return <Image {...rest} src={imgSrc} unoptimized onError={() => setError(true)} />; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: WeGo-Together/WeGo_FrontEnd
Length of output: 1850
🏁 Script executed:
Repository: WeGo-Together/WeGo_FrontEnd
Length of output: 98
🏁 Script executed:
Repository: WeGo-Together/WeGo_FrontEnd
Length of output: 1011
🏁 Script executed:
Repository: WeGo-Together/WeGo_FrontEnd
Length of output: 53
🏁 Script executed:
Repository: WeGo-Together/WeGo_FrontEnd
Length of output: 3597
Fix function name typo and use proper query parameter handling.
Two issues identified:
This change affects at least one call site in
src/hooks/use-user/use-user-notification/index.ts(line 10).Apply this diff:
Update the call site in
src/hooks/use-user/use-user-notification/index.ts(line 10) to use the corrected function name.📝 Committable suggestion
🤖 Prompt for AI Agents