From 9b7f8404f7da0533e640164009e44d388b6c5a78 Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 15:36:52 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20api=20=EC=B6=94=EA=B0=80=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/apis/user/user-mutations.ts | 10 +++++++++- src/shared/constants/api.ts | 1 + src/shared/constants/query-key.ts | 1 + src/shared/types/user-types.ts | 10 ++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/shared/apis/user/user-mutations.ts b/src/shared/apis/user/user-mutations.ts index c282ea20..475059d1 100644 --- a/src/shared/apis/user/user-mutations.ts +++ b/src/shared/apis/user/user-mutations.ts @@ -4,7 +4,7 @@ import { USER_KEY } from '@constants/query-key'; import queryClient from '@libs/query-client'; import { mutationOptions } from '@tanstack/react-query'; import type { responseTypes } from '@/shared/types/base-types'; -import type { postUserInfoNicknameRequest, postUserInfoRequest } from '@/shared/types/user-types'; +import type { postEditProfileRequest, postUserInfoNicknameRequest, postUserInfoRequest } from '@/shared/types/user-types'; export const userMutations = { NICKNAME: () => @@ -32,4 +32,12 @@ export const userMutations = { console.error('로그아웃 실패', err); }, }), + + EDIT_PROFILE: () => mutationOptions({ + mutationKey: USER_KEY.EDIT_PROFILE(), + mutationFn: () => post(END_POINT.POST_EDIT_PROFILE), + onSuccess: async () => { + queryClient.invalidateQueries({queryKey: USER_KEY.ALL}) + } + }) }; diff --git a/src/shared/constants/api.ts b/src/shared/constants/api.ts index d9df69db..e235a2f1 100644 --- a/src/shared/constants/api.ts +++ b/src/shared/constants/api.ts @@ -12,6 +12,7 @@ export const END_POINT = { GET_KAKAO_INFO: '/v1/users/kakao/info', USER_INFO: '/v1/users/info', POST_INFO_NICKNAME: '/v1/users/info/nickname', + POST_EDIT_PROFILE: '/v2/users/info', // 경기 관련 GET_GAME_SCHEDULE: (date: string) => `/v1/users/game/schedule?date=${date}`, diff --git a/src/shared/constants/query-key.ts b/src/shared/constants/query-key.ts index 716bfb1a..45c48e33 100644 --- a/src/shared/constants/query-key.ts +++ b/src/shared/constants/query-key.ts @@ -6,6 +6,7 @@ export const USER_KEY = { INFO: () => [...USER_KEY.ALL, 'info'] as const, NICKNAME: () => [...USER_KEY.ALL, 'nickname'] as const, LOGOUT: () => [...USER_KEY.ALL, 'logout'] as const, + EDIT_PROFILE: () => [...USER_KEY.ALL, 'edit'] as const } as const; export const AUTH_KEY = { diff --git a/src/shared/types/user-types.ts b/src/shared/types/user-types.ts index 6db61c7f..822639cb 100644 --- a/src/shared/types/user-types.ts +++ b/src/shared/types/user-types.ts @@ -31,3 +31,13 @@ export interface postUserInfoRequest { export interface postUserInfoNicknameRequest { nickname: string; } + +/** + * 사용자 정보 수정 + * post + * /v2/users/info + */ +export interface postEditProfileRequest { + field: string; + value: string; +} From 306fc2a273d666dd19025080455bd952797b90ca Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 15:48:46 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/edit-profile/edit-profile.tsx | 15 ++++++++++++--- .../edit-profile/schema/EditProfileSchema.ts | 9 +++++++++ src/shared/apis/user/user-mutations.ts | 16 ++++++++++++---- src/shared/constants/query-key.ts | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 src/pages/edit-profile/schema/EditProfileSchema.ts diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index eaa1d87c..9609a8f5 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -1,3 +1,4 @@ +import { userMutations } from '@apis/user/user-mutations'; import Button from '@components/button/button/button'; import Divider from '@components/divider/divider'; import Input from '@components/input/input'; @@ -13,15 +14,21 @@ import { } from '@pages/onboarding/constants/onboarding'; import { INFORMATION_RULE_MESSAGE, NICKNAME_RULE_MESSAGE } from '@pages/sign-up/constants/NOTICE'; import { INFORMATION_PLACEHOLDER, NICKNAME_PLACEHOLDER } from '@pages/sign-up/constants/validation'; +import { useMutation } from '@tanstack/react-query'; import { useMemo, useRef, useState } from 'react'; const EditProfile = () => { + const [nickname, setNickname] = useState(''); + const [information, setInformation] = useState(''); + const [team, setTeam] = useState(mockEditData.team); const [gender, setGender] = useState(mockEditData.genderPreference); const [mateTeam, setMateTeam] = useState(mockEditData.teamAllowed || '상관없어요'); const [viewStyle, setViewStyle] = useState(mockEditData.style); const [isSubmit, setIsSubmit] = useState(false); +const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); + const initialValue = useRef({ team: mockEditData.team, gender: mockEditData.genderPreference, @@ -29,7 +36,7 @@ const EditProfile = () => { viewStyle: mockEditData.style, }); - const isDirty = useMemo(() => { + const isMatchDirty = useMemo(() => { const init = initialValue.current; return ( @@ -40,16 +47,18 @@ const EditProfile = () => { ); }, [team, gender, mateTeam, viewStyle]); - const isSubmitDisabled = !isDirty || isSubmit; + const isSubmitDisabled = !isMatchDirty || isSubmit; const handleSaveClick = () => { - if (!isDirty) return; + if (!isMatchDirty) return; setIsSubmit(true); // TODO: 실제 API 호출 }; + + return (

프로필 수정

diff --git a/src/pages/edit-profile/schema/EditProfileSchema.ts b/src/pages/edit-profile/schema/EditProfileSchema.ts new file mode 100644 index 00000000..10592aaa --- /dev/null +++ b/src/pages/edit-profile/schema/EditProfileSchema.ts @@ -0,0 +1,9 @@ +import { NicknameSchema } from '@pages/sign-up/schema/validation-schema'; +import { z } from 'zod'; + +export const EditProfileSchema = NicknameSchema.pick({ + nickname: true, + information: true, +}) + +export type ProfileEditValues = z.infer; \ No newline at end of file diff --git a/src/shared/apis/user/user-mutations.ts b/src/shared/apis/user/user-mutations.ts index 475059d1..0687de5b 100644 --- a/src/shared/apis/user/user-mutations.ts +++ b/src/shared/apis/user/user-mutations.ts @@ -4,7 +4,11 @@ import { USER_KEY } from '@constants/query-key'; import queryClient from '@libs/query-client'; import { mutationOptions } from '@tanstack/react-query'; import type { responseTypes } from '@/shared/types/base-types'; -import type { postEditProfileRequest, postUserInfoNicknameRequest, postUserInfoRequest } from '@/shared/types/user-types'; +import type { + postEditProfileRequest, + postUserInfoNicknameRequest, + postUserInfoRequest, +} from '@/shared/types/user-types'; export const userMutations = { NICKNAME: () => @@ -33,11 +37,15 @@ export const userMutations = { }, }), - EDIT_PROFILE: () => mutationOptions({ + EDIT_PROFILE: () => + mutationOptions({ mutationKey: USER_KEY.EDIT_PROFILE(), mutationFn: () => post(END_POINT.POST_EDIT_PROFILE), onSuccess: async () => { - queryClient.invalidateQueries({queryKey: USER_KEY.ALL}) + queryClient.invalidateQueries({ queryKey: USER_KEY.ALL }); + }, + onError: (err) => { + console.error('수정에 실패했어요', err) } - }) + }), }; diff --git a/src/shared/constants/query-key.ts b/src/shared/constants/query-key.ts index 45c48e33..793b698f 100644 --- a/src/shared/constants/query-key.ts +++ b/src/shared/constants/query-key.ts @@ -6,7 +6,7 @@ export const USER_KEY = { INFO: () => [...USER_KEY.ALL, 'info'] as const, NICKNAME: () => [...USER_KEY.ALL, 'nickname'] as const, LOGOUT: () => [...USER_KEY.ALL, 'logout'] as const, - EDIT_PROFILE: () => [...USER_KEY.ALL, 'edit'] as const + EDIT_PROFILE: () => [...USER_KEY.ALL, 'edit'] as const, } as const; export const AUTH_KEY = { From f3bda12885848a1c40f3b40d8761d0b64de0d025 Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 16:06:22 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20api=20=EC=97=B0=EA=B2=B0=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/edit-profile/edit-profile.tsx | 153 ++++++++++++------ .../edit-profile/schema/EditProfileSchema.ts | 8 +- src/shared/apis/user/user-mutations.ts | 4 +- 3 files changed, 110 insertions(+), 55 deletions(-) diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index 9609a8f5..a788ea51 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -2,10 +2,15 @@ import { userMutations } from '@apis/user/user-mutations'; import Button from '@components/button/button/button'; import Divider from '@components/divider/divider'; import Input from '@components/input/input'; +import { zodResolver } from '@hookform/resolvers/zod'; import { cn } from '@libs/cn'; import SelectionGroup from '@pages/edit-profile/components/selection-group'; import { PROFILE_SYNC_MATE } from '@pages/edit-profile/constants/edit-profile'; import { mockEditData } from '@pages/edit-profile/mocks/mockEditData'; +import { + EditProfileSchema, + type EditProfileValues, +} from '@pages/edit-profile/schema/EditProfileSchema'; import { GENDER, NO_TEAM_OPTION, @@ -16,18 +21,46 @@ import { INFORMATION_RULE_MESSAGE, NICKNAME_RULE_MESSAGE } from '@pages/sign-up/ import { INFORMATION_PLACEHOLDER, NICKNAME_PLACEHOLDER } from '@pages/sign-up/constants/validation'; import { useMutation } from '@tanstack/react-query'; import { useMemo, useRef, useState } from 'react'; +import { Controller, useForm } from 'react-hook-form'; const EditProfile = () => { - const [nickname, setNickname] = useState(''); - const [information, setInformation] = useState(''); - const [team, setTeam] = useState(mockEditData.team); const [gender, setGender] = useState(mockEditData.genderPreference); - const [mateTeam, setMateTeam] = useState(mockEditData.teamAllowed || '상관없어요'); - const [viewStyle, setViewStyle] = useState(mockEditData.style); + const [mateTeam, setMateTeam] = useState(mockEditData.teamAllowed[0] || ''); + const [viewStyle, setViewStyle] = useState(mockEditData.style[0] || ''); const [isSubmit, setIsSubmit] = useState(false); -const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); + const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); + + const { + control, + handleSubmit, + formState: { isSubmitting, dirtyFields }, + watch, + } = useForm({ + resolver: zodResolver(EditProfileSchema), + mode: 'onChange', + defaultValues: { + nickname: '', + information: '', + }, + }); + + const informationValue = watch('information', ''); + + const onSubmitNickname = (values: EditProfileValues) => { + editProfile({ + field: '닉네임', + value: values.nickname.trim(), + }); + }; + + const onSubmitInformation = (values: EditProfileValues) => { + editProfile({ + field: '소개', + value: values.information.trim(), + }); + }; const initialValue = useRef({ team: mockEditData.team, @@ -38,7 +71,6 @@ const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); const isMatchDirty = useMemo(() => { const init = initialValue.current; - return ( team !== init.team || gender !== init.gender || @@ -51,39 +83,69 @@ const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); const handleSaveClick = () => { if (!isMatchDirty) return; - setIsSubmit(true); - - // TODO: 실제 API 호출 + // TODO: 매칭 조건 API 호출 }; - - return (

프로필 수정

- -
-
- - -
-
+
+ ( + + )} + /> +
+
+ + +
+ ( + + )} + /> +
+
+
@@ -95,23 +157,19 @@ const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE());

수정한 조건을 기반으로 새로운 메이트를 추천해드려요!

-

응원팀

- {TEAMS.map((option) => { - const selected = team === option; - return ( -
- - - ; \ No newline at end of file +export type EditProfileValues = z.infer; diff --git a/src/shared/apis/user/user-mutations.ts b/src/shared/apis/user/user-mutations.ts index 0687de5b..29ba2c52 100644 --- a/src/shared/apis/user/user-mutations.ts +++ b/src/shared/apis/user/user-mutations.ts @@ -45,7 +45,7 @@ export const userMutations = { queryClient.invalidateQueries({ queryKey: USER_KEY.ALL }); }, onError: (err) => { - console.error('수정에 실패했어요', err) - } + console.error('수정에 실패했어요', err); + }, }), }; From a24ff62b72ae78470fe274385e13fa31ce08b6b8 Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 16:06:53 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20zod=20=EC=95=9E=20type=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/edit-profile/schema/EditProfileSchema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/edit-profile/schema/EditProfileSchema.ts b/src/pages/edit-profile/schema/EditProfileSchema.ts index 1d0e6f59..f2ceea10 100644 --- a/src/pages/edit-profile/schema/EditProfileSchema.ts +++ b/src/pages/edit-profile/schema/EditProfileSchema.ts @@ -1,5 +1,5 @@ import { NicknameSchema } from '@pages/sign-up/schema/validation-schema'; -import { z } from 'zod'; +import type { z } from 'zod'; export const EditProfileSchema = NicknameSchema.pick({ nickname: true, From 42dfe33f4eebff01cdd4344c95bf990733317f7a Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 16:27:00 +0900 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20put=20=EB=A9=94=EC=86=8C=EB=93=9C?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/edit-profile/edit-profile.tsx | 136 +++++++++++++----------- src/shared/apis/base/http.ts | 4 + src/shared/apis/user/user-mutations.ts | 4 +- 3 files changed, 79 insertions(+), 65 deletions(-) diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index a788ea51..1600802a 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -26,16 +26,17 @@ import { Controller, useForm } from 'react-hook-form'; const EditProfile = () => { const [team, setTeam] = useState(mockEditData.team); const [gender, setGender] = useState(mockEditData.genderPreference); - const [mateTeam, setMateTeam] = useState(mockEditData.teamAllowed[0] || ''); - const [viewStyle, setViewStyle] = useState(mockEditData.style[0] || ''); + const [mateTeam, setMateTeam] = useState(mockEditData.teamAllowed?.[0] ?? ''); + const [viewStyle, setViewStyle] = useState(mockEditData.style?.[0] ?? ''); const [isSubmit, setIsSubmit] = useState(false); const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); const { control, - handleSubmit, - formState: { isSubmitting, dirtyFields }, + formState: { errors, isSubmitting }, + trigger, + getValues, watch, } = useForm({ resolver: zodResolver(EditProfileSchema), @@ -46,19 +47,24 @@ const EditProfile = () => { }, }); - const informationValue = watch('information', ''); + const nicknameVal = watch('nickname', ''); + const informationVal = watch('information', ''); - const onSubmitNickname = (values: EditProfileValues) => { + const submitNickname = async () => { + const ok = await trigger('nickname'); + if (!ok) return; editProfile({ field: '닉네임', - value: values.nickname.trim(), + value: getValues('nickname').trim(), }); }; - const onSubmitInformation = (values: EditProfileValues) => { + const submitInformation = async () => { + const ok = await trigger('information'); + if (!ok) return; editProfile({ field: '소개', - value: values.information.trim(), + value: getValues('information').trim(), }); }; @@ -90,62 +96,62 @@ const EditProfile = () => { return (

프로필 수정

+ + {/* 닉네임 */}
-
- ( - - )} - /> -
-
- - -
- ( - - )} + )} + /> +
+
- + )} + /> +
+
@@ -157,6 +163,7 @@ const EditProfile = () => {

수정한 조건을 기반으로 새로운 메이트를 추천해드려요!

+

응원팀

@@ -166,14 +173,14 @@ const EditProfile = () => { key={option} label={option} variant={team === option ? 'skyblue' : 'gray2'} - className="cap_14_sb w-auto px-[1.6rem] py-[0.6rem] text-gray-900" + className="cap_14_sb w-auto px-[1.6rem] py-[0.6rem]" onClick={() => setTeam(option)} /> ))}
+ { onSelect={setMateTeam} disabled={team === NO_TEAM_OPTION} /> + + (...args: Parameters): Promise { export function patch(...args: Parameters): Promise { return instance.patch(...args).then((res) => res.data); } + +export function put(...args: Parameters): Promise { + return instance.put(...args).then((res) => res.data); +} diff --git a/src/shared/apis/user/user-mutations.ts b/src/shared/apis/user/user-mutations.ts index 29ba2c52..c0fc3bb8 100644 --- a/src/shared/apis/user/user-mutations.ts +++ b/src/shared/apis/user/user-mutations.ts @@ -1,4 +1,4 @@ -import { post } from '@apis/base/http'; +import { post, put } from '@apis/base/http'; import { END_POINT } from '@constants/api'; import { USER_KEY } from '@constants/query-key'; import queryClient from '@libs/query-client'; @@ -40,7 +40,7 @@ export const userMutations = { EDIT_PROFILE: () => mutationOptions({ mutationKey: USER_KEY.EDIT_PROFILE(), - mutationFn: () => post(END_POINT.POST_EDIT_PROFILE), + mutationFn: ({ field, value }) => put(END_POINT.POST_EDIT_PROFILE, { field, value }), onSuccess: async () => { queryClient.invalidateQueries({ queryKey: USER_KEY.ALL }); }, From e88fe200915ddabdbb21c879a49f723ecc75df8a Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 17:04:54 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=B4=88=EA=B8=B0=EA=B0=92=20get=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/edit-profile/edit-profile.tsx | 75 ++++++++++++------------- src/shared/apis/user/user-queries.ts | 8 ++- src/shared/constants/api.ts | 1 + src/shared/constants/query-key.ts | 1 + src/shared/types/user-types.ts | 12 ++++ 5 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index 1600802a..3e597a41 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -1,4 +1,5 @@ import { userMutations } from '@apis/user/user-mutations'; +import { userQueries } from '@apis/user/user-queries'; import Button from '@components/button/button/button'; import Divider from '@components/divider/divider'; import Input from '@components/input/input'; @@ -6,7 +7,6 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { cn } from '@libs/cn'; import SelectionGroup from '@pages/edit-profile/components/selection-group'; import { PROFILE_SYNC_MATE } from '@pages/edit-profile/constants/edit-profile'; -import { mockEditData } from '@pages/edit-profile/mocks/mockEditData'; import { EditProfileSchema, type EditProfileValues, @@ -19,15 +19,17 @@ import { } from '@pages/onboarding/constants/onboarding'; import { INFORMATION_RULE_MESSAGE, NICKNAME_RULE_MESSAGE } from '@pages/sign-up/constants/NOTICE'; import { INFORMATION_PLACEHOLDER, NICKNAME_PLACEHOLDER } from '@pages/sign-up/constants/validation'; -import { useMutation } from '@tanstack/react-query'; -import { useMemo, useRef, useState } from 'react'; +import { useMutation, useQuery } from '@tanstack/react-query'; +import { useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; const EditProfile = () => { - const [team, setTeam] = useState(mockEditData.team); - const [gender, setGender] = useState(mockEditData.genderPreference); - const [mateTeam, setMateTeam] = useState(mockEditData.teamAllowed?.[0] ?? ''); - const [viewStyle, setViewStyle] = useState(mockEditData.style?.[0] ?? ''); + const { data } = useQuery(userQueries.MATCH_CONDITION()); + + const [team, setTeam] = useState(undefined); + const [gender, setGender] = useState(undefined); + const [mateTeam, setMateTeam] = useState(undefined); + const [viewStyle, setViewStyle] = useState(undefined); const [isSubmit, setIsSubmit] = useState(false); const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); @@ -41,10 +43,7 @@ const EditProfile = () => { } = useForm({ resolver: zodResolver(EditProfileSchema), mode: 'onChange', - defaultValues: { - nickname: '', - information: '', - }, + defaultValues: { nickname: '', information: '' }, }); const nicknameVal = watch('nickname', ''); @@ -53,37 +52,32 @@ const EditProfile = () => { const submitNickname = async () => { const ok = await trigger('nickname'); if (!ok) return; - editProfile({ - field: '닉네임', - value: getValues('nickname').trim(), - }); + editProfile({ field: '닉네임', value: getValues('nickname').trim() }); }; const submitInformation = async () => { const ok = await trigger('information'); if (!ok) return; - editProfile({ - field: '소개', - value: getValues('information').trim(), - }); + editProfile({ field: '소개', value: getValues('information').trim() }); }; - const initialValue = useRef({ - team: mockEditData.team, - gender: mockEditData.genderPreference, - mateTeam: mockEditData.teamAllowed, - viewStyle: mockEditData.style, - }); + const initial = { + team: data?.team ?? '', + gender: data?.genderPreference ?? '', + mateTeam: data?.teamAllowed ?? '', + viewStyle: data?.style?.replace(' ', '') ?? '', + }; + + const teamValue = team ?? initial.team; + const genderValue = gender ?? initial.gender; + const viewStyleValue = viewStyle ?? initial.viewStyle; + const mateTeamValue = (teamValue === NO_TEAM_OPTION ? '' : (mateTeam ?? initial.mateTeam)) ?? ''; - const isMatchDirty = useMemo(() => { - const init = initialValue.current; - return ( - team !== init.team || - gender !== init.gender || - mateTeam !== init.mateTeam || - viewStyle !== init.viewStyle - ); - }, [team, gender, mateTeam, viewStyle]); + const isMatchDirty = + teamValue !== initial.team || + genderValue !== initial.gender || + mateTeamValue !== initial.mateTeam || + viewStyleValue !== initial.viewStyle; const isSubmitDisabled = !isMatchDirty || isSubmit; @@ -158,6 +152,7 @@ const EditProfile = () => {
+ {/* 매칭 조건 */}

매칭 조건 수정

@@ -172,14 +167,14 @@ const EditProfile = () => {

diff --git a/src/shared/apis/user/user-queries.ts b/src/shared/apis/user/user-queries.ts index a3e5d2d0..e92d0dd7 100644 --- a/src/shared/apis/user/user-queries.ts +++ b/src/shared/apis/user/user-queries.ts @@ -2,7 +2,7 @@ import { get } from '@apis/base/http'; import { END_POINT } from '@constants/api'; import { USER_KEY } from '@constants/query-key'; import { queryOptions } from '@tanstack/react-query'; -import type { getUserInfoResponse } from '@/shared/types/user-types'; +import type { getMatchConditionResponse, getUserInfoResponse } from '@/shared/types/user-types'; export const userQueries = { ALL: () => queryOptions({ queryKey: USER_KEY.ALL }), @@ -18,4 +18,10 @@ export const userQueries = { queryKey: USER_KEY.INFO(), queryFn: () => get(END_POINT.USER_INFO), }), + + MATCH_CONDITION: () => + queryOptions({ + queryKey: USER_KEY.MATCH_CONDITION(), + queryFn: () => get(END_POINT.MATCH_CONDITION), + }), }; diff --git a/src/shared/constants/api.ts b/src/shared/constants/api.ts index e235a2f1..de527b61 100644 --- a/src/shared/constants/api.ts +++ b/src/shared/constants/api.ts @@ -13,6 +13,7 @@ export const END_POINT = { USER_INFO: '/v1/users/info', POST_INFO_NICKNAME: '/v1/users/info/nickname', POST_EDIT_PROFILE: '/v2/users/info', + MATCH_CONDITION: '/v2/users/match-condition', // 경기 관련 GET_GAME_SCHEDULE: (date: string) => `/v1/users/game/schedule?date=${date}`, diff --git a/src/shared/constants/query-key.ts b/src/shared/constants/query-key.ts index 793b698f..0a26f7ad 100644 --- a/src/shared/constants/query-key.ts +++ b/src/shared/constants/query-key.ts @@ -7,6 +7,7 @@ export const USER_KEY = { NICKNAME: () => [...USER_KEY.ALL, 'nickname'] as const, LOGOUT: () => [...USER_KEY.ALL, 'logout'] as const, EDIT_PROFILE: () => [...USER_KEY.ALL, 'edit'] as const, + MATCH_CONDITION: () => [...USER_KEY.ALL, 'match_condition'] as const, } as const; export const AUTH_KEY = { diff --git a/src/shared/types/user-types.ts b/src/shared/types/user-types.ts index 822639cb..e70b8c24 100644 --- a/src/shared/types/user-types.ts +++ b/src/shared/types/user-types.ts @@ -41,3 +41,15 @@ export interface postEditProfileRequest { field: string; value: string; } + +/** + * 매칭 조건 조회 + * get + * /v2/users/match-condition + */ +export interface getMatchConditionResponse { + team: string; + teamAllowed: string | null; + style: string; + genderPreference: string; +} From 2ab45b905cdc416ca47738fc078ce374a6a40aeb Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 17:37:05 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=88=98=EC=A0=95=20api=20=EC=97=B0=EA=B2=B0=20(#3?= =?UTF-8?q?25)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edit-profile/constants/edit-profile.ts | 15 +++++++++++ src/pages/edit-profile/edit-profile.tsx | 25 +++++++++++-------- src/shared/apis/user/user-mutations.ts | 10 +++++++- src/shared/types/user-types.ts | 12 +++++++++ 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/pages/edit-profile/constants/edit-profile.ts b/src/pages/edit-profile/constants/edit-profile.ts index 2b62bf94..ed25cfbe 100644 --- a/src/pages/edit-profile/constants/edit-profile.ts +++ b/src/pages/edit-profile/constants/edit-profile.ts @@ -1 +1,16 @@ export const PROFILE_SYNC_MATE = ['같은 팀 메이트', '상관없어요']; + +export const PROFILE_VIEWING_STYLE = [ + { + id: 1, + label: '열정 응원러', + }, + { + id: 2, + label: '경기 집중러', + }, + { + id: 3, + label: '직관 먹방러', + }, +]; diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index 3e597a41..a3480761 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -6,17 +6,15 @@ import Input from '@components/input/input'; import { zodResolver } from '@hookform/resolvers/zod'; import { cn } from '@libs/cn'; import SelectionGroup from '@pages/edit-profile/components/selection-group'; -import { PROFILE_SYNC_MATE } from '@pages/edit-profile/constants/edit-profile'; +import { + PROFILE_SYNC_MATE, + PROFILE_VIEWING_STYLE, +} from '@pages/edit-profile/constants/edit-profile'; import { EditProfileSchema, type EditProfileValues, } from '@pages/edit-profile/schema/EditProfileSchema'; -import { - GENDER, - NO_TEAM_OPTION, - TEAMS, - VIEWING_STYLE, -} from '@pages/onboarding/constants/onboarding'; +import { GENDER, NO_TEAM_OPTION, TEAMS } from '@pages/onboarding/constants/onboarding'; import { INFORMATION_RULE_MESSAGE, NICKNAME_RULE_MESSAGE } from '@pages/sign-up/constants/NOTICE'; import { INFORMATION_PLACEHOLDER, NICKNAME_PLACEHOLDER } from '@pages/sign-up/constants/validation'; import { useMutation, useQuery } from '@tanstack/react-query'; @@ -33,6 +31,7 @@ const EditProfile = () => { const [isSubmit, setIsSubmit] = useState(false); const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE()); + const { mutate: editMatchCondition } = useMutation(userMutations.EDIT_MATCH_CONDITION()); const { control, @@ -65,7 +64,7 @@ const EditProfile = () => { team: data?.team ?? '', gender: data?.genderPreference ?? '', mateTeam: data?.teamAllowed ?? '', - viewStyle: data?.style?.replace(' ', '') ?? '', + viewStyle: data?.style ?? '', }; const teamValue = team ?? initial.team; @@ -84,7 +83,13 @@ const EditProfile = () => { const handleSaveClick = () => { if (!isMatchDirty) return; setIsSubmit(true); - // TODO: 매칭 조건 API 호출 + + editMatchCondition({ + team: teamValue, + genderPreference: genderValue, + style: viewStyleValue, + teamAllowed: teamValue === NO_TEAM_OPTION ? null : mateTeamValue || null, + }); }; return ( @@ -194,7 +199,7 @@ const EditProfile = () => { diff --git a/src/shared/apis/user/user-mutations.ts b/src/shared/apis/user/user-mutations.ts index c0fc3bb8..e4bc6e19 100644 --- a/src/shared/apis/user/user-mutations.ts +++ b/src/shared/apis/user/user-mutations.ts @@ -1,4 +1,4 @@ -import { post, put } from '@apis/base/http'; +import { patch, post, put } from '@apis/base/http'; import { END_POINT } from '@constants/api'; import { USER_KEY } from '@constants/query-key'; import queryClient from '@libs/query-client'; @@ -6,6 +6,7 @@ import { mutationOptions } from '@tanstack/react-query'; import type { responseTypes } from '@/shared/types/base-types'; import type { postEditProfileRequest, + postMatchConditionRequest, postUserInfoNicknameRequest, postUserInfoRequest, } from '@/shared/types/user-types'; @@ -48,4 +49,11 @@ export const userMutations = { console.error('수정에 실패했어요', err); }, }), + + EDIT_MATCH_CONDITION: () => + mutationOptions({ + mutationKey: USER_KEY.MATCH_CONDITION(), + mutationFn: ({ team, teamAllowed, style, genderPreference }) => + patch(END_POINT.MATCH_CONDITION, { team, teamAllowed, style, genderPreference }), + }), }; diff --git a/src/shared/types/user-types.ts b/src/shared/types/user-types.ts index e70b8c24..80f97675 100644 --- a/src/shared/types/user-types.ts +++ b/src/shared/types/user-types.ts @@ -53,3 +53,15 @@ export interface getMatchConditionResponse { style: string; genderPreference: string; } + +/** + * 매칭 조건 수정 + * post + * /v2/users/match-condition + */ +export interface postMatchConditionRequest { + team: string; + teamAllowed: string | null; + style: string; + genderPreference: string; +} From 8e866e37b5c9149f6cbc345f722413c7120def1c Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 18:20:32 +0900 Subject: [PATCH 8/9] feat: conflict (#325) --- src/pages/edit-profile/edit-profile.tsx | 34 ++++++++----------- .../edit-profile/schema/EditProfileSchema.ts | 6 ++-- src/shared/apis/user/user-mutations.ts | 6 ++-- src/shared/apis/user/user-queries.ts | 2 +- src/shared/constants/api.ts | 4 +-- 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index e30d957d..9da8858d 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -15,22 +15,15 @@ import { type EditProfileValues, } from '@pages/edit-profile/schema/EditProfileSchema'; import { GENDER, NO_TEAM_OPTION, TEAMS } from '@pages/onboarding/constants/onboarding'; -import { INFORMATION_RULE_MESSAGE, NICKNAME_RULE_MESSAGE } from '@pages/sign-up/constants/NOTICE'; -import { INFORMATION_PLACEHOLDER, NICKNAME_PLACEHOLDER } from '@pages/sign-up/constants/validation'; -import { useMutation, useQuery } from '@tanstack/react-query'; -import { useState } from 'react'; -import { Controller, useForm } from 'react-hook-form'; - GENDER, - NO_TEAM_OPTION, - TEAMS, - VIEWING_STYLE, -} from '@pages/onboarding/constants/onboarding'; import { INTRODUCTION_RULE_MESSAGE, NICKNAME_RULE_MESSAGE } from '@pages/sign-up/constants/NOTICE'; import { INTRODUCTION_PLACEHOLDER, NICKNAME_PLACEHOLDER, } from '@pages/sign-up/constants/validation'; -import { useMemo, useRef, useState } from 'react'; +import { useMutation, useQuery } from '@tanstack/react-query'; +import { useState } from 'react'; +import { Controller, useForm } from 'react-hook-form'; + const EditProfile = () => { const { data } = useQuery(userQueries.MATCH_CONDITION()); @@ -53,11 +46,11 @@ const EditProfile = () => { } = useForm({ resolver: zodResolver(EditProfileSchema), mode: 'onChange', - defaultValues: { nickname: '', information: '' }, + defaultValues: { nickname: '', introduction: '' }, }); const nicknameVal = watch('nickname', ''); - const informationVal = watch('information', ''); + const introductionVal = watch('introduction', ''); const submitNickname = async () => { const ok = await trigger('nickname'); @@ -66,9 +59,9 @@ const EditProfile = () => { }; const submitInformation = async () => { - const ok = await trigger('information'); + const ok = await trigger('introduction'); if (!ok) return; - editProfile({ field: '소개', value: getValues('information').trim() }); + editProfile({ field: '소개', value: getValues('introduction').trim() }); }; const initial = { @@ -135,28 +128,29 @@ const EditProfile = () => {
( 0} - length={informationVal.length} + length={introductionVal.length} hasLength className="h-[10.4rem]" label="한 줄 소개" multiline /> )} + />
diff --git a/src/pages/edit-profile/schema/EditProfileSchema.ts b/src/pages/edit-profile/schema/EditProfileSchema.ts index f2ceea10..e3d81789 100644 --- a/src/pages/edit-profile/schema/EditProfileSchema.ts +++ b/src/pages/edit-profile/schema/EditProfileSchema.ts @@ -1,9 +1,9 @@ -import { NicknameSchema } from '@pages/sign-up/schema/validation-schema'; +import { UserInfoSchema } from '@pages/sign-up/schema/validation-schema'; import type { z } from 'zod'; -export const EditProfileSchema = NicknameSchema.pick({ +export const EditProfileSchema = UserInfoSchema.pick({ nickname: true, - information: true, + introduction: true, }); export type EditProfileValues = z.infer; diff --git a/src/shared/apis/user/user-mutations.ts b/src/shared/apis/user/user-mutations.ts index 5eb082c4..287d42a7 100644 --- a/src/shared/apis/user/user-mutations.ts +++ b/src/shared/apis/user/user-mutations.ts @@ -7,12 +7,12 @@ import { ROUTES } from '@routes/routes-config'; import { mutationOptions } from '@tanstack/react-query'; import type { responseTypes } from '@/shared/types/base-types'; import type { + postAgreementInfoRequest, postEditProfileRequest, postMatchConditionRequest, postUserInfoRequest, } from '@/shared/types/user-types'; - export const userMutations = { USER_INFO: () => mutationOptions({ @@ -41,13 +41,14 @@ export const userMutations = { console.error('로그아웃 실패', err); }, }), - + EDIT_PROFILE: () => mutationOptions({ mutationKey: USER_KEY.EDIT_PROFILE(), mutationFn: ({ field, value }) => put(END_POINT.POST_EDIT_PROFILE, { field, value }), onSuccess: async () => { queryClient.invalidateQueries({ queryKey: USER_KEY.ALL }); + window.location.reload(); }, onError: (err) => { console.error('수정에 실패했어요', err); @@ -59,6 +60,7 @@ export const userMutations = { mutationKey: USER_KEY.MATCH_CONDITION(), mutationFn: ({ team, teamAllowed, style, genderPreference }) => patch(END_POINT.MATCH_CONDITION, { team, teamAllowed, style, genderPreference }), + }), AGREEMENT_INFO: () => mutationOptions({ diff --git a/src/shared/apis/user/user-queries.ts b/src/shared/apis/user/user-queries.ts index e92d0dd7..1f4ace60 100644 --- a/src/shared/apis/user/user-queries.ts +++ b/src/shared/apis/user/user-queries.ts @@ -16,7 +16,7 @@ export const userQueries = { USER_INFO: () => queryOptions({ queryKey: USER_KEY.INFO(), - queryFn: () => get(END_POINT.USER_INFO), + queryFn: () => get(END_POINT.GET_USER_INFO), }), MATCH_CONDITION: () => diff --git a/src/shared/constants/api.ts b/src/shared/constants/api.ts index 5854b912..d1724fef 100644 --- a/src/shared/constants/api.ts +++ b/src/shared/constants/api.ts @@ -10,12 +10,12 @@ export const END_POINT = { // 유저 관련 GET_KAKAO_INFO: '/v1/users/kakao/info', + AGREEMENT_INFO: '/v2/users/consent', USER_INFO: '/v2/users/info', + GET_USER_INFO: '/v1/users/info', POST_INFO_NICKNAME: '/v1/users/info/nickname', POST_EDIT_PROFILE: '/v2/users/info', MATCH_CONDITION: '/v2/users/match-condition', - AGREEMENT_INFO: '/v2/users/consent', - // 경기 관련 GET_GAME_SCHEDULE: (date: string) => `/v1/users/game/schedule?date=${date}`, From 73b055f5ba39eb200ef06ebedf84d33372604d5d Mon Sep 17 00:00:00 2001 From: heesunee Date: Sun, 31 Aug 2025 18:20:57 +0900 Subject: [PATCH 9/9] feat: sort (#325) --- src/pages/edit-profile/edit-profile.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/edit-profile/edit-profile.tsx b/src/pages/edit-profile/edit-profile.tsx index 9da8858d..cdfa95e6 100644 --- a/src/pages/edit-profile/edit-profile.tsx +++ b/src/pages/edit-profile/edit-profile.tsx @@ -24,7 +24,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; - const EditProfile = () => { const { data } = useQuery(userQueries.MATCH_CONDITION());